Conversation
## Motivation and Context `Discovery.parse_www_authenticate` walked the Bearer challenge's parameters by slicing the header at the cursor and trimming the slice for every `key=value` pair, which copies the remainder of the header each time. The cost therefore grew with the square of the header's length, and the header is the server's to choose: parsing one with 200,000 parameters took over 20 seconds, on every request that drew such a `401` or `403`, before the client could act on it. The walk now uses a `StringScanner`, which matches each pair at the current position without copying, so the cost grows with the length of the header. The scanner locates the Bearer challenge as well, so a header whose earlier challenge holds multibyte text yields the same parameters as before. The header is also the server's to fill. A value whose bytes are not valid in the string's encoding, such as a header tagged UTF-8 that carries a stray `0xFF`, made the patterns raise `ArgumentError` from inside the transport's `401` handling, ahead of any `AuthorizationError` a caller is prepared for; the default adapter hands header values over as ASCII-8BIT, where every byte is valid, so it took a caller-supplied adapter or a header re-tagged along the way. The header is now scrubbed before it is parsed, so such bytes become the replacement character and the other parameters still come through, while a binary header is unchanged by the scrub. ## How Has This Been Tested? New tests in `test/mcp/client/oauth/discovery_test.rb` parse a header with 200,000 parameters within a bound the previous implementation exceeded many times over, and a header whose earlier challenge holds multibyte text. Two more parse a UTF-8 header with an invalid byte inside a quoted value, which raised against the previous library, and a binary header with a high byte. ## Breaking Changes None.
atesgoral
approved these changes
Sep 23, 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
Discovery.parse_www_authenticatewalked the Bearer challenge's parameters by slicing the header at the cursor and trimming the slice for everykey=valuepair, which copies the remainder of the header each time. The cost therefore grew with the square of the header's length, and the header is the server's to choose: parsing one with 200,000 parameters took over 20 seconds, on every request that drew such a401or403, before the client could act on it.The walk now uses a
StringScanner, which matches each pair at the current position without copying, so the cost grows with the length of the header. The scanner locates the Bearer challenge as well, so a header whose earlier challenge holds multibyte text yields the same parameters as before.The header is also the server's to fill. A value whose bytes are not valid in the string's encoding, such as a header tagged UTF-8 that carries a stray
0xFF, made the patterns raiseArgumentErrorfrom inside the transport's401handling, ahead of anyAuthorizationErrora caller is prepared for; the default adapter hands header values over as ASCII-8BIT, where every byte is valid, so it took a caller-supplied adapter or a header re-tagged along the way. The header is now scrubbed before it is parsed, so such bytes become the replacement character and the other parameters still come through, while a binary header is unchanged by the scrub.How Has This Been Tested?
New tests in
test/mcp/client/oauth/discovery_test.rbparse a header with 200,000 parameters within a bound the previous implementation exceeded many times over, and a header whose earlier challenge holds multibyte text. Two more parse a UTF-8 header with an invalid byte inside a quoted value, which raised against the previous library, and a binary header with a high byte.Breaking Changes
None.
Types of changes
Checklist