This repository has been archived by the owner on Oct 17, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
redirector.go
148 lines (121 loc) · 2.97 KB
/
redirector.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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package redirector
import (
"fmt"
"net"
"net/http"
"strings"
"github.com/aofei/air"
"golang.org/x/net/idna"
)
// WWW2NonWWWGasConfig is a set of configurations for the `WWW2NonWWWGas`.
type WWW2NonWWWGasConfig struct {
HTTPSEnforced bool
Skippable func(*air.Request, *air.Response) bool
}
// WWW2NonWWWGas returns an `air.Gas` that is used to redirect www requests to
// non-www.
func WWW2NonWWWGas(w2nwgc WWW2NonWWWGasConfig) air.Gas {
return func(next air.Handler) air.Handler {
return func(req *air.Request, res *air.Response) error {
if w2nwgc.Skippable != nil &&
w2nwgc.Skippable(req, res) {
return next(req, res)
}
if strings.HasPrefix(
strings.ToLower(req.Authority),
"www.",
) {
res.Status = http.StatusMovedPermanently
scheme := req.Scheme
if w2nwgc.HTTPSEnforced {
scheme = "https"
}
return res.Redirect(fmt.Sprintf(
"%s://%s%s",
scheme,
req.Authority[4:],
req.Path,
))
}
return next(req, res)
}
}
}
// NonWWW2WWWGasConfig is a set of configurations for the `NonWWW2WWWGas`.
type NonWWW2WWWGasConfig struct {
HTTPSEnforced bool
Skippable func(*air.Request, *air.Response) bool
}
// NonWWW2WWWGas returns an `air.Gas` that is used to redirect non-www requests
// to www.
func NonWWW2WWWGas(nw2wgc NonWWW2WWWGasConfig) air.Gas {
return func(next air.Handler) air.Handler {
return func(req *air.Request, res *air.Response) error {
if nw2wgc.Skippable != nil &&
nw2wgc.Skippable(req, res) {
return next(req, res)
}
if !strings.HasPrefix(
strings.ToLower(req.Authority),
"www.",
) {
res.Status = http.StatusMovedPermanently
scheme := req.Scheme
if nw2wgc.HTTPSEnforced {
scheme = "https"
}
return res.Redirect(fmt.Sprintf(
"%s://www.%s%s",
scheme,
req.Authority,
req.Path,
))
}
return next(req, res)
}
}
}
// OneHostGasConfig is a set of configurations for the `OneHostGas`.
type OneHostGasConfig struct {
Host string
HTTPSEnforced bool
Skippable func(*air.Request, *air.Response) bool
}
// OneHostGas returns an `air.Gas` that is used to ensure that there is only one
// host.
func OneHostGas(oagc OneHostGasConfig) air.Gas {
if h, err := idna.Lookup.ToASCII(oagc.Host); err == nil {
oagc.Host = h
}
return func(next air.Handler) air.Handler {
return func(req *air.Request, res *air.Response) error {
if oagc.Skippable != nil && oagc.Skippable(req, res) {
return next(req, res)
}
if oagc.Host == "" {
return next(req, res)
}
h, _, err := net.SplitHostPort(req.Authority)
if err != nil {
h = req.Authority
}
if h, err = idna.Lookup.ToASCII(h); err != nil {
return err
}
if h != oagc.Host {
res.Status = http.StatusMovedPermanently
scheme := req.Scheme
if oagc.HTTPSEnforced {
scheme = "https"
}
return res.Redirect(fmt.Sprintf(
"%s://%s%s",
scheme,
oagc.Host,
req.Path,
))
}
return next(req, res)
}
}
}