diff options
Diffstat (limited to 'echo/middleware/www_redirect.go')
-rw-r--r-- | echo/middleware/www_redirect.go | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/echo/middleware/www_redirect.go b/echo/middleware/www_redirect.go new file mode 100644 index 0000000..905a5cf --- /dev/null +++ b/echo/middleware/www_redirect.go | |||
@@ -0,0 +1,77 @@ | |||
1 | package middleware | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "net" | ||
6 | "net/http" | ||
7 | "strings" | ||
8 | |||
9 | "github.com/labstack/echo/v4" | ||
10 | "github.com/labstack/echo/v4/middleware" | ||
11 | ) | ||
12 | |||
13 | /* | ||
14 | WWW Redirect Middleware | ||
15 | |||
16 | This is a duplicate of existing functionality in Echo. This exists | ||
17 | because we don't want to prefix www to a request that is an IP address | ||
18 | only, only requests that use hostnames. | ||
19 | */ | ||
20 | |||
21 | type WWWRedirectConfig struct { | ||
22 | Skipper middleware.Skipper | ||
23 | Code int | ||
24 | } | ||
25 | |||
26 | var DefaultWWWRedirectConfig = WWWRedirectConfig{ | ||
27 | Skipper: middleware.DefaultSkipper, | ||
28 | Code: http.StatusMovedPermanently, | ||
29 | } | ||
30 | |||
31 | func WWWRedirect() echo.MiddlewareFunc { | ||
32 | return WWWRedirectWithConfig(DefaultWWWRedirectConfig) | ||
33 | } | ||
34 | |||
35 | func WWWRedirectWithConfig(config WWWRedirectConfig) echo.MiddlewareFunc { | ||
36 | if config.Skipper == nil { | ||
37 | config.Skipper = DefaultWWWRedirectConfig.Skipper | ||
38 | } | ||
39 | if config.Code == 0 { | ||
40 | config.Code = DefaultWWWRedirectConfig.Code | ||
41 | } | ||
42 | |||
43 | return func(next echo.HandlerFunc) echo.HandlerFunc { | ||
44 | return func(c echo.Context) error { | ||
45 | req := c.Request() | ||
46 | |||
47 | if config.Skipper(c) || strings.HasPrefix(req.Host, "www.") { | ||
48 | return next(c) | ||
49 | } | ||
50 | |||
51 | host, _, err := net.SplitHostPort(req.Host) | ||
52 | if err != nil { | ||
53 | return echo.ErrBadRequest | ||
54 | } | ||
55 | |||
56 | // Never prefix an IP with www | ||
57 | // | ||
58 | // We have to parse the hostname for something that looks like an IP | ||
59 | // because the golang http server removes the header from the header | ||
60 | // map and there's no good way to unambiguously determine if this was | ||
61 | // a raw IP request or if a hostname was submitted. | ||
62 | // | ||
63 | // TLS connections could use the req.TLS.ServerName property which | ||
64 | // should have the correct hostname but there's no such thing for HTTP. | ||
65 | // Instead we just try to parse anything that makes it to this point | ||
66 | // because it should be a small one-time cost for a few requests. | ||
67 | if ip := net.ParseIP(host); ip != nil { | ||
68 | return next(c) | ||
69 | } | ||
70 | |||
71 | return c.Redirect( | ||
72 | config.Code, | ||
73 | fmt.Sprintf("https://www.%s%s", req.Host, req.RequestURI), | ||
74 | ) | ||
75 | } | ||
76 | } | ||
77 | } | ||