Repository navigation
Conversation
## Motivation and Context The streamable HTTP transport validates the `Host`, `Origin`, `Accept`, and `Content-Type` headers with `downcase`, `split`, and regexps. A Rack server hands header values over as ASCII-8BIT, where every byte is valid, but Rack::Test, `Rack::MockRequest`, and a framework that re-tags the env can pass them as UTF-8, and then a header carrying an invalid byte sequence makes those calls raise `ArgumentError`. For `Host` and `Origin` on any method and for `Accept` on a GET the exception escapes the Rack call, and on a POST the `Accept` and `Content-Type` checks turn it into a 500 with an exception report, instead of the rejection the check exists to produce. The transport now reads those headers as bytes, so both environments behave like a Rack server does: a `Host` or `Origin` carrying an invalid byte in the compared part answers 403, an `Accept` whose required media type carries one answers 406, and a `Content-Type` whose media type carries one answers 415. Nothing changes for ASCII values, which host names and media types are on the wire (an internationalized host travels as punycode). ## How Has This Been Tested? A new transport test sends each of the four headers with a trailing invalid byte in a UTF-8-tagged string and asserts the status and message the check produces. It errors with `ArgumentError: input string invalid` without the change. A second test sends such an `Accept` on a GET, which answers 406 now and raised before, since nothing rescues in `handle_get`. ## Breaking Changes An `allowed_hosts:` or `allowed_origins:` entry with a non-ASCII character no longer matches a header tagged UTF-8 in a test or framework environment; it never matched the bytes a Rack server hands over, so a deployment is unchanged.
atesgoral
approved these changes
Oct 30, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation and Context
The streamable HTTP transport validates the
Host,Origin,Accept, andContent-Typeheaders withdowncase,split, and regexps. A Rack server hands header values over as ASCII-8BIT, where every byte is valid, but Rack::Test,Rack::MockRequest, and a framework that re-tags the env can pass them as UTF-8, and then a header carrying an invalid byte sequence makes those calls raiseArgumentError. ForHostandOriginon any method and forAccepton a GET the exception escapes the Rack call, and on a POST theAcceptandContent-Typechecks turn it into a 500 with an exception report, instead of the rejection the check exists to produce.The transport now reads those headers as bytes, so both environments behave like a Rack server does: a
HostorOrigincarrying an invalid byte in the compared part answers 403, anAcceptwhose required media type carries one answers 406, and aContent-Typewhose media type carries one answers 415. Nothing changes for ASCII values, which host names and media types are on the wire (an internationalized host travels as punycode).How Has This Been Tested?
A new transport test sends each of the four headers with a trailing invalid byte in a UTF-8-tagged string and asserts the status and message the check produces. It errors with
ArgumentError: input string invalidwithout the change.A second test sends such an
Accepton a GET, which answers 406 now and raised before, since nothing rescues inhandle_get.Breaking Changes
An
allowed_hosts:orallowed_origins:entry with a non-ASCII character no longer matches a header tagged UTF-8 in a test or framework environment; it never matched the bytes a Rack server hands over, so a deployment is unchanged.Types of changes
Checklist