Repository navigation
fix(client,retry,paginate,upload,repos): issue #4-#10 全量修复与加固 - #11
Merged
Merged
Conversation
added 2 commits
November 11, 2026 02:26
- #4 Retry-After 三道闸:统一 retryAfterDuration——非正值/不可解析回 落指数退避、delay-seconds 与 HTTP-date 双形式、与指数退避共用 MaxBackoff 钳制、超大秒数防溢出;零值退避字段按文档默认归一 - #5 Paginate 50 页封顶(与 go-gongfeng 对齐)+ ErrTooManyPages 哨兵, 截断与取完可区分;服务端恒返满页不再无限打请求 - #6 新增 pathf/pathSeg/pathSegs:383 处端点路径从裸 Sprintf 收编到 统一段转义(/ ? # 等被隔离在自身段内);文件路径走 pathSegs 保留 分隔符;search/events/namespace/archive/contents 六处裸拼 query 值 改 QueryEscape/url.Values - #7 响应体读取全量收口 readBodyLimited:JSON 16MiB / 下载 1GiB 分层 上限,SetMaxResponseBodySize 可覆盖,超限报 ResponseBodyTooLargeError - #8 baseURL/httpClient 读侧统一 requestSnapshot(RLock),并发 SetHTTPClient/SetBaseURL 与请求不再 data race(-race 验证) - #9 upload 构造 multipart 后走 doBufferedRequestAt 共享管线:审计 hook 触发、429/5xx 重试生效;顺带修复重试复用已耗尽 body 的潜伏 缺陷(req.GetBody 重放,三次尝试 body 逐字一致有测) - #10 ListRepositoriesOptions 自有 toQuery(遮蔽嵌入方法)收敛 Type/Sort 上 wire,ListRepositories 两分支与 ListCurrentUserRepositories 共用,杜绝再分叉 请求执行核心合并为 doBufferedRequestAt/doRawRequestWith 单管线; 删除手写 min 用内建;地板提升 go 1.27(CI matrix/lint/fmt/release 与 .golangci.yml 同步);hardening_test.go 逐 issue table-driven 测试; 门禁 go test -race ./... 全绿、gofmt -s -l 空、go vet 过
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概述
issue 清零战车道 A3 第一批:go-gitcode 7 单全量修复。每单修根因、配 table-driven 测试(
hardening_test.go),门禁go test -race ./...全绿、gofmt -s -l空、go vet过。逐单
Retry-After 解析缺三道闸(#4)
retryAfterDuration:delay-seconds 与 HTTP-date(http.ParseTime)双形式;非正值(负秒/零/过去日期)与不可解析值回落指数退避(不再产负时长致忙等);解析结果与指数退避共用MaxBackoff钳制(Retry-After: 3600不再等 1 小时);超大秒数在 Duration 转换前封顶防溢出。InitialBackoff/MaxBackoff按文档默认(1s/30s)归一——此前零MaxBackoff会把所有等待钳成 0。TestRetryAfterDuration(9 例表)、TestGetRetryWaitTimeRetryAfter(11 例表)、TestRetryAfterHeaderHonoredOn429(真实 429→200 交换断言等待)。Paginate 无页数上限(#5)
maxPaginatePages = 50(与 go-gongfeng 对齐),触顶 yield 哨兵ErrTooManyPages(errors.Is 可判定)——「封顶截断」与「取完」可区分。TestCollectAll即是该形态),误杀面大于收益;封顶已把损害有界化(300ms 12 万请求 → 最多 50 次)。TestPaginatePageCap(恒满页 → 恰好 50 页 + 哨兵错误)、TestPaginateEndsNormally。383 处路径裸拼接零 PathEscape(#6)
path.go:pathf(format, args...)——路径侧(?前)字符串实参一律url.PathEscape;query 侧实参不动;%d原样;pathSegs逐段转义保留/分隔符(仓库文件路径、archive format),以escapedPath标记防二次转义。fmt.Sprintf("/...→pathf("/...),逐处可审:纯机械替换 + 6 处文件路径手包pathSegs+ query 裸拼值(search 的 q/过滤参数、events year/next、namespace path、archive ref/format、contents/raw 的 ref)改QueryEscape/url.Values。TestPathfEscaping(10 例表)、TestEndpointPathIsolation(httptest 断言 RequestURI:evil/../admin→evil%2F..%2Fadmin、org?x=1→org%3Fx=1)、TestRawFilePathSegments。响应体无 LimitReader(#7)
readBodyLimited(io.LimitReader(limit+1)判超限)收口 client/upload/oauth 全部 9 处io.ReadAll;分层默认:JSON 16 MiB、二进制下载(raw/release 资产/artifact/日志归档)1 GiB;SetMaxResponseBodySize全局覆盖(<=0恢复默认)。ResponseBodyTooLargeError(IsResponseBodyTooLarge判定)。TestResponseBodyLimit(4 例表:json/raw/upload 超限 + 达限通过)、TestReadBodyLimited、TestMaxResponseBodySizeSetter。RWMutex 只护写不护读(#8)
requestSnapshot(RLock 下取baseURL/httpClient),收编 doRequest/doRawRequest/doFormRequest/doRawBodyRequest/retry 循环/upload 全部裸读点,与仓内retryPolicy/hooks 既有持锁读法对齐。TestConcurrentSettersAndRequests(100 轮 SetHTTPClient/SetBaseURL 并发 GetCurrentUser,-race 干净)。upload 绕过 hook 与 retry(#9)
UploadFileReader/UploadImageReader构造 multipart body([]byte,可重放)后走共享核心doBufferedRequestAt:鉴权 → request hook → 重试 → response hook → 有界读体,与 CHANGELOG「All HTTP request methods now run request/response hooks and support retry policy」承诺对齐。req.GetBody重放,JSON POST 与 multipart 上传重试均真正可重入。TestUploadRunsHooksAndRetries(500×2 后 200:attempts=3、hook 各 1 次、终次 body 完整)、TestUploadImageRunsHooks、TestJSONBodyReplayOnRetry(三次 body 逐字一致)。ListRepositories 静默丢 Type/Sort(#10)
ListRepositoriesOptions自有toQuery(遮蔽嵌入ListOptions.toQuery)把type/sort(经 QueryEscape)一并上 wire;ListRepositories(含 Owner 分支)与ListCurrentUserRepositories收敛到同一 helper,同端点同结构体不再分叉。TestListRepositoriesFiltersOnWire(3 入口 × 断言 query 全参数)、TestListRepositoriesOptionsNoFilters。附带
doBufferedRequestAt+doRawRequestWith(行为差异仅一处收敛:form 空 body 从 unmarshal 报错改为跳过解码)。.golangci.yml同步;本仓零第三方依赖,go get -u ./...无可升项;删除手写min用内建,for range n/slices.Clone就位。Closes #4
Closes #5
Closes #6
Closes #7
Closes #8
Closes #9
Closes #10