File size: 1,883 Bytes
0f07ba7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
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.
// 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 {
			prefixes := c.Request().Header.Values("X-Forwarded-Prefix")
			originalPath := c.Request().URL.Path

			for _, prefix := range prefixes {
				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)
		}
	}
}