diff --git a/DEV-VERSION b/DEV-VERSION index e0ca1d4..8ce6236 100644 --- a/DEV-VERSION +++ b/DEV-VERSION @@ -1 +1 @@ -25w09b \ No newline at end of file +25w10t-1 diff --git a/pages/index.html b/pages/index.html index bffeb0a..554c293 100644 --- a/pages/index.html +++ b/pages/index.html @@ -369,17 +369,17 @@ let formattedLink = ""; if (githubLink.startsWith("https://github.com/") || githubLink.startsWith("http://github.com/")) { - formattedLink = "https://" + currentHost + "/github.com" + githubLink.substring(githubLink.indexOf("/", 8)); + formattedLink = window.location.protocol + "//" + currentHost + "/github.com" + githubLink.substring(githubLink.indexOf("/", 8)); } else if (githubLink.startsWith("github.com/")) { - formattedLink = "https://" + currentHost + "/" + githubLink; + formattedLink = window.location.protocol + "//" + currentHost + "/" + githubLink; } else if (githubLink.startsWith("https://raw.githubusercontent.com/") || githubLink.startsWith("http://raw.githubusercontent.com/")) { - formattedLink = "https://" + currentHost + githubLink.substring(githubLink.indexOf("/", 7)); + formattedLink = window.location.protocol + "//" + currentHost + githubLink.substring(githubLink.indexOf("/", 7)); } else if (githubLink.startsWith("raw.githubusercontent.com/")) { - formattedLink = "https://" + currentHost + "/" + githubLink; + formattedLink = window.location.protocol + "//" + currentHost + "/" + githubLink; } else if (githubLink.startsWith("https://gist.githubusercontent.com/") || githubLink.startsWith("http://gist.githubusercontent.com/")) { - formattedLink = "https://" + currentHost + "/gist.github.com" + githubLink.substring(githubLink.indexOf("/", 18)); + formattedLink = window.location.protocol + "//" + currentHost + "/gist.github.com" + githubLink.substring(githubLink.indexOf("/", 18)); } else if (githubLink.startsWith("gist.githubusercontent.com/")) { - formattedLink = "https://" + currentHost + "/" + githubLink; + formattedLink = window.location.protocol + "//" + currentHost + "/" + githubLink; } else { showToast('请输入有效的GitHub链接'); return null; @@ -437,4 +437,4 @@ - \ No newline at end of file + diff --git a/proxy/chunkreq.go b/proxy/chunkreq.go index a0e4fca..44b5759 100644 --- a/proxy/chunkreq.go +++ b/proxy/chunkreq.go @@ -5,7 +5,9 @@ import ( "fmt" "ghproxy/config" "io" + "net" "net/http" + "strconv" "sync" "time" @@ -34,9 +36,16 @@ func InitReq() { func initChunkedHTTPClient() { ctr = &http.Transport{ - MaxIdleConns: 100, - MaxConnsPerHost: 60, - IdleConnTimeout: 20 * time.Second, + MaxIdleConns: 100, + MaxConnsPerHost: 60, + IdleConnTimeout: 20 * time.Second, + TLSHandshakeTimeout: 10 * time.Second, + ExpectContinueTimeout: 1 * time.Second, + ResponseHeaderTimeout: 10 * time.Second, + DialContext: (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + }).DialContext, } cclient = &http.Client{ Transport: ctr, @@ -62,13 +71,32 @@ func ChunkedProxyRequest(c *gin.Context, u string, cfg *config.Config, mode stri HandleError(c, fmt.Sprintf("Failed to send request: %v", err)) return } - defer headResp.Body.Close() + //defer headResp.Body.Close() + defer func(Body io.ReadCloser) { + if err := Body.Close(); err != nil { + logError("Failed to close response body: %v", err) + } + }(headResp.Body) - if err := HandleResponseSize(headResp, cfg, c); err != nil { - logWarning("%s %s %s %s %s Response-Size-Error: %v", c.ClientIP(), method, u, c.Request.Header.Get("User-Agent"), c.Request.Proto, err) - return + contentLength := headResp.Header.Get("Content-Length") + sizelimit := cfg.Server.SizeLimit * 1024 * 1024 + if contentLength != "" { + size, err := strconv.Atoi(contentLength) + if err == nil && size > sizelimit { + finalURL := headResp.Request.URL.String() + c.Redirect(http.StatusMovedPermanently, finalURL) + logWarning("%s %s %s %s %s Final-URL: %s Size-Limit-Exceeded: %d", c.ClientIP(), c.Request.Method, c.Request.URL.String(), c.Request.Header.Get("User-Agent"), c.Request.Proto, finalURL, size) + return + } } + /* + if err := HandleResponseSize(headResp, cfg, c); err != nil { + logWarning("%s %s %s %s %s Response-Size-Error: %v", c.ClientIP(), method, u, c.Request.Header.Get("User-Agent"), c.Request.Proto, err) + return + } + */ + body, err := readRequestBody(c) if err != nil { HandleError(c, err.Error()) @@ -84,7 +112,6 @@ func ChunkedProxyRequest(c *gin.Context, u string, cfg *config.Config, mode stri return } - req.Header.Set("Transfer-Encoding", "chunked") // 确保设置分块传输编码 setRequestHeaders(c, req) removeWSHeader(req) // 删除Conection Upgrade头, 避免与HTTP/2冲突(检查是否存在Upgrade头) AuthPassThrough(c, cfg, req) @@ -96,12 +123,45 @@ func ChunkedProxyRequest(c *gin.Context, u string, cfg *config.Config, mode stri } defer resp.Body.Close() - if err := HandleResponseSize(resp, cfg, c); err != nil { - logWarning("%s %s %s %s %s Response-Size-Error: %v", c.ClientIP(), method, u, c.Request.Header.Get("User-Agent"), c.Request.Proto, err) - return + /* + if err := HandleResponseSize(resp, cfg, c); err != nil { + logWarning("%s %s %s %s %s Response-Size-Error: %v", c.ClientIP(), method, u, c.Request.Header.Get("User-Agent"), c.Request.Proto, err) + return + } + */ + + contentLength = resp.Header.Get("Content-Length") + if contentLength != "" { + size, err := strconv.Atoi(contentLength) + if err == nil && size > sizelimit { + finalURL := resp.Request.URL.String() + c.Redirect(http.StatusMovedPermanently, finalURL) + logWarning("%s %s %s %s %s Final-URL: %s Size-Limit-Exceeded: %d", c.ClientIP(), c.Request.Method, c.Request.URL.String(), c.Request.Header.Get("User-Agent"), c.Request.Proto, finalURL, size) + return + } } - CopyResponseHeaders(resp, c, cfg) + 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) + } + + if cfg.CORS.Enabled { + c.Header("Access-Control-Allow-Origin", "*") + } else { + c.Header("Access-Control-Allow-Origin", "") + } c.Status(resp.StatusCode) diff --git a/proxy/gitreq.go b/proxy/gitreq.go index 173fa6c..6dbd20d 100644 --- a/proxy/gitreq.go +++ b/proxy/gitreq.go @@ -6,6 +6,7 @@ import ( "ghproxy/config" "io" "net/http" + "strconv" "time" "github.com/gin-gonic/gin" @@ -48,11 +49,24 @@ func GitReq(c *gin.Context, u string, cfg *config.Config, mode string, runMode s HandleError(c, fmt.Sprintf("Failed to send request: %v", err)) return } - defer headResp.Body.Close() - if err := HandleResponseSize(headResp, cfg, c); err != nil { - logWarning("%s %s %s %s %s Response-Size-Error: %v", c.ClientIP(), method, u, c.Request.Header.Get("User-Agent"), c.Request.Proto, err) - return + // defer headResp.Body.Close() + defer func(Body io.ReadCloser) { + if err := Body.Close(); err != nil { + logError("Failed to close response body: %v", err) + } + }(headResp.Body) + + contentLength := headResp.Header.Get("Content-Length") + sizelimit := cfg.Server.SizeLimit * 1024 * 1024 + if contentLength != "" { + size, err := strconv.Atoi(contentLength) + if err == nil && size > sizelimit { + finalURL := headResp.Request.URL.String() + c.Redirect(http.StatusMovedPermanently, finalURL) + logWarning("%s %s %s %s %s Final-URL: %s Size-Limit-Exceeded: %d", c.ClientIP(), c.Request.Method, c.Request.URL.String(), c.Request.Header.Get("User-Agent"), c.Request.Proto, finalURL, size) + return + } } body, err := readRequestBody(c) @@ -77,14 +91,52 @@ func GitReq(c *gin.Context, u string, cfg *config.Config, mode string, runMode s HandleError(c, fmt.Sprintf("Failed to send request: %v", err)) return } - defer resp.Body.Close() + //defer resp.Body.Close() + defer func(Body io.ReadCloser) { + if err := Body.Close(); err != nil { + logError("Failed to close response body: %v", err) + } + }(resp.Body) - if err := HandleResponseSize(resp, cfg, c); err != nil { - logWarning("%s %s %s %s %s Response-Size-Error: %v", c.ClientIP(), method, u, c.Request.Header.Get("User-Agent"), c.Request.Proto, err) - return + /* + if err := HandleResponseSize(resp, cfg, c); err != nil { + logWarning("%s %s %s %s %s Response-Size-Error: %v", c.ClientIP(), method, u, c.Request.Header.Get("User-Agent"), c.Request.Proto, err) + return + } + */ + contentLength = resp.Header.Get("Content-Length") + if contentLength != "" { + size, err := strconv.Atoi(contentLength) + if err == nil && size > sizelimit { + finalURL := resp.Request.URL.String() + c.Redirect(http.StatusMovedPermanently, finalURL) + logWarning("%s %s %s %s %s Final-URL: %s Size-Limit-Exceeded: %d", c.ClientIP(), c.Request.Method, c.Request.URL.String(), c.Request.Header.Get("User-Agent"), c.Request.Proto, finalURL, size) + 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) + } + + if cfg.CORS.Enabled { + c.Header("Access-Control-Allow-Origin", "*") + } else { + c.Header("Access-Control-Allow-Origin", "") } - CopyResponseHeaders(resp, c, cfg) c.Status(resp.StatusCode) if _, err := io.Copy(c.Writer, resp.Body); err != nil { diff --git a/proxy/proxy.go b/proxy/proxy.go index 80a9aa2..ca45203 100644 --- a/proxy/proxy.go +++ b/proxy/proxy.go @@ -5,9 +5,6 @@ import ( "io" "net/http" "regexp" - "strconv" - - "ghproxy/config" "github.com/WJQSERVER-STUDIO/go-utils/logger" "github.com/gin-gonic/gin" @@ -60,22 +57,6 @@ func SendRequest(c *gin.Context, req *req.Request, method, url string) (*req.Res } */ -// 处理响应大小 -func HandleResponseSize(resp *http.Response, cfg *config.Config, c *gin.Context) error { - contentLength := resp.Header.Get("Content-Length") - sizelimit := cfg.Server.SizeLimit * 1024 * 1024 - if contentLength != "" { - size, err := strconv.Atoi(contentLength) - if err == nil && size > sizelimit { - finalURL := resp.Request.URL.String() - c.Redirect(http.StatusMovedPermanently, finalURL) - logWarning("%s %s %s %s %s Final-URL: %s Size-Limit-Exceeded: %d", c.ClientIP(), c.Request.Method, c.Request.URL.String(), c.Request.Header.Get("User-Agent"), c.Request.Proto, finalURL, size) - return fmt.Errorf("Path: %s size limit exceeded: %d", finalURL, size) - } - } - return nil -} - func HandleError(c *gin.Context, message string) { c.String(http.StatusInternalServerError, fmt.Sprintf("server error %v", message)) logWarning(message) @@ -91,3 +72,21 @@ func CheckURL(u string, c *gin.Context) []string { logWarning(errMsg) return nil } + +/* +// 处理响应大小 +func HandleResponseSize(resp *http.Response, cfg *config.Config, c *gin.Context) error { + contentLength := resp.Header.Get("Content-Length") + sizelimit := cfg.Server.SizeLimit * 1024 * 1024 + if contentLength != "" { + size, err := strconv.Atoi(contentLength) + if err == nil && size > sizelimit { + finalURL := resp.Request.URL.String() + c.Redirect(http.StatusMovedPermanently, finalURL) + logWarning("%s %s %s %s %s Final-URL: %s Size-Limit-Exceeded: %d", c.ClientIP(), c.Request.Method, c.Request.URL.String(), c.Request.Header.Get("User-Agent"), c.Request.Proto, finalURL, size) + return fmt.Errorf("Path: %s size limit exceeded: %d", finalURL, size) + } + } + return nil +} +*/ diff --git a/proxy/respheader.go b/proxy/respheader.go deleted file mode 100644 index 2655844..0000000 --- a/proxy/respheader.go +++ /dev/null @@ -1,56 +0,0 @@ -package proxy - -import ( - "ghproxy/config" - "net/http" - - "github.com/gin-gonic/gin" -) - -func CopyResponseHeaders(resp *http.Response, c *gin.Context, cfg *config.Config) { - - copyHeaders(resp, c) - - removeHeaders(resp) - - setCORSHeaders(c, cfg) - - setDefaultHeaders(c) -} - -// 复制响应头 -func copyHeaders(resp *http.Response, c *gin.Context) { - for key, values := range resp.Header { - for _, value := range values { - c.Header(key, value) - } - } -} - -// 移除指定响应头 -func removeHeaders(resp *http.Response) { - headersToRemove := map[string]struct{}{ - "Content-Security-Policy": {}, - "Referrer-Policy": {}, - "Strict-Transport-Security": {}, - } - - for header := range headersToRemove { - resp.Header.Del(header) - } -} - -// CORS配置 -func setCORSHeaders(c *gin.Context, cfg *config.Config) { - if cfg.CORS.Enabled { - c.Header("Access-Control-Allow-Origin", "*") - } else { - c.Header("Access-Control-Allow-Origin", "") - } -} - -// 默认响应 -func setDefaultHeaders(c *gin.Context) { - c.Header("Age", "10") - c.Header("Cache-Control", "max-age=300") -}