Skip to content

fix: clamp a suffix range whose length exceeds the representation#66

Merged
blakeembrey merged 3 commits into
jshttp:masterfrom
spokodev:fix-suffix-length-overflow
Jun 25, 2026
Merged

fix: clamp a suffix range whose length exceeds the representation#66
blakeembrey merged 3 commits into
jshttp:masterfrom
spokodev:fix-suffix-length-overflow

Conversation

@spokodev

Copy link
Copy Markdown
Contributor

Problem

A bytes=-N suffix range whose length is larger than the representation size is rejected as unsatisfiable, instead of using the whole representation:

parse(100, 'bytes=-101')  // -1   (expected [{ start: 0, end: 99 }])
parse(100, 'bytes=-500')  // -1
parse(100, 'bytes=-100')  // [{ start: 0, end: 99 }]   (works only because start === 0 exactly)

Cause

RFC 7233 §2.1: "If the selected representation is shorter than the specified suffix-length, the entire representation is used."

The suffix branch computes start = size - suffixLength, which goes negative when the suffix is larger than the representation, and the negative start is then dropped by the start < 0 unsatisfiable check:

if (startStr.length === 0) {
  start = size - end   // negative when the suffix length > size
  end = size - 1
}

The parser already clamps the analogous overflow for the first-last form (if (end > size - 1) end = size - 1, e.g. bytes=0-9999 on a 100-byte representation); the suffix form just missed the same clamp.

Fix

Clamp the suffix start to 0, so an over-long suffix uses the whole representation. bytes=-0 (start becomes size, start > end) and an empty representation stay unsatisfiable.

Verification

  • Added a test asserting parse(100, 'bytes=-101') is [{ start: 0, end: 99 }]. It fails on master and passes with the fix; the existing suite is unchanged (35 passing).
  • Fuzz (100k random size/suffix pairs) vs an RFC 7233 oracle: 0 disagreements. bytes=-0 and zero-length representations remain unsatisfiable.

`bytes=-N` where N is larger than the representation size was rejected as
unsatisfiable instead of using the whole representation:

    parse(100, 'bytes=-101') // -1   (expected [{ start: 0, end: 99 }])
    parse(100, 'bytes=-500') // -1

RFC 7233 §2.1: "If the selected representation is shorter than the
specified suffix-length, the entire representation is used." The parser
already clamps the analogous last-byte-pos overflow (`bytes=0-9999`); the
suffix form just missed it, letting `start = size - suffixLength` go
negative and get dropped. Clamp that start to 0. `bytes=-0` and an empty
representation stay unsatisfiable.

@bjohansebas bjohansebas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change looks good to me, just for the next major version.

Comment thread index.js Outdated
@blakeembrey blakeembrey merged commit f4bf173 into jshttp:master Jun 25, 2026
28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants