diff --git a/middleware/redirect/redirect.go b/middleware/redirect/redirect.go index 77689bc0..96ff1d0e 100644 --- a/middleware/redirect/redirect.go +++ b/middleware/redirect/redirect.go @@ -9,12 +9,45 @@ import ( "github.com/mholt/caddy/middleware" ) -// New creates a new redirect middleware. +// New instantiates a new Rewrites middleware. func New(c middleware.Controller) (middleware.Middleware, error) { - var redirects []Redirect + rules, err := parse(c) + if err != nil { + return nil, err + } + + return func(next middleware.Handler) middleware.Handler { + return Redirect{Next: next, Rules: rules} + }, nil +} + +// Redirect is middleware to respond with HTTP redirects +type Redirect struct { + Next middleware.Handler + Rules []Rule +} + +// ServeHTTP implements the middleware.Handler interface. +func (rd Redirect) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) { + for _, rule := range rd.Rules { + if middleware.Path(r.URL.Path).Matches(rule.From) { + if rule.From == "/" { + // Catchall redirect preserves path (TODO: This should be made more consistent...) + http.Redirect(w, r, strings.TrimSuffix(rule.To, "/")+r.URL.Path, rule.Code) + return 0, nil + } + http.Redirect(w, r, rule.To, rule.Code) + return 0, nil + } + } + return rd.Next.ServeHTTP(w, r) +} + +func parse(c middleware.Controller) ([]Rule, error) { + var redirects []Rule for c.Next() { - var rule Redirect + var rule Rule args := c.RemainingArgs() if len(args) == 1 { @@ -28,39 +61,23 @@ func New(c middleware.Controller) (middleware.Middleware, error) { rule.From = args[0] rule.To = args[1] if code, ok := httpRedirs[args[2]]; !ok { - return nil, c.Err("Invalid redirect code '" + c.Val() + "'") + return redirects, c.Err("Invalid redirect code '" + c.Val() + "'") } else { rule.Code = code } redirects = append(redirects, rule) } else { - return nil, c.ArgErr() + return redirects, c.ArgErr() } } - return func(next middleware.Handler) middleware.Handler { - return middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { - for _, rule := range redirects { - if middleware.Path(r.URL.Path).Matches(rule.From) { - if rule.From == "/" { - // Catchall redirect preserves path (TODO: This should be made more consistent...) - http.Redirect(w, r, strings.TrimSuffix(rule.To, "/")+r.URL.Path, rule.Code) - return 0, nil - } - http.Redirect(w, r, rule.To, rule.Code) - return 0, nil - } - } - return next.ServeHTTP(w, r) - }) - }, nil + return redirects, nil } -// redirect describes an HTTP redirect rule. -type Redirect struct { - From string - To string - Code int +// Rule describes an HTTP redirect rule. +type Rule struct { + From, To string + Code int } // httpRedirs is a list of supported HTTP redirect codes.