- Fix handling of
Stream#read(0), it must return a mutable string (or clear the given buffer).
- Introduce
Protocol::HTTP::RefusedErrorfor indicating a stream or request was refused before processing and can be safely retried.RequestRefusedErroris provided as an alias for backwards compatibility.
- Expose
Protocol::HTTP::Body::Writable#countattribute to provide access to the number of chunks written to the body.
- Introduce
Protocol::HTTP::Middleware.loadmethod for loading middleware applications from files. - Prevent
ZLib::BufErrorwhen deflating empty chunks by skipping deflation for empty chunks.
Protocol::HTTP::DuplicateHeaderErrornow includes the existing and new values for better debugging.
- Move trailer validation to
Headers#addmethod to ensure all additions are checked at the time of addition as this is a hard requirement. - Introduce
Headers#headermethod to enumerate only the main headers, excluding trailers. This can be used after invokingHeaders#trailer!to avoid race conditions. - Fix
Headers#to_hso that indexed headers are not left in an inconsistent state if errors occur during processing.
- Always use
#parsewhen parsing header values from strings to ensure proper normalization and validation. - Introduce
Protocol::HTTP::InvalidTrailerErrorwhich is raised when a trailer header is not allowed by the current policy. - Breaking:
Headers#eachnow yields parsed values according to the current policy. For the previous behaviour, useHeaders#fields.
- Introduce
Header::*.parse(value)which parses a raw header value string into a header instance. - Introduce
Header::*.coerce(value)which coerces any value (String,Array, etc.) into a header instance with normalization. Header::*#initializenow accepts arrays without normalization for efficiency, or strings for backward compatibility.- Update
Headers#[]=to usecoerce(value)for smart conversion of user input. - Normalization (e.g., lowercasing) is applied by
parse,coerce, and<<methods, but not bynewwhen given arrays.
- Breaking: Move
Protocol::HTTP::Header::QuotedStringtoProtocol::HTTP::QuotedStringfor better reusability. - Breaking: Handle cookie key/value pairs using
QuotedStringas per RFC 6265.- Don't use URL encoding for cookie key/value.
- Breaking: Remove
Protocol::HTTP::URLandProtocol::HTTP::Reference– replaced byProtocol::URLgem.Protocol::HTTP::URL->Protocol::URL::Encoding.Protocol::HTTP::Reference->Protocol::URL::Reference.
- Introduce rich support for
Header::Digest,Header::ServerTiming,Header::TE,Header::TrailerandHeader::TransferEncoding.
This release introduces significant security improvements for HTTP trailer handling, addressing potential HTTP request smuggling vulnerabilities by implementing a restrictive-by-default policy for trailer headers.
- Security-by-default: HTTP trailers are now validated and restricted by default to prevent HTTP request smuggling attacks.
- Only safe headers are permitted in trailers:
date- Response generation timestamps (safe metadata)digest- Content integrity verification (safe metadata)etag- Cache validation tags (safe metadata)server-timing- Performance metrics (safe metadata)
- All other trailers are ignored by default.
If you are using this library for gRPC, you will need to use a custom policy to allow the grpc-status and grpc-message trailers:
module GRPCStatus
def self.new(value)
Integer(value)
end
def self.trailer?
true
end
end
module GRPCMessage
def self.new(value)
value
end
def self.trailer?
true
end
end
GRPC_POLICY = Protocol::HTTP::Headers::POLICY.dup
GRPC_POLICY["grpc-status"] = GRPCStatus
GRPC_POLICY["grpc-message"] = GRPCMessage
# Reinterpret the headers using the new policy:
response.headers.policy = GRPC_POLICY
response.headers["grpc-status"] # => 0
response.headers["grpc-message"] # => "OK"- Improve consistency of Body
#inspect. - Improve
as_jsonsupport for Body wrappers.
- Add
Protocol::HTTP::Headers#to_amethod that returns the fields array, providing compatibility with standard Ruby array conversion pattern. - Expose
tailinHeaders.newso that trailers can be accurately reproduced. - Add agent context.
Protocol::HTTP::Headersnow raise aDuplicateHeaderErrorwhen a duplicate singleton header (e.g.content-length) is added.Protocol::HTTP::Headers#addnow coerces the value to a string when adding a header, ensuring consistent behaviour.Protocol::HTTP::Body::Head.fornow accepts an optionallengthparameter, allowing it to create a head body even when the body is not provided, based on the known content length.
- Drop support for Ruby v3.1.
- Add support for parsing
accept,accept-charset,accept-encodingandaccept-languageheaders into structured values.
- Add support for
priority:header.
- Clarify behaviour of streaming bodies and copy
Protocol::Rack::Body::StreamingtoProtocol::HTTP::Body::Streamable. - Copy
Async::HTTP::Body::WritabletoProtocol::HTTP::Body::Writable.
- Ensure chunks are flushed if required, when streaming.
The Request[] and Response[] methods now support keyword arguments as a convenient way to set various positional arguments.
# Request keyword arguments:
client.get("/", headers: {"accept" => "text/html"}, authority: "example.com")
# Response keyword arguments:
def call(request)
return Response[200, headers: {"content-Type" => "text/html"}, body: "Hello, World!"]
endThe Request class now exposes a #interim_response attribute which can be used to handle interim responses both on the client side and server side.
On the client side, you can pass a callback using the interim_response keyword argument which will be invoked whenever an interim response is received:
client = ...
interim_response = proc do |status, headers|
puts "Received interim response: #{status} -> #{headers.inspect}"
end
response = client.get("/index", interim_response: interim_response)On the server side, you can send an interim response using the #send_interim_response method:
def call(request)
if request.headers["expect"] == "100-continue"
# Send an interim response:
request.send_interim_response(100)
end
# ...
end- Introduce
rewindandrewindable?methods for body rewinding capabilities. - Add support for output buffer in
read_partial/readpartialmethods. Reader#buffered!now returnsselffor method chaining.
- Add convenient
Reader#buffered!method to buffer the body. - Modernize gem infrastructure with RuboCop integration.
- Expand stream interface to support
gets/putsoperations. - Skip empty key/value pairs in header processing.
- Prefer lowercase method names for consistency.
- Add
as_jsonsupport to avoid default Rails implementation. - Use
@callbackto track invocation state. - Drop
base64gem dependency.
- Prefer connection
closeoverkeep-alivewhen both are present. - Add support for
#readpartialmethod. - Add
base64dependency.
- Introduce explicit support for informational responses (1xx status codes).
- Add
cache-controlsupport formust-revalidate,proxy-revalidate, ands-maxagedirectives. - Add
#strong_match?and#weak_match?methods toETagsheader. - Fix
last-modified,if-modified-sinceandif-unmodified-sinceheaders to use properDateparsing. - Improve date/expires header parsing.
- Add tests for
Stream#close_read. - Check if input is closed before raising
IOError. - Ensure saved files truncate existing file by default.
- Add output stream
#<<as alias for#write. - Add support for
Headers#include?and#key?methods. - Fix URL unescape functionality.
- Fix cookie parsing issues.
- Fix superclass mismatch in
Protocol::HTTP::Middleware::Builder. - Allow trailers without explicit
trailerheader. - Fix cookie handling and Ruby 2 keyword arguments.
- Improve argument handling.
- Rename
pathparameter totargetto better match RFCs.
- Rename
trailerstotrailerfor consistency.
- Streaming interface improvements.
- Rename
StreamabletoCompletable.
- Improve
Authorizationheader implementation.
- Expose
Body#ready?for more efficient response handling.
- Add
#trailersmethod which enumerates trailers without marking tail. - Don't clear trailers in
#dup, move functionality toflatten!. - All requests and responses must have mutable headers instance.
- Remove deferred headers due to complexity.
- Remove deprecated
Headers#slice!. - Add support for static, dynamic and streaming content to
cache-controlmodel. - Initial support for trailers.
- Add support for
Response#not_modified?.
- Add support for
if-matchandif-none-matchheaders. - Revert
Request#targetchange for HTTP/2 compatibility.
- Prefer
Request#targetoverRequest#path. - Add body implementation to support HEAD requests.
- Add support for computing digest on buffered body.
- Add
Headers#set(key, value)to replace existing values. - Add support for
varyheader. - Add support for
no-cache&no-storecache directives.
- Add
Cacheablebody for buffering and caching responses. - Add support for
cache-controlheader.
- Add support for
connectionheader. - Fix handling of keyword arguments.
- Improved handling of
cookieheader. - Add
Headers#clearmethod.
- Ensure
Body#callinvokesstream.closewhen done.
- Allow user to specify size for character devices.
- Add support for
authorizationheader.
- Remove
reasonfromResponse.
- Explicit path handling in
Reference#with.
- Initial version with basic HTTP protocol support.
- Fix path splitting behavior when path is empty.
- Add
connectmethod. - Support protocol in
[]constructor. - Incorporate middleware functionality.
- Add
Request,ResponseandBodyclasses fromasync-http. - Allow deletion of non-existent header fields.
- Initial release of
protocol-httpgem. - Initial implementation of HTTP/2 flow control.
- Support for connection preface and settings frames.
- Initial headers support.
- Implementation of
Connection,Client&Serverclasses. - HTTP/2 protocol framing and headers.