This commit is contained in:
WJQSERVER 2025-02-16 19:48:53 +08:00
parent bd666e08d1
commit 785a74dfeb
14 changed files with 241 additions and 126 deletions

View file

@ -7,66 +7,15 @@ import (
"io"
"net/http"
"strconv"
"sync"
"time"
"github.com/gin-gonic/gin"
httpc "github.com/satomitouka/touka-httpc"
)
var BufferSize int = 32 * 1024 // 32KB
var (
ctr *http.Transport
BufferPool *sync.Pool
cclient *httpc.Client
)
func InitReq(cfg *config.Config) {
initChunkedHTTPClient(cfg)
initGitHTTPClient(cfg)
// 初始化固定大小的缓存池
BufferPool = &sync.Pool{
New: func() interface{} {
return make([]byte, BufferSize)
},
}
}
func initChunkedHTTPClient(cfg *config.Config) {
/*
ctr = &http.Transport{
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,
}
*/
ctr = &http.Transport{
MaxIdleConns: 100,
MaxConnsPerHost: 60,
IdleConnTimeout: 20 * time.Second,
}
if cfg.Outbound.Enabled {
initTransport(cfg, ctr)
}
cclient = httpc.New(
httpc.WithTransport(ctr),
)
}
func ChunkedProxyRequest(c *gin.Context, u string, cfg *config.Config, mode string, runMode string) {
method := c.Request.Method
// 发送HEAD请求, 预获取Content-Length
headReq, err := cclient.NewRequest("HEAD", u, nil)
headReq, err := client.NewRequest("HEAD", u, nil)
if err != nil {
HandleError(c, fmt.Sprintf("Failed to create request: %v", err))
return
@ -75,7 +24,7 @@ func ChunkedProxyRequest(c *gin.Context, u string, cfg *config.Config, mode stri
removeWSHeader(headReq) // 删除Conection Upgrade头, 避免与HTTP/2冲突(检查是否存在Upgrade头)
AuthPassThrough(c, cfg, headReq)
headResp, err := cclient.Do(headReq)
headResp, err := client.Do(headReq)
if err != nil {
HandleError(c, fmt.Sprintf("Failed to send request: %v", err))
return
@ -107,7 +56,7 @@ func ChunkedProxyRequest(c *gin.Context, u string, cfg *config.Config, mode stri
bodyReader := bytes.NewBuffer(body)
req, err := cclient.NewRequest(method, u, bodyReader)
req, err := client.NewRequest(method, u, bodyReader)
if err != nil {
HandleError(c, fmt.Sprintf("Failed to create request: %v", err))
return
@ -116,7 +65,7 @@ func ChunkedProxyRequest(c *gin.Context, u string, cfg *config.Config, mode stri
removeWSHeader(req) // 删除Conection Upgrade头, 避免与HTTP/2冲突(检查是否存在Upgrade头)
AuthPassThrough(c, cfg, req)
resp, err := cclient.Do(req)
resp, err := client.Do(req)
if err != nil {
HandleError(c, fmt.Sprintf("Failed to send request: %v", err))
return

View file

@ -7,42 +7,16 @@ import (
"io"
"net/http"
"strconv"
"time"
"github.com/gin-gonic/gin"
httpc "github.com/satomitouka/touka-httpc"
)
var (
gclient *httpc.Client
gtr *http.Transport
)
func initGitHTTPClient(cfg *config.Config) {
gtr = &http.Transport{
MaxIdleConns: 30,
MaxConnsPerHost: 30,
IdleConnTimeout: 30 * time.Second,
}
if cfg.Outbound.Enabled {
initTransport(cfg, gtr)
}
/*
gclient = &http.Client{
Transport: gtr,
}
*/
gclient = httpc.New(
httpc.WithTransport(gtr),
)
}
func GitReq(c *gin.Context, u string, cfg *config.Config, mode string, runMode string) {
method := c.Request.Method
logInfo("%s %s %s %s %s", c.ClientIP(), method, u, c.Request.Header.Get("User-Agent"), c.Request.Proto)
// 发送HEAD请求, 预获取Content-Length
headReq, err := gclient.NewRequest("HEAD", u, nil)
headReq, err := client.NewRequest("HEAD", u, nil)
if err != nil {
HandleError(c, fmt.Sprintf("Failed to create request: %v", err))
return
@ -50,7 +24,7 @@ func GitReq(c *gin.Context, u string, cfg *config.Config, mode string, runMode s
setRequestHeaders(c, headReq)
AuthPassThrough(c, cfg, headReq)
headResp, err := gclient.Do(headReq)
headResp, err := client.Do(headReq)
if err != nil {
HandleError(c, fmt.Sprintf("Failed to send request: %v", err))
return
@ -84,7 +58,7 @@ func GitReq(c *gin.Context, u string, cfg *config.Config, mode string, runMode s
bodyReader := bytes.NewBuffer(body)
// 创建请求
req, err := gclient.NewRequest(method, u, bodyReader)
req, err := client.NewRequest(method, u, bodyReader)
if err != nil {
HandleError(c, fmt.Sprintf("Failed to create request: %v", err))
return
@ -92,7 +66,7 @@ func GitReq(c *gin.Context, u string, cfg *config.Config, mode string, runMode s
setRequestHeaders(c, req)
AuthPassThrough(c, cfg, req)
resp, err := gclient.Do(req)
resp, err := client.Do(req)
if err != nil {
HandleError(c, fmt.Sprintf("Failed to send request: %v", err))
return
@ -139,7 +113,15 @@ func GitReq(c *gin.Context, u string, cfg *config.Config, mode string, runMode s
c.Status(resp.StatusCode)
if _, err := io.Copy(c.Writer, resp.Body); err != nil {
logError("%s %s %s %s %s Response-Copy-Error: %v", c.ClientIP(), method, u, c.Request.Header.Get("User-Agent"), c.Request.Proto, err)
// 使用固定32KB缓冲池
buffer := BufferPool.Get().([]byte)
defer BufferPool.Put(buffer)
_, err = io.CopyBuffer(c.Writer, resp.Body, buffer)
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.Proto, err)
return
} else {
c.Writer.Flush() // 确保刷入
}
}

View file

@ -61,7 +61,7 @@ func NoRouteHandler(cfg *config.Config, limiter *rate.RateLimiter, iplimiter *ra
// 白名单检查
if cfg.Whitelist.Enabled {
whitelist := auth.CheckWhitelist(repouser, username, repo)
whitelist := auth.CheckWhitelist(username, repo)
if !whitelist {
logErrMsg := fmt.Sprintf("%s %s %s %s %s Whitelist Blocked repo: %s", c.ClientIP(), c.Request.Method, rawPath, c.Request.Header.Get("User-Agent"), c.Request.Proto, repouser)
errMsg := fmt.Sprintf("Whitelist Blocked repo: %s", repouser)

88
proxy/httpc.go Normal file
View file

@ -0,0 +1,88 @@
package proxy
import (
"fmt"
"ghproxy/config"
"net/http"
"sync"
"time"
httpc "github.com/satomitouka/touka-httpc"
)
var BufferSize int = 32 * 1024 // 32KB
var (
tr *http.Transport
BufferPool *sync.Pool
client *httpc.Client
)
func InitReq(cfg *config.Config) {
initHTTPClient(cfg)
// 初始化固定大小的缓存池
BufferPool = &sync.Pool{
New: func() interface{} {
return make([]byte, BufferSize)
},
}
}
func initHTTPClient(cfg *config.Config) {
/*
ctr = &http.Transport{
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,
}
*/
if cfg.Httpc.Mode == "auto" {
tr = &http.Transport{
//MaxIdleConns: 160,
IdleConnTimeout: 30 * time.Second,
WriteBufferSize: 32 * 1024, // 32KB
ReadBufferSize: 32 * 1024, // 32KB
}
} else if cfg.Httpc.Mode == "advanced" {
tr = &http.Transport{
MaxIdleConns: cfg.Httpc.MaxIdleConns,
MaxConnsPerHost: cfg.Httpc.MaxConnsPerHost,
MaxIdleConnsPerHost: cfg.Httpc.MaxIdleConnsPerHost,
WriteBufferSize: 32 * 1024, // 32KB
ReadBufferSize: 32 * 1024, // 32KB
}
} else {
// 错误的模式
logError("unknown httpc mode: %s", cfg.Httpc.Mode)
fmt.Println("unknown httpc mode: ", cfg.Httpc.Mode)
logWarning("use Auto to Run HTTP Client")
fmt.Println("use Auto to Run HTTP Client")
tr = &http.Transport{
//MaxIdleConns: 160,
IdleConnTimeout: 30 * time.Second,
WriteBufferSize: 32 * 1024, // 32KB
ReadBufferSize: 32 * 1024, // 32KB
}
}
if cfg.Outbound.Enabled {
initTransport(cfg, tr)
}
if cfg.Server.Debug {
client = httpc.New(
httpc.WithTransport(tr),
httpc.WithDumpLog(),
)
} else {
client = httpc.New(
httpc.WithTransport(tr),
)
}
}