Compare commits

...

9 Commits

Author SHA1 Message Date
WJQSERVER
c13dd9082b Merge pull request #124 from WJQSERVER-STUDIO/dev
3.5.5
2025-06-14 22:17:46 +08:00
wjqserver
e0cbfed1e7 3.5.5 2025-06-14 22:17:13 +08:00
wjqserver
1b06260a14 25w47a 2025-06-14 22:11:31 +08:00
wjqserver
8ab622d149 update matcher for gist usercontent 2025-06-14 22:05:45 +08:00
WJQSERVER
96c30889f4 Merge pull request #123 from WJQSERVER-STUDIO/dev
3.5.4
2025-06-14 12:50:36 +08:00
wjqserver
bbb108689a 3.5.4 2025-06-14 12:50:26 +08:00
wjqserver
41395b1d72 25w46c 2025-06-14 07:16:43 +08:00
wjqserver
bd8412f157 25w46b 2025-06-14 06:51:41 +08:00
wjqserver
d2a0177015 25w46a 2025-06-14 06:47:47 +08:00
11 changed files with 101 additions and 26 deletions

View File

@@ -1,5 +1,33 @@
# 更新日志
3.5.5 - 2025-06-14
---
- CHANGE: 修正新匹配器的覆盖问题, 同时增加test的覆盖
25w47a - 2025-06-14
---
- PRE-RELEASE: 此版本是v3.5.5预发布版本,请勿在生产环境中使用;
- CHANGE: 修正新匹配器的覆盖问题, 同时增加test的覆盖
3.5.4 - 2025-06-14
---
- CHANGE: 移植来自于[GHProxy-Touka](https://github.com/WJQSERVER-STUDIO/ghproxy-touka)的blob处理逻辑与302处理逻辑
25w46c - 2025-06-14
---
- PRE-RELEASE: 此版本是v3.5.4预发布版本,请勿在生产环境中使用;
- CHANGE: 移植来自于[GHProxy-Touka](https://github.com/WJQSERVER-STUDIO/ghproxy-touka)的blob处理逻辑与302处理逻辑
25w46b - 2025-06-14
---
- PRE-RELEASE: 此版本是v3.5.4预发布版本,请勿在生产环境中使用;
- CHANGE: 修改关闭行为以测试问题
25w46a - 2025-06-14
---
- PRE-RELEASE: 此版本是v3.5.4预发布版本,请勿在生产环境中使用;
- CHANGE: 修改payload行为以测试问题
3.5.3 - 2025-06-13
---
- CHANGE: 显式配置`WithStreamBody(true)`

View File

@@ -1 +1 @@
25w45a
25w47a

View File

@@ -109,7 +109,7 @@ wget -O install-dev.sh https://raw.githubusercontent.com/WJQSERVER-STUDIO/ghprox
## LICENSE
v3.5.2开始, 本项目使用 [WJQserver Studio License 2.0](https://wjqserver-studio.github.io/LICENSE/LICENSE.html) 和 [Mozilla Public License Version 2.0](https://mozilla.org/MPL/2.0/) 双重许可, 您可从中选择一个使用
v3.5.2开始, 本项目使用 [WJQserver Studio License 2.1](https://wjqserver-studio.github.io/LICENSE/LICENSE.html) 和 [Mozilla Public License Version 2.0](https://mozilla.org/MPL/2.0/) 双重许可, 您可从中选择一个使用
前端位于单独仓库中, 且各个主题均存在各自的许可证, 本项目许可证并不包括前端

View File

@@ -1 +1 @@
3.5.3
3.5.5

View File

@@ -507,7 +507,7 @@ func main() {
proxy.NoRouteHandler(cfg, limiter, iplimiter)(ctx, c)
})
r.GET("/api.github.com/repos/:user/:repo/*filepath", func(ctx context.Context, c *app.RequestContext) {
r.Any("/api.github.com/repos/:user/:repo/*filepath", func(ctx context.Context, c *app.RequestContext) {
c.Set("matcher", "api")
proxy.RoutingHandler(cfg, limiter, iplimiter)(ctx, c)
})

View File

@@ -23,16 +23,17 @@ func ChunkedProxyRequest(ctx context.Context, c *app.RequestContext, u string, c
go func() {
<-ctx.Done()
if resp != nil && resp.Body != nil {
resp.Body.Close()
}
if req != nil {
req.Body.Close()
err := resp.Body.Close()
if err != nil {
logError("Failed to close response body: %v", err)
}
}
}()
rb := client.NewRequestBuilder(string(c.Request.Method()), u)
rb.NoDefaultHeaders()
rb.SetBody(c.Request.BodyStream())
//rb.SetBody(bytes.NewBuffer(c.Request.Body()))
rb.SetBody(c.RequestBodyStream())
rb.WithContext(ctx)
req, err = rb.Build()
@@ -56,6 +57,20 @@ func ChunkedProxyRequest(ctx context.Context, c *app.RequestContext, u string, c
return
}
// 处理302情况
if resp.StatusCode == 302 {
finalURL := resp.Header.Get("Location")
if finalURL != "" {
err = resp.Body.Close()
if err != nil {
logError("Failed to close response body: %v", err)
}
c.Request.Header.Del("Referer")
logInfo("Internal Redirecting to %s", finalURL)
ChunkedProxyRequest(ctx, c, finalURL, cfg, matcher)
}
}
var (
bodySize int
contentLength string
@@ -110,8 +125,6 @@ func ChunkedProxyRequest(ctx context.Context, c *app.RequestContext, u string, c
bodyReader = limitreader.NewRateLimitedReader(bodyReader, bandwidthLimit, int(bandwidthBurst), ctx)
}
defer bodyReader.Close()
if MatcherShell(u) && matchString(matcher) && cfg.Shell.Editor {
// 判断body是不是gzip
var compress string

View File

@@ -17,15 +17,16 @@ func GitReq(ctx context.Context, c *app.RequestContext, u string, cfg *config.Co
var (
req *http.Request
resp *http.Response
err error
)
go func() {
<-ctx.Done()
if resp != nil && resp.Body != nil {
resp.Body.Close()
}
if req != nil {
req.Body.Close()
err = resp.Body.Close()
if err != nil {
logError("Failed to close response body: %v", err)
}
}
}()
@@ -51,7 +52,7 @@ func GitReq(ctx context.Context, c *app.RequestContext, u string, cfg *config.Co
rb.SetBody(reqBodyReader)
rb.WithContext(ctx)
req, err := rb.Build()
req, err = rb.Build()
if err != nil {
HandleError(c, fmt.Sprintf("Failed to create request: %v", err))
return

View File

@@ -68,7 +68,10 @@ func NoRouteHandler(cfg *config.Config, limiter *rate.RateLimiter, iplimiter *ra
// 处理blob/raw路径
if matcher == "blob" {
rawPath = strings.Replace(rawPath, "/blob/", "/raw/", 1)
rawPath = rawPath[10:]
rawPath = "raw.githubusercontent.com" + rawPath
rawPath = strings.Replace(rawPath, "/blob/", "/", 1)
matcher = "raw"
}
logDebug("Matched: %v", matcher)

View File

@@ -10,14 +10,16 @@ import (
)
var (
githubPrefix = "https://github.com/"
rawPrefix = "https://raw.githubusercontent.com/"
gistPrefix = "https://gist.github.com/"
apiPrefix = "https://api.github.com/"
githubPrefixLen int
rawPrefixLen int
gistPrefixLen int
apiPrefixLen int
githubPrefix = "https://github.com/"
rawPrefix = "https://raw.githubusercontent.com/"
gistPrefix = "https://gist.github.com/"
gistContentPrefix = "https://gist.githubusercontent.com/"
apiPrefix = "https://api.github.com/"
githubPrefixLen int
rawPrefixLen int
gistPrefixLen int
gistContentPrefixLen int
apiPrefixLen int
)
func init() {
@@ -25,6 +27,7 @@ func init() {
rawPrefixLen = len(rawPrefix)
gistPrefixLen = len(gistPrefix)
apiPrefixLen = len(apiPrefix)
gistContentPrefixLen = len(gistContentPrefix)
//log.Printf("githubPrefixLen: %d, rawPrefixLen: %d, gistPrefixLen: %d, apiPrefixLen: %d", githubPrefixLen, rawPrefixLen, gistPrefixLen, apiPrefixLen)
}
@@ -114,6 +117,23 @@ func Matcher(rawPath string, cfg *config.Config) (string, string, string, *GHPro
return user, "", "gist", nil
}
// 匹配 "https://gist.githubusercontent.com/"
if strings.HasPrefix(rawPath, gistContentPrefix) {
remaining := rawPath[gistContentPrefixLen:]
i := strings.IndexByte(remaining, '/')
if i <= 0 {
// case: https://gist.githubusercontent.com/user
// 这种情况下, gist_id 缺失, 但我们仍然可以认为 user 是有效的
if len(remaining) > 0 {
return remaining, "", "gist", nil
}
return "", "", "", NewErrorWithStatusLookup(400, "malformed gist url: missing user")
}
// case: https://gist.githubusercontent.com/user/gist_id...
user := remaining[:i]
return user, "", "gist", nil
}
// 匹配 "https://api.github.com/"
if strings.HasPrefix(rawPath, apiPrefix) {
if !cfg.Auth.ForceAllowApi && (cfg.Auth.Method != "header" || !cfg.Auth.Enabled) {

View File

@@ -87,6 +87,12 @@ func TestMatcher_Compatibility(t *testing.T) {
config: cfgWithAuth,
expectedUser: "user", expectedRepo: "", expectedMatcher: "gist",
},
{
name: "Gist UserContent Path",
rawPath: "https://gist.githubusercontent.com/user/abcdef1234567890",
config: cfgWithAuth,
expectedUser: "user", expectedRepo: "", expectedMatcher: "gist",
},
{
name: "API Repos Path (with Auth)",
rawPath: "https://api.github.com/repos/owner/repo/pulls",

View File

@@ -48,9 +48,13 @@ func RoutingHandler(cfg *config.Config, limiter *rate.RateLimiter, iplimiter *ra
return
}
// 处理blob/raw路径
// 处理blob/raw路径
if matcher == "blob" {
rawPath = strings.Replace(rawPath, "/blob/", "/raw/", 1)
rawPath = rawPath[10:]
rawPath = "raw.githubusercontent.com" + rawPath
rawPath = strings.Replace(rawPath, "/blob/", "/", 1)
matcher = "raw"
}
// 为rawpath加入https:// 头