2
.github/ISSUE_TEMPLATE/features_request.md
vendored
2
.github/ISSUE_TEMPLATE/features_request.md
vendored
@@ -2,7 +2,7 @@
|
|||||||
name: Features request
|
name: Features request
|
||||||
about: 提出新功能建议
|
about: 提出新功能建议
|
||||||
title: "[Features]"
|
title: "[Features]"
|
||||||
labels: enhancement
|
labels: 改进
|
||||||
assignees: ''
|
assignees: ''
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
21
CHANGELOG.md
21
CHANGELOG.md
@@ -1,5 +1,26 @@
|
|||||||
# 更新日志
|
# 更新日志
|
||||||
|
|
||||||
|
3.0.3 - 2025-04-19
|
||||||
|
---
|
||||||
|
- CHANGE: 增加移除部分header的处置, 避免向服务端/客户端透露过多信息
|
||||||
|
- FIX: 修正非预期的header操作行为
|
||||||
|
- CHANGE: 合并header相关逻辑, 避免多次操作
|
||||||
|
- CHANGE: 对editor模式下的input进行处置, 增加隐式关闭处理
|
||||||
|
- CHANGE: 增加`netlib`配置项
|
||||||
|
|
||||||
|
25w29b - 2025-04-19
|
||||||
|
---
|
||||||
|
- PRE-RELEASE: 此版本是v3.0.3预发布版本,请勿在生产环境中使用;
|
||||||
|
- CHANGE: 增加`netlib`配置项
|
||||||
|
|
||||||
|
25w29a - 2025-04-17
|
||||||
|
---
|
||||||
|
- PRE-RELEASE: 此版本是v3.0.3预发布版本,请勿在生产环境中使用;
|
||||||
|
- CHANGE: 增加移除部分header的处置, 避免向服务端/客户端透露过多信息
|
||||||
|
- FIX: 修正非预期的header操作行为
|
||||||
|
- CHANGE: 合并header相关逻辑, 避免多次操作
|
||||||
|
- CHANGE: 对editor模式下的input进行处置, 增加隐式关闭处理
|
||||||
|
|
||||||
3.0.2 - 2025-04-15
|
3.0.2 - 2025-04-15
|
||||||
---
|
---
|
||||||
- CHANGE: 避免重复的re编译操作
|
- CHANGE: 避免重复的re编译操作
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
25w28b
|
25w29b
|
||||||
@@ -22,15 +22,20 @@ type Config struct {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
[server]
|
[server]
|
||||||
host = "0.0.0.0" # 监听地址
|
host = "0.0.0.0"
|
||||||
port = 8080 # 监听端口
|
port = 8080
|
||||||
sizeLimit = 125 # 125MB
|
netlib = "netpoll" # "netpoll" / "std" "standard" "net/http" "net"
|
||||||
H2C = true # 是否开启H2C传输
|
sizeLimit = 125 # MB
|
||||||
|
memLimit = 0 # MB
|
||||||
|
H2C = true
|
||||||
|
cors = "*" # "*"/"" -> "*" ; "nil" -> "" ;
|
||||||
|
debug = false
|
||||||
*/
|
*/
|
||||||
|
|
||||||
type ServerConfig struct {
|
type ServerConfig struct {
|
||||||
Port int `toml:"port"`
|
Port int `toml:"port"`
|
||||||
Host string `toml:"host"`
|
Host string `toml:"host"`
|
||||||
|
NetLib string `toml:"netlib"`
|
||||||
SizeLimit int `toml:"sizeLimit"`
|
SizeLimit int `toml:"sizeLimit"`
|
||||||
MemLimit int64 `toml:"memLimit"`
|
MemLimit int64 `toml:"memLimit"`
|
||||||
H2C bool `toml:"H2C"`
|
H2C bool `toml:"H2C"`
|
||||||
@@ -180,6 +185,7 @@ func DefaultConfig() *Config {
|
|||||||
Server: ServerConfig{
|
Server: ServerConfig{
|
||||||
Port: 8080,
|
Port: 8080,
|
||||||
Host: "0.0.0.0",
|
Host: "0.0.0.0",
|
||||||
|
NetLib: "netpoll",
|
||||||
SizeLimit: 125,
|
SizeLimit: 125,
|
||||||
MemLimit: 0,
|
MemLimit: 0,
|
||||||
H2C: true,
|
H2C: true,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
[server]
|
[server]
|
||||||
host = "0.0.0.0"
|
host = "0.0.0.0"
|
||||||
port = 8080
|
port = 8080
|
||||||
|
netlib = "netpoll" # "netpoll" / "std" "standard" "net/http" "net"
|
||||||
sizeLimit = 125 # MB
|
sizeLimit = 125 # MB
|
||||||
memLimit = 0 # MB
|
memLimit = 0 # MB
|
||||||
H2C = true
|
H2C = true
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
[server]
|
[server]
|
||||||
host = "127.0.0.1"
|
host = "127.0.0.1"
|
||||||
port = 8080
|
port = 8080
|
||||||
|
netlib = "netpoll" # "netpoll" / "std" "standard" "net/http" "net"
|
||||||
sizeLimit = 125 # MB
|
sizeLimit = 125 # MB
|
||||||
memLimit = 0 # MB
|
memLimit = 0 # MB
|
||||||
H2C = true
|
H2C = true
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
[server]
|
[server]
|
||||||
host = "0.0.0.0"
|
host = "0.0.0.0"
|
||||||
port = 8080
|
port = 8080
|
||||||
|
netlib = "netpoll" # "netpoll" / "std" "standard" "net/http" "net"
|
||||||
sizeLimit = 125 # MB
|
sizeLimit = 125 # MB
|
||||||
memLimit = 0 # MB
|
memLimit = 0 # MB
|
||||||
H2C = true
|
H2C = true
|
||||||
@@ -83,6 +84,10 @@ url = "socks5://127.0.0.1:1080" # "http://127.0.0.1:7890"
|
|||||||
* 类型: 整数 (`int`)
|
* 类型: 整数 (`int`)
|
||||||
* 默认值: `8080`
|
* 默认值: `8080`
|
||||||
* 说明: 设置 `ghproxy` 监听的端口号。
|
* 说明: 设置 `ghproxy` 监听的端口号。
|
||||||
|
* `netlib`: 底层网络库。
|
||||||
|
* 类型: 字符串 (`string`)
|
||||||
|
* 默认值: `""` (HertZ默认处置)
|
||||||
|
* 说明: `"std"` `"standard"` `"net/http"` `"net"` 均会被设置为go标准库`net/http`, 设置为`"netpoll"`或`""`会由`HertZ`默认逻辑处理
|
||||||
* `sizeLimit`: 请求体大小限制。
|
* `sizeLimit`: 请求体大小限制。
|
||||||
* 类型: 整数 (`int`)
|
* 类型: 整数 (`int`)
|
||||||
* 默认值: `125` (MB)
|
* 默认值: `125` (MB)
|
||||||
|
|||||||
61
main.go
61
main.go
@@ -19,15 +19,16 @@ import (
|
|||||||
"ghproxy/rate"
|
"ghproxy/rate"
|
||||||
|
|
||||||
"github.com/WJQSERVER-STUDIO/go-utils/logger"
|
"github.com/WJQSERVER-STUDIO/go-utils/logger"
|
||||||
|
"github.com/hertz-contrib/http2/factory"
|
||||||
|
|
||||||
"github.com/cloudwego/hertz/pkg/app"
|
"github.com/cloudwego/hertz/pkg/app"
|
||||||
"github.com/cloudwego/hertz/pkg/app/middlewares/server/recovery"
|
"github.com/cloudwego/hertz/pkg/app/middlewares/server/recovery"
|
||||||
"github.com/cloudwego/hertz/pkg/app/server"
|
"github.com/cloudwego/hertz/pkg/app/server"
|
||||||
"github.com/cloudwego/hertz/pkg/common/adaptor"
|
"github.com/cloudwego/hertz/pkg/common/adaptor"
|
||||||
"github.com/cloudwego/hertz/pkg/common/hlog"
|
"github.com/cloudwego/hertz/pkg/common/hlog"
|
||||||
|
"github.com/cloudwego/hertz/pkg/network/standard"
|
||||||
|
|
||||||
//"github.com/cloudwego/hertz/pkg/network/standard"
|
_ "net/http/pprof"
|
||||||
"github.com/hertz-contrib/http2/factory"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -360,32 +361,47 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// 如果 showVersion 为 true,则在 init 阶段已退出,这里直接返回
|
|
||||||
if showVersion || showHelp {
|
if showVersion || showHelp {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logDebug("Run Mode: %s", runMode)
|
logDebug("Run Mode: %s Netlib: %s", runMode, cfg.Server.NetLib)
|
||||||
|
|
||||||
// 确保在程序配置加载且非版本显示模式下执行
|
|
||||||
if cfg == nil {
|
if cfg == nil {
|
||||||
fmt.Println("Config not loaded, exiting.")
|
fmt.Println("Config not loaded, exiting.")
|
||||||
return // 如果配置未加载,则不继续执行
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
addr := fmt.Sprintf("%s:%d", cfg.Server.Host, cfg.Server.Port)
|
addr := fmt.Sprintf("%s:%d", cfg.Server.Host, cfg.Server.Port)
|
||||||
|
if cfg.Server.NetLib == "std" || cfg.Server.NetLib == "standard" || cfg.Server.NetLib == "net" || cfg.Server.NetLib == "net/http" {
|
||||||
if cfg.Server.H2C {
|
if cfg.Server.H2C {
|
||||||
r = server.New(
|
r = server.New(
|
||||||
server.WithHostPorts(addr),
|
server.WithH2C(true),
|
||||||
server.WithH2C(true),
|
server.WithHostPorts(addr),
|
||||||
// server.WithALPN(true),
|
server.WithTransport(standard.NewTransporter),
|
||||||
// server.WithTransport(standard.NewTransporter),
|
)
|
||||||
)
|
r.AddProtocol("h2", factory.NewServerFactory())
|
||||||
r.AddProtocol("h2", factory.NewServerFactory())
|
} else {
|
||||||
|
r = server.New(
|
||||||
|
server.WithHostPorts(addr),
|
||||||
|
server.WithTransport(standard.NewTransporter),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else if cfg.Server.NetLib == "netpoll" || cfg.Server.NetLib == "" {
|
||||||
|
if cfg.Server.H2C {
|
||||||
|
r = server.New(
|
||||||
|
server.WithH2C(true),
|
||||||
|
server.WithHostPorts(addr),
|
||||||
|
)
|
||||||
|
r.AddProtocol("h2", factory.NewServerFactory())
|
||||||
|
} else {
|
||||||
|
r = server.New(
|
||||||
|
server.WithHostPorts(addr),
|
||||||
|
)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
r = server.New(
|
logError("Invalid NetLib: %s", cfg.Server.NetLib)
|
||||||
server.WithHostPorts(addr),
|
fmt.Printf("Invalid NetLib: %s\n", cfg.Server.NetLib)
|
||||||
)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加Recovery中间件
|
// 添加Recovery中间件
|
||||||
@@ -447,11 +463,18 @@ func main() {
|
|||||||
fmt.Printf("A Go Based High-Performance Github Proxy \n")
|
fmt.Printf("A Go Based High-Performance Github Proxy \n")
|
||||||
fmt.Printf("Made by WJQSERVER-STUDIO\n")
|
fmt.Printf("Made by WJQSERVER-STUDIO\n")
|
||||||
|
|
||||||
|
if cfg.Server.Debug {
|
||||||
|
go func() {
|
||||||
|
http.ListenAndServe("localhost:6060", nil)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
r.Spin()
|
r.Spin()
|
||||||
defer logger.Close()
|
defer logger.Close()
|
||||||
defer func() {
|
defer func() {
|
||||||
if hertZfile != nil {
|
if hertZfile != nil {
|
||||||
err := hertZfile.Close()
|
var err error
|
||||||
|
err = hertZfile.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logError("Failed to close hertz log file: %v", err)
|
logError("Failed to close hertz log file: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,29 +5,60 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"ghproxy/config"
|
"ghproxy/config"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/cloudwego/hertz/pkg/app"
|
"github.com/cloudwego/hertz/pkg/app"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
respHeadersToRemove = map[string]struct{}{
|
||||||
|
"Content-Security-Policy": {},
|
||||||
|
"Referrer-Policy": {},
|
||||||
|
"Strict-Transport-Security": {},
|
||||||
|
"X-Github-Request-Id": {},
|
||||||
|
"X-Timer": {},
|
||||||
|
"X-Served-By": {},
|
||||||
|
"X-Fastly-Request-Id": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
reqHeadersToRemove = map[string]struct{}{
|
||||||
|
"CF-IPCountry": {},
|
||||||
|
"CF-RAY": {},
|
||||||
|
"CF-Visitor": {},
|
||||||
|
"CF-Connecting-IP": {},
|
||||||
|
"CF-EW-Via": {},
|
||||||
|
"CDN-Loop": {},
|
||||||
|
"Upgrade": {},
|
||||||
|
"Connection": {},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
func ChunkedProxyRequest(ctx context.Context, c *app.RequestContext, u string, cfg *config.Config, matcher string) {
|
func ChunkedProxyRequest(ctx context.Context, c *app.RequestContext, u string, cfg *config.Config, matcher string) {
|
||||||
method := c.Request.Method
|
|
||||||
|
|
||||||
body := c.Request.Body()
|
var (
|
||||||
|
method []byte
|
||||||
|
bodyReader *bytes.Buffer
|
||||||
|
req *http.Request
|
||||||
|
resp *http.Response
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
bodyReader := bytes.NewBuffer(body)
|
method = c.Request.Method()
|
||||||
|
bodyReader = bytes.NewBuffer(c.Request.Body())
|
||||||
|
|
||||||
req, err := client.NewRequest(string(method()), u, bodyReader)
|
req, err = client.NewRequest(string(method), u, bodyReader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HandleError(c, fmt.Sprintf("Failed to create request: %v", err))
|
HandleError(c, fmt.Sprintf("Failed to create request: %v", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
resp, err := client.Do(req)
|
resp, err = client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HandleError(c, fmt.Sprintf("Failed to send request: %v", err))
|
HandleError(c, fmt.Sprintf("Failed to send request: %v", err))
|
||||||
return
|
return
|
||||||
@@ -55,8 +86,9 @@ func ChunkedProxyRequest(ctx context.Context, c *app.RequestContext, u string, c
|
|||||||
bodySize = -1
|
bodySize = -1
|
||||||
}
|
}
|
||||||
if err == nil && bodySize > sizelimit {
|
if err == nil && bodySize > sizelimit {
|
||||||
finalURL := resp.Request.URL.String()
|
var finalURL string
|
||||||
err := resp.Body.Close()
|
finalURL = resp.Request.URL.String()
|
||||||
|
err = resp.Body.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logError("Failed to close response body: %v", err)
|
logError("Failed to close response body: %v", err)
|
||||||
}
|
}
|
||||||
@@ -66,20 +98,26 @@ func ChunkedProxyRequest(ctx context.Context, c *app.RequestContext, u string, c
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for key, values := range resp.Header {
|
/*
|
||||||
for _, value := range values {
|
for header := range headersToRemove {
|
||||||
c.Header(key, value)
|
resp.Header.Del(header)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
headersToRemove := map[string]struct{}{
|
for key := range resp.Header {
|
||||||
"Content-Security-Policy": {},
|
var values []string = resp.Header.Values(key)
|
||||||
"Referrer-Policy": {},
|
for _, value := range values {
|
||||||
"Strict-Transport-Security": {},
|
c.Header(key, value)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
for header := range headersToRemove {
|
// 复制响应头,排除需要移除的 header
|
||||||
resp.Header.Del(header)
|
for key, values := range resp.Header {
|
||||||
|
if _, shouldRemove := respHeadersToRemove[key]; !shouldRemove {
|
||||||
|
for _, value := range values {
|
||||||
|
c.Header(key, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch cfg.Server.Cors {
|
switch cfg.Server.Cors {
|
||||||
@@ -105,7 +143,9 @@ func ChunkedProxyRequest(ctx context.Context, c *app.RequestContext, u string, c
|
|||||||
logInfo("Is Shell: %s %s %s %s %s", c.ClientIP(), method, u, c.Request.Header.Get("User-Agent"), c.Request.Header.GetProtocol())
|
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", "")
|
c.Header("Content-Length", "")
|
||||||
|
|
||||||
reader, _, err := processLinks(resp.Body, compress, string(c.Request.Host()), cfg)
|
var reader io.Reader
|
||||||
|
|
||||||
|
reader, _, err = processLinks(resp.Body, compress, string(c.Request.Host()), cfg)
|
||||||
c.SetBodyStream(reader, -1)
|
c.SetBodyStream(reader, -1)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ func GitReq(ctx context.Context, c *app.RequestContext, u string, cfg *config.Co
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
setRequestHeaders(c, req)
|
setRequestHeaders(c, req)
|
||||||
removeWSHeader(req)
|
//removeWSHeader(req)
|
||||||
AuthPassThrough(c, cfg, req)
|
AuthPassThrough(c, cfg, req)
|
||||||
|
|
||||||
resp, err = gitclient.Do(req)
|
resp, err = gitclient.Do(req)
|
||||||
@@ -58,7 +58,7 @@ func GitReq(ctx context.Context, c *app.RequestContext, u string, cfg *config.Co
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
setRequestHeaders(c, req)
|
setRequestHeaders(c, req)
|
||||||
removeWSHeader(req)
|
//removeWSHeader(req)
|
||||||
AuthPassThrough(c, cfg, req)
|
AuthPassThrough(c, cfg, req)
|
||||||
|
|
||||||
resp, err = client.Do(req)
|
resp, err = client.Do(req)
|
||||||
|
|||||||
@@ -41,13 +41,19 @@ func NoRouteHandler(cfg *config.Config, limiter *rate.RateLimiter, iplimiter *ra
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rawPath := strings.TrimPrefix(string(c.Request.RequestURI()), "/") // 去掉前缀/
|
var (
|
||||||
matches := re.FindStringSubmatch(rawPath) // 匹配路径
|
rawPath string
|
||||||
|
matches []string
|
||||||
|
errMsg string
|
||||||
|
)
|
||||||
|
|
||||||
|
rawPath = strings.TrimPrefix(string(c.Request.RequestURI()), "/") // 去掉前缀/
|
||||||
|
matches = re.FindStringSubmatch(rawPath) // 匹配路径
|
||||||
logInfo("URL: %v", matches)
|
logInfo("URL: %v", matches)
|
||||||
|
|
||||||
// 匹配路径错误处理
|
// 匹配路径错误处理
|
||||||
if len(matches) < 3 {
|
if len(matches) < 3 {
|
||||||
errMsg := fmt.Sprintf("%s %s %s %s %s Invalid URL", c.ClientIP(), c.Method(), rawPath, c.Request.Header.UserAgent(), c.Request.Header.GetProtocol())
|
errMsg = fmt.Sprintf("%s %s %s %s %s Invalid URL", c.ClientIP(), c.Method(), rawPath, c.Request.Header.UserAgent(), c.Request.Header.GetProtocol())
|
||||||
logWarning(errMsg)
|
logWarning(errMsg)
|
||||||
c.String(http.StatusForbidden, "Invalid URL Format. Path: %s", rawPath)
|
c.String(http.StatusForbidden, "Invalid URL Format. Path: %s", rawPath)
|
||||||
return
|
return
|
||||||
@@ -56,7 +62,14 @@ func NoRouteHandler(cfg *config.Config, limiter *rate.RateLimiter, iplimiter *ra
|
|||||||
// 制作url
|
// 制作url
|
||||||
rawPath = "https://" + matches[2]
|
rawPath = "https://" + matches[2]
|
||||||
|
|
||||||
user, repo, matcher, err := Matcher(rawPath, cfg)
|
var (
|
||||||
|
user string
|
||||||
|
repo string
|
||||||
|
matcher string
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
user, repo, matcher, err = Matcher(rawPath, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, ErrInvalidURL) {
|
if errors.Is(err, ErrInvalidURL) {
|
||||||
c.String(http.StatusForbidden, "Invalid URL Format. Path: %s", rawPath)
|
c.String(http.StatusForbidden, "Invalid URL Format. Path: %s", rawPath)
|
||||||
@@ -69,18 +82,19 @@ func NoRouteHandler(cfg *config.Config, limiter *rate.RateLimiter, iplimiter *ra
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
username := user
|
|
||||||
|
|
||||||
logInfo("%s %s %s %s %s Matched-Username: %s, Matched-Repo: %s", c.ClientIP(), c.Method(), rawPath, c.Request.Header.UserAgent(), c.Request.Header.GetProtocol(), username, repo)
|
logInfo("%s %s %s %s %s Matched-Username: %s, Matched-Repo: %s", c.ClientIP(), c.Method(), rawPath, c.Request.Header.UserAgent(), c.Request.Header.GetProtocol(), user, repo)
|
||||||
// dump log 记录详细信息 c.ClientIP(), c.Method(), rawPath,c.Request.Header.UserAgent(), c.Request.Header.GetProtocol(), full Header
|
// dump log 记录详细信息 c.ClientIP(), c.Method(), rawPath,c.Request.Header.UserAgent(), c.Request.Header.GetProtocol(), full Header
|
||||||
logDump("%s %s %s %s %s %s", c.ClientIP(), c.Method(), rawPath, c.Request.Header.UserAgent(), c.Request.Header.GetProtocol(), c.Request.Header.Header())
|
logDump("%s %s %s %s %s %s", c.ClientIP(), c.Method(), rawPath, c.Request.Header.UserAgent(), c.Request.Header.GetProtocol(), c.Request.Header.Header())
|
||||||
repouser := fmt.Sprintf("%s/%s", username, repo)
|
var repouser string
|
||||||
|
repouser = fmt.Sprintf("%s/%s", user, repo)
|
||||||
|
|
||||||
// 白名单检查
|
// 白名单检查
|
||||||
if cfg.Whitelist.Enabled {
|
if cfg.Whitelist.Enabled {
|
||||||
whitelist := auth.CheckWhitelist(username, repo)
|
var whitelist bool
|
||||||
|
whitelist = auth.CheckWhitelist(user, repo)
|
||||||
if !whitelist {
|
if !whitelist {
|
||||||
errMsg := fmt.Sprintf("Whitelist Blocked repo: %s", repouser)
|
errMsg = fmt.Sprintf("Whitelist Blocked repo: %s", repouser)
|
||||||
c.JSON(http.StatusForbidden, map[string]string{"error": errMsg})
|
c.JSON(http.StatusForbidden, map[string]string{"error": errMsg})
|
||||||
logWarning("%s %s %s %s %s Whitelist Blocked repo: %s", c.ClientIP(), c.Method(), rawPath, c.Request.Header.UserAgent(), c.Request.Header.GetProtocol(), repouser)
|
logWarning("%s %s %s %s %s Whitelist Blocked repo: %s", c.ClientIP(), c.Method(), rawPath, c.Request.Header.UserAgent(), c.Request.Header.GetProtocol(), repouser)
|
||||||
return
|
return
|
||||||
@@ -89,9 +103,10 @@ func NoRouteHandler(cfg *config.Config, limiter *rate.RateLimiter, iplimiter *ra
|
|||||||
|
|
||||||
// 黑名单检查
|
// 黑名单检查
|
||||||
if cfg.Blacklist.Enabled {
|
if cfg.Blacklist.Enabled {
|
||||||
blacklist := auth.CheckBlacklist(username, repo)
|
var blacklist bool
|
||||||
|
blacklist = auth.CheckBlacklist(user, repo)
|
||||||
if blacklist {
|
if blacklist {
|
||||||
errMsg := fmt.Sprintf("Blacklist Blocked repo: %s", repouser)
|
errMsg = fmt.Sprintf("Blacklist Blocked repo: %s", repouser)
|
||||||
c.JSON(http.StatusForbidden, map[string]string{"error": errMsg})
|
c.JSON(http.StatusForbidden, map[string]string{"error": errMsg})
|
||||||
logWarning("%s %s %s %s %s Blacklist Blocked repo: %s", c.ClientIP(), c.Method(), rawPath, c.Request.Header.UserAgent(), c.Request.Header.GetProtocol(), repouser)
|
logWarning("%s %s %s %s %s Blacklist Blocked repo: %s", c.ClientIP(), c.Method(), rawPath, c.Request.Header.UserAgent(), c.Request.Header.GetProtocol(), repouser)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"ghproxy/config"
|
"ghproxy/config"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
httpc "github.com/satomitouka/touka-httpc"
|
httpc "github.com/satomitouka/touka-httpc"
|
||||||
@@ -13,11 +12,10 @@ import (
|
|||||||
var BufferSize int = 32 * 1024 // 32KB
|
var BufferSize int = 32 * 1024 // 32KB
|
||||||
|
|
||||||
var (
|
var (
|
||||||
tr *http.Transport
|
tr *http.Transport
|
||||||
gittr *http.Transport
|
gittr *http.Transport
|
||||||
BufferPool *sync.Pool
|
client *httpc.Client
|
||||||
client *httpc.Client
|
gitclient *httpc.Client
|
||||||
gitclient *httpc.Client
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func InitReq(cfg *config.Config) {
|
func InitReq(cfg *config.Config) {
|
||||||
@@ -25,13 +23,6 @@ func InitReq(cfg *config.Config) {
|
|||||||
if cfg.GitClone.Mode == "cache" {
|
if cfg.GitClone.Mode == "cache" {
|
||||||
initGitHTTPClient(cfg)
|
initGitHTTPClient(cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化固定大小的缓存池
|
|
||||||
BufferPool = &sync.Pool{
|
|
||||||
New: func() interface{} {
|
|
||||||
return make([]byte, BufferSize)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func initHTTPClient(cfg *config.Config) {
|
func initHTTPClient(cfg *config.Config) {
|
||||||
|
|||||||
@@ -246,7 +246,7 @@ func extractParts(rawURL string) (string, string, string, url.Values, error) {
|
|||||||
var urlPattern = regexp.MustCompile(`https?://[^\s'"]+`)
|
var urlPattern = regexp.MustCompile(`https?://[^\s'"]+`)
|
||||||
|
|
||||||
// processLinks 处理链接,返回包含处理后数据的 io.Reader
|
// processLinks 处理链接,返回包含处理后数据的 io.Reader
|
||||||
func processLinks(input io.Reader, compress string, host string, cfg *config.Config) (readerOut io.Reader, written int64, err error) {
|
func processLinks(input io.ReadCloser, compress string, host string, cfg *config.Config) (readerOut io.Reader, written int64, err error) {
|
||||||
pipeReader, pipeWriter := io.Pipe() // 创建 io.Pipe
|
pipeReader, pipeWriter := io.Pipe() // 创建 io.Pipe
|
||||||
readerOut = pipeReader
|
readerOut = pipeReader
|
||||||
|
|
||||||
@@ -268,6 +268,13 @@ func processLinks(input io.Reader, compress string, host string, cfg *config.Con
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err := input.Close(); err != nil {
|
||||||
|
logError("input close failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}()
|
||||||
|
|
||||||
var bufReader *bufio.Reader
|
var bufReader *bufio.Reader
|
||||||
|
|
||||||
if compress == "gzip" {
|
if compress == "gzip" {
|
||||||
|
|||||||
@@ -6,13 +6,27 @@ import (
|
|||||||
"github.com/cloudwego/hertz/pkg/app"
|
"github.com/cloudwego/hertz/pkg/app"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
// 设置请求头
|
// 设置请求头
|
||||||
func setRequestHeaders(c *app.RequestContext, req *http.Request) {
|
func setRequestHeaders(c *app.RequestContext, req *http.Request) {
|
||||||
c.Request.Header.VisitAll(func(key, value []byte) {
|
c.Request.Header.VisitAll(func(key, value []byte) {
|
||||||
req.Header.Set(string(key), string(value))
|
req.Header.Set(string(key), string(value))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
func setRequestHeaders(c *app.RequestContext, req *http.Request) {
|
||||||
|
c.Request.Header.VisitAll(func(key, value []byte) {
|
||||||
|
headerKey := string(key)
|
||||||
|
headerValue := string(value)
|
||||||
|
if _, shouldRemove := reqHeadersToRemove[headerKey]; !shouldRemove {
|
||||||
|
req.Header.Set(headerKey, headerValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// removeWSHeader removes the "Upgrade" and "Connection" headers from the given
|
// removeWSHeader removes the "Upgrade" and "Connection" headers from the given
|
||||||
// Request, which are added by the client when it wants to upgrade the
|
// Request, which are added by the client when it wants to upgrade the
|
||||||
// connection to a WebSocket connection.
|
// connection to a WebSocket connection.
|
||||||
@@ -20,3 +34,4 @@ func removeWSHeader(req *http.Request) {
|
|||||||
req.Header.Del("Upgrade")
|
req.Header.Del("Upgrade")
|
||||||
req.Header.Del("Connection")
|
req.Header.Del("Connection")
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user