Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

knob to set clean url with a 308 redirect #465

Closed
wants to merge 2 commits into from
Closed

knob to set clean url with a 308 redirect #465

wants to merge 2 commits into from

Conversation

toravir
Copy link

@toravir toravir commented Apr 3, 2019

fixes issue described in #420

I am a little unsure if there should be a check to see if the method is non-GET and then only do this or is it good to do this for everything (current pr) - please comment.

@toravir
Copy link
Author

toravir commented Apr 3, 2019

Just noticed that #463 conflicts with this PR.. will rework this PR if the other one is merged first.

Copy link
Contributor

@elithrar elithrar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not clear that this is a useful addition for most users. Those who really desire to use 308's can wrap the ResponseWriter with middleware.

@@ -92,6 +92,11 @@ type routeConf struct {
buildScheme string

buildVarsFunc BuildVarsFunc

// If true, if the url is cleaned, will send
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RE: this -

  • How do you know the URL is cleaned? (note: uppercase "URL")
  • Why is this useful to a user to enable, if they haven't read this PR or the history?

@@ -363,6 +372,15 @@ func (r *Router) Walk(walkFn WalkFunc) error {
return r.walk(walkFn, []*Route{})
}

// CleanRedirectUse308 defines the redirect code following a path cleaning. The
// default value is false - meaning it will use 301 (Moved Permanently) code.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a user, what would a 308 get me over a 301?

(Note: I know, but someone trying to learn mux will not)

@elithrar elithrar self-assigned this Apr 3, 2019
@toravir
Copy link
Author

toravir commented Apr 3, 2019

It's not clear that this is a useful addition for most users. Those who really desire to use 308's can wrap the ResponseWriter with middleware.

Middleware is simple for a blind (301->308) - but it becomes complicated if it needs to be done when URL cleaning was done.. wrote up one: https://gist.github.com/toravir/8c9bab5756f33963fa745d977d85f94e - but still it does not handle/relay other status codes - then there is the 'multiple response.WriteHeader calls' error if middleware tries to overwrite the status. Agree, most users will not need this - but few who want to do the 308, this knob provides a simple way to do. Will address comments about the docs later in the day..

@elithrar
Copy link
Contributor

elithrar commented Apr 5, 2019

You need to handle the 'wrote header' case - the standard library implementations of http.ResponseWriter often have a wroteHeader bool field: https://golang.org/src/net/http/server.go

Working example that rewrites 301/302 and wraps the entire router:

package main

import (
	"fmt"
	"log"
	"net/http"

	"github.com/gorilla/mux"
)

type statusResponseWriter struct {
	http.ResponseWriter
	wroteHeader bool
}

func (srw *statusResponseWriter) WriteHeader(code int) {
	if !srw.wroteHeader {
		switch code {
		case 301:
			code = 308
		case 302:
			code = 307
		}

		srw.wroteHeader = true
		srw.ResponseWriter.WriteHeader(code)
	}
}

func statusRewriter(next http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		wrappedWriter := &statusResponseWriter{ResponseWriter: w}
		next.ServeHTTP(wrappedWriter, r)
	}

	return http.HandlerFunc(fn)
}

func handler(w http.ResponseWriter, r *http.Request) {
	http.Redirect(w, r, "/target", 302)
}

func target(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, "hello")
}

func main() {
	r := mux.NewRouter()

	r.HandleFunc("/", handler)

	log.Fatal(
		http.ListenAndServe("localhost:8000",
			statusRewriter(r),
		))
}

@toravir
Copy link
Author

toravir commented Apr 5, 2019

Ah.. translate the status at the first writing itself.. yes that does the work. Earlier, I was only thinking of re-writing the status after the actual handler completes.

This knob isn't useful - unless in a corner case where one wants a behavior of using 308 ONLY for the case of URL cleaning is done. In my current project, i don't have any handlers returning 301 - so i can use the blanket middleware to do the job - since 301 is generated only when url is cleaned.

Thx. Will close the PR in a day.

@elithrar
Copy link
Contributor

elithrar commented Apr 5, 2019 via email

@toravir toravir closed this Apr 5, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants