Grade S3 metadata as header bytes, and let clients encode or refuse it - #4
Merged
Merged
Conversation
The transport reads request header values as ISO-8859-1, so é sent as e9 and é sent as UTF-8 differ. New S3 and S3 Express cases, verified live, cover encoded words outside ISO-8859-1, decoding on a read, names with any HTTP token character and names that differ only in case. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
S3 metadata writes outside ASCII now pass by refusing the value, and S3 Express reads pass by returning a stored encoded word as it is. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
A read must decode a value that S3 returns as several encoded words. A tab passes raw, and spaces at either end must be encoded or refused, since HTTP drops them. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
…lues. New cases cover whitespace at either end, control characters, CR and LF, text that reads as an encoded word, and general-purpose names that differ only in case. Where no request reads back as sent, the case expects a refusal. A wrong verdict now carries the case's purpose, and a connection that closes before its first byte is no transport failure, which made reports differ between runs. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
A general-purpose bucket reads each space-separated token that starts with =? and ends with ?= as an RFC 2047 encoded word. A new case holds a value with =? that is no such token and forbids refusing it, and the encoded-word purposes state the rule. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
…mes. Each case sits just past the boundary of a refusal, so a client that refuses too much fails: part 10,000, a 64-byte block ID, a page of one entry and the metadata name _a1. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
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.
A general-purpose bucket reads metadata header bytes as ISO-8859-1.
ésent as UTF-8 is stored asé, and S3 returns it as the RFC 2047 encoded word=?UTF-8?Q?caf=C3=83=C2=A9?=. The grader read header values as UTF-8, so it passed that corrupting request and errored on the bytee9, which storesé. The S3 metadata cases now pin down what a client must send and read, measured live on a general-purpose bucket and a directory bucket.Two client policies
éase9or as an encoded word.Where no request reads back as sent, the case expects a refusal.
Cases
épasses as the bytee9(general-purpose only), as an encoded word, or refused.雪passes as an encoded word or refused. Raw UTF-8 fails everywhere.=?and ends with?=as an encoded word: it decodes it, or answers 400 or 500. Such a value must be wrapped in an encoded word of its own, or refused. A value likea=?b?=c x=?UTF-8?Q?caf=C3=A9?=yholds no such token, and must be sent: a refusal fails.one,two, and a directory bucket answers 400.A case past every refusal
Each case that permits a refusal passes a client that refuses too much. So each refusal now names a neighbor just past its boundary that a client must send, and the case generator rejects a refusal without one. The audit added four cases, verified live:
stage-part-10000on S3 and S3 Express, paststage-part-10001.stage-id-64-byteson Azure, past the 65-bytestage-id-too-long.list-page-size-oneon Azure, pastlist-max-keys-zero.put-metadata-identifier-name(_a1) on Azure, pastput-metadata-invalid-name.Grader
purpose, which states the rule it grades.Every request path was verified live. The AWS C++ SDK fails 8 of the metadata cases on a general-purpose bucket and 9 on a directory bucket, and passes the new neighbor cases, as the Azure C++ SDK does. The pinned borink adapter passes the Azure neighbors and reports every S3 case unsupported, so its grading shows no wrong case.
Co-Authored-By: Claude Opus 5.5 (1M context) [email protected]