Files
ghproxy/proxy/chunkreq.go
wjqserver bed6c486dc 25w28b
2025-04-15 10:23:29 +08:00

124 lines
3.2 KiB
Go

package proxy
import (
"bytes"
"context"
"fmt"
"ghproxy/config"
"net/http"
"strconv"
"github.com/cloudwego/hertz/pkg/app"
)
func ChunkedProxyRequest(ctx context.Context, c *app.RequestContext, u string, cfg *config.Config, matcher string) {
method := c.Request.Method
body := c.Request.Body()
bodyReader := bytes.NewBuffer(body)
req, err := client.NewRequest(string(method()), u, bodyReader)
if err != nil {
HandleError(c, fmt.Sprintf("Failed to create request: %v", err))
return
}
setRequestHeaders(c, req)
removeWSHeader(req) // 删除Conection Upgrade头, 避免与HTTP/2冲突(检查是否存在Upgrade头)
AuthPassThrough(c, cfg, req)
resp, err := client.Do(req)
if err != nil {
HandleError(c, fmt.Sprintf("Failed to send request: %v", err))
return
}
// 错误处理(404)
if resp.StatusCode == 404 {
//c.String(http.StatusNotFound, "File Not Found")
c.Status(http.StatusNotFound)
return
}
var (
bodySize int
contentLength string
sizelimit int
)
sizelimit = cfg.Server.SizeLimit * 1024 * 1024
contentLength = resp.Header.Get("Content-Length")
if contentLength != "" {
var err error
bodySize, err = strconv.Atoi(contentLength)
if err != nil {
logWarning("%s %s %s %s %s Content-Length header is not a valid integer: %v", c.ClientIP(), c.Method(), c.Path(), c.UserAgent(), c.Request.Header.GetProtocol(), err)
bodySize = -1
}
if err == nil && bodySize > sizelimit {
finalURL := resp.Request.URL.String()
err := resp.Body.Close()
if err != nil {
logError("Failed to close response body: %v", err)
}
c.Redirect(http.StatusMovedPermanently, []byte(finalURL))
logWarning("%s %s %s %s %s Final-URL: %s Size-Limit-Exceeded: %d", c.ClientIP(), c.Method(), c.Path(), c.UserAgent(), c.Request.Header.GetProtocol(), finalURL, bodySize)
return
}
}
for key, values := range resp.Header {
for _, value := range values {
c.Header(key, value)
}
}
headersToRemove := map[string]struct{}{
"Content-Security-Policy": {},
"Referrer-Policy": {},
"Strict-Transport-Security": {},
}
for header := range headersToRemove {
resp.Header.Del(header)
}
switch cfg.Server.Cors {
case "*":
c.Header("Access-Control-Allow-Origin", "*")
case "":
c.Header("Access-Control-Allow-Origin", "*")
case "nil":
c.Header("Access-Control-Allow-Origin", "")
default:
c.Header("Access-Control-Allow-Origin", cfg.Server.Cors)
}
c.Status(resp.StatusCode)
if MatcherShell(u) && matchString(matcher, matchedMatchers) && cfg.Shell.Editor {
// 判断body是不是gzip
var compress string
if resp.Header.Get("Content-Encoding") == "gzip" {
compress = "gzip"
}
logInfo("Is Shell: %s %s %s %s %s", c.ClientIP(), method, u, c.Request.Header.Get("User-Agent"), c.Request.Header.GetProtocol())
c.Header("Content-Length", "")
reader, _, err := processLinks(resp.Body, compress, string(c.Request.Host()), cfg)
c.SetBodyStream(reader, -1)
if err != nil {
logError("%s %s %s %s %s Failed to copy response body: %v", c.ClientIP(), method, u, c.Request.Header.Get("User-Agent"), c.Request.Header.GetProtocol(), err)
return
}
} else {
if contentLength != "" {
c.SetBodyStream(resp.Body, bodySize)
return
}
c.SetBodyStream(resp.Body, -1)
}
}