diff --git a/DEV-VERSION b/DEV-VERSION index 8dfa506..98260d3 100644 --- a/DEV-VERSION +++ b/DEV-VERSION @@ -1 +1 @@ -25w31t-1 \ No newline at end of file +25w31t-2 \ No newline at end of file diff --git a/go.mod b/go.mod index 1820f16..4144ee8 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/WJQSERVER-STUDIO/go-utils/logger v1.5.0 github.com/cloudwego/hertz v0.9.7 github.com/hertz-contrib/http2 v0.1.8 - github.com/satomitouka/touka-httpc v0.4.0 + github.com/satomitouka/touka-httpc v0.4.1 golang.org/x/net v0.39.0 golang.org/x/time v0.11.0 ) @@ -36,3 +36,5 @@ require ( golang.org/x/text v0.24.0 // indirect google.golang.org/protobuf v1.36.6 // indirect ) + +//replace github.com/satomitouka/touka-httpc v0.4.1 => /data/github/satomitoka/touka-httpc diff --git a/go.sum b/go.sum index b6da4cc..47257b7 100644 --- a/go.sum +++ b/go.sum @@ -50,8 +50,8 @@ github.com/nyaruka/phonenumbers v1.6.1 h1:XAJcTdYow16VrVKfglznMpJZz8KMJoMjx/91sX github.com/nyaruka/phonenumbers v1.6.1/go.mod h1:7gjs+Lchqm49adhAKB5cdcng5ZXgt6x7Jgvi0ZorUtU= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/satomitouka/touka-httpc v0.4.0 h1:cnOONdyJHJImMY8L64bvYF+7Ow/5CPf2Yr3RQRRMZOU= -github.com/satomitouka/touka-httpc v0.4.0/go.mod h1:sNXyW5XBufkwB9ZJ+PIlgN/6xiJ7aZV1fWGrXR0u3bA= +github.com/satomitouka/touka-httpc v0.4.1 h1:K1LJwSJJKRPkol6MPOEzc8bReAIUqxVuzdFfTAi/2AI= +github.com/satomitouka/touka-httpc v0.4.1/go.mod h1:E1JeXw81XclzvlqVvSio/GcDmvN8wWLPpbNRN42Uwfc= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= diff --git a/proxy/ghcr.go b/proxy/ghcr.go index 71d764d..c3e9ca3 100644 --- a/proxy/ghcr.go +++ b/proxy/ghcr.go @@ -2,13 +2,101 @@ package proxy import ( "context" + "fmt" "ghproxy/config" + "net/http" + "strconv" "github.com/cloudwego/hertz/pkg/app" ) func GhcrRouting(cfg *config.Config) app.HandlerFunc { return func(ctx context.Context, c *app.RequestContext) { - ChunkedProxyRequest(ctx, c, "https://ghcr.io"+string(c.Request.RequestURI()), cfg, "ghcr") + GhcrRequest(ctx, c, "https://ghcr.io"+string(c.Request.RequestURI()), cfg, "ghcr") } } + +func GhcrRequest(ctx context.Context, c *app.RequestContext, u string, cfg *config.Config, matcher string) { + + var ( + method []byte + req *http.Request + resp *http.Response + err error + ) + + method = c.Request.Method() + + rb := client.NewRequestBuilder(string(method), u) + rb.NoDefaultHeaders() + + //req, err = client.NewRequest(string(method), u, c.Request.BodyStream()) + req, err = rb.Build() + if err != nil { + HandleError(c, fmt.Sprintf("Failed to create request: %v", err)) + return + } + + c.Request.Header.VisitAll(func(key, value []byte) { + headerKey := string(key) + headerValue := string(value) + req.Header.Add(headerKey, headerValue) + }) + + resp, err = client.Do(req) + if err != nil { + HandleError(c, fmt.Sprintf("Failed to send request: %v", err)) + return + } + + // 错误处理(404) + if resp.StatusCode == 404 { + ErrorPage(c, NewErrorWithStatusLookup(404, "Page Not Found (From Github)")) + 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 { + var finalURL string + finalURL = resp.Request.URL.String() + err = resp.Body.Close() + if err != nil { + logError("Failed to close response body: %v", err) + } + c.Redirect(301, []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 + } + } + + // 复制响应头,排除需要移除的 header + for key, values := range resp.Header { + for _, value := range values { + //c.Header(key, value) + c.Response.Header.Add(key, value) + } + } + + c.Status(resp.StatusCode) + + if contentLength != "" { + c.SetBodyStream(resp.Body, bodySize) + return + } + c.SetBodyStream(resp.Body, -1) + +}