diff options
Diffstat (limited to 'vendor/github.com/labstack/echo/middleware/proxy.go')
-rw-r--r-- | vendor/github.com/labstack/echo/middleware/proxy.go | 122 |
1 files changed, 99 insertions, 23 deletions
diff --git a/vendor/github.com/labstack/echo/middleware/proxy.go b/vendor/github.com/labstack/echo/middleware/proxy.go index 4f55f39d..ae3ff527 100644 --- a/vendor/github.com/labstack/echo/middleware/proxy.go +++ b/vendor/github.com/labstack/echo/middleware/proxy.go @@ -8,6 +8,9 @@ import ( "net/http" "net/http/httputil" "net/url" + "regexp" + "strings" + "sync" "sync/atomic" "time" @@ -24,32 +27,48 @@ type ( // Balancer defines a load balancing technique. // Required. - // Possible values: - // - RandomBalancer - // - RoundRobinBalancer Balancer ProxyBalancer + + // Rewrite defines URL path rewrite rules. The values captured in asterisk can be + // retrieved by index e.g. $1, $2 and so on. + // Examples: + // "/old": "/new", + // "/api/*": "/$1", + // "/js/*": "/public/javascripts/$1", + // "/users/*/orders/*": "/user/$1/order/$2", + Rewrite map[string]string + + rewriteRegex map[*regexp.Regexp]string } // ProxyTarget defines the upstream target. ProxyTarget struct { - URL *url.URL + Name string + URL *url.URL } - // RandomBalancer implements a random load balancing technique. - RandomBalancer struct { - Targets []*ProxyTarget - random *rand.Rand + // ProxyBalancer defines an interface to implement a load balancing technique. + ProxyBalancer interface { + AddTarget(*ProxyTarget) bool + RemoveTarget(string) bool + Next() *ProxyTarget } - // RoundRobinBalancer implements a round-robin load balancing technique. - RoundRobinBalancer struct { - Targets []*ProxyTarget - i uint32 + commonBalancer struct { + targets []*ProxyTarget + mutex sync.RWMutex } - // ProxyBalancer defines an interface to implement a load balancing technique. - ProxyBalancer interface { - Next() *ProxyTarget + // RandomBalancer implements a random load balancing technique. + randomBalancer struct { + *commonBalancer + random *rand.Rand + } + + // RoundRobinBalancer implements a round-robin load balancing technique. + roundRobinBalancer struct { + *commonBalancer + i uint32 } ) @@ -104,19 +123,61 @@ func proxyRaw(t *ProxyTarget, c echo.Context) http.Handler { }) } +// NewRandomBalancer returns a random proxy balancer. +func NewRandomBalancer(targets []*ProxyTarget) ProxyBalancer { + b := &randomBalancer{commonBalancer: new(commonBalancer)} + b.targets = targets + return b +} + +// NewRoundRobinBalancer returns a round-robin proxy balancer. +func NewRoundRobinBalancer(targets []*ProxyTarget) ProxyBalancer { + b := &roundRobinBalancer{commonBalancer: new(commonBalancer)} + b.targets = targets + return b +} + +// AddTarget adds an upstream target to the list. +func (b *commonBalancer) AddTarget(target *ProxyTarget) bool { + for _, t := range b.targets { + if t.Name == target.Name { + return false + } + } + b.mutex.Lock() + defer b.mutex.Unlock() + b.targets = append(b.targets, target) + return true +} + +// RemoveTarget removes an upstream target from the list. +func (b *commonBalancer) RemoveTarget(name string) bool { + b.mutex.Lock() + defer b.mutex.Unlock() + for i, t := range b.targets { + if t.Name == name { + b.targets = append(b.targets[:i], b.targets[i+1:]...) + return true + } + } + return false +} + // Next randomly returns an upstream target. -func (r *RandomBalancer) Next() *ProxyTarget { - if r.random == nil { - r.random = rand.New(rand.NewSource(int64(time.Now().Nanosecond()))) +func (b *randomBalancer) Next() *ProxyTarget { + if b.random == nil { + b.random = rand.New(rand.NewSource(int64(time.Now().Nanosecond()))) } - return r.Targets[r.random.Intn(len(r.Targets))] + b.mutex.RLock() + defer b.mutex.RUnlock() + return b.targets[b.random.Intn(len(b.targets))] } // Next returns an upstream target using round-robin technique. -func (r *RoundRobinBalancer) Next() *ProxyTarget { - r.i = r.i % uint32(len(r.Targets)) - t := r.Targets[r.i] - atomic.AddUint32(&r.i, 1) +func (b *roundRobinBalancer) Next() *ProxyTarget { + b.i = b.i % uint32(len(b.targets)) + t := b.targets[b.i] + atomic.AddUint32(&b.i, 1) return t } @@ -139,6 +200,13 @@ func ProxyWithConfig(config ProxyConfig) echo.MiddlewareFunc { if config.Balancer == nil { panic("echo: proxy middleware requires balancer") } + config.rewriteRegex = map[*regexp.Regexp]string{} + + // Initialize + for k, v := range config.Rewrite { + k = strings.Replace(k, "*", "(\\S*)", -1) + config.rewriteRegex[regexp.MustCompile(k)] = v + } return func(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) (err error) { @@ -150,6 +218,14 @@ func ProxyWithConfig(config ProxyConfig) echo.MiddlewareFunc { res := c.Response() tgt := config.Balancer.Next() + // Rewrite + for k, v := range config.rewriteRegex { + replacer := captureTokens(k, req.URL.Path) + if replacer != nil { + req.URL.Path = replacer.Replace(v) + } + } + // Fix header if req.Header.Get(echo.HeaderXRealIP) == "" { req.Header.Set(echo.HeaderXRealIP, c.RealIP()) |