@@ -31,12 +31,12 @@ func (h *HTTPBin) Index(w http.ResponseWriter, r *http.Request) {
3131 return
3232 }
3333 w .Header ().Set ("Content-Security-Policy" , "default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' camo.githubusercontent.com" )
34- writeHTML (w , mustStaticAsset ( "index.html" ) , http .StatusOK )
34+ writeHTML (w , h . indexHTML , http .StatusOK )
3535}
3636
3737// FormsPost renders an HTML form that submits a request to the /post endpoint
3838func (h * HTTPBin ) FormsPost (w http.ResponseWriter , _ * http.Request ) {
39- writeHTML (w , mustStaticAsset ( "forms-post.html" ) , http .StatusOK )
39+ writeHTML (w , h . formsPostHTML , http .StatusOK )
4040}
4141
4242// UTF8 renders an HTML encoding stress test
@@ -161,13 +161,13 @@ type statusCase struct {
161161 body []byte
162162}
163163
164- var (
165- statusRedirectHeaders = & statusCase {
164+ func createSpecialCases ( prefix string ) map [ int ] * statusCase {
165+ statusRedirectHeaders : = & statusCase {
166166 headers : map [string ]string {
167- "Location" : "/redirect/1" ,
167+ "Location" : prefix + "/redirect/1" ,
168168 },
169169 }
170- statusNotAcceptableBody = []byte (`{
170+ statusNotAcceptableBody : = []byte (`{
171171 "message": "Client did not request a supported media type",
172172 "accept": [
173173 "image/webp",
@@ -178,31 +178,31 @@ var (
178178 ]
179179}
180180` )
181- statusHTTP300body = []byte (`<!doctype html>
181+ statusHTTP300body : = []byte ( fmt . Sprintf (`<!doctype html>
182182<head>
183183<title>Multiple Choices</title>
184184</head>
185185<body>
186186<ul>
187- <li><a href="/image/jpeg">/image/jpeg</a></li>
188- <li><a href="/image/png">/image/png</a></li>
189- <li><a href="/image/svg">/image/svg</a></li>
187+ <li><a href="%[1]s /image/jpeg">/image/jpeg</a></li>
188+ <li><a href="%[1]s /image/png">/image/png</a></li>
189+ <li><a href="%[1]s /image/svg">/image/svg</a></li>
190190</body>
191- </html>` )
191+ </html>` , prefix ) )
192192
193- statusHTTP308Body = []byte (`<!doctype html>
193+ statusHTTP308Body : = []byte ( fmt . Sprintf (`<!doctype html>
194194<head>
195195<title>Permanent Redirect</title>
196196</head>
197- <body>Permanently redirected to <a href="/image/jpeg">/image/jpeg</a>
197+ <body>Permanently redirected to <a href="%[1]s /image/jpeg">%[1]s /image/jpeg</a>
198198</body>
199- </html>` )
199+ </html>` , prefix ) )
200200
201- statusSpecialCases = map [int ]* statusCase {
201+ return map [int ]* statusCase {
202202 300 : {
203203 body : statusHTTP300body ,
204204 headers : map [string ]string {
205- "Location" : "/image/jpeg" ,
205+ "Location" : prefix + "/image/jpeg" ,
206206 },
207207 },
208208 301 : statusRedirectHeaders ,
@@ -213,7 +213,7 @@ var (
213213 308 : {
214214 body : statusHTTP308Body ,
215215 headers : map [string ]string {
216- "Location" : "/image/jpeg" ,
216+ "Location" : prefix + "/image/jpeg" ,
217217 },
218218 },
219219 401 : {
@@ -245,7 +245,7 @@ var (
245245 },
246246 },
247247 }
248- )
248+ }
249249
250250// Status responds with the specified status code. TODO: support random choice
251251// from multiple, optionally weighted status codes.
@@ -265,7 +265,7 @@ func (h *HTTPBin) Status(w http.ResponseWriter, r *http.Request) {
265265 // for special cases
266266 w .Header ().Set ("Content-Type" , textContentType )
267267
268- if specialCase , ok := statusSpecialCases [code ]; ok {
268+ if specialCase , ok := h . statusSpecialCases [code ]; ok {
269269 for key , val := range specialCase .headers {
270270 w .Header ().Set (key , val )
271271 }
@@ -326,7 +326,7 @@ func (h *HTTPBin) ResponseHeaders(w http.ResponseWriter, r *http.Request) {
326326 mustMarshalJSON (w , args )
327327}
328328
329- func redirectLocation (r * http.Request , relative bool , n int ) string {
329+ func ( h * HTTPBin ) redirectLocation (r * http.Request , relative bool , n int ) string {
330330 var location string
331331 var path string
332332
@@ -350,7 +350,7 @@ func redirectLocation(r *http.Request, relative bool, n int) string {
350350 return location
351351}
352352
353- func doRedirect (w http.ResponseWriter , r * http.Request , relative bool ) {
353+ func ( h * HTTPBin ) handleRedirect (w http.ResponseWriter , r * http.Request , relative bool ) {
354354 parts := strings .Split (r .URL .Path , "/" )
355355 if len (parts ) != 3 {
356356 writeError (w , http .StatusNotFound , nil )
@@ -365,8 +365,7 @@ func doRedirect(w http.ResponseWriter, r *http.Request, relative bool) {
365365 return
366366 }
367367
368- w .Header ().Set ("Location" , redirectLocation (r , relative , n - 1 ))
369- w .WriteHeader (http .StatusFound )
368+ h .doRedirect (w , h .redirectLocation (r , relative , n - 1 ), http .StatusFound )
370369}
371370
372371// Redirect responds with 302 redirect a given number of times. Defaults to a
@@ -375,17 +374,17 @@ func doRedirect(w http.ResponseWriter, r *http.Request, relative bool) {
375374func (h * HTTPBin ) Redirect (w http.ResponseWriter , r * http.Request ) {
376375 params := r .URL .Query ()
377376 relative := strings .ToLower (params .Get ("absolute" )) != "true"
378- doRedirect (w , r , relative )
377+ h . handleRedirect (w , r , relative )
379378}
380379
381380// RelativeRedirect responds with an HTTP 302 redirect a given number of times
382381func (h * HTTPBin ) RelativeRedirect (w http.ResponseWriter , r * http.Request ) {
383- doRedirect (w , r , true )
382+ h . handleRedirect (w , r , true )
384383}
385384
386385// AbsoluteRedirect responds with an HTTP 302 redirect a given number of times
387386func (h * HTTPBin ) AbsoluteRedirect (w http.ResponseWriter , r * http.Request ) {
388- doRedirect (w , r , false )
387+ h . handleRedirect (w , r , false )
389388}
390389
391390// RedirectTo responds with a redirect to a specific URL with an optional
@@ -423,8 +422,7 @@ func (h *HTTPBin) RedirectTo(w http.ResponseWriter, r *http.Request) {
423422 }
424423 }
425424
426- w .Header ().Set ("Location" , u .String ())
427- w .WriteHeader (statusCode )
425+ h .doRedirect (w , u .String (), statusCode )
428426}
429427
430428// Cookies responds with the cookies in the incoming request
@@ -447,8 +445,7 @@ func (h *HTTPBin) SetCookies(w http.ResponseWriter, r *http.Request) {
447445 HttpOnly : true ,
448446 })
449447 }
450- w .Header ().Set ("Location" , "/cookies" )
451- w .WriteHeader (http .StatusFound )
448+ h .doRedirect (w , "/cookies" , http .StatusFound )
452449}
453450
454451// DeleteCookies deletes cookies specified in query params and redirects to
@@ -464,8 +461,7 @@ func (h *HTTPBin) DeleteCookies(w http.ResponseWriter, r *http.Request) {
464461 Expires : time .Now ().Add (- 1 * 24 * 365 * time .Hour ),
465462 })
466463 }
467- w .Header ().Set ("Location" , "/cookies" )
468- w .WriteHeader (http .StatusFound )
464+ h .doRedirect (w , "/cookies" , http .StatusFound )
469465}
470466
471467// BasicAuth requires basic authentication
@@ -916,18 +912,17 @@ func (h *HTTPBin) Links(w http.ResponseWriter, r *http.Request) {
916912 writeError (w , http .StatusBadRequest , fmt .Errorf ("invalid offset: %w" , err ))
917913 return
918914 }
919- doLinksPage (w , r , n , offset )
915+ h . doLinksPage (w , r , n , offset )
920916 return
921917 }
922918
923919 // Otherwise, redirect from /links/<n> to /links/<n>/0
924920 r .URL .Path = r .URL .Path + "/0"
925- w .Header ().Set ("Location" , r .URL .String ())
926- w .WriteHeader (http .StatusFound )
921+ h .doRedirect (w , r .URL .String (), http .StatusFound )
927922}
928923
929924// doLinksPage renders a page with a series of N links
930- func doLinksPage (w http.ResponseWriter , _ * http.Request , n int , offset int ) {
925+ func ( h * HTTPBin ) doLinksPage (w http.ResponseWriter , _ * http.Request , n int , offset int ) {
931926 w .Header ().Add ("Content-Type" , htmlContentType )
932927 w .WriteHeader (http .StatusOK )
933928
@@ -936,12 +931,23 @@ func doLinksPage(w http.ResponseWriter, _ *http.Request, n int, offset int) {
936931 if i == offset {
937932 fmt .Fprintf (w , "%d " , i )
938933 } else {
939- fmt .Fprintf (w , `<a href="/links/%d/%d">%d</a> ` , n , i , i )
934+ fmt .Fprintf (w , `<a href="%s /links/%d/%d">%d</a> ` , h . prefix , n , i , i )
940935 }
941936 }
942937 w .Write ([]byte ("</body></html>" ))
943938}
944939
940+ // doRedirect set redirect header
941+ func (h * HTTPBin ) doRedirect (w http.ResponseWriter , path string , code int ) {
942+ var sb strings.Builder
943+ if strings .HasPrefix (path , "/" ) {
944+ sb .WriteString (h .prefix )
945+ }
946+ sb .WriteString (path )
947+ w .Header ().Set ("Location" , sb .String ())
948+ w .WriteHeader (code )
949+ }
950+
945951// ImageAccept responds with an appropriate image based on the Accept header
946952func (h * HTTPBin ) ImageAccept (w http.ResponseWriter , r * http.Request ) {
947953 accept := r .Header .Get ("Accept" )
0 commit comments