mirror of
https://github.com/WJQSERVER-STUDIO/ghproxy.git
synced 2026-02-03 08:11:11 +08:00
25w10t-1 (#41)
This commit is contained in:
parent
5d08993cbc
commit
6782a51aa2
6 changed files with 159 additions and 104 deletions
|
|
@ -1 +1 @@
|
||||||
25w09b
|
25w10t-1
|
||||||
|
|
|
||||||
|
|
@ -369,17 +369,17 @@
|
||||||
let formattedLink = "";
|
let formattedLink = "";
|
||||||
|
|
||||||
if (githubLink.startsWith("https://github.com/") || githubLink.startsWith("http://github.com/")) {
|
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/")) {
|
} 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/")) {
|
} 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/")) {
|
} 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/")) {
|
} 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/")) {
|
} else if (githubLink.startsWith("gist.githubusercontent.com/")) {
|
||||||
formattedLink = "https://" + currentHost + "/" + githubLink;
|
formattedLink = window.location.protocol + "//" + currentHost + "/" + githubLink;
|
||||||
} else {
|
} else {
|
||||||
showToast('请输入有效的GitHub链接');
|
showToast('请输入有效的GitHub链接');
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,9 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"ghproxy/config"
|
"ghproxy/config"
|
||||||
"io"
|
"io"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -37,6 +39,13 @@ func initChunkedHTTPClient() {
|
||||||
MaxIdleConns: 100,
|
MaxIdleConns: 100,
|
||||||
MaxConnsPerHost: 60,
|
MaxConnsPerHost: 60,
|
||||||
IdleConnTimeout: 20 * time.Second,
|
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{
|
cclient = &http.Client{
|
||||||
Transport: ctr,
|
Transport: ctr,
|
||||||
|
|
@ -62,12 +71,31 @@ func ChunkedProxyRequest(c *gin.Context, u string, cfg *config.Config, mode stri
|
||||||
HandleError(c, fmt.Sprintf("Failed to send request: %v", err))
|
HandleError(c, fmt.Sprintf("Failed to send request: %v", err))
|
||||||
return
|
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)
|
||||||
|
|
||||||
|
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 {
|
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)
|
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
|
return
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
body, err := readRequestBody(c)
|
body, err := readRequestBody(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -84,7 +112,6 @@ func ChunkedProxyRequest(c *gin.Context, u string, cfg *config.Config, mode stri
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Set("Transfer-Encoding", "chunked") // 确保设置分块传输编码
|
|
||||||
setRequestHeaders(c, req)
|
setRequestHeaders(c, req)
|
||||||
removeWSHeader(req) // 删除Conection Upgrade头, 避免与HTTP/2冲突(检查是否存在Upgrade头)
|
removeWSHeader(req) // 删除Conection Upgrade头, 避免与HTTP/2冲突(检查是否存在Upgrade头)
|
||||||
AuthPassThrough(c, cfg, req)
|
AuthPassThrough(c, cfg, req)
|
||||||
|
|
@ -96,12 +123,45 @@ func ChunkedProxyRequest(c *gin.Context, u string, cfg *config.Config, mode stri
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
/*
|
||||||
if err := HandleResponseSize(resp, cfg, c); err != nil {
|
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)
|
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
|
return
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
CopyResponseHeaders(resp, c, cfg)
|
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", "")
|
||||||
|
}
|
||||||
|
|
||||||
c.Status(resp.StatusCode)
|
c.Status(resp.StatusCode)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"ghproxy/config"
|
"ghproxy/config"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
|
@ -48,12 +49,25 @@ func GitReq(c *gin.Context, u string, cfg *config.Config, mode string, runMode s
|
||||||
HandleError(c, fmt.Sprintf("Failed to send request: %v", err))
|
HandleError(c, fmt.Sprintf("Failed to send request: %v", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer headResp.Body.Close()
|
|
||||||
|
|
||||||
if err := HandleResponseSize(headResp, cfg, c); err != nil {
|
// defer headResp.Body.Close()
|
||||||
logWarning("%s %s %s %s %s Response-Size-Error: %v", c.ClientIP(), method, u, c.Request.Header.Get("User-Agent"), c.Request.Proto, err)
|
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
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
body, err := readRequestBody(c)
|
body, err := readRequestBody(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -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))
|
HandleError(c, fmt.Sprintf("Failed to send request: %v", err))
|
||||||
return
|
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 {
|
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)
|
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
|
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)
|
c.Status(resp.StatusCode)
|
||||||
|
|
||||||
if _, err := io.Copy(c.Writer, resp.Body); err != nil {
|
if _, err := io.Copy(c.Writer, resp.Body); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,6 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"ghproxy/config"
|
|
||||||
|
|
||||||
"github.com/WJQSERVER-STUDIO/go-utils/logger"
|
"github.com/WJQSERVER-STUDIO/go-utils/logger"
|
||||||
"github.com/gin-gonic/gin"
|
"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) {
|
func HandleError(c *gin.Context, message string) {
|
||||||
c.String(http.StatusInternalServerError, fmt.Sprintf("server error %v", message))
|
c.String(http.StatusInternalServerError, fmt.Sprintf("server error %v", message))
|
||||||
logWarning(message)
|
logWarning(message)
|
||||||
|
|
@ -91,3 +72,21 @@ func CheckURL(u string, c *gin.Context) []string {
|
||||||
logWarning(errMsg)
|
logWarning(errMsg)
|
||||||
return nil
|
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
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
|
||||||
|
|
@ -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")
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue