From d8e7adcdb471e4ef5465e7f9b8fbbcdcd20b5160 Mon Sep 17 00:00:00 2001 From: Matthew Holt Date: Sat, 11 Apr 2015 17:24:47 -0600 Subject: [PATCH] Refactored proxy middleware --- middleware/proxy/proxy.go | 112 ++++++++++++++++------------ middleware/websockets/websockets.go | 2 +- 2 files changed, 64 insertions(+), 50 deletions(-) diff --git a/middleware/proxy/proxy.go b/middleware/proxy/proxy.go index 4e58361ea..5c1c56fd3 100644 --- a/middleware/proxy/proxy.go +++ b/middleware/proxy/proxy.go @@ -2,7 +2,6 @@ package proxy import ( - "log" "net/http" "net/http/httputil" "net/url" @@ -11,60 +10,75 @@ import ( "github.com/mholt/caddy/middleware" ) +// Proxy represents a middleware instance that can proxy requests. +type Proxy struct { + Next middleware.Handler + Rules []Rule +} + +// ServeHTTP satisfies the middleware.Handler interface. +func (p Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) { + + for _, rule := range p.Rules { + if middleware.Path(r.URL.Path).Matches(rule.From) { + var base string + + if strings.HasPrefix(rule.To, "http") { // includes https + // destination includes a scheme! no need to guess + base = rule.To + } else { + // no scheme specified; assume same as request + var scheme string + if r.TLS == nil { + scheme = "http" + } else { + scheme = "https" + } + base = scheme + "://" + rule.To + } + + baseUrl, err := url.Parse(base) + if err != nil { + return http.StatusInternalServerError, err + } + r.Host = baseUrl.Host + + // TODO: Construct this before; not during every request, if possible + proxy := httputil.NewSingleHostReverseProxy(baseUrl) + proxy.ServeHTTP(w, r) + return 0, nil + } + } + + return p.Next.ServeHTTP(w, r) +} + // New creates a new instance of proxy middleware. func New(c middleware.Controller) (middleware.Middleware, error) { - var rules []proxyRule - - for c.Next() { - rule := proxyRule{} - - if !c.Args(&rule.from, &rule.to) { - return nil, c.ArgErr() - } - - rules = append(rules, rule) + rules, err := parse(c) + if err != nil { + return nil, err } return func(next middleware.Handler) middleware.Handler { - return middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { - - for _, rule := range rules { - if middleware.Path(r.URL.Path).Matches(rule.from) { - var base string - - if strings.HasPrefix(rule.to, "http") { // includes https - // destination includes a scheme! no need to guess - base = rule.to - } else { - // no scheme specified; assume same as request - var scheme string - if r.TLS == nil { - scheme = "http" - } else { - scheme = "https" - } - base = scheme + "://" + rule.to - } - - baseUrl, err := url.Parse(base) - if err != nil { - log.Fatal(err) - } - r.Host = baseUrl.Host - - // TODO: Construct this before; not during every request, if possible - proxy := httputil.NewSingleHostReverseProxy(baseUrl) - proxy.ServeHTTP(w, r) - return 0, nil - } - } - - return next.ServeHTTP(w, r) - }) + return Proxy{Next: next, Rules: rules} }, nil } -type proxyRule struct { - from string - to string +func parse(c middleware.Controller) ([]Rule, error) { + var rules []Rule + + for c.Next() { + var rule Rule + if !c.Args(&rule.From, &rule.To) { + return rules, c.ArgErr() + } + rules = append(rules, rule) + } + + return rules, nil +} + +type Rule struct { + From, To string } diff --git a/middleware/websockets/websockets.go b/middleware/websockets/websockets.go index ff70607c7..c1f235de4 100644 --- a/middleware/websockets/websockets.go +++ b/middleware/websockets/websockets.go @@ -108,7 +108,7 @@ func New(c middleware.Controller) (middleware.Middleware, error) { Path: path, Command: cmd, Arguments: args, - Respawn: respawn, + Respawn: respawn, // TODO: This isn't used currently }) }