Skip to content

Commit b0388e6

Browse files
authored
Merge pull request #156 from WJQSERVER-STUDIO/dev
4.2.5
2 parents 4b3f8e1 + 208ce8a commit b0388e6

5 files changed

Lines changed: 77 additions & 69 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# 更新日志
22

3+
4.2.5 - 2025-07-31
4+
---
5+
- CHANGE: 进一步完善匹配器, 兼容更多情况
6+
37
4.2.4 - 2025-07-29
48
---
59
- CHANGE: 改进匹配器, 防止匹配不应匹配的内容

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
4.2.4
1+
4.2.5

main.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,11 @@ func main() {
399399
proxy.RoutingHandler(cfg)(c)
400400
})
401401

402+
r.GET("/github.com/:user/:repo/releases/:tag/download/*filepath", func(c *touka.Context) {
403+
c.Set("matcher", "releases")
404+
proxy.RoutingHandler(cfg)(c)
405+
})
406+
402407
r.GET("/github.com/:user/:repo/archive/*filepath", func(c *touka.Context) {
403408
c.Set("matcher", "releases")
404409
proxy.RoutingHandler(cfg)(c)

proxy/match.go

Lines changed: 60 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -42,37 +42,62 @@ func Matcher(rawPath string, cfg *config.Config) (string, string, string, *GHPro
4242

4343
// 匹配 "https://github.com/"
4444
if strings.HasPrefix(rawPath, githubPrefix) {
45-
remaining := rawPath[githubPrefixLen:]
46-
i := strings.IndexByte(remaining, '/')
45+
pathAfterDomain := rawPath[githubPrefixLen:]
46+
47+
// 解析 user
48+
i := strings.IndexByte(pathAfterDomain, '/')
4749
if i <= 0 {
4850
return "", "", "", NewErrorWithStatusLookup(400, "malformed github path: missing user")
4951
}
50-
user := remaining[:i]
51-
remaining = remaining[i+1:]
52-
i = strings.IndexByte(remaining, '/')
52+
user := pathAfterDomain[:i]
53+
pathAfterUser := pathAfterDomain[i+1:]
54+
55+
// 解析 repo
56+
i = strings.IndexByte(pathAfterUser, '/')
5357
if i <= 0 {
54-
return "", "", "", NewErrorWithStatusLookup(400, "malformed github path: missing repo")
58+
return "", "", "", NewErrorWithStatusLookup(400, "malformed github path: missing action")
5559
}
56-
repo := remaining[:i]
57-
remaining = remaining[i+1:]
58-
if len(remaining) == 0 {
60+
repo := pathAfterUser[:i]
61+
pathAfterRepo := pathAfterUser[i+1:]
62+
63+
if len(pathAfterRepo) == 0 {
5964
return "", "", "", NewErrorWithStatusLookup(400, "malformed github path: missing action")
6065
}
61-
i = strings.IndexByte(remaining, '/')
62-
action := remaining
66+
67+
// 优先处理所有 "releases" 相关的下载路径
68+
if strings.HasPrefix(pathAfterRepo, "releases/") {
69+
// 情况 A: "releases/download/..."
70+
if strings.HasPrefix(pathAfterRepo, "releases/download/") {
71+
return user, repo, "releases", nil
72+
}
73+
// 情况 B: "releases/:tag/download/..."
74+
pathAfterReleases := pathAfterRepo[len("releases/"):]
75+
slashIndex := strings.IndexByte(pathAfterReleases, '/')
76+
if slashIndex > 0 { // 确保tag不为空
77+
pathAfterTag := pathAfterReleases[slashIndex+1:]
78+
if strings.HasPrefix(pathAfterTag, "download/") {
79+
return user, repo, "releases", nil
80+
}
81+
}
82+
// 如果不满足上述下载链接的结构, 则为网页浏览路径, 予以拒绝
83+
return "", "", "", NewErrorWithStatusLookup(400, "unsupported releases page, only download links are allowed")
84+
}
85+
86+
// 检查 "archive/" 路径
87+
if strings.HasPrefix(pathAfterRepo, "archive/") {
88+
// 根据测试用例, archive路径的matcher也应为releases
89+
return user, repo, "releases", nil
90+
}
91+
92+
// 如果不是下载路径, 则解析action并进行分类
93+
i = strings.IndexByte(pathAfterRepo, '/')
94+
action := pathAfterRepo
6395
if i != -1 {
64-
action = remaining[:i]
96+
action = pathAfterRepo[:i]
6597
}
98+
6699
var matcher string
67100
switch action {
68-
case "releases":
69-
if strings.HasPrefix(remaining, releasesDownloadSnippet) {
70-
matcher = "releases"
71-
} else {
72-
return "", "", "", NewErrorWithStatusLookup(400, "malformed github path: not a releases download url")
73-
}
74-
case "archive":
75-
matcher = "releases"
76101
case "blob":
77102
matcher = "blob"
78103
case "raw":
@@ -88,59 +113,27 @@ func Matcher(rawPath string, cfg *config.Config) (string, string, string, *GHPro
88113
// 匹配 "https://raw.githubusercontent.com/"
89114
if strings.HasPrefix(rawPath, rawPrefix) {
90115
remaining := rawPath[rawPrefixLen:]
91-
// 这里的逻辑与 github.com 的类似, 需要提取 user, repo, branch, file...
92-
// 我们只需要 user 和 repo
93-
i := strings.IndexByte(remaining, '/')
94-
if i <= 0 {
95-
return "", "", "", NewErrorWithStatusLookup(400, "malformed raw url: missing user")
96-
}
97-
user := remaining[:i]
98-
remaining = remaining[i+1:]
99-
i = strings.IndexByte(remaining, '/')
100-
if i <= 0 {
101-
return "", "", "", NewErrorWithStatusLookup(400, "malformed raw url: missing repo")
102-
}
103-
repo := remaining[:i]
104-
// raw 链接至少需要 user/repo/branch 三部分
105-
remaining = remaining[i+1:]
106-
if len(remaining) == 0 {
107-
return "", "", "", NewErrorWithStatusLookup(400, "malformed raw url: missing branch/commit")
116+
parts := strings.SplitN(remaining, "/", 3)
117+
if len(parts) < 3 {
118+
return "", "", "", NewErrorWithStatusLookup(400, "malformed raw url: path too short")
108119
}
109-
return user, repo, "raw", nil
120+
return parts[0], parts[1], "raw", nil
110121
}
111122

112-
// 匹配 "https://gist.github.com/"
113-
if strings.HasPrefix(rawPath, gistPrefix) {
114-
remaining := rawPath[gistPrefixLen:]
115-
i := strings.IndexByte(remaining, '/')
116-
if i <= 0 {
117-
// case: https://gist.github.com/user
118-
// 这种情况下, gist_id 缺失, 但我们仍然可以认为 user 是有效的
119-
if len(remaining) > 0 {
120-
return remaining, "", "gist", nil
121-
}
122-
return "", "", "", NewErrorWithStatusLookup(400, "malformed gist url: missing user")
123+
// 匹配 "https://gist.github.com/" 或 "https://gist.githubusercontent.com/"
124+
isGist := strings.HasPrefix(rawPath, gistPrefix)
125+
if isGist || strings.HasPrefix(rawPath, gistContentPrefix) {
126+
var remaining string
127+
if isGist {
128+
remaining = rawPath[gistPrefixLen:]
129+
} else {
130+
remaining = rawPath[gistContentPrefixLen:]
123131
}
124-
// case: https://gist.github.com/user/gist_id...
125-
user := remaining[:i]
126-
return user, "", "gist", nil
127-
}
128-
129-
// 匹配 "https://gist.githubusercontent.com/"
130-
if strings.HasPrefix(rawPath, gistContentPrefix) {
131-
remaining := rawPath[gistContentPrefixLen:]
132-
i := strings.IndexByte(remaining, '/')
133-
if i <= 0 {
134-
// case: https://gist.githubusercontent.com/user
135-
// 这种情况下, gist_id 缺失, 但我们仍然可以认为 user 是有效的
136-
if len(remaining) > 0 {
137-
return remaining, "", "gist", nil
138-
}
132+
parts := strings.SplitN(remaining, "/", 2)
133+
if len(parts) == 0 || parts[0] == "" {
139134
return "", "", "", NewErrorWithStatusLookup(400, "malformed gist url: missing user")
140135
}
141-
// case: https://gist.githubusercontent.com/user/gist_id...
142-
user := remaining[:i]
143-
return user, "", "gist", nil
136+
return parts[0], "", "gist", nil
144137
}
145138

146139
// 匹配 "https://api.github.com/"

proxy/matcher_test.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,17 @@ func TestMatcher_Compatibility(t *testing.T) {
3333
expectedErrCode int
3434
}{
3535
{
36-
name: "GH Releases Path",
36+
name: "GH Releases Path 1",
3737
rawPath: "https://github.com/owner/repo/releases/download/v1.0/asset.zip",
3838
config: cfgWithAuth,
3939
expectedUser: "owner", expectedRepo: "repo", expectedMatcher: "releases",
4040
},
41+
{
42+
name: "GH Releases Path 2",
43+
rawPath: "https://github.com/owner/repo/releases/v1.0/download/asset.zip",
44+
config: cfgWithAuth,
45+
expectedUser: "owner", expectedRepo: "repo", expectedMatcher: "releases",
46+
},
4147
{
4248
name: "GH Releases Path Page",
4349
rawPath: "https://github.com/owner/repo/releases",

0 commit comments

Comments
 (0)