-
Notifications
You must be signed in to change notification settings - Fork 249
/
Copy pathproxy.go
90 lines (77 loc) · 2.02 KB
/
proxy.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
package e2e
import (
"io"
"net/http"
"net/http/httptest"
"sync/atomic"
"testing"
)
// Hop-by-hop headers. These are removed when sent to the backend.
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html
var hopHeaders = []string{
"Connection",
"Keep-Alive",
"Proxy-Authenticate",
"Proxy-Authorization",
"Te", // canonicalized version of "TE"
"Trailers",
"Transfer-Encoding",
"Upgrade",
}
func copyHeader(dst, src http.Header) {
for k, vv := range src {
for _, v := range vv {
dst.Add(k, v)
}
}
}
func delHopHeaders(header http.Header) {
for _, h := range hopHeaders {
header.Del(h)
}
}
type httpProxy struct {
successReqs int64
errorReqs int64
}
func (p *httpProxy) ServeHTTP(wr http.ResponseWriter, req *http.Request) {
if req.URL.Scheme != "http" && req.URL.Scheme != "https" {
msg := "unsupported protocol scheme " + req.URL.Scheme
http.Error(wr, msg, http.StatusBadRequest)
return
}
// We need to explicitly set New Transport with no Proxy to make
// sure ServeHttp only receives the requests once. Otherwise, it
// causes httpProxy to call itself infinitely over and over again.
client := &http.Client{
Transport: &http.Transport{Proxy: nil},
}
// http: Request.RequestURI can't be set in client requests.
// http://golang.org/src/pkg/net/http/client.go
req.RequestURI = ""
delHopHeaders(req.Header)
resp, err := client.Do(req)
if err != nil {
http.Error(wr, "Server Error", http.StatusInternalServerError)
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusOK {
atomic.AddInt64(&p.successReqs, 1)
} else {
atomic.AddInt64(&p.errorReqs, 1)
}
delHopHeaders(resp.Header)
copyHeader(wr.Header(), resp.Header)
wr.WriteHeader(resp.StatusCode)
io.Copy(wr, resp.Body)
}
func (p *httpProxy) isSuccessful(totalReqs int64) bool {
return totalReqs == atomic.LoadInt64(&p.successReqs) && atomic.LoadInt64(&p.errorReqs) == 0
}
func setupProxy(t *testing.T, p *httpProxy) string {
proxysrv := httptest.NewServer(p)
t.Cleanup(func() {
proxysrv.Close()
})
return proxysrv.URL
}