Skip to content

Fix Get Blob suffix range bytes=-1 500 on 1-byte blobs - #2862

Open
Joel Town Road (hippi345) wants to merge 4 commits into
Azure:mainfrom
hippi345:fix/2856-suffix-range-1-byte
Open

Joel Town Road (hippi345) wants to merge 4 commits into
Azure:mainfrom
hippi345:fix/2856-suffix-range-1-byte

Conversation

@hippi345

@hippi345 Joel Town Road (hippi345) commented Oct 17, 2026 •

Copy link
Copy Markdown

Problem

Get Blob with a suffix range on a 1-byte block blob returned HTTP 500 instead of 206.

Range: bytes=-1 was parsed as start NaN, so Azurite logged NormalizedDownloadRange=bytes=NaN-0 and then threw a RangeError. Azure Storage returns 206 with the last byte (Content-Range: bytes 0-0/1).

Fixes #2856

Fix

  • Parse HTTP suffix-byte-range-spec (bytes=-N with N > 0) in deserializeRangeHeader, opt-in for downloads only (allowSuffixRange defaults to false).
  • Resolve suffix ranges against blob length in block, append, and page blob download before clamping.
  • Page mutations (Clear Pages and Upload Pages) reject suffix/empty ranges with HTTP 416. Get Page Ranges does not: suffix and empty values (bytes=-1, bytes=-99, bytes=-0, bytes=-, bytes=, empty) keep the upstream 200 (empty PageList). Malformed values such as bytes=5-2 and garbage still return 416 rather than 500.
  • bytes=-N (N > 0) on a 0-byte blob returns 416 with Content-Range: bytes */0 on both the block/append download path and the page blob download path.
  • Invalid suffix/empty Range on page-blob Get Blob (bytes=-0, bytes=-, bytes=) is ignored like block and append blobs (HTTP 200, full body) instead of 500.
  • Added an Upcoming Release entry in ChangeLog.md as required by this project's contribution guidelines.

Test helper: RangePolicyFactory sets only the Range header. InjectorPolicyFactory has its own policy that sets x-ms-range after SDK serialization, so existing Range-header tests still exercise the plain Range header.

Testing

Added coverage in tests/blob/apis/blob.test.ts and tests/blob/apis/pageblob.test.ts.

1-byte suffix download (unmodified upstream):

  BlobAPIs
    1) download suffix range bytes=-1 on a 1-byte blob @loki @sql


  0 passing (84ms)
  1 failing

  1) BlobAPIs
       download suffix range bytes=-1 on a 1-byte blob @loki @sql:
     RestError
      at handleErrorResponse (node_modules/@azure/core-client/src/deserializationPolicy.ts:255:17)
      at deserializeResponseBody (node_modules/@azure/core-client/src/deserializationPolicy.ts:159:43)
      at processTicksAndRejections (node:internal/process/task_queues:105:5)

After the download suffix fix (nearby download/range tests):

  BlobAPIs
    ✔ download all parameters set @loki @sql
    ✔ download entire with range @loki @sql
    ✔ download out of range @loki @sql
    ✔ download invalid range @loki @sql
    ✔ download partial range (via custom policy) @loki @sql
    ✔ download suffix range bytes=-1 on a 1-byte blob @loki @sql


  6 passing (122ms)

0-byte suffix download and page-mutation suffix ranges (on 43914f2):

  0 passing (122ms)
  4 failing
  (0-byte downloads returned 206; populated clearPages returned 500; empty-map clearPages succeeded)

After opt-in suffix parsing and 0-byte 416:

  4 passing (109ms)

Get Page Ranges and page-blob invalid Range (on d111d92, before this commit):

  PageBlobAPIs
    1) download ignores invalid suffix and empty Range like block blobs @loki
    2) getPageRanges returns 200 for suffix or empty x-ms-range and 416 for malformed @loki


  0 passing (75ms)
  2 failing

  1) RestError  (page-blob Get Blob 500 for bytes=-0 / bytes=- / bytes=)

  2) RestError: The page range specified is invalid.
     (Get Page Ranges 416 for bytes=-1; upstream is 200)

After restoring Get Page Ranges 200 and ignoring invalid page-blob download ranges:

  PageBlobAPIs
    ✔ download ignores invalid suffix and empty Range like block blobs @loki
    ✔ download suffix range bytes=-1 on a 0-byte page blob returns 416 @loki
    ✔ clearPages with suffix range bytes=-512 on a populated page map returns 416 @loki
    ✔ clearPages with suffix range bytes=-512 on an empty page map returns 416 @loki
    ✔ getPageRanges returns 200 for suffix or empty x-ms-range and 416 for malformed @loki

  BlobAPIs
    ✔ download suffix range bytes=-1 on a 1-byte blob @loki @sql
    ✔ download suffix range bytes=-1 on a 0-byte blob returns 416 @loki @sql


  7 passing (153ms)

loki suites (blob, pageblob, appendblob, blockblob, container, conditions) plus lint and tsc:

eslint src/**/*.ts  (exit 0)
tsc -p .            (exit 0)

  372 passing (2m)
  3 pending

utils suite (no @loki tags):

  16 passing (11ms)

This change was prepared with AI assistance. I remain responsible for the contribution and have reviewed it.

Parse HTTP suffix ranges and resolve them against blob length so a
1-byte blob with Range: bytes=-1 returns 206 with the last byte.
Copilot AI balanced review requested due to automatic review settings October 17, 2026 01:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Page-clear requests can regress to HTTP 500, and empty-blob suffix downloads produce invalid partial responses.

2 open issues
What changed in this PR

Fixes suffix-range Get Blob downloads for issue #2856, including the one-byte bytes=-1 failure.

Changes:

  • Parses suffix ranges and resolves them against block, append, and page blob lengths.
  • Adds a one-byte download regression test.
  • Documents the fix in the upcoming release notes.
File Description
tests/​blob/​apis/​blob.test.ts Adds the one-byte suffix-range regression test.
src/​blob/​utils/​utils.ts Adds suffix parsing and range resolution.
src/​blob/​handlers/​BlobHandler.ts Resolves suffix ranges before download clamping.
ChangeLog.md Records the user-visible fix.

Review effort: Balanced

Comment thread src/blob/utils/utils.ts
Comment thread src/blob/utils/utils.ts Outdated
Suffix ranges bytes=-N are opt-in for blob downloads so page mutations
keep rejecting them. Zero-byte suffix downloads now return 416 with
Content-Range bytes */0.
Copilot AI balanced review requested due to automatic review settings October 17, 2026 01:52

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Range validation still allows malformed suffixes and introduces an unhandled error in Get Page Ranges.

1 open issue
1 previously missed issue

In code that hasn't changed since last review

Medium severity Reject malformed suffix lengths instead of using parseInt

src/​blob/​utils/​utils.ts:239

Validate the entire suffix length before accepting it. parseInt accepts malformed headers such as bytes=-1oops and bytes=-1,2 as one-byte suffixes, so a block blob containing abcdef returns 206 with f instead of reaching the existing invalid-range handling. Require decimal digits only, and add malformed-suffix regression cases.

2 resolved since last review

Review effort: Balanced

Comment thread src/blob/utils/utils.ts Outdated
…lper

Wrap Get Page Ranges range parsing in try/catch and map failures to
getInvalidPageRange. Restore RangePolicy to Range-only and give
InjectorPolicyFactory its own x-ms-range policy.
Copilot AI balanced review requested due to automatic review settings October 17, 2026 02:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

Malformed suffixes are accepted as valid partial-download ranges instead of following invalid-range handling.

1 open issue
1 previously missed issue

In code that hasn't changed since last review

Medium severity Reject malformed suffix ranges with trailing or fractional characters

src/​blob/​utils/​utils.ts:239

parseInt accepts numeric prefixes, so malformed suffixes such as bytes=-3oops and bytes=-3.5 become valid three-byte ranges and are served as HTTP 206. Validate that the entire suffix contains decimal digits before accepting it, so these headers follow the existing invalid-range handling instead of silently selecting a different range.

Review effort: Balanced

… downloads

Get Page Ranges keeps upstream 200 for suffix/empty x-ms-range values and
still returns 416 for malformed ranges. Page blob Get Blob ignores
bytes=-0, bytes=-, and empty Range like block and append blobs.
Copilot AI balanced review requested due to automatic review settings October 17, 2026 02:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

Malformed suffixes still produce partial responses instead of using the invalid-range fallback.

No open issues 🎉

2 previously missed issues

In code that hasn't changed since last review

Medium severity Reject malformed suffix ranges instead of truncating with parseInt

src/​blob/​utils/​utils.ts:231

Malformed suffixes such as bytes=-1.5 and bytes=-1junk are accepted as bytes=-1 because parseInt stops at the first non-digit. Both download paths then return 206 with the last byte rather than using their invalid-range fallback (200 with the full blob). Validate the entire suffix as decimal digits before parsing, and add regression cases for these inputs.

Low severity Add multi-byte suffix download tests for exact ranges and clamping

src/​blob/​utils/​utils.ts:287

The only successful suffix-download test uses a one-byte blob, so it cannot detect a resolver that always returns the whole blob. Add successful downloads with distinguishable multi-byte content for block, append, and populated page blobs. Cover suffix lengths smaller than and larger than the blob length, asserting the exact body, 206 status, and Content-Range to verify both offset calculation and clamping.

1 resolved since last review

Review effort: Balanced

@hippi345
Joel Town Road (hippi345) marked this pull request as ready for review October 17, 2026 02:26
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.

Get Blob with Range bytes=-1 returns 500

2 participants