-
Notifications
You must be signed in to change notification settings - Fork 3
/
module.go
111 lines (88 loc) · 2.31 KB
/
module.go
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package naddy
import (
"fmt"
"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
"github.com/tj/go-redirects"
"html"
"net/http"
"path"
"strconv"
)
func init() {
caddy.RegisterModule(Middleware{})
}
func (Middleware) CaddyModule() caddy.ModuleInfo {
return caddy.ModuleInfo{
ID: "http.handlers." + ModuleName,
New: func() caddy.Module { return new(Middleware) },
}
}
func (m *Middleware) Provision(ctx caddy.Context) error {
m.Logger = ctx.Logger(m)
m.Logger.Info(fmt.Sprintf("provisioned with %v redirects", len(m.Redirects)))
return nil
}
func (m Middleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
scheme := "http://"
if r.TLS != nil {
scheme = "https://"
}
mc := &MatchContext{
Scheme: scheme,
OriginalUrl: r.URL,
}
reqUrl, err := ParseUrlWithContext(path.Join(r.Host, r.URL.Path), mc)
if err != nil {
m.Logger.Error(err.Error())
return err
}
reqUrl.RawQuery = r.URL.RawQuery
for _, rule := range m.Redirects {
result := MatchUrlToRule(rule, reqUrl, mc)
if result.Error != nil {
m.Logger.Error(result.Error.Error())
continue
}
if result.IsMatched == false {
continue
}
return m.handleRedirectResponse(result, rule, w, r)
}
return next.ServeHTTP(w, r)
}
func (m *Middleware) handleRedirectResponse(result MatchResult, rule redirects.Rule, w http.ResponseWriter, r *http.Request) error {
body := ""
if rule.Status < 300 || rule.Status >= 400 {
body = buildHtmlRedirect(result.ResolvedTo.String())
}
s := &caddyhttp.StaticResponse{
StatusCode: caddyhttp.WeakString(strconv.Itoa(rule.Status)),
Headers: http.Header{
"Location": []string{result.ResolvedTo.String()},
},
Body: body,
}
err := s.ServeHTTP(w, r, nil)
if err != nil {
m.Logger.Error(fmt.Sprintf("did not expect an error, but got: %v", err))
}
return err
}
func buildHtmlRedirect(url string) string {
const metaRedir = `<!DOCTYPE html>
<html>
<head>
<title>Redirecting...</title>
<script>window.location.replace("%s");</script>
<meta http-equiv="refresh" content="0; URL='%s'">
</head>
<body>Redirecting to <a href="%s">%s</a>...</body>
</html>
`
safeTo := html.EscapeString(url)
return fmt.Sprintf(metaRedir, safeTo, safeTo, safeTo, safeTo)
}
var (
_ caddyhttp.MiddlewareHandler = (*Middleware)(nil)
)