Skip to content

Commit

Permalink
Create redirects for prefix
Browse files Browse the repository at this point in the history
  • Loading branch information
waschik committed May 20, 2023
1 parent 6906ef9 commit 55b2b2a
Show file tree
Hide file tree
Showing 8 changed files with 271 additions and 175 deletions.
5 changes: 5 additions & 0 deletions httpbin/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ func mainImpl(args []string, getEnv func(string) string, getHostname func() (str
httpbin.WithMaxDuration(cfg.MaxDuration),
httpbin.WithObserver(httpbin.StdLogObserver(logger)),
}
if cfg.Prefix != "" {
opts = append(opts, httpbin.WithPrefix(cfg.Prefix))
}
if cfg.RealHostname != "" {
opts = append(opts, httpbin.WithHostname(cfg.RealHostname))
}
Expand Down Expand Up @@ -102,6 +105,7 @@ type config struct {
ListenPort int
MaxBodySize int64
MaxDuration time.Duration
Prefix string
RealHostname string
TLSCertFile string
TLSKeyFile string
Expand Down Expand Up @@ -138,6 +142,7 @@ func loadConfig(args []string, getEnv func(string) string, getHostname func() (s
fs.IntVar(&cfg.ListenPort, "port", defaultListenPort, "Port to listen on")
fs.StringVar(&cfg.rawAllowedRedirectDomains, "allowed-redirect-domains", "", "Comma-separated list of domains the /redirect-to endpoint will allow")
fs.StringVar(&cfg.ListenHost, "host", defaultListenHost, "Host to listen on")
fs.StringVar(&cfg.Prefix, "prefix", "", "Path prefix (empty or start with slash and does not end with slash)")
fs.StringVar(&cfg.TLSCertFile, "https-cert-file", "", "HTTPS Server certificate file")
fs.StringVar(&cfg.TLSKeyFile, "https-key-file", "", "HTTPS Server private key file")

Expand Down
68 changes: 34 additions & 34 deletions httpbin/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ func (h *HTTPBin) Index(w http.ResponseWriter, r *http.Request) {
return
}
w.Header().Set("Content-Security-Policy", "default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' camo.githubusercontent.com")
writeHTML(w, mustStaticAsset("index.html"), http.StatusOK)
writeHTML(w, h.index_html, http.StatusOK)
}

// FormsPost renders an HTML form that submits a request to the /post endpoint
func (h *HTTPBin) FormsPost(w http.ResponseWriter, r *http.Request) {
writeHTML(w, mustStaticAsset("forms-post.html"), http.StatusOK)
writeHTML(w, h.forms_post_html, http.StatusOK)
}

// UTF8 renders an HTML encoding stress test
Expand Down Expand Up @@ -154,13 +154,13 @@ type statusCase struct {
body []byte
}

var (
statusRedirectHeaders = &statusCase{
func createSpecialCases(prefix string) map[int]*statusCase {
statusRedirectHeaders := &statusCase{
headers: map[string]string{
"Location": "/redirect/1",
"Location": prefix + "/redirect/1",
},
}
statusNotAcceptableBody = []byte(`{
statusNotAcceptableBody := []byte(`{
"message": "Client did not request a supported media type",
"accept": [
"image/webp",
Expand All @@ -171,31 +171,31 @@ var (
]
}
`)
statusHTTP300body = []byte(`<!doctype html>
statusHTTP300body := []byte(fmt.Sprintf(`<!doctype html>
<head>
<title>Multiple Choices</title>
</head>
<body>
<ul>
<li><a href="/image/jpeg">/image/jpeg</a></li>
<li><a href="/image/png">/image/png</a></li>
<li><a href="/image/svg">/image/svg</a></li>
<li><a href="%[1]s/image/jpeg">/image/jpeg</a></li>
<li><a href="%[1]s/image/png">/image/png</a></li>
<li><a href="%[1]s/image/svg">/image/svg</a></li>
</body>
</html>`)
</html>`, prefix))

statusHTTP308Body = []byte(`<!doctype html>
statusHTTP308Body := []byte(fmt.Sprintf(`<!doctype html>
<head>
<title>Permanent Redirect</title>
</head>
<body>Permanently redirected to <a href="/image/jpeg">/image/jpeg</a>
<body>Permanently redirected to <a href="%[1]s/image/jpeg">%[1]s/image/jpeg</a>
</body>
</html>`)
</html>`, prefix))

statusSpecialCases = map[int]*statusCase{
return map[int]*statusCase{
300: {
body: statusHTTP300body,
headers: map[string]string{
"Location": "/image/jpeg",
"Location": prefix + "/image/jpeg",
},
},
301: statusRedirectHeaders,
Expand All @@ -206,7 +206,7 @@ var (
308: {
body: statusHTTP308Body,
headers: map[string]string{
"Location": "/image/jpeg",
"Location": prefix + "/image/jpeg",
},
},
401: {
Expand Down Expand Up @@ -238,7 +238,7 @@ var (
},
},
}
)
}

// Status responds with the specified status code. TODO: support random choice
// from multiple, optionally weighted status codes.
Expand All @@ -254,7 +254,7 @@ func (h *HTTPBin) Status(w http.ResponseWriter, r *http.Request) {
return
}

if specialCase, ok := statusSpecialCases[code]; ok {
if specialCase, ok := h.specialCases[code]; ok {
for key, val := range specialCase.headers {
w.Header().Set(key, val)
}
Expand Down Expand Up @@ -315,16 +315,16 @@ func (h *HTTPBin) ResponseHeaders(w http.ResponseWriter, r *http.Request) {
mustMarshalJSON(w, args)
}

func redirectLocation(r *http.Request, relative bool, n int) string {
func (h *HTTPBin) redirectLocation(r *http.Request, relative bool, n int) string {
var location string
var path string

if n < 1 {
path = "/get"
path = h.prefix + "/get"
} else if relative {
path = fmt.Sprintf("/relative-redirect/%d", n)
path = fmt.Sprintf("%s/relative-redirect/%d", h.prefix, n)
} else {
path = fmt.Sprintf("/absolute-redirect/%d", n)
path = fmt.Sprintf("%s/absolute-redirect/%d", h.prefix, n)
}

if relative {
Expand All @@ -339,7 +339,7 @@ func redirectLocation(r *http.Request, relative bool, n int) string {
return location
}

func doRedirect(w http.ResponseWriter, r *http.Request, relative bool) {
func (h *HTTPBin) doRedirect(w http.ResponseWriter, r *http.Request, relative bool) {
parts := strings.Split(r.URL.Path, "/")
if len(parts) != 3 {
http.Error(w, "Not found", http.StatusNotFound)
Expand All @@ -351,7 +351,7 @@ func doRedirect(w http.ResponseWriter, r *http.Request, relative bool) {
return
}

w.Header().Set("Location", redirectLocation(r, relative, n-1))
w.Header().Set("Location", h.redirectLocation(r, relative, n-1))
w.WriteHeader(http.StatusFound)
}

Expand All @@ -361,17 +361,17 @@ func doRedirect(w http.ResponseWriter, r *http.Request, relative bool) {
func (h *HTTPBin) Redirect(w http.ResponseWriter, r *http.Request) {
params := r.URL.Query()
relative := strings.ToLower(params.Get("absolute")) != "true"
doRedirect(w, r, relative)
h.doRedirect(w, r, relative)
}

// RelativeRedirect responds with an HTTP 302 redirect a given number of times
func (h *HTTPBin) RelativeRedirect(w http.ResponseWriter, r *http.Request) {
doRedirect(w, r, true)
h.doRedirect(w, r, true)
}

// AbsoluteRedirect responds with an HTTP 302 redirect a given number of times
func (h *HTTPBin) AbsoluteRedirect(w http.ResponseWriter, r *http.Request) {
doRedirect(w, r, false)
h.doRedirect(w, r, false)
}

// RedirectTo responds with a redirect to a specific URL with an optional
Expand Down Expand Up @@ -442,7 +442,7 @@ func (h *HTTPBin) SetCookies(w http.ResponseWriter, r *http.Request) {
HttpOnly: true,
})
}
w.Header().Set("Location", "/cookies")
w.Header().Set("Location", h.prefix+"/cookies")
w.WriteHeader(http.StatusFound)
}

Expand All @@ -459,7 +459,7 @@ func (h *HTTPBin) DeleteCookies(w http.ResponseWriter, r *http.Request) {
Expires: time.Now().Add(-1 * 24 * 365 * time.Hour),
})
}
w.Header().Set("Location", "/cookies")
w.Header().Set("Location", h.prefix+"/cookies")
w.WriteHeader(http.StatusFound)
}

Expand Down Expand Up @@ -874,18 +874,18 @@ func (h *HTTPBin) Links(w http.ResponseWriter, r *http.Request) {
if err != nil {
http.Error(w, "Invalid offset", http.StatusBadRequest)
}
doLinksPage(w, r, n, offset)
h.doLinksPage(w, r, n, offset)
return
}

// Otherwise, redirect from /links/<n> to /links/<n>/0
r.URL.Path = r.URL.Path + "/0"
r.URL.Path = h.prefix + r.URL.Path + "/0"
w.Header().Set("Location", r.URL.String())
w.WriteHeader(http.StatusFound)
}

// doLinksPage renders a page with a series of N links
func doLinksPage(w http.ResponseWriter, r *http.Request, n int, offset int) {
func (h *HTTPBin) doLinksPage(w http.ResponseWriter, r *http.Request, n int, offset int) {
w.Header().Add("Content-Type", htmlContentType)
w.WriteHeader(http.StatusOK)

Expand All @@ -894,7 +894,7 @@ func doLinksPage(w http.ResponseWriter, r *http.Request, n int, offset int) {
if i == offset {
fmt.Fprintf(w, "%d ", i)
} else {
fmt.Fprintf(w, `<a href="/links/%d/%d">%d</a> `, n, i, i)
fmt.Fprintf(w, `<a href="%s/links/%d/%d">%d</a> `, h.prefix, n, i, i)
}
}
w.Write([]byte("</body></html>"))
Expand Down
Loading

0 comments on commit 55b2b2a

Please sign in to comment.