Repository navigation
fix(b2): validate each range download response in NewRangeReader - #286
Conversation
david-santacruz-backblaze
left a comment
There was a problem hiding this comment.
Mate, a few things to check before merge:
- Breaking change.
base.ErrInvalidRangeResponseis new, andDownloadFile*now errors on a 200 or a missingContent-Range. Mark the changie fragment**Breaking:**and say what callers must do. Content-Rangecheck. #179 wants a matching length and a stop at the total. Only the start is checked, sobytes 2-999999/10passes.- 206 vs 200. A longer 206 body is silently truncated, but a longer 200 errors. Make them consistent.
- Chunked 200 at offset 0. It's rejected for having no
Content-Length. Test it or justify it. - Test helpers. Use
internal/b2wiretestfor the new wire tests, and share one range fake across the four edited fixtures. - Unit test. Add a direct
basetest ofvalidateRangeResponse.
|
Fixed in The changelog fragment is now a |
Range downloads accepted full-object replies and trusted their content length, allowing a server that ignores Range to return bytes past the requested bound and repeat unbounded reads. Require a partial response at the requested offset and limit each response to its requested chunk. Closes #179
Make the affected fake servers follow B2 response semantics: whole-file offset-zero ranges return 200, while partial ranges return 206 with a matching Content-Range. Add the current-main changelog fragment required for the production validation change. Closes #179
Report the actual B2 download method in invalid-range errors and accept an offset-zero HTTP 200 only when its declared body fits the requested range. Strengthen bounded and unbounded reader regressions so an oversized full-object response yields no bytes. Keep the release note in the changie fragment and record that this branch corrects four pre-existing wire fixtures: downloadbyid_extended, progress, sha1, and ssec. Closes #179
Reject a non-partial response even when its Content-Range otherwise matches the requested range, and preserve an equal Content-Length header without applying the oversized-response clamp. Closes #179
Validate the end, total, and declared length of each partial response, and reject oversized or chunked replies before exposing bytes. Share one range fixture across wire tests and document the breaking error behavior. Closes #179
Use the shared range response helper so one-byte chunks carry matching Content-Range and Content-Length headers after strict response validation. Closes #179
fc8c529 to
7add7ab
Compare
|
CI is green after rebasing on On live coverage (per the review question): the B2-dependent behavior is already exercised live by |
Context
NewRangeReader/downloadFileaccepted any 2xx download response without checking it satisfied the Range request. A server returning HTTP 200 (whole file) to a nonzero-offset range, a 206 without a matchingContent-Range, or a range-ignoring 200 whose body exceeds the requested size, was read as if the bytes started at the requested offset — silently shifting or truncating data, and for a chunked read repeating the object without end.Root cause
No validation of the range response status /
Content-Rangeat the base HTTP boundary — the only place the status and headers are available.Changes
base.ErrInvalidRangeResponseandvalidateRangeResponse: accept HTTP 200 at offset 0 only when the response encompasses the whole object (declaredContent-Lengthwithin the requested size, or an unbounded read); otherwise require 206 with aContent-Rangewhose start equals the requested offset. Error messages name the actual B2 method (by-name or by-id).Content-Lengthat the requested size for bounded reads.Content-Range). No SDK assertions changed — only fake response construction.offset 0, length -1, smallChunkSize) full-object rejection requiring zero returned bytes, by-id method naming, the non-206 status check in isolation, and theContent-Length == sizeclamp boundary.CHANGELOG.mdedit).Verification
go test -race ./b2/... ./basegreen;BASE_REF=gh/main make cigreen (build, vet, tidy, verify, lint 0 issues, race, cross-compiles, scripts). Each new test fails without its fix: the by-id method name, the oversized offset-zero 200 (bounded and unbounded), the status check, and the clamp boundary — verified by reverting each guard.Closes #179