Validate Content-Range for ranged requests in base downloads (by name and by ID)

未关闭
#175 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

还没有人认领这个 Issue。

评估

难度
4/5
预计耗时
3-5 天
新手友好度
56/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
活跃
技术栈
go
领域
api, backend

调研方向

Start with base/base.go, especially downloadFile, newFileReaderWithMaxLength, and the FileReader definition. Trace the by-name and by-ID download tests, then inspect b2.Reader to see how it consumes the returned metadata. Done means ranged responses are validated, ignored ranges return a typed error, and tests cover valid and malformed 206 responses plus 200 responses at nonzero and zero offsets.

由索引模型根据 Issue 内容生成。

描述

bug

Summary

base.(*Bucket).DownloadFileByName, DownloadFileByID and their WithSSEC variants all go through downloadFile, which sends a Range header whenever an offset or size is given. The response check accepts either 200 or 206 and never reads Content-Range. RFC 9110 allows a server or intermediary to ignore Range and return the full representation with 200; blazer then hands the caller the whole object as if it were the requested bytes. FileReader has no field that lets the caller notice.

B2's own endpoints honor Range. The problem appears when a caching proxy, a custom Transport or a B2-compatible test server sits in between. b2.Reader builds its range and chunked reads on these calls, so it needs the status and Content-Range from base to detect this case.

Current behavior

At a5e0d13:

  • base/base.go:1803-1836: downloadFile sets Range (1826-1829) for by-name (1784-1789) and by-ID (1797-1801) downloads alike.
  • base/base.go:1843-1848: newFileReaderWithMaxLength accepts any 200 or 206 and parses only Content-Length.
  • base/base.go:1758-1765: FileReader carries ContentLength, ContentType, SHA1, ID and Info, but not the status, the returned range or the total size.

Reproduced locally at a5e0d13 with a server that ignores Range and answers 200 with 100 bytes: DownloadFileByName(ctx, "o", 50, 20, false) and DownloadFileByID(ctx, "id", 50, 20, false) both succeed and return ContentLength 100.

Through b2.Reader, with x/b2sim behind a Transport that removes the Range header (10-byte object):

Object.NewRangeReader(ctx, 2, 4), ChunkSize 2: 20 bytes ("0123456789" twice), no error
Object.NewReader, ChunkSize 4: the object repeated until the test's 64-byte cap

Without the Range removal, x/b2sim answers 206 with Content-Range and the range read returns "2345".

Expected behavior

A ranged download either returns exactly the requested bytes or returns an error.

Proposed change

When a Range header was sent:

  • On 206, parse Content-Range (bytes first-last/total), require first == offset, last no greater than offset+size-1 when size is positive, and Content-Length == last-first+1; otherwise close the body and return an error.
  • On 200, accept only when offset == 0; otherwise close the body and return a typed, non-retryable error such as base.ErrRangeIgnored.
  • Add Status, RangeStart, RangeEnd and TotalSize (or a ContentRange struct) to FileReader so b2.Reader can stop at the known total.

Acceptance criteria

  • A 200 answer to offset=50,size=20 returns ErrRangeIgnored and closes the body, by name and by ID.
  • A 206 whose Content-Range starts at the wrong offset, or whose length disagrees with Content-Length, returns an error.
  • A correct 206 (for example from x/b2sim) fills the new fields; a 200 to offset=0 reports the total size.
  • Existing 206 and 416 tests pass.

Related

Backblaze/blazer#57 (closed) bounded the reader's short-read retry loop. Backblaze/blazer#59 (open) is a different Reader wake-up bug. Backblaze/blazer#121 (merged) fixed exact range reads at a chunk boundary. Backblaze/blazer#146 (closed, fixed by Backblaze/blazer#155) was about a bounded reader requesting past the range, not about validating the response. Backblaze/blazer#147 (merged) added x/b2sim, which honors Range. Backblaze/blazer#158 (open) asks for a full Reader for DownloadFileByID, which would read through the same code path.

主要语言
Go
星标
66
派生
18
平均合并
1 天 10 小时
30 天内合并 PR
132

环境准备

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

Backblaze/blazer 的其他 Issue

查看 Backblaze/blazer 的全部 Issue

相似的 Issue

更多 Go Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。