mirror of
https://github.com/mudler/LocalAI.git
synced 2026-11-06 20:43:27 -05:00
StripPathPrefix and the redirect from / and /browse still read X-Forwarded-Prefix from any peer, after BaseURL and BasePathPrefix were gated on --trusted-proxies. A client could make the server strip a path prefix or add one to a redirect. Gate both on the same trusted-proxy resolver. The resolver is now stamped into the request before StripPathPrefix runs, and the check is exported as ForwardedHeadersTrusted. The explorer has no --trusted-proxies option and keeps its old behavior by trusting every peer for this one header. The docs say that the prefix needs a trusted proxy. Assisted-by: Claude:claude-sonnet-5-5 go-test
68 lines
2.1 KiB
Go
68 lines
2.1 KiB
Go
package middleware
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/labstack/echo/v4"
|
|
)
|
|
|
|
// StripPathPrefix returns middleware that strips a path prefix from the request path.
|
|
// The path prefix is obtained from the X-Forwarded-Prefix HTTP request header.
|
|
// The header is believed only when the TCP peer is a trusted proxy (see
|
|
// TrustedProxies); otherwise the path is left alone.
|
|
// This must be registered as Pre middleware (using e.Pre()) to modify the path before routing.
|
|
func StripPathPrefix() echo.MiddlewareFunc {
|
|
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
|
return func(c echo.Context) error {
|
|
if !ForwardedHeadersTrusted(c) {
|
|
return next(c)
|
|
}
|
|
prefixes := c.Request().Header.Values("X-Forwarded-Prefix")
|
|
originalPath := c.Request().URL.Path
|
|
|
|
for _, prefix := range prefixes {
|
|
validated, ok := SafeForwardedPrefix(prefix)
|
|
if !ok {
|
|
continue
|
|
}
|
|
prefix = validated
|
|
if prefix != "" {
|
|
normalizedPrefix := prefix
|
|
if !strings.HasSuffix(prefix, "/") {
|
|
normalizedPrefix = prefix + "/"
|
|
}
|
|
|
|
if strings.HasPrefix(originalPath, normalizedPrefix) {
|
|
// Update the request path by stripping the normalized prefix
|
|
newPath := originalPath[len(normalizedPrefix):]
|
|
if newPath == "" {
|
|
newPath = "/"
|
|
}
|
|
// Ensure path starts with / for proper routing
|
|
if !strings.HasPrefix(newPath, "/") {
|
|
newPath = "/" + newPath
|
|
}
|
|
// Update the URL path - Echo's router uses URL.Path for routing
|
|
c.Request().URL.Path = newPath
|
|
c.Request().URL.RawPath = ""
|
|
// Update RequestURI to match the new path (needed for proper routing)
|
|
if c.Request().URL.RawQuery != "" {
|
|
c.Request().RequestURI = newPath + "?" + c.Request().URL.RawQuery
|
|
} else {
|
|
c.Request().RequestURI = newPath
|
|
}
|
|
// Store original path for BaseURL utility
|
|
c.Set("_original_path", originalPath)
|
|
break
|
|
} else if originalPath == prefix || originalPath == prefix+"/" {
|
|
// Redirect to prefix with trailing slash (use 302 to match test expectations)
|
|
return c.Redirect(302, normalizedPrefix)
|
|
}
|
|
}
|
|
}
|
|
|
|
return next(c)
|
|
}
|
|
}
|
|
}
|