123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081 |
- package engine
- import (
- "net/http"
- "net/url"
- log "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 {
- log.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 {
- log.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
- }
|