-
Notifications
You must be signed in to change notification settings - Fork 1
/
server.go
154 lines (127 loc) · 3.85 KB
/
server.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
149
150
151
152
153
154
package gotor
import (
"bytes"
"compress/gzip"
"context"
"crypto/tls"
"net"
"net/http"
"net/http/cgi"
"net/http/fcgi"
"strconv"
"strings"
"sync"
"github.com/caddyserver/certmagic"
)
var NotFound http.HandlerFunc = http.NotFound
func SmartHandler(src http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
rw := newSmartRespWriter(w, r)
src.ServeHTTP(rw, r)
rw.Close()
}
}
func HTTP(addr string, h http.Handler) error {
return http.ListenAndServe(addr, SmartHandler(h))
}
func ServeHTTP(lnr net.Listener, h http.Handler) error {
return http.Serve(lnr, SmartHandler(h))
}
var changeDefaultACMEMtx sync.Mutex
func newTLSConfig(email string, domains []string) (*tls.Config, error) {
changeDefaultACMEMtx.Lock()
certmagic.DefaultACME.Agreed = true
certmagic.DefaultACME.Email = email
cfg := certmagic.NewDefault()
changeDefaultACMEMtx.Unlock()
err := cfg.ManageSync(context.Background(), domains)
if err != nil {
return nil, err
}
tlsConfig := cfg.TLSConfig()
tlsConfig.NextProtos = append([]string{"h2", "http/1.1"}, tlsConfig.NextProtos...)
return tlsConfig, nil
}
func listenTLS(addr string, email string, domains []string) (net.Listener, error) {
tlsConfig, err := newTLSConfig(email, domains)
if err != nil {
return nil, err
}
return tls.Listen("tcp", addr, tlsConfig)
}
func getDomains(domainHandlers HostRouter) []string {
var domains []string
for domain := range domainHandlers {
domains = append(domains, domain)
}
return domains
}
func HTTPS(addr string, email string, domainHandlers HostRouter) error {
lnr, err := listenTLS(addr, email, getDomains(domainHandlers))
if err != nil {
return err
}
return http.Serve(lnr, SmartHandler(domainHandlers))
}
func ServeHTTPS(lnr net.Listener, email string, domainHandlers HostRouter) error {
tlsConfig, err := newTLSConfig(email, getDomains(domainHandlers))
if err != nil {
return err
}
return http.Serve(tls.NewListener(lnr, tlsConfig), SmartHandler(domainHandlers))
}
var http2HTTPSCode = []byte(`<html><head><script type="text/javascript">location.protocol='https:'</script></head><body></body></html>`)
var http2HTTPSCodeLenStr = strconv.Itoa(len(http2HTTPSCode))
func getGzipHTTP2HTTPSCode() []byte {
b := bytes.NewBuffer([]byte{})
z := gzip.NewWriter(b)
z.Write(http2HTTPSCode)
z.Close()
return b.Bytes()
}
var gzipHTTP2HTTPSCode = getGzipHTTP2HTTPSCode()
var gzipHTTP2HTTPSCodeLenStr = strconv.Itoa(len(gzipHTTP2HTTPSCode))
func HTTPSWithHTTP(addr string, email string, domainHandlers HostRouter) error {
domains := getDomains(domainHandlers)
host, port, err := net.SplitHostPort(addr)
if err == nil && port == "443" {
var h80 http.HandlerFunc
if len(domains) == 1 {
h80 = RedirectionSite("https://"+domains[0], http.StatusTemporaryRedirect)
} else {
h80 = func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=UTF-8")
w.Header().Set("Cache-Control", "no-cache")
if strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
w.Header().Set("Content-Encoding", "gzip")
w.Header().Set("Content-Length", gzipHTTP2HTTPSCodeLenStr)
w.WriteHeader(http.StatusOK)
w.Write(gzipHTTP2HTTPSCode)
return
}
w.Header().Set("Content-Length", http2HTTPSCodeLenStr)
w.WriteHeader(http.StatusOK)
w.Write(http2HTTPSCode)
}
}
go http.ListenAndServe(net.JoinHostPort(host, "80"), h80)
}
lnr, err := listenTLS(addr, email, domains)
if err != nil {
return err
}
return http.Serve(lnr, SmartHandler(domainHandlers))
}
func CGI(h http.HandlerFunc) error {
return cgi.Serve(SmartHandler(h))
}
func FastCGI(addr string, h http.HandlerFunc) error {
ln, err := net.Listen("tcp", addr)
if err != nil {
return err
}
return fcgi.Serve(ln, SmartHandler(h))
}
func ServeFastCGI(lnr net.Listener, h http.HandlerFunc) error {
return fcgi.Serve(lnr, SmartHandler(h))
}