Skip to content

Releases

v0.4.0

Choose a tag to compare

@github-actions github-actions released this 09 Nov 07:25
77e0afa
  • Requires base-scheduler 0.5, base-pool 0.5 and base-endpoint 0.3. This is a breaking change: scheduler, pool and endpoint types such as Cancellation and ReadableStream appear in the public API, so callers must use the same versions. The HTTP crates read sockets only through read_into and try_read_into, whose readiness contract scheduler 0.5 leaves unchanged, so HTTP/1 input and the client's idle-connection check are unaffected by its wider readiness rule. The Tokio adapter's read_into now clears readiness after a short read on Linux and Android, which that contract already allowed. Scheduler 0.5 removes the Direct backend; run on base-scheduler-native or base-scheduler-tokio instead.
  • Add base-http-content, which reads a request's body into a structure declared with base-web-content's #[derive(Content)]. read_content chooses the format from the request's Content-Type, refuses a request whose Content-Length exceeds the largest body the declaration could accept with 413 before reading any of it, reads the body frame by frame as it arrives, and streams uploads to an UploadStore. When the content is refused, or reading or storing fails, it aborts the upload in progress, removes every upload it stored, and closes the body. ReadError::status gives one status for each failure: 413, the content error's own 400, 413 or 415, 422 for violations, 400 for a malformed Content-Type or a body that fails, and 500 for a store that fails. FileStore saves each upload to a new file at a path the application chooses from the field's declared path, never from the submitted filename: it creates the file exclusively, refusing anything at the path including a symbolic link, with permissions 0600 on Unix by default, removes it when the upload is aborted, as read_content does whenever writing it fails, and does its file I/O on the scheduler's blocking threads. NoUploads reads declarations without uploads. Cleanup is asynchronous, so a read whose future is dropped, as base-http-server drops a handler's future at shutdown, leaves what it stored in place. The package depends on base-http, base-web-content, base-web-media-type and the scheduler interface, not on a server or protocol codec.
  • base-http adds Status::UNPROCESSABLE_CONTENT (422).
  • base-http's license.md and the headers of its messages, fields and bodies, which are ported from protocol-http, again credit the authors and years of the files they derive from, restoring the copyright lines that the first release's license update replaced.

v0.3.0

Choose a tag to compare

@github-actions github-actions released this 03 Nov 04:46
90d6b1f
  • base-http1 drops trailers on HTTP/1.0 instead of refusing them. HTTP/1.0 has no chunked framing, so trailers cannot be carried, and HTTP semantics let a recipient discard them. Previously an HTTP/1.0 request whose body reported may_have_trailers, which every BodyReader does, was refused with "trailers require HTTP/1.1 chunked framing", and a response to an HTTP/1.0 client failed when its body produced trailers. An HTTP/1.0 request body of known length is now sent with Content-Length, and a response is sent with its length or close-delimited; trailers either produces are validated and then dropped. This applies to RequestWriter::write_request, RequestWriter::write_frame and ResponseWriter::write_response, so it reaches base-http-client and base-http-server. An HTTP/1.0 request body of unknown length is still refused, but now with "HTTP/1.0 request requires a body length", since an HTTP/1.0 request cannot be close-delimited. A Trailer field, which is only a hint, no longer causes an HTTP/1.0 request or response to be refused; it is sent as an ordinary field. A 205 response to an HTTP/1.0 client whose body may have trailers now declares Content-Length: 0 instead of being close-delimited. A Trailer field no longer selects chunked framing on HTTP/1.1 either; framing follows the body, and the field is sent as an ordinary field.
  • base-http1 sends an HTTP/1.1 request of known length with Content-Length even when its body may have trailers, and drops any trailers it produces after validating them. Previously such a request, including every BodyReader::with_length upload and any imperative request with a Trailer field, was chunked. Request trailers are rare, a client cannot assume the server accepts Transfer-Encoding, and servers that require a length answer a chunked upload with 411. The length comes from the body or from the content_length given to RequestWriter::begin_request, so a base-http-client request opened with a content_length behaves the same; writing trailers to it no longer fails. A request of unknown length is still chunked and keeps its trailers. Responses are unchanged: a response body that may have trailers is chunked even when its length is known, while one that cannot have them, such as a BufferedBody or a received Content-Length or close-delimited body being forwarded, keeps Content-Length, and HEAD, 204 and 304 responses take no framing.
  • A body of known length now decides the length a message sends. base-http1 previously refused a request or response whose typed content_length contradicted its body's length with LengthMismatch, which the server answered with a 500 and the client reported as an error. This usually came from stale metadata, such as a proxy that replaced a body but kept the received content_length. The typed declaration is now ignored and any generated Content-Length comes from the body. A response without data, to HEAD or with 304, still uses its declaration, a 204 still refuses one, a raw Content-Length field the body contradicts is still refused, a declared length alongside a raw Transfer-Encoding is still refused, and a declared length on a body of unknown length is still enforced while the body is written. base-http adds RequestMetadata::declared_length and ResponseMetadata::declared_length, which apply the rule and which every codec uses, and Request::length and Response::length, which return the resulting length for a message that sends data.
  • base-http-server responds with 500 Internal Server Error when a handler returns a final response that HTTP/1 cannot send, such as an informational status, conflicting Content-Length and Transfer-Encoding fields, or an unsolicited upgrade. Previously the connection closed without writing anything, so the client saw an empty reply. Because the writer refuses such a response before writing any of it, the server can still send a best-effort bodiless 500 with Connection: close, after any interim responses the handler sent, and then closes the connection. Serving the connection reports the new Error::Response, whose source is the refusal, instead of Error::Protocol. A failure after the response has started still only closes the connection. This is a breaking change: Error gains a public variant.
  • base-http-server responds to a handler error with 400 Bad Request or 500 Internal Server Error. Previously a handler Err closed the connection without writing a response, so the client saw an empty reply. The server now writes a best-effort bodiless response with Connection: close, after any interim responses the handler sent, then always closes the connection. The status is 400 when reading the request failed, for example because the handler propagated a malformed or truncated body error, and 500 otherwise. base-http1 adds RequestReader::is_poisoned, which reports a failed read. Serving the connection still reports Error::Handler, so serve counts it in Statistics::failed_connections. An error caused by cancellation still closes without a response, and a body failure after the response has started still closes the connection.
  • base-http-client checks an idle pooled connection before reusing it. A connection the server closed while idle, for example after its keep-alive timeout, was previously handed to the next request, which failed with "truncated HTTP/1 message". Before sending any request bytes on a connection that has already completed an exchange, the client now attempts one immediate read on it with ReadableStream::try_read_into, which reaches the transport rather than any readiness the scheduler has cached, so it observes a close the operating system has already received. If the read finds data, EOF or an error, including a TLS close notification, the client retires the connection and the request uses another or a new one. TLS records that carry no application data, such as key updates, keep the connection. A server can still close a connection after the check or during the exchange, so that request still fails, and requests are not retried. base-http1 adds ResponseReader::probe_viable, which performs the check.
  • base-http-server listeners survive transient accept failures. serve and serve_tls previously stopped accepting on any accept error, then joined their connections before closing the listener, so a single ECONNABORTED or EMFILE left the port open with nothing accepting. Failures belonging to one pending peer (ECONNABORTED, ECONNRESET, ECONNREFUSED, EINTR including Windows WSAEINTR, EAGAIN, EPROTO, network-down or unreachable errors and, on Linux, EPERM firewall rejections and the pending-peer errors ENOPROTOOPT, EHOSTDOWN and ENONET) are retried immediately, backing off after 16 consecutive failures so a persistent one cannot spin. Resource exhaustion (EMFILE, ENFILE, ENOBUFS, ENOMEM, and Windows WSAEMFILE and WSAENOBUFS) pauses acceptance for 100 ms on the scheduler's clock, honouring cancellation, while existing connections continue. Both are counted in the new Statistics::accept_errors. Any other accept failure, including scheduler closure, EACCES and EOPNOTSUPP, or a failed backoff wait, still ends serving with an error, which now takes precedence over a consequent listener close failure. On every shutdown the listener now closes before active connections are cancelled and joined, so new peers are refused immediately. This is a breaking change: serve and serve_tls now require the scheduler to implement Clock, which every Base scheduler backend provides, and Statistics gains a public field.
  • Requires base-scheduler 0.4, base-pool 0.4 and base-endpoint 0.2. The idle-connection check relies on the new ReadableStream::try_read_into. This is a breaking change: scheduler and pool types such as Cancellation appear in the public API, so callers must use the same versions.

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 31 Oct 05:30
73d7dfc
  • base-http-client and base-http-server disable Nagle's algorithm (TCP_NODELAY) on each TCP connection they establish or accept, so small writes such as streamed frames on long-lived duplex exchanges are not delayed by Nagle's algorithm interacting with delayed acknowledgements. Set the new Options::tcp_nodelay to false to leave the socket options unchanged. Setting the option is best effort and does not fail a connection. This is a breaking change: Options in both crates gains the public tcp_nodelay field, so struct literals need it or ..Default::default(), and Client::new, serve and serve_tls now require the scheduler to implement SocketSetOption<TcpNoDelay>, which every Base scheduler backend provides. serve_connection leaves the options of a caller-accepted socket unchanged.
  • base-http1 incoming body reads are cancellation safe. Dropping a pending read, or cancelling its wait, loses no input, so a later read resumes at the same position. Previously any later read failed with "previous body read failed or was abandoned". A read that fails for another reason still fails every later read, now with "previous body read failed".

v0.1.0

Choose a tag to compare

@github-actions github-actions released this 30 Oct 09:27
8e9a72c
  • First release of base-http, base-http1, base-http-protocol, base-http-client and base-http-server. base-http defines runtime-independent HTTP semantics: requests and responses, methods, statuses, versions, request targets, ordered fields with header interpretation and combination policies, interim responses, and buffered and streaming bodies. Constructing messages and mapping bodies performs no I/O.
  • base-http1 implements native HTTP/1.0 and HTTP/1.1 framing over Base scheduler streams. It parses heads with a hand-written parser and handles fixed-length, chunked and close-delimited bodies, trailers and interim responses. The server side also manages 101 upgrades and CONNECT. base-http-protocol selects the protocol for a connection, including through ALPN.
  • base-http-client provides a cloneable client with an explicit driver that pools HTTP/1 connections through base-pool, over plain TCP or, with the rustls feature, TLS. base-http-server serves connections and listeners with a connection limit, over plain TCP or, with the rustls feature, TLS.
  • Errors report each cause once: an error either describes its cause in its message or returns it from source. A connection that fails to open is base_http_client::Error::Connect, which carries the endpoint address.
  • Requires Rust 1.87, base-scheduler 0.3, base-pool 0.3 and base-endpoint 0.1.