-
Notifications
You must be signed in to change notification settings - Fork 113
4.3.5 #172
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
4.3.5 #172
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| 4.3.0-rc.0 | ||
| 4.3.5-rc.0 |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -2,14 +2,78 @@ package proxy | |||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| import ( | ||||||||||||||||||||||||||||||||||||||||||
| "bufio" | ||||||||||||||||||||||||||||||||||||||||||
| "bytes" | ||||||||||||||||||||||||||||||||||||||||||
| "fmt" | ||||||||||||||||||||||||||||||||||||||||||
| "ghproxy/config" | ||||||||||||||||||||||||||||||||||||||||||
| "io" | ||||||||||||||||||||||||||||||||||||||||||
| "strings" | ||||||||||||||||||||||||||||||||||||||||||
| "sync" | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| "github.com/infinite-iroha/touka" | ||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| 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://") | ||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+15
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 域名匹配缺少主机边界,可能误改写相似域名(安全/正确性)
应用最小改动(增加结尾 - 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/")并同步调整字符串版 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| func EditorMatcherBytes(rawPath []byte, cfg *config.Config) (bool, error) { | ||||||||||||||||||||||||||||||||||||||||||
| if bytes.HasPrefix(rawPath, prefixGithub) { | ||||||||||||||||||||||||||||||||||||||||||
| return true, nil | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| if bytes.HasPrefix(rawPath, prefixRawUser) { | ||||||||||||||||||||||||||||||||||||||||||
| return true, nil | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| if bytes.HasPrefix(rawPath, prefixRaw) { | ||||||||||||||||||||||||||||||||||||||||||
| return true, nil | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| if bytes.HasPrefix(rawPath, prefixGistUser) { | ||||||||||||||||||||||||||||||||||||||||||
| return true, nil | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| if bytes.HasPrefix(rawPath, prefixGist) { | ||||||||||||||||||||||||||||||||||||||||||
| return true, nil | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| if cfg.Shell.RewriteAPI { | ||||||||||||||||||||||||||||||||||||||||||
| if bytes.HasPrefix(rawPath, prefixAPI) { | ||||||||||||||||||||||||||||||||||||||||||
| return true, nil | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| return false, nil | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| func modifyURLBytes(url []byte, host []byte, cfg *config.Config) []byte { | ||||||||||||||||||||||||||||||||||||||||||
| matched, err := EditorMatcherBytes(url, cfg) | ||||||||||||||||||||||||||||||||||||||||||
| if err != nil || !matched { | ||||||||||||||||||||||||||||||||||||||||||
| return url | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| var u []byte | ||||||||||||||||||||||||||||||||||||||||||
| if bytes.HasPrefix(url, prefixHTTPS) { | ||||||||||||||||||||||||||||||||||||||||||
| u = url[len(prefixHTTPS):] | ||||||||||||||||||||||||||||||||||||||||||
| } else if bytes.HasPrefix(url, prefixHTTP) { | ||||||||||||||||||||||||||||||||||||||||||
| u = url[len(prefixHTTP):] | ||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||
| u = url | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| newLen := len(prefixHTTPS) + len(host) + 1 + len(u) | ||||||||||||||||||||||||||||||||||||||||||
| newURL := make([]byte, newLen) | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| written := 0 | ||||||||||||||||||||||||||||||||||||||||||
| written += copy(newURL[written:], prefixHTTPS) | ||||||||||||||||||||||||||||||||||||||||||
| written += copy(newURL[written:], host) | ||||||||||||||||||||||||||||||||||||||||||
| written += copy(newURL[written:], []byte("/")) | ||||||||||||||||||||||||||||||||||||||||||
| copy(newURL[written:], u) | ||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+68
to
+72
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 这段手动构建
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| return newURL | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| func EditorMatcher(rawPath string, cfg *config.Config) (bool, error) { | ||||||||||||||||||||||||||||||||||||||||||
| // 匹配 "https://github.com"开头的链接 | ||||||||||||||||||||||||||||||||||||||||||
| if strings.HasPrefix(rawPath, "https://github.com") { | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -64,87 +128,126 @@ func modifyURL(url string, host string, cfg *config.Config) string { | |||||||||||||||||||||||||||||||||||||||||
| return url | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| // processLinks 处理链接,返回包含处理后数据的 io.Reader | ||||||||||||||||||||||||||||||||||||||||||
| func processLinks(input io.ReadCloser, host string, cfg *config.Config, c *touka.Context) (readerOut io.Reader, written int64, err error) { | ||||||||||||||||||||||||||||||||||||||||||
| pipeReader, pipeWriter := io.Pipe() // 创建 io.Pipe | ||||||||||||||||||||||||||||||||||||||||||
| var bufferPool = sync.Pool{ | ||||||||||||||||||||||||||||||||||||||||||
| New: func() interface{} { | ||||||||||||||||||||||||||||||||||||||||||
| return new(bytes.Buffer) | ||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| // processLinksStreamingInternal is a link processing function that reads the input line by line. | ||||||||||||||||||||||||||||||||||||||||||
| // It is memory-safe for large files but less performant due to numerous small allocations. | ||||||||||||||||||||||||||||||||||||||||||
| func processLinksStreamingInternal(input io.ReadCloser, host string, cfg *config.Config, c *touka.Context) (readerOut io.Reader, written int64, err error) { | ||||||||||||||||||||||||||||||||||||||||||
| pipeReader, pipeWriter := io.Pipe() | ||||||||||||||||||||||||||||||||||||||||||
| readerOut = pipeReader | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| go func() { // 在 Goroutine 中执行写入操作 | ||||||||||||||||||||||||||||||||||||||||||
| go func() { | ||||||||||||||||||||||||||||||||||||||||||
| 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() | ||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
144
to
+151
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 在 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)
}
}() |
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| defer func() { | ||||||||||||||||||||||||||||||||||||||||||
| if err := input.Close(); err != nil { | ||||||||||||||||||||||||||||||||||||||||||
| c.Errorf("input close failed: %v", err) | ||||||||||||||||||||||||||||||||||||||||||
| bufReader := bufio.NewReader(input) | ||||||||||||||||||||||||||||||||||||||||||
| bufWriter := bufio.NewWriterSize(pipeWriter, 4096) | ||||||||||||||||||||||||||||||||||||||||||
| defer bufWriter.Flush() | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| for { | ||||||||||||||||||||||||||||||||||||||||||
| line, readErr := bufReader.ReadString('\n') | ||||||||||||||||||||||||||||||||||||||||||
| if readErr != nil && readErr != io.EOF { | ||||||||||||||||||||||||||||||||||||||||||
| err = fmt.Errorf("read error: %w", readErr) | ||||||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| }() | ||||||||||||||||||||||||||||||||||||||||||
| modifiedLine := urlPattern.ReplaceAllStringFunc(line, func(originalURL string) string { | ||||||||||||||||||||||||||||||||||||||||||
| return modifyURL(originalURL, host, cfg) | ||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| var bufReader *bufio.Reader | ||||||||||||||||||||||||||||||||||||||||||
| var n int | ||||||||||||||||||||||||||||||||||||||||||
| n, err = bufWriter.WriteString(modifiedLine) | ||||||||||||||||||||||||||||||||||||||||||
| written += int64(n) | ||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||
| err = fmt.Errorf("write error: %w", err) | ||||||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| bufReader = bufio.NewReader(input) | ||||||||||||||||||||||||||||||||||||||||||
| if readErr == io.EOF { | ||||||||||||||||||||||||||||||||||||||||||
| break | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| }() | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| var bufWriter *bufio.Writer | ||||||||||||||||||||||||||||||||||||||||||
| return readerOut, written, nil | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| bufWriter = bufio.NewWriterSize(pipeWriter, 4096) // 使用 pipeWriter | ||||||||||||||||||||||||||||||||||||||||||
| // processLinks acts as a dispatcher, choosing the best processing strategy based on file size. | ||||||||||||||||||||||||||||||||||||||||||
| // It uses a memory-safe streaming approach for large or unknown-size files, | ||||||||||||||||||||||||||||||||||||||||||
| // and a high-performance buffered approach for smaller files. | ||||||||||||||||||||||||||||||||||||||||||
| func processLinks(input io.ReadCloser, host string, cfg *config.Config, c *touka.Context, bodySize int) (readerOut io.Reader, written int64, err error) { | ||||||||||||||||||||||||||||||||||||||||||
| const sizeThreshold = 256 * 1024 // 256KB | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| // Use streaming for large or unknown size files to prevent OOM | ||||||||||||||||||||||||||||||||||||||||||
| if bodySize == -1 || bodySize > sizeThreshold { | ||||||||||||||||||||||||||||||||||||||||||
| c.Debugf("Using streaming processor for large/unknown size file (%d bytes)", bodySize) | ||||||||||||||||||||||||||||||||||||||||||
| return processLinksStreamingInternal(input, host, cfg, c) | ||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||
| c.Debugf("Using buffered processor for small file (%d bytes)", bodySize) | ||||||||||||||||||||||||||||||||||||||||||
| return processLinksBufferedInternal(input, host, cfg, c) | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| // processLinksBufferedInternal a link processing function that reads the entire content into a buffer. | ||||||||||||||||||||||||||||||||||||||||||
| // It is optimized for performance on smaller files but carries an OOM risk for large files. | ||||||||||||||||||||||||||||||||||||||||||
| func processLinksBufferedInternal(input io.ReadCloser, host string, cfg *config.Config, c *touka.Context) (readerOut io.Reader, written int64, err error) { | ||||||||||||||||||||||||||||||||||||||||||
| pipeReader, pipeWriter := io.Pipe() | ||||||||||||||||||||||||||||||||||||||||||
| readerOut = pipeReader | ||||||||||||||||||||||||||||||||||||||||||
| hostBytes := []byte(host) | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| //确保writer关闭 | ||||||||||||||||||||||||||||||||||||||||||
| go func() { | ||||||||||||||||||||||||||||||||||||||||||
| // 在 goroutine 退出时, 根据 err 是否为 nil, 带错误或正常关闭 pipeWriter | ||||||||||||||||||||||||||||||||||||||||||
| defer func() { | ||||||||||||||||||||||||||||||||||||||||||
| if flushErr := bufWriter.Flush(); flushErr != nil { | ||||||||||||||||||||||||||||||||||||||||||
| c.Errorf("writer flush failed %v", flushErr) | ||||||||||||||||||||||||||||||||||||||||||
| // 如果已经存在错误,则保留。否则,记录此错误。 | ||||||||||||||||||||||||||||||||||||||||||
| if err == nil { | ||||||||||||||||||||||||||||||||||||||||||
| err = flushErr | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| if closeErr := input.Close(); closeErr != nil { | ||||||||||||||||||||||||||||||||||||||||||
| c.Errorf("input close failed: %v", closeErr) | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| }() | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| // 使用正则表达式匹配 http 和 https 链接 | ||||||||||||||||||||||||||||||||||||||||||
| for { | ||||||||||||||||||||||||||||||||||||||||||
| line, readErr := bufReader.ReadString('\n') | ||||||||||||||||||||||||||||||||||||||||||
| if readErr != nil { | ||||||||||||||||||||||||||||||||||||||||||
| if readErr == io.EOF { | ||||||||||||||||||||||||||||||||||||||||||
| break // 文件结束 | ||||||||||||||||||||||||||||||||||||||||||
| defer func() { | ||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||
| if closeErr := pipeWriter.CloseWithError(err); closeErr != nil { | ||||||||||||||||||||||||||||||||||||||||||
| c.Errorf("pipeWriter close with error failed: %v", closeErr) | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||
| if closeErr := pipeWriter.Close(); closeErr != nil { | ||||||||||||||||||||||||||||||||||||||||||
| c.Errorf("pipeWriter close failed: %v", closeErr) | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| err = fmt.Errorf("读取行错误: %v", readErr) // 传递错误 | ||||||||||||||||||||||||||||||||||||||||||
| return // Goroutine 中使用 return 返回错误 | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| }() | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| // 替换所有匹配的 URL | ||||||||||||||||||||||||||||||||||||||||||
| modifiedLine := urlPattern.ReplaceAllStringFunc(line, func(originalURL string) string { | ||||||||||||||||||||||||||||||||||||||||||
| return modifyURL(originalURL, host, cfg) // 假设 modifyURL 函数已定义 | ||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||
| buf := bufferPool.Get().(*bytes.Buffer) | ||||||||||||||||||||||||||||||||||||||||||
| buf.Reset() | ||||||||||||||||||||||||||||||||||||||||||
| defer bufferPool.Put(buf) | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| n, writeErr := bufWriter.WriteString(modifiedLine) | ||||||||||||||||||||||||||||||||||||||||||
| written += int64(n) // 更新写入的字节数 | ||||||||||||||||||||||||||||||||||||||||||
| if writeErr != nil { | ||||||||||||||||||||||||||||||||||||||||||
| err = fmt.Errorf("写入文件错误: %v", writeErr) // 传递错误 | ||||||||||||||||||||||||||||||||||||||||||
| return // Goroutine 中使用 return 返回错误 | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| // 将全部输入读入复用的缓冲区 | ||||||||||||||||||||||||||||||||||||||||||
| if _, err = buf.ReadFrom(input); err != nil { | ||||||||||||||||||||||||||||||||||||||||||
| err = fmt.Errorf("reading input failed: %w", err) | ||||||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| // 在返回之前,再刷新一次 (虽然 defer 中已经有 flush,但这里再加一次确保及时刷新) | ||||||||||||||||||||||||||||||||||||||||||
| if flushErr := bufWriter.Flush(); flushErr != nil { | ||||||||||||||||||||||||||||||||||||||||||
| if err == nil { // 避免覆盖之前的错误 | ||||||||||||||||||||||||||||||||||||||||||
| err = flushErr | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| return // Goroutine 中使用 return 返回错误 | ||||||||||||||||||||||||||||||||||||||||||
| // 使用 ReplaceAllFunc 和字节版本辅助函数, 实现准零分配 | ||||||||||||||||||||||||||||||||||||||||||
| modifiedBytes := urlPattern.ReplaceAllFunc(buf.Bytes(), func(originalURL []byte) []byte { | ||||||||||||||||||||||||||||||||||||||||||
| return modifyURLBytes(originalURL, hostBytes, cfg) | ||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| // 将处理后的字节写回管道 | ||||||||||||||||||||||||||||||||||||||||||
| var n int | ||||||||||||||||||||||||||||||||||||||||||
| n, err = pipeWriter.Write(modifiedBytes) | ||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||
| err = fmt.Errorf("writing to pipe failed: %w", err) | ||||||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| written = int64(n) | ||||||||||||||||||||||||||||||||||||||||||
| }() | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| return readerOut, written, nil // 返回 reader 和 written,error 由 Goroutine 通过 pipeWriter.CloseWithError 传递 | ||||||||||||||||||||||||||||||||||||||||||
| return readerOut, written, nil | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个
buildHandlerPath函数与proxy/routing.go中的buildRoutingPath函数功能非常相似,导致了代码重复。建议将它们合并为一个通用的函数,以提高代码的可维护性。合并后的函数可以放在一个共享的文件中,例如proxy/pathbuilder.go。