-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathmain.go
124 lines (108 loc) · 3.1 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
120
121
122
123
124
package main
import (
"bytes"
"flag"
"fmt"
"io/ioutil"
"log"
"net"
"net/http"
"net/http/httputil"
"net/url"
"os"
"time"
"github.com/sensiblecodeio/tiny-ssl-reverse-proxy/proxyprotocol"
)
// Version number
const Version = "0.24.0"
var message = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>
Backend Unavailable
</title>
<style>
body {
font-family: fantasy;
text-align: center;
padding-top: 20%;
background-color: #f1f6f8;
}
</style>
</head>
<body>
<h1>503 Backend Unavailable</h1>
<p>Sorry, we‘re having a brief problem. You can retry.</p>
<p>If the problem persists, please get in touch.</p>
</body>
</html>`
type ConnectionErrorHandler struct{ http.RoundTripper }
func (c *ConnectionErrorHandler) RoundTrip(req *http.Request) (*http.Response, error) {
resp, err := c.RoundTripper.RoundTrip(req)
if err != nil {
log.Printf("Error: backend request failed for %v: %v",
req.RemoteAddr, err)
}
if _, ok := err.(*net.OpError); ok {
r := &http.Response{
StatusCode: http.StatusServiceUnavailable,
Body: ioutil.NopCloser(bytes.NewBufferString(message)),
}
return r, nil
}
return resp, err
}
func main() {
var (
listen, cert, key, where string
useTLS, useLogging, behindTCPProxy bool
flushInterval time.Duration
)
flag.StringVar(&listen, "listen", ":443", "Bind address to listen on")
flag.StringVar(&key, "key", "/etc/ssl/private/key.pem", "Path to PEM key")
flag.StringVar(&cert, "cert", "/etc/ssl/private/cert.pem", "Path to PEM certificate")
flag.StringVar(&where, "where", "http://localhost:80", "Place to forward connections to")
flag.BoolVar(&useTLS, "tls", true, "accept HTTPS connections")
flag.BoolVar(&useLogging, "logging", true, "log requests")
flag.BoolVar(&behindTCPProxy, "behind-tcp-proxy", false, "running behind TCP proxy (such as ELB or HAProxy)")
flag.DurationVar(&flushInterval, "flush-interval", 0, "minimum duration between flushes to the client (default: off)")
oldUsage := flag.Usage
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "\n%v version %v\n\n", os.Args[0], Version)
oldUsage()
}
flag.Parse()
url, err := url.Parse(where)
if err != nil {
log.Fatalln("Fatal parsing -where:", err)
}
httpProxy := httputil.NewSingleHostReverseProxy(url)
httpProxy.Transport = &ConnectionErrorHandler{http.DefaultTransport}
httpProxy.FlushInterval = flushInterval
var handler http.Handler
handler = httpProxy
originalHandler := handler
handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/_version" {
w.Header().Add("X-Tiny-SSL-Version", Version)
}
r.Header.Set("X-Forwarded-Proto", "https")
originalHandler.ServeHTTP(w, r)
})
if useLogging {
handler = &LoggingMiddleware{handler}
}
server := &http.Server{Addr: listen, Handler: handler}
switch {
case useTLS && behindTCPProxy:
err = proxyprotocol.BehindTCPProxyListenAndServeTLS(server, cert, key)
case behindTCPProxy:
err = proxyprotocol.BehindTCPProxyListenAndServe(server)
case useTLS:
err = server.ListenAndServeTLS(cert, key)
default:
err = server.ListenAndServe()
}
log.Fatalln(err)
}