summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/labstack/echo/middleware/proxy.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/labstack/echo/middleware/proxy.go')
-rw-r--r--vendor/github.com/labstack/echo/middleware/proxy.go122
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())