fix: avoid fixed-path miss panic and trim 405 fallback work

This commit is contained in:
wjqserver 2026-04-07 09:57:16 +08:00
parent fa027347d3
commit 987ea81329
2 changed files with 27 additions and 5 deletions

View file

@ -155,22 +155,25 @@ var methodNotAllowedHandler HandlerFunc = func(c *Context) {
c.Status(http.StatusOK) c.Status(http.StatusOK)
return return
} }
return
} }
// 尝试遍历所有方法树,看是否有其他方法可以匹配当前路径 // 尝试遍历所有方法树,看是否有其他方法可以匹配当前路径
tempSkippedNodes := GetTempSkippedNodes()
for _, treeIter := range engine.methodTrees { for _, treeIter := range engine.methodTrees {
if treeIter.method == httpMethod { // 已经处理过当前方法,跳过 if treeIter.method == httpMethod { // 已经处理过当前方法,跳过
continue continue
} }
// 注意这里 treeIter.root 才是正确的,因为 treeIter 是 methodTree 类型 // 注意这里 treeIter.root 才是正确的,因为 treeIter 是 methodTree 类型
tempSkippedNodes := GetTempSkippedNodes() *tempSkippedNodes = (*tempSkippedNodes)[:0]
value := treeIter.root.getValue(requestPath, nil, tempSkippedNodes, false) // 只查找是否存在,不需要参数 value := treeIter.root.getValue(requestPath, nil, tempSkippedNodes, false) // 只查找是否存在,不需要参数
PutTempSkippedNodes(tempSkippedNodes)
if value.handlers != nil { if value.handlers != nil {
PutTempSkippedNodes(tempSkippedNodes)
// 使用定义的ErrorHandle处理 // 使用定义的ErrorHandle处理
engine.errorHandle.handler(c, http.StatusMethodNotAllowed, errMethodNotAllowed) engine.errorHandle.handler(c, http.StatusMethodNotAllowed, errMethodNotAllowed)
return return
} }
} }
PutTempSkippedNodes(tempSkippedNodes)
} }
var notFoundHandler HandlerFunc = func(c *Context) { var notFoundHandler HandlerFunc = func(c *Context) {
@ -815,7 +818,7 @@ func (engine *Engine) handleRequest(c *Context) {
c.Redirect(http.StatusMovedPermanently, string(ciPath)) // 301 永久重定向到修正后的路径 c.Redirect(http.StatusMovedPermanently, string(ciPath)) // 301 永久重定向到修正后的路径
return return
} }
c.fixedPathBuf = ciPath[:0] c.fixedPathBuf = c.fixedPathBuf[:0]
} }
} }
} }
@ -872,15 +875,16 @@ func (engine *Engine) allowedMethodsForPath(requestPath string, allowedMethods [
} else { } else {
allowedMethods = allowedMethods[:0] allowedMethods = allowedMethods[:0]
} }
tempSkippedNodes := GetTempSkippedNodes()
for _, treeIter := range engine.methodTrees { for _, treeIter := range engine.methodTrees {
// 注意这里 treeIter.root 才是正确的,因为 treeIter 是 methodTree 类型 // 注意这里 treeIter.root 才是正确的,因为 treeIter 是 methodTree 类型
tempSkippedNodes := GetTempSkippedNodes() *tempSkippedNodes = (*tempSkippedNodes)[:0]
value := treeIter.root.getValue(requestPath, nil, tempSkippedNodes, false) value := treeIter.root.getValue(requestPath, nil, tempSkippedNodes, false)
PutTempSkippedNodes(tempSkippedNodes)
if value.handlers != nil { if value.handlers != nil {
allowedMethods = append(allowedMethods, treeIter.method) allowedMethods = append(allowedMethods, treeIter.method)
} }
} }
PutTempSkippedNodes(tempSkippedNodes)
return allowedMethods return allowedMethods
} }

View file

@ -48,6 +48,24 @@ func TestHandleRequestKeepsFixedPathLookupForUppercaseMiss(t *testing.T) {
} }
} }
func TestHandleRequestFixedPathLookupMissDoesNotPanic(t *testing.T) {
engine := New()
engine.GET("/Users/Profile", func(c *Context) {
c.Status(http.StatusNoContent)
})
defer func() {
if r := recover(); r != nil {
t.Fatalf("unexpected panic for fixed-path miss: %v", r)
}
}()
rr := PerformRequest(engine, http.MethodGet, "/users/unknown", nil, nil)
if rr.Code != http.StatusNotFound {
t.Fatalf("expected fixed-path miss to stay as 404, got %d", rr.Code)
}
}
func TestNoRouteCanContinueToDefaultNotFound(t *testing.T) { func TestNoRouteCanContinueToDefaultNotFound(t *testing.T) {
engine := New() engine := New()
engine.NoRoute(func(c *Context) { engine.NoRoute(func(c *Context) {