-
-
Github文件加速
-为访问Github文件进行加速
- - -GitHub 链接带不带协议头均可,支持 release、archive 以及文件,转换后链接均可使用。
+
+
+
+
+
+
+
GitHub 文件加速服务
+高速稳定的 GitHub 资源访问解决方案
+
+
+
+
+
+
-
+
+
+
+
+
-
-
-
-
+
+
+ 文件大小限制
-...
+
+
+
+
-
+
+
+ ...
文件大小限制
+ 最大支持文件尺寸
-
-
-
+ 白名单状态
-...
+
+
+
-
+
+
+ ...
白名单状态
+ 访问控制列表
-
-
-
+
+
+
-
+ 黑名单状态
-...
+
+
+
+
+
+
+
+
+ ...
+ 黑名单状态
+ 屏蔽列表状态 +
+
+
+
📚 详细使用指南
+ +
+
+
+ 支持的工具
+-
+
- ✅ 终端工具:Git / Wget / Curl +
- ✅ 支持域名:github.com +
- ✅ 支持域名:raw.githubusercontent.com +
- ✅ 支持域名:gist.githubusercontent.com +
- ❌ 不支持 SSH 协议克隆 +
+
+
+ 基础用法示例
+ +
+
+
+ Git 克隆
+git clone https://example.com/https://github.com/user/project.git
+
+ 私有仓库克隆
+git clone https://user:your_token@example.com/https://github.com/user/project.git
+
+
+ 文件下载
+wget https://example.com/https://raw.githubusercontent.com/user/project/main/README.md
+
+ 版本发布
+curl -LO https://example.com/https://github.com/user/project/releases/download/v1.0.0./project_1.0.0.amd64.tar.gz
+
+
-
- 支持的文件类型
+ +
+
+
+
+
+
+ 原始文件
+https://raw.githubusercontent.com/user/repo/main/file.txt
+
+
+
+
+
+ 分支源码
+https://github.com/user/repo/archive/main.zip
+
+
+
+
+
+ 版本发布
+https://github.com/user/repo/releases/download/v1.0.0/app.zip
+
+
+
Gist 文件
+https://gist.githubusercontent.com/user/gist_id/raw/file.txt
-
Date: Sun, 16 Feb 2025 19:48:53 +0800
Subject: [PATCH 07/13] 25w14t-2
---
CHANGELOG.md | 9 +++++
DEV-VERSION | 2 +-
README.md | 6 +++
auth/auth.go | 12 +++++-
auth/whitelist.go | 98 ++++++++++++++++++++++++++++++----------------
config/config.go | 15 +++++++
config/config.toml | 6 +++
deploy/config.toml | 6 +++
go.mod | 4 +-
go.sum | 14 +++++++
proxy/chunkreq.go | 59 ++--------------------------
proxy/gitreq.go | 46 +++++++---------------
proxy/handler.go | 2 +-
proxy/httpc.go | 88 +++++++++++++++++++++++++++++++++++++++++
14 files changed, 241 insertions(+), 126 deletions(-)
create mode 100644 proxy/httpc.go
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 97f9876..6f57a7c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,14 @@
# 更新日志
+25w14t-2
+---
+- PRE-RELEASE: 此版本是测试验证版本,请勿在生产环境中使用;
+- CHANGE: 使用`touka-httpc`封装`HTTP Client`,更新到`v0.1.0`版本, 参看`touka-httpc`
+- CHANGE: 重构`whitelist`实现
+- CHANGE: 对`proxy`进行结构性调整
+- CHANGE: `chunckedreq`与`gitreq`共用`BufferPool`和`HTTP Client`
+- CHANGE: 新增`HTTP Client`配置块
+
25w14t-1
---
- PRE-RELEASE: 此版本是测试验证版本,请勿在生产环境中使用;
diff --git a/DEV-VERSION b/DEV-VERSION
index cca0ffd..b0f9cf0 100644
--- a/DEV-VERSION
+++ b/DEV-VERSION
@@ -1 +1 @@
-25w14t-1
\ No newline at end of file
+25w14t-2
\ No newline at end of file
diff --git a/README.md b/README.md
index bf604ad..97b1c8a 100644
--- a/README.md
+++ b/README.md
@@ -91,6 +91,12 @@ port = 8080 # 监听端口
sizeLimit = 125 # 125MB
enableH2C = "on" # 是否开启H2C传输(latest和dev版本请开启) on/off
+[httpc]
+mode = "auto" # "auto" or "advanced" HTTP客户端模式 自动/高级模式
+maxIdleConns = 100 # only for advanced mode 仅用于高级模式
+maxIdleConnsPerHost = 60 # only for advanced mode 仅用于高级模式
+maxConnsPerHost = 0 # only for advanced mode 仅用于高级模式
+
[pages]
enabled = false # 是否开启内置静态页面(Docker版本请关闭此项)
staticPath = "/data/www" # 静态页面文件路径
diff --git a/auth/auth.go b/auth/auth.go
index fdc5833..99cb6de 100644
--- a/auth/auth.go
+++ b/auth/auth.go
@@ -18,10 +18,18 @@ var (
func Init(cfg *config.Config) {
if cfg.Blacklist.Enabled {
- InitBlacklist(cfg)
+ err := InitBlacklist(cfg)
+ if err != nil {
+ logError(err.Error())
+ return
+ }
}
if cfg.Whitelist.Enabled {
- LoadWhitelist(cfg)
+ err := InitWhitelist(cfg)
+ if err != nil {
+ logError(err.Error())
+ return
+ }
}
logDebug("Auth Init")
}
diff --git a/auth/whitelist.go b/auth/whitelist.go
index 000b016..ee93c20 100644
--- a/auth/whitelist.go
+++ b/auth/whitelist.go
@@ -2,58 +2,90 @@ package auth
import (
"encoding/json"
+ "fmt"
"ghproxy/config"
"os"
"strings"
+ "sync"
)
-type WhitelistConfig struct {
- Whitelist []string `json:"whitelist"`
+// Whitelist 用于存储白名单信息
+type Whitelist struct {
+ userSet map[string]struct{} // 用户级白名单
+ repoSet map[string]map[string]struct{} // 仓库级白名单
+ initOnce sync.Once // 确保初始化只执行一次
+ initialized bool // 初始化状态标识
}
var (
- whitelistfile = "/data/ghproxy/config/whitelist.json"
- whitelist *WhitelistConfig
+ whitelistInstance *Whitelist
+ whitelistInitErr error
)
-func LoadWhitelist(cfg *config.Config) {
- whitelistfile = cfg.Whitelist.WhitelistFile
- whitelist = &WhitelistConfig{}
+// InitWhitelist 初始化白名单(线程安全,仅执行一次)
+func InitWhitelist(cfg *config.Config) error {
+ whitelistInstance = &Whitelist{
+ userSet: make(map[string]struct{}),
+ repoSet: make(map[string]map[string]struct{}),
+ }
- data, err := os.ReadFile(whitelistfile)
+ data, err := os.ReadFile(cfg.Whitelist.WhitelistFile)
if err != nil {
- logError("Failed to read whitelist file: %v", err)
+ return fmt.Errorf("failed to read whitelist: %w", err)
}
- err = json.Unmarshal(data, whitelist)
- if err != nil {
- logError("Failed to unmarshal whitelist JSON: %v", err)
+ var list struct {
+ Entries []string `json:"whitelist"`
}
-}
-
-func CheckWhitelist(fullrepo string, user string, repo string) bool {
- return forRangeCheckWhitelist(whitelist.Whitelist, fullrepo, user)
-}
-
-func sliceRepoName_Whitelist(fullrepo string) (string, string) {
- s := strings.Split(fullrepo, "/")
- if len(s) != 2 {
- return "", ""
+ if err := json.Unmarshal(data, &list); err != nil {
+ return fmt.Errorf("invalid whitelist format: %w", err)
}
- return s[0], s[1]
-}
-func forRangeCheckWhitelist(wlist []string, fullrepo string, user string) bool {
- for _, passd := range wlist {
- users, _ := sliceRepoName_Whitelist(passd)
- if users == user {
- if strings.HasSuffix(passd, "/*") {
- return true
- }
- if fullrepo == passd {
- return true
+ for _, entry := range list.Entries {
+ user, repo := splitUserRepoWhitelist(entry)
+ switch {
+ case repo == "" || repo == "*":
+ whitelistInstance.userSet[user] = struct{}{}
+ default:
+ if _, exists := whitelistInstance.repoSet[user]; !exists {
+ whitelistInstance.repoSet[user] = make(map[string]struct{})
}
+ whitelistInstance.repoSet[user][repo] = struct{}{}
}
}
+
+ whitelistInstance.initialized = true
+ return nil
+}
+
+// CheckWhitelist 检查用户和仓库是否在白名单中(无锁设计)
+func CheckWhitelist(username, repo string) bool {
+ if whitelistInstance == nil || !whitelistInstance.initialized {
+ return false
+ }
+
+ // 先检查用户级白名单
+ if _, exists := whitelistInstance.userSet[username]; exists {
+ return true
+ }
+
+ // 再检查仓库级白名单
+ if repos, userExists := whitelistInstance.repoSet[username]; userExists {
+ // 允许仓库名为空时的全用户仓库匹配
+ if repo == "" {
+ return true
+ }
+ _, repoExists := repos[repo]
+ return repoExists
+ }
+
return false
}
+
+// splitUserRepoWhitelist 分割用户和仓库信息(仅初始化时使用)
+func splitUserRepoWhitelist(fullRepo string) (user, repo string) {
+ if idx := strings.Index(fullRepo, "/"); idx > 0 {
+ return fullRepo[:idx], fullRepo[idx+1:]
+ }
+ return fullRepo, ""
+}
diff --git a/config/config.go b/config/config.go
index 9335b14..bad1557 100644
--- a/config/config.go
+++ b/config/config.go
@@ -6,6 +6,7 @@ import (
type Config struct {
Server ServerConfig
+ Httpc HttpcConfig
Pages PagesConfig
Log LogConfig
CORS CORSConfig
@@ -24,6 +25,20 @@ type ServerConfig struct {
Debug bool `toml:"debug"`
}
+/*
+[httpc]
+mode = "auto" # "auto" or "advanced"
+maxIdleConns = 100 # only for advanced mode
+maxIdleConnsPerHost = 60 # only for advanced mode
+maxConnsPerHost = 0 # only for advanced mode
+*/
+type HttpcConfig struct {
+ Mode string `toml:"mode"`
+ MaxIdleConns int `toml:"maxIdleConns"`
+ MaxIdleConnsPerHost int `toml:"maxIdleConnsPerHost"`
+ MaxConnsPerHost int `toml:"maxConnsPerHost"`
+}
+
type PagesConfig struct {
Enabled bool `toml:"enabled"`
StaticDir string `toml:"staticDir"`
diff --git a/config/config.toml b/config/config.toml
index 5613f2e..12f1422 100644
--- a/config/config.toml
+++ b/config/config.toml
@@ -5,6 +5,12 @@ sizeLimit = 125 # MB
enableH2C = "on" # "on" or "off"
debug = false
+[httpc]
+mode = "auto" # "auto" or "advanced"
+maxIdleConns = 100 # only for advanced mode
+maxIdleConnsPerHost = 60 # only for advanced mode
+maxConnsPerHost = 0 # only for advanced mode
+
[pages]
enabled = false
staticDir = "/data/www"
diff --git a/deploy/config.toml b/deploy/config.toml
index c217b5d..bdbcfcf 100644
--- a/deploy/config.toml
+++ b/deploy/config.toml
@@ -5,6 +5,12 @@ sizeLimit = 125 # MB
enableH2C = "on"
debug = false
+[httpc]
+mode = "auto" # "auto" or "advanced"
+maxIdleConns = 100 # only for advanced mode
+maxIdleConnsPerHost = 60 # only for advanced mode
+maxConnsPerHost = 0 # only for advanced mode
+
[pages]
enabled = false
staticDir = "/usr/local/ghproxy/pages"
diff --git a/go.mod b/go.mod
index 73e5d65..0447312 100644
--- a/go.mod
+++ b/go.mod
@@ -6,7 +6,7 @@ require (
github.com/BurntSushi/toml v1.4.0
github.com/WJQSERVER-STUDIO/go-utils/logger v1.3.0
github.com/gin-gonic/gin v1.10.0
- github.com/satomitouka/touka-httpc v0.0.3
+ github.com/satomitouka/touka-httpc v0.1.0
golang.org/x/net v0.35.0
golang.org/x/time v0.10.0
)
@@ -19,7 +19,7 @@ require (
github.com/gin-contrib/sse v1.0.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
- github.com/go-playground/validator/v10 v10.24.0 // indirect
+ github.com/go-playground/validator/v10 v10.25.0 // indirect
github.com/goccy/go-json v0.10.5 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
diff --git a/go.sum b/go.sum
index 897730f..f54b7f8 100644
--- a/go.sum
+++ b/go.sum
@@ -27,6 +27,8 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.24.0 h1:KHQckvo8G6hlWnrPX4NJJ+aBfWNAE/HH+qdL2cBpCmg=
github.com/go-playground/validator/v10 v10.24.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus=
+github.com/go-playground/validator/v10 v10.25.0 h1:5Dh7cjvzR7BRZadnsVOzPhWsrwUr0nmsZJxEAnFLNO8=
+github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus=
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
@@ -53,6 +55,18 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/satomitouka/touka-httpc v0.0.3 h1:SLb14DWBIDeIaNQ0wMwRwJMjUDakHVR1Jbdct3Qi8fA=
github.com/satomitouka/touka-httpc v0.0.3/go.mod h1:ULB/0Ze0Apm46YKl35Jmj1hW5YLVVeOGqCqn+ijqGPM=
+github.com/satomitouka/touka-httpc v0.0.4 h1:sZs/2kqTSyLQ/pDHs/71l7MSG46j4rZNKfqn3CFAboU=
+github.com/satomitouka/touka-httpc v0.0.4/go.mod h1:ULB/0Ze0Apm46YKl35Jmj1hW5YLVVeOGqCqn+ijqGPM=
+github.com/satomitouka/touka-httpc v0.0.5 h1:ov1v29vrjvwRNbGqFJHmrCp+3/qXLoyWubO4kTDvb28=
+github.com/satomitouka/touka-httpc v0.0.5/go.mod h1:ULB/0Ze0Apm46YKl35Jmj1hW5YLVVeOGqCqn+ijqGPM=
+github.com/satomitouka/touka-httpc v0.0.6 h1:1iSaTB9KpviXy2NHvMXuRzy5mkcvle+fktWPhpS907c=
+github.com/satomitouka/touka-httpc v0.0.6/go.mod h1:ULB/0Ze0Apm46YKl35Jmj1hW5YLVVeOGqCqn+ijqGPM=
+github.com/satomitouka/touka-httpc v0.0.7 h1:igoLqXs6R1yNIdKMcfpwRB1l6KLLus6DvWT3xL1T5FY=
+github.com/satomitouka/touka-httpc v0.0.7/go.mod h1:ULB/0Ze0Apm46YKl35Jmj1hW5YLVVeOGqCqn+ijqGPM=
+github.com/satomitouka/touka-httpc v0.0.8 h1:KW521Z2z9BarnTgCajug/W/tIbnoIH+CzA7CON19iAg=
+github.com/satomitouka/touka-httpc v0.0.8/go.mod h1:ULB/0Ze0Apm46YKl35Jmj1hW5YLVVeOGqCqn+ijqGPM=
+github.com/satomitouka/touka-httpc v0.1.0 h1:CXCsr6NhdskK/W/ezvhwK2CP8QGCxewkBhsEjrM7K8s=
+github.com/satomitouka/touka-httpc v0.1.0/go.mod h1:ULB/0Ze0Apm46YKl35Jmj1hW5YLVVeOGqCqn+ijqGPM=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
diff --git a/proxy/chunkreq.go b/proxy/chunkreq.go
index a315e5c..313dd41 100644
--- a/proxy/chunkreq.go
+++ b/proxy/chunkreq.go
@@ -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
diff --git a/proxy/gitreq.go b/proxy/gitreq.go
index 4ceeac9..3b2c13f 100644
--- a/proxy/gitreq.go
+++ b/proxy/gitreq.go
@@ -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() // 确保刷入
}
}
diff --git a/proxy/handler.go b/proxy/handler.go
index 480aa67..f999b47 100644
--- a/proxy/handler.go
+++ b/proxy/handler.go
@@ -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)
diff --git a/proxy/httpc.go b/proxy/httpc.go
new file mode 100644
index 0000000..8048821
--- /dev/null
+++ b/proxy/httpc.go
@@ -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),
+ )
+ }
+}
From 83368969797bc0a23d1881a10358a4b7cddcc896 Mon Sep 17 00:00:00 2001
From: WJQSERVER
Date: Tue, 18 Feb 2025 10:19:11 +0800
Subject: [PATCH 08/13] feat(pages): add page theme configuration and static
files
---
README.md | 1 +
config/config.go | 7 +
config/config.toml | 1 +
deploy/config.toml | 1 +
deploy/install-dev.sh | 4 +-
deploy/install.sh | 4 +-
go.mod | 2 +-
go.sum | 18 +-
main.go | 24 +-
pages/{ => bootstrap}/favicon.ico | Bin
pages/bootstrap/index.html | 440 ++++++++++++++++++++++++++++++
pages/nebula/favicon.ico | Bin 0 -> 3262 bytes
pages/{ => nebula}/index.html | 0
13 files changed, 477 insertions(+), 25 deletions(-)
rename pages/{ => bootstrap}/favicon.ico (100%)
create mode 100644 pages/bootstrap/index.html
create mode 100644 pages/nebula/favicon.ico
rename pages/{ => nebula}/index.html (100%)
diff --git a/README.md b/README.md
index 97b1c8a..eb246b7 100644
--- a/README.md
+++ b/README.md
@@ -99,6 +99,7 @@ maxConnsPerHost = 0 # only for advanced mode 仅用于高级模式
[pages]
enabled = false # 是否开启内置静态页面(Docker版本请关闭此项)
+theme = "bootstrap" # "bootstrap" or "nebula" 内置主题
staticPath = "/data/www" # 静态页面文件路径
[log]
diff --git a/config/config.go b/config/config.go
index bad1557..de887ce 100644
--- a/config/config.go
+++ b/config/config.go
@@ -39,8 +39,15 @@ type HttpcConfig struct {
MaxConnsPerHost int `toml:"maxConnsPerHost"`
}
+/*
+[pages]
+enabled = false
+theme = "bootstrap" # "bootstrap" or "nebula"
+staticDir = "/data/www"
+*/
type PagesConfig struct {
Enabled bool `toml:"enabled"`
+ Theme string `toml:"theme"`
StaticDir string `toml:"staticDir"`
}
diff --git a/config/config.toml b/config/config.toml
index 12f1422..919bcb8 100644
--- a/config/config.toml
+++ b/config/config.toml
@@ -13,6 +13,7 @@ maxConnsPerHost = 0 # only for advanced mode
[pages]
enabled = false
+theme = "bootstrap" # "bootstrap" or "nebula"
staticDir = "/data/www"
[log]
diff --git a/deploy/config.toml b/deploy/config.toml
index bdbcfcf..8f80a32 100644
--- a/deploy/config.toml
+++ b/deploy/config.toml
@@ -13,6 +13,7 @@ maxConnsPerHost = 0 # only for advanced mode
[pages]
enabled = false
+theme = "bootstrap" # "bootstrap" or "nebula"
staticDir = "/usr/local/ghproxy/pages"
[log]
diff --git a/deploy/install-dev.sh b/deploy/install-dev.sh
index 03d6030..e412c46 100644
--- a/deploy/install-dev.sh
+++ b/deploy/install-dev.sh
@@ -90,8 +90,8 @@ tar -zxvf ${ghproxy_dir}/ghproxy-linux-$ARCH.tar.gz -C ${ghproxy_dir}
chmod +x ${ghproxy_dir}/ghproxy
# 下载pages
-wget -q -O ${ghproxy_dir}/pages/index.html https://raw.githubusercontent.com/WJQSERVER-STUDIO/ghproxy/dev/pages/index.html
-wget -q -O ${ghproxy_dir}/pages/favicon.ico https://raw.githubusercontent.com/WJQSERVER-STUDIO/ghproxy/dev/pages/favicon.ico
+wget -q -O ${ghproxy_dir}/pages/index.html https://raw.githubusercontent.com/WJQSERVER-STUDIO/ghproxy/dev/pages/boostrap/index.html
+wget -q -O ${ghproxy_dir}/pages/favicon.ico https://raw.githubusercontent.com/WJQSERVER-STUDIO/ghproxy/dev/pages/bootstrap/favicon.ico
# 下载配置文件
diff --git a/deploy/install.sh b/deploy/install.sh
index b054299..f050a0b 100644
--- a/deploy/install.sh
+++ b/deploy/install.sh
@@ -90,8 +90,8 @@ tar -zxvf ${ghproxy_dir}/ghproxy-linux-$ARCH.tar.gz -C ${ghproxy_dir}
chmod +x ${ghproxy_dir}/ghproxy
# 下载pages
-wget -q -O ${ghproxy_dir}/pages/index.html https://raw.githubusercontent.com/WJQSERVER-STUDIO/ghproxy/main/pages/index.html
-wget -q -O ${ghproxy_dir}/pages/favicon.ico https://raw.githubusercontent.com/WJQSERVER-STUDIO/ghproxy/main/pages/favicon.ico
+wget -q -O ${ghproxy_dir}/pages/index.html https://raw.githubusercontent.com/WJQSERVER-STUDIO/ghproxy/main/pages/bootstrap/index.html
+wget -q -O ${ghproxy_dir}/pages/favicon.ico https://raw.githubusercontent.com/WJQSERVER-STUDIO/ghproxy/main/pages/bootstrap/favicon.ico
# 下载配置文件
diff --git a/go.mod b/go.mod
index 0447312..f739c4e 100644
--- a/go.mod
+++ b/go.mod
@@ -6,7 +6,7 @@ require (
github.com/BurntSushi/toml v1.4.0
github.com/WJQSERVER-STUDIO/go-utils/logger v1.3.0
github.com/gin-gonic/gin v1.10.0
- github.com/satomitouka/touka-httpc v0.1.0
+ github.com/satomitouka/touka-httpc v0.2.0
golang.org/x/net v0.35.0
golang.org/x/time v0.10.0
)
diff --git a/go.sum b/go.sum
index f54b7f8..7c6bb67 100644
--- a/go.sum
+++ b/go.sum
@@ -25,8 +25,6 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
-github.com/go-playground/validator/v10 v10.24.0 h1:KHQckvo8G6hlWnrPX4NJJ+aBfWNAE/HH+qdL2cBpCmg=
-github.com/go-playground/validator/v10 v10.24.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus=
github.com/go-playground/validator/v10 v10.25.0 h1:5Dh7cjvzR7BRZadnsVOzPhWsrwUr0nmsZJxEAnFLNO8=
github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus=
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
@@ -53,20 +51,8 @@ github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNH
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
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.0.3 h1:SLb14DWBIDeIaNQ0wMwRwJMjUDakHVR1Jbdct3Qi8fA=
-github.com/satomitouka/touka-httpc v0.0.3/go.mod h1:ULB/0Ze0Apm46YKl35Jmj1hW5YLVVeOGqCqn+ijqGPM=
-github.com/satomitouka/touka-httpc v0.0.4 h1:sZs/2kqTSyLQ/pDHs/71l7MSG46j4rZNKfqn3CFAboU=
-github.com/satomitouka/touka-httpc v0.0.4/go.mod h1:ULB/0Ze0Apm46YKl35Jmj1hW5YLVVeOGqCqn+ijqGPM=
-github.com/satomitouka/touka-httpc v0.0.5 h1:ov1v29vrjvwRNbGqFJHmrCp+3/qXLoyWubO4kTDvb28=
-github.com/satomitouka/touka-httpc v0.0.5/go.mod h1:ULB/0Ze0Apm46YKl35Jmj1hW5YLVVeOGqCqn+ijqGPM=
-github.com/satomitouka/touka-httpc v0.0.6 h1:1iSaTB9KpviXy2NHvMXuRzy5mkcvle+fktWPhpS907c=
-github.com/satomitouka/touka-httpc v0.0.6/go.mod h1:ULB/0Ze0Apm46YKl35Jmj1hW5YLVVeOGqCqn+ijqGPM=
-github.com/satomitouka/touka-httpc v0.0.7 h1:igoLqXs6R1yNIdKMcfpwRB1l6KLLus6DvWT3xL1T5FY=
-github.com/satomitouka/touka-httpc v0.0.7/go.mod h1:ULB/0Ze0Apm46YKl35Jmj1hW5YLVVeOGqCqn+ijqGPM=
-github.com/satomitouka/touka-httpc v0.0.8 h1:KW521Z2z9BarnTgCajug/W/tIbnoIH+CzA7CON19iAg=
-github.com/satomitouka/touka-httpc v0.0.8/go.mod h1:ULB/0Ze0Apm46YKl35Jmj1hW5YLVVeOGqCqn+ijqGPM=
-github.com/satomitouka/touka-httpc v0.1.0 h1:CXCsr6NhdskK/W/ezvhwK2CP8QGCxewkBhsEjrM7K8s=
-github.com/satomitouka/touka-httpc v0.1.0/go.mod h1:ULB/0Ze0Apm46YKl35Jmj1hW5YLVVeOGqCqn+ijqGPM=
+github.com/satomitouka/touka-httpc v0.2.0 h1:JohnKH0T5KuVcouycqSI70oJIhMxY1nlNDhgZRxI73s=
+github.com/satomitouka/touka-httpc v0.2.0/go.mod h1:ULB/0Ze0Apm46YKl35Jmj1hW5YLVVeOGqCqn+ijqGPM=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
diff --git a/main.go b/main.go
index 88606f7..863caa6 100644
--- a/main.go
+++ b/main.go
@@ -35,8 +35,10 @@ var (
)
var (
- //go:embed pages/*
+ //go:embed pages/bootstrap/*
pagesFS embed.FS
+ //go:embed pages/nebula/*
+ NebulaPagesFS embed.FS
)
var (
@@ -159,9 +161,23 @@ func init() {
})
router.StaticFile("/favicon.ico", faviconPath)
} else if !cfg.Pages.Enabled {
- pages, err := fs.Sub(pagesFS, "pages")
- if err != nil {
- logError("Failed when processing pages: %s", err)
+ var pages fs.FS
+ var err error
+ if cfg.Pages.Theme == "bootstrap" {
+ pages, err = fs.Sub(pagesFS, "pages/bootstrap")
+ if err != nil {
+ logError("Failed when processing pages: %s", err)
+ }
+ } else if cfg.Pages.Theme == "nebula" {
+ pages, err = fs.Sub(NebulaPagesFS, "pages/nebula")
+ if err != nil {
+ logError("Failed when processing pages: %s", err)
+ }
+ } else {
+ pages, err = fs.Sub(pagesFS, "pages/bootstrap")
+ if err != nil {
+ logError("Failed when processing pages: %s", err)
+ }
}
router.GET("/", gin.WrapH(http.FileServer(http.FS(pages))))
router.GET("/favicon.ico", gin.WrapH(http.FileServer(http.FS(pages))))
diff --git a/pages/favicon.ico b/pages/bootstrap/favicon.ico
similarity index 100%
rename from pages/favicon.ico
rename to pages/bootstrap/favicon.ico
diff --git a/pages/bootstrap/index.html b/pages/bootstrap/index.html
new file mode 100644
index 0000000..066332a
--- /dev/null
+++ b/pages/bootstrap/index.html
@@ -0,0 +1,440 @@
+
+
+
+
+
+
+ Github文件加速
+
+
+
+
+
+
+
+ k4_k~2{*$u+lPAVnFQnV84`
zu2mwhy4uW$JqDx_t)3gx3@R6g~s8NNtS-h{~Q4w9s4>n
zn0*F-6UM&!nXe3$@bU5S=;&xgMaB2;-+yyhYHDg}Y3cCr@ZsU16bNB<_nD@dmpGrh
zySwG(<$ivCoSBD*hx5r4U{3GDiKCcPfz)pG~&Pj=jZ1?KR>e(6ig|c9A#czT@9W*jRK#=
z#l=HILn9+2EiEm*y}cwHA0N*=7z{8zwQ{4cYtYx%Cvip$uBud3RdsQ3v9+~DwO3bH
zcXoDygM$Td06+45R&auXK3*#T
z>EmETVTlkDH1$!$`ucjnl-Cf!Pfbmc`Qzi`{{BAsZ)|Lk|MvEFNJxl*DTFd9Dk^f)
z*NL2;pNEBo8H&K2ot@-UR#rARI0)FMF&0f+hk;KVVB8zT3aOza_){Os&37|Dv2
zmX^jX_4V~-J|Q9D^70ZEZGmxaZcg)#2p{(fGjy(jK^mvAu@QiZgM-Dz#lcEXPhVbM
zzQ4bJd3gc+af2QG=l1q?U|_)MltpL1Ak8W3EHX1Q(Nz9XQBjeRk$jevlz_z0lw(G*
zmX?+R0s=Ve*w|Qqe}C?ORA5`
zSW{EuUSFXX78VRqbS?%&lf2U4;RBPhU{nd1qT{%lh+JJm6rINo*lb+R{QSI0L&p>z
z9?qixX)dA&D!QRxU0p>)M1YjIkj>4_LIQR*mKGNm4Mjvc%+b*i
zOZJUx3r$T;fVIbe-6%gu~~7e}$r0#5FBK`uu(&a(8#v-QC^R)ivnf@
zT^&}ni;0N|^9!Qn83}}$PgRVU+uz@>%-xGCoC$Gqa>7PJLqk;rlezgMfx5c7gM$Nz
zWc3wsvm=AQzP_g06DTVyiylQA%*e=~_07!8@Vf@y
Date: Tue, 18 Feb 2025 10:34:24 +0800
Subject: [PATCH 09/13] 25w14a
---
CHANGELOG.md | 13 ++
DEV-VERSION | 2 +-
main.go | 2 +
pages/bootstrap/index.html | 341 +------------------------------------
pages/bootstrap/script.js | 84 +++++++++
pages/bootstrap/style.css | 259 ++++++++++++++++++++++++++++
pages/nebula/index.html | 310 +--------------------------------
pages/nebula/script.js | 131 ++++++++++++++
pages/nebula/style.css | 157 +++++++++++++++++
9 files changed, 651 insertions(+), 648 deletions(-)
create mode 100644 pages/bootstrap/script.js
create mode 100644 pages/bootstrap/style.css
create mode 100644 pages/nebula/script.js
create mode 100644 pages/nebula/style.css
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6f57a7c..ec95b6c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,18 @@
# 更新日志
+25w14a
+---
+- PRE-RELEASE: 此版本是v2.3.0的预发布版本,请勿在生产环境中使用;
+- CHANGE: 使用`touka-httpc`封装`HTTP Client`, 更新到`v0.2.0`版本, 参看`touka-httpc`
+- CHANGE: 重构前端页面, 见[#49](https://github.com/WJQSERVER-STUDIO/ghproxy/pull/49)
+- CHANGE: 重构`blacklist`实现
+- CHANGE: 优化404处理
+- CHANGE: 重构`whitelist`实现
+- CHANGE: 对`proxy`进行结构性调整
+- CHANGE: `chunckedreq`与`gitreq`共用`BufferPool`和`HTTP Client`
+- CHANGE: 新增`HTTP Client`配置块
+- CHANGE: 加入内置主题配置, 支持通过配置切换主题
+
25w14t-2
---
- PRE-RELEASE: 此版本是测试验证版本,请勿在生产环境中使用;
diff --git a/DEV-VERSION b/DEV-VERSION
index b0f9cf0..678daff 100644
--- a/DEV-VERSION
+++ b/DEV-VERSION
@@ -1 +1 @@
-25w14t-2
\ No newline at end of file
+25w14a
\ No newline at end of file
diff --git a/main.go b/main.go
index 863caa6..cc2eecc 100644
--- a/main.go
+++ b/main.go
@@ -181,6 +181,8 @@ func init() {
}
router.GET("/", gin.WrapH(http.FileServer(http.FS(pages))))
router.GET("/favicon.ico", gin.WrapH(http.FileServer(http.FS(pages))))
+ router.GET("/script.js", gin.WrapH(http.FileServer(http.FS(pages))))
+ router.GET("/style.css", gin.WrapH(http.FileServer(http.FS(pages))))
}
router.NoRoute(func(c *gin.Context) {
diff --git a/pages/bootstrap/index.html b/pages/bootstrap/index.html
index 066332a..b785d42 100644
--- a/pages/bootstrap/index.html
+++ b/pages/bootstrap/index.html
@@ -8,259 +8,7 @@
-
+
@@ -349,92 +97,7 @@
-
+
+
+
-
@@ -319,13 +315,17 @@
const input = document.getElementById('inputUrl');
const output = document.getElementById('output');
const outputLink = document.getElementById('outputLink');
+
// 获取当前域名
+ const CURRENT_PROTOCOL = window.location.protocol.replace(':', '');
const CURRENT_HOST = window.location.host;
- document.querySelectorAll('code').forEach(code => {
- const spanElement = code.querySelector('span');
- if (spanElement) {
- spanElement.textContent = CURRENT_HOST;
- }
+ // 替换协议部分
+ document.querySelectorAll('code .protocol').forEach(span => {
+ span.textContent = CURRENT_PROTOCOL;
+ });
+ // 替换域名部分
+ document.querySelectorAll('code .host').forEach(span => {
+ span.textContent = CURRENT_HOST;
});
// URL 转换规则
From 55afe7676cdc6feee679fbe2d5101ae0e18e86ed Mon Sep 17 00:00:00 2001
From: WJQSERVER
Date: Wed, 12 Feb 2025 19:26:10 +0800
Subject: [PATCH 03/13] fix drak mode
---
pages/index.html | 54 ++++++++++++++++++++++++++++++++++--------------
1 file changed, 38 insertions(+), 16 deletions(-)
diff --git a/pages/index.html b/pages/index.html
index e82eda6..3a44101 100644
--- a/pages/index.html
+++ b/pages/index.html
@@ -4,26 +4,26 @@
- GitHub 文件加速服务
+ GitHub加速服务
@@ -299,7 +312,7 @@
diff --git a/proxy/chunkreq.go b/proxy/chunkreq.go
index e1279b2..a315e5c 100644
--- a/proxy/chunkreq.go
+++ b/proxy/chunkreq.go
@@ -5,21 +5,21 @@ import (
"fmt"
"ghproxy/config"
"io"
- "net"
"net/http"
"strconv"
"sync"
"time"
"github.com/gin-gonic/gin"
+ httpc "github.com/satomitouka/touka-httpc"
)
var BufferSize int = 32 * 1024 // 32KB
var (
- cclient *http.Client
ctr *http.Transport
BufferPool *sync.Pool
+ cclient *httpc.Client
)
func InitReq(cfg *config.Config) {
@@ -35,31 +35,38 @@ func InitReq(cfg *config.Config) {
}
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,
- TLSHandshakeTimeout: 10 * time.Second,
- ExpectContinueTimeout: 1 * time.Second,
- ResponseHeaderTimeout: 10 * time.Second,
- DialContext: (&net.Dialer{
- Timeout: 30 * time.Second,
- KeepAlive: 30 * time.Second,
- }).DialContext,
+ MaxIdleConns: 100,
+ MaxConnsPerHost: 60,
+ IdleConnTimeout: 20 * time.Second,
}
if cfg.Outbound.Enabled {
initTransport(cfg, ctr)
}
- cclient = &http.Client{
- Transport: 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 := http.NewRequest("HEAD", u, nil)
+ headReq, err := cclient.NewRequest("HEAD", u, nil)
if err != nil {
HandleError(c, fmt.Sprintf("Failed to create request: %v", err))
return
@@ -92,13 +99,6 @@ func ChunkedProxyRequest(c *gin.Context, u string, cfg *config.Config, mode stri
}
}
- /*
- 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())
@@ -107,13 +107,11 @@ func ChunkedProxyRequest(c *gin.Context, u string, cfg *config.Config, mode stri
bodyReader := bytes.NewBuffer(body)
- // 创建请求
- req, err := http.NewRequest(method, u, bodyReader)
+ req, err := cclient.NewRequest(method, u, bodyReader)
if err != nil {
HandleError(c, fmt.Sprintf("Failed to create request: %v", err))
return
}
-
setRequestHeaders(c, req)
removeWSHeader(req) // 删除Conection Upgrade头, 避免与HTTP/2冲突(检查是否存在Upgrade头)
AuthPassThrough(c, cfg, req)
@@ -125,13 +123,6 @@ 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
- }
- */
-
// 错误处理(404)
if resp.StatusCode == 404 {
c.String(http.StatusNotFound, "File Not Found")
diff --git a/proxy/gitreq.go b/proxy/gitreq.go
index 117de27..4ceeac9 100644
--- a/proxy/gitreq.go
+++ b/proxy/gitreq.go
@@ -10,10 +10,11 @@ import (
"time"
"github.com/gin-gonic/gin"
+ httpc "github.com/satomitouka/touka-httpc"
)
var (
- gclient *http.Client
+ gclient *httpc.Client
gtr *http.Transport
)
@@ -26,20 +27,22 @@ func initGitHTTPClient(cfg *config.Config) {
if cfg.Outbound.Enabled {
initTransport(cfg, gtr)
}
- gclient = &http.Client{
- Transport: 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)
- // 创建HTTP客户端
- //client := &http.Client{}
-
// 发送HEAD请求, 预获取Content-Length
- headReq, err := http.NewRequest("HEAD", u, nil)
+ headReq, err := gclient.NewRequest("HEAD", u, nil)
if err != nil {
HandleError(c, fmt.Sprintf("Failed to create request: %v", err))
return
@@ -81,7 +84,7 @@ func GitReq(c *gin.Context, u string, cfg *config.Config, mode string, runMode s
bodyReader := bytes.NewBuffer(body)
// 创建请求
- req, err := http.NewRequest(method, u, bodyReader)
+ req, err := gclient.NewRequest(method, u, bodyReader)
if err != nil {
HandleError(c, fmt.Sprintf("Failed to create request: %v", err))
return
@@ -101,12 +104,6 @@ func GitReq(c *gin.Context, u string, cfg *config.Config, mode string, runMode s
}
}(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
- }
- */
contentLength = resp.Header.Get("Content-Length")
if contentLength != "" {
size, err := strconv.Atoi(contentLength)
From 785a74dfeb83504a30cef129a054adf2a6246ccf Mon Sep 17 00:00:00 2001
From: WJQSERVER
+
-
-
-
+
\ No newline at end of file
From 0d6c1d7e3535b8620557164aa07b0ea89d661615 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=B8=85=E9=9F=B5=27s?= <2359824360@qq.com>
Date: Wed, 12 Feb 2025 09:04:26 +0800
Subject: [PATCH 02/13] =?UTF-8?q?=E5=8A=A8=E6=80=81=E9=80=82=E9=85=8D?=
=?UTF-8?q?=E7=A4=BA=E4=BE=8B=E9=93=BE=E6=8E=A5=E5=8D=8F=E8=AE=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pages/index.html | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/pages/index.html b/pages/index.html
index 30e59e0..e82eda6 100644
--- a/pages/index.html
+++ b/pages/index.html
@@ -228,25 +228,21 @@
基础用法示例
-Git 克隆
git clone https://example.com/https://github.com/user/project.git
-
+ class="d-block mb-3">git clone https://example.com/https://github.com/user/project.git
私有仓库克隆
git clone https://user:your_token@example.com/https://github.com/user/project.git
+ class="d-block">git clone https://user:your_token@example.com/https://github.com/user/project.git
文件下载
wget https://example.com/https://raw.githubusercontent.com/user/project/main/README.md
-
+ class="d-block mb-3">wget https://example.com/https://raw.githubusercontent.com/user/project/main/README.md
版本发布
curl -LO https://example.com/https://github.com/user/project/releases/download/v1.0.0./project_1.0.0.amd64.tar.gz
+ class="d-block">curl -LO https://example.com/https://github.com/user/project/releases/download/v1.0.0/project_1.0.0.amd64.tar.gz
HTTPS Git Clone
-https://github.com/user/repo.git
+ git clone https://github.com/user/repo.git
+
+
+
+
+
+
+
+
+
+ Github文件加速
+为访问Github文件进行加速
+ + +GitHub 链接带不带协议头均可,支持 release、archive 以及文件,转换后链接均可使用。
+
+
+
+
+
+
+
+
+ 文件大小限制
+...
+
+
+
+
+
+
+ 白名单状态
+...
+
+
+
+
+
+
+ 黑名单状态
+...
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/nebula/favicon.ico b/pages/nebula/favicon.ico
new file mode 100644
index 0000000000000000000000000000000000000000..9c04d31ade74151073f9c5d87d6dc75f72d58111
GIT binary patch
literal 3262
zcmc(g%PaO<6vux!?)QX)(#zx+G4Yz1oB=`x
+
+
+