facebook / react · Issue No. 37156
React version: main (6cb4322d65f4c68daa183df24b5f81668cedab14)
1.Pass a string text-row header declaring a byte length of 0x1000:
processStringChunk(response, streamState, '0:T1000,');
2.Pass a separate one-character string as the text content chunk:
processStringChunk(response, streamState, 'x');
Link to code example:
processStringChunk accepts the content chunk and resolves the text row as "x", even though a one-code-unit JavaScript string cannot have a UTF-8 byte length of 4096.
The current validation is:
if (rowLength < chunk.length || chunk.length > rowLength * 3) {
throw new Error(...);
}
For non-negative lengths, the second condition is already implied by the first:
chunk.length > rowLength * 3
implies
rowLength < chunk.length
As a result, the validation detects an impossibly small declared byte length, but does not detect an impossibly large one.
For example, with rowLength = 4096 and chunk.length = 1, both current conditions are false.
For a JavaScript string encoded as UTF-8, the possible relationship between UTF-16 code units and UTF-8 bytes is:
chunk.length <= rowLength <= chunk.length * 3
The validation should reject values outside that range:
if (rowLength < chunk.length || rowLength > chunk.length * 3) {
throw new Error(...);
}
This preserves the existing approximate validation without requiring TextEncoder, while rejecting malformed string-chunk wiring with an impossible oversized declared byte length.
I can submit a PR with the condition fixed and regression coverage for valid ASCII, valid multibyte text, undersized declarations, and oversized declarations.
Relay reads this issue against the repository's contribution signals: the files it is likely to touch, how the maintainers triage work this size, and what the first contribution would exercise.
The full analysis for this issue is still being assembled. Until then, the description above and the thread on GitHub are the most reliable context.