This repository has been archived by the owner on Sep 26, 2021. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmain.go
119 lines (111 loc) · 2.83 KB
/
main.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
package main
import (
"encoding/json"
"flag"
"fmt"
"net"
"net/http"
"net/url"
"os"
"strings"
"time"
)
var (
listenAddress string
targetHost string
hostQueryParam string
alwaysHTTPS bool
)
type logEntry struct {
Time time.Time
RemoteIP string
Method string
Host string
RequestURI string
Referrer string
UserAgent string
ForwardedFor string
ForwardedHost string
ForwardedProto string
}
func (req *logEntry) Log() {
b, _ := json.Marshal(req)
fmt.Fprintln(os.Stdout, string(b))
}
type redirectOptions struct {
TargetHost string
HostQueryParam string
AlwaysHTTPS bool
}
func redirectURL(req *http.Request, options *redirectOptions) *url.URL {
// Copy the request URL struct:
targetURL := new(url.URL)
*targetURL = *req.URL
// Remove any existing user:password authentication:
targetURL.User = nil
if options.AlwaysHTTPS {
// Always redirect to HTTPS:
targetURL.Scheme = "https"
} else {
targetURL.Scheme = "http"
}
originalHost := req.Header.Get("X-Forwarded-Host")
if len(originalHost) == 0 {
originalHost = req.Host
}
if len(originalHost) != 0 && len(options.TargetHost) != 0 {
if options.HostQueryParam != "" {
query := targetURL.Query()
query.Set(options.HostQueryParam, originalHost)
targetURL.RawQuery = query.Encode()
}
part := strings.Split(originalHost, ".")[0]
if strings.IndexByte(part, ':') >= 0 {
part, _, _ = net.SplitHostPort(part)
}
targetURL.Host = part + "." + options.TargetHost
} else {
targetURL.Host = originalHost
}
return targetURL
}
func redirectHandler(resp http.ResponseWriter, req *http.Request) {
ip, _, _ := net.SplitHostPort(req.RemoteAddr)
forwardedProto := req.Header.Get("X-Forwarded-Proto")
entry := &logEntry{
Time: time.Now().UTC(),
RemoteIP: ip,
Method: req.Method,
Host: req.Host,
RequestURI: req.URL.RequestURI(),
Referrer: req.Header.Get("Referer"),
UserAgent: req.Header.Get("User-Agent"),
ForwardedFor: req.Header.Get("X-Forwarded-For"),
ForwardedHost: req.Header.Get("X-Forwarded-Host"),
ForwardedProto: req.Header.Get("X-Forwarded-Proto"),
}
defer entry.Log()
options := &redirectOptions{
TargetHost: targetHost,
HostQueryParam: hostQueryParam,
AlwaysHTTPS: alwaysHTTPS || (forwardedProto == "https"),
}
http.Redirect(
resp,
req,
redirectURL(req, options).String(),
http.StatusFound,
)
}
func main() {
flag.StringVar(&listenAddress, "a", ":8080", "TCP listen address")
flag.StringVar(&hostQueryParam, "q", "via", "Original host query parameter")
flag.BoolVar(&alwaysHTTPS, "s", false, "Always redirect using HTTPS")
flag.Parse()
targetHost = flag.Arg(0)
err := http.ListenAndServe(listenAddress, http.HandlerFunc(redirectHandler))
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}