mirror of
https://github.com/go-gitea/gitea
synced 2025-07-22 18:28:37 +00:00
Fix duplicate sub-path for avatars (#31365)
Fix #31361, and add tests And this PR introduces an undocumented & debug-purpose-only config option: `USE_SUB_URL_PATH`. It does nothing for end users, it only helps the development of sub-path related problems. And also fix #31366 Co-authored-by: @ExplodingDragon
This commit is contained in:
@@ -25,7 +25,7 @@ import (
|
||||
// ProtocolMiddlewares returns HTTP protocol related middlewares, and it provides a global panic recovery
|
||||
func ProtocolMiddlewares() (handlers []any) {
|
||||
// first, normalize the URL path
|
||||
handlers = append(handlers, stripSlashesMiddleware)
|
||||
handlers = append(handlers, normalizeRequestPathMiddleware)
|
||||
|
||||
// prepare the ContextData and panic recovery
|
||||
handlers = append(handlers, func(next http.Handler) http.Handler {
|
||||
@@ -75,9 +75,9 @@ func ProtocolMiddlewares() (handlers []any) {
|
||||
return handlers
|
||||
}
|
||||
|
||||
func stripSlashesMiddleware(next http.Handler) http.Handler {
|
||||
func normalizeRequestPathMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
||||
// First of all escape the URL RawPath to ensure that all routing is done using a correctly escaped URL
|
||||
// escape the URL RawPath to ensure that all routing is done using a correctly escaped URL
|
||||
req.URL.RawPath = req.URL.EscapedPath()
|
||||
|
||||
urlPath := req.URL.RawPath
|
||||
@@ -86,19 +86,42 @@ func stripSlashesMiddleware(next http.Handler) http.Handler {
|
||||
urlPath = rctx.RoutePath
|
||||
}
|
||||
|
||||
sanitizedPath := &strings.Builder{}
|
||||
prevWasSlash := false
|
||||
for _, chr := range strings.TrimRight(urlPath, "/") {
|
||||
if chr != '/' || !prevWasSlash {
|
||||
sanitizedPath.WriteRune(chr)
|
||||
normalizedPath := strings.TrimRight(urlPath, "/")
|
||||
// the following code block is a slow-path for replacing all repeated slashes "//" to one single "/"
|
||||
// if the path doesn't have repeated slashes, then no need to execute it
|
||||
if strings.Contains(normalizedPath, "//") {
|
||||
buf := &strings.Builder{}
|
||||
prevWasSlash := false
|
||||
for _, chr := range normalizedPath {
|
||||
if chr != '/' || !prevWasSlash {
|
||||
buf.WriteRune(chr)
|
||||
}
|
||||
prevWasSlash = chr == '/'
|
||||
}
|
||||
prevWasSlash = chr == '/'
|
||||
normalizedPath = buf.String()
|
||||
}
|
||||
|
||||
if setting.UseSubURLPath {
|
||||
remainingPath, ok := strings.CutPrefix(normalizedPath, setting.AppSubURL+"/")
|
||||
if ok {
|
||||
normalizedPath = "/" + remainingPath
|
||||
} else if normalizedPath == setting.AppSubURL {
|
||||
normalizedPath = "/"
|
||||
} else if !strings.HasPrefix(normalizedPath+"/", "/v2/") {
|
||||
// do not respond to other requests, to simulate a real sub-path environment
|
||||
http.Error(resp, "404 page not found, sub-path is: "+setting.AppSubURL, http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
// TODO: it's not quite clear about how req.URL and rctx.RoutePath work together.
|
||||
// Fortunately, it is only used for debug purpose, we have enough time to figure it out in the future.
|
||||
req.URL.RawPath = normalizedPath
|
||||
req.URL.Path = normalizedPath
|
||||
}
|
||||
|
||||
if rctx == nil {
|
||||
req.URL.Path = sanitizedPath.String()
|
||||
req.URL.Path = normalizedPath
|
||||
} else {
|
||||
rctx.RoutePath = sanitizedPath.String()
|
||||
rctx.RoutePath = normalizedPath
|
||||
}
|
||||
next.ServeHTTP(resp, req)
|
||||
})
|
||||
|
Reference in New Issue
Block a user