-
-
Notifications
You must be signed in to change notification settings - Fork 141
/
Copy pathrevproxy.go
81 lines (72 loc) · 2.38 KB
/
revproxy.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
package engine
import (
"net/http"
"net/url"
"github.com/sirupsen/logrus"
"github.com/xyproto/algernon/utils"
)
// ReverseProxy holds which path prefix (like "/api") should be sent where (like "http://localhost:8080")
type ReverseProxy struct {
PathPrefix string
Endpoint url.URL
}
// ReverseProxyConfig holds several "path prefix --> URL" ReverseProxy structs,
// together with structures that speeds up the prefix matching.
type ReverseProxyConfig struct {
proxyMatcher utils.PrefixMatch
prefix2rproxy map[string]int
ReverseProxies []ReverseProxy
}
// NewReverseProxyConfig creates a new and empty ReverseProxyConfig struct
func NewReverseProxyConfig() *ReverseProxyConfig {
return &ReverseProxyConfig{}
}
// Add can add a ReverseProxy and will also (re-)initialize the internal proxy matcher
func (rc *ReverseProxyConfig) Add(rp *ReverseProxy) {
rc.ReverseProxies = append(rc.ReverseProxies, *rp)
rc.Init()
}
// DoProxyPass tries to proxy the given http.Request to where the ReverseProxy points
func (rp *ReverseProxy) DoProxyPass(req http.Request) (*http.Response, error) {
client := &http.Client{}
endpoint := rp.Endpoint
req.RequestURI = ""
req.URL.Path = req.URL.Path[len(rp.PathPrefix):]
req.URL.Scheme = endpoint.Scheme
req.URL.Host = endpoint.Host
res, err := client.Do(&req)
if err != nil {
logrus.Errorf("reverse proxy error: %v\nPlease check your server config for AddReverseProxy calls.\n", err)
return nil, err
}
return res, nil
}
// Init prepares the proxyMatcher and prefix2rproxy fields according to the ReverseProxy structs
func (rc *ReverseProxyConfig) Init() {
keys := make([]string, 0, len(rc.ReverseProxies))
rc.prefix2rproxy = make(map[string]int)
for i, rp := range rc.ReverseProxies {
keys = append(keys, rp.PathPrefix)
rc.prefix2rproxy[rp.PathPrefix] = i
}
rc.proxyMatcher.Build(keys)
}
// FindMatchingReverseProxy checks if the given URL path should be proxied
func (rc *ReverseProxyConfig) FindMatchingReverseProxy(path string) *ReverseProxy {
matches := rc.proxyMatcher.Match(path)
if len(matches) == 0 {
return nil
}
if len(matches) > 1 {
logrus.Warnf("found more than one reverse proxy for `%s`: %+v. returning the longest", matches, path)
}
var match *ReverseProxy
maxlen := 0
for _, prefix := range matches {
if len(prefix) > maxlen {
maxlen = len(prefix)
match = &rc.ReverseProxies[rc.prefix2rproxy[prefix]]
}
}
return match
}