diff --git a/config/setup/redir.go b/config/setup/redir.go index 23a23eb1..b83a8e47 100644 --- a/config/setup/redir.go +++ b/config/setup/redir.go @@ -26,17 +26,21 @@ func redirParse(c *Controller) ([]redirect.Rule, error) { var rule redirect.Rule args := c.RemainingArgs() + // Always set the default Code, then overwrite + rule.Code = http.StatusMovedPermanently + switch len(args) { case 1: // To specified rule.From = "/" rule.To = args[0] - rule.Code = http.StatusMovedPermanently case 2: // To and Code specified rule.From = "/" rule.To = args[0] - if code, ok := httpRedirs[args[1]]; !ok { + if "meta" == args[1] { + rule.Meta = true + } else if code, ok := httpRedirs[args[1]]; !ok { return redirects, c.Err("Invalid redirect code '" + args[1] + "'") } else { rule.Code = code @@ -45,7 +49,9 @@ func redirParse(c *Controller) ([]redirect.Rule, error) { // From, To, and Code specified rule.From = args[0] rule.To = args[1] - if code, ok := httpRedirs[args[2]]; !ok { + if "meta" == args[2] { + rule.Meta = true + } else if code, ok := httpRedirs[args[2]]; !ok { return redirects, c.Err("Invalid redirect code '" + args[2] + "'") } else { rule.Code = code diff --git a/middleware/redirect/redirect.go b/middleware/redirect/redirect.go index c480de5e..f9a1812b 100644 --- a/middleware/redirect/redirect.go +++ b/middleware/redirect/redirect.go @@ -3,6 +3,8 @@ package redirect import ( + "fmt" + "html" "net/http" "strings" @@ -20,11 +22,20 @@ func (rd Redirect) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error for _, rule := range rd.Rules { if rule.From == "/" { // Catchall redirect preserves path (TODO: Standardize/formalize this behavior) - http.Redirect(w, r, strings.TrimSuffix(rule.To, "/")+r.URL.Path, rule.Code) + newPath := strings.TrimSuffix(rule.To, "/") + r.URL.Path + if rule.Meta { + fmt.Fprintf(w, metaRedir, html.EscapeString(newPath)) + } else { + http.Redirect(w, r, newPath, rule.Code) + } return 0, nil } if r.URL.Path == rule.From { - http.Redirect(w, r, rule.To, rule.Code) + if rule.Meta { + fmt.Fprintf(w, metaRedir, html.EscapeString(rule.To)) + } else { + http.Redirect(w, r, rule.To, rule.Code) + } return 0, nil } } @@ -35,4 +46,12 @@ func (rd Redirect) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error type Rule struct { From, To string Code int + Meta bool } + +var metaRedir = ` + + + +redirecting... +` diff --git a/middleware/redirect/redirect_test.go b/middleware/redirect/redirect_test.go index af6bb538..662010f1 100644 --- a/middleware/redirect/redirect_test.go +++ b/middleware/redirect/redirect_test.go @@ -1,6 +1,8 @@ package redirect import ( + "bytes" + "io/ioutil" "net/http" "net/http/httptest" "testing" @@ -8,6 +10,35 @@ import ( "github.com/mholt/caddy/middleware" ) +func TestMetaRedirect(t *testing.T) { + re := Redirect{ + Rules: []Rule{ + {From: "/", Meta: true, To: "https://example.com/"}, + {From: "/whatever", Meta: true, To: "https://example.com/whatever"}, + }, + } + + for i, test := range re.Rules { + req, err := http.NewRequest("GET", test.From, nil) + if err != nil { + t.Fatalf("Test %d: Could not create HTTP request: %v", i, err) + } + + rec := httptest.NewRecorder() + re.ServeHTTP(rec, req) + + body, err := ioutil.ReadAll(rec.Body) + if err != nil { + t.Fatalf("Test %d: Could not read HTTP response body: %v", i, err) + } + expectedSnippet := `` + if !bytes.Contains(body, []byte(expectedSnippet)) { + t.Errorf("Test %d: Expected Response Body to contain %q but was %q", + i, expectedSnippet, body) + } + } +} + func TestRedirect(t *testing.T) { for i, test := range []struct { from string