From 5d7d5521e991ad1be99c9e7566e79486885abf34 Mon Sep 17 00:00:00 2001 From: Yarchik Date: Tue, 23 Jun 2026 00:18:22 +0100 Subject: [PATCH 1/3] fix: clamp a suffix range whose length exceeds the representation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `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. --- index.js | 5 +++++ test/range-parser.js | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/index.js b/index.js index 41e1cd3..7bfdbf8 100644 --- a/index.js +++ b/index.js @@ -59,6 +59,11 @@ function rangeParser (size, str, options) { if (startStr.length === 0) { start = size - end end = size - 1 + + // a suffix-length larger than the representation uses the whole representation + if (start < 0) { + start = 0 + } } else if (endStr.length === 0) { end = size - 1 } diff --git a/test/range-parser.js b/test/range-parser.js index 9f2c483..5a23854 100644 --- a/test/range-parser.js +++ b/test/range-parser.js @@ -109,6 +109,13 @@ describe('parseRange(len, str)', function () { deepEqual(range[0], { start: 600, end: 999 }) }) + it('should use the whole representation when the suffix-length is larger', function () { + var range = parse(100, 'bytes=-101') + assert.strictEqual(range.type, 'bytes') + assert.strictEqual(range.length, 1) + deepEqual(range[0], { start: 0, end: 99 }) + }) + it('should parse str with only start', function () { var range = parse(1000, 'bytes=400-') assert.strictEqual(range.type, 'bytes') From 50a64681b3e897749090bab0aea28c76333d502f Mon Sep 17 00:00:00 2001 From: Blake Embrey Date: Thu, 25 Jun 2026 13:04:03 -0700 Subject: [PATCH 2/3] Use Math.max --- index.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/index.js b/index.js index 7bfdbf8..ad2b6cc 100644 --- a/index.js +++ b/index.js @@ -57,13 +57,8 @@ function rangeParser (size, str, options) { var end = parsePos(endStr) if (startStr.length === 0) { - start = size - end + start = Math.max(size - end, 0) end = size - 1 - - // a suffix-length larger than the representation uses the whole representation - if (start < 0) { - start = 0 - } } else if (endStr.length === 0) { end = size - 1 } @@ -79,7 +74,7 @@ function rangeParser (size, str, options) { } // skip unsatisfiable ranges - if (start > end || start < 0) { + if (start > end) { valid = true continue } From da93ab26d640b2d50e8c1dbe1cf950437403211e Mon Sep 17 00:00:00 2001 From: Blake Embrey Date: Thu, 25 Jun 2026 13:46:05 -0700 Subject: [PATCH 3/3] Add -0 to test cases --- test/range-parser.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/range-parser.js b/test/range-parser.js index 5a23854..5147754 100644 --- a/test/range-parser.js +++ b/test/range-parser.js @@ -109,6 +109,11 @@ describe('parseRange(len, str)', function () { deepEqual(range[0], { start: 600, end: 999 }) }) + it('should be unsatisfiable asking for -0', function () { + var range = parse(1000, 'bytes=-0') + assert.strictEqual(range, -1) + }) + it('should use the whole representation when the suffix-length is larger', function () { var range = parse(100, 'bytes=-101') assert.strictEqual(range.type, 'bytes')