Commit d6a7dfc1 authored by AJ ONeal's avatar AJ ONeal

add ability to do meta redirects

Proper Location redirects are disadvantageous in some situations.
For example, you may want a developer to know that a resource is available
via https, but you don't want an insecure call to the API to succeed.
parent 3a795de8
......@@ -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
......
......@@ -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 {
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 = `<html>
<head>
<meta http-equiv="refresh" content="0;URL='%s'">
</head>
<body>redirecting...</body>
</html>`
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 := `<meta http-equiv="refresh" content="0;URL='` + test.To + `'">`
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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment