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

allow router to use request.URL.RawPath #209

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions router.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,13 @@ type Router struct {
// The handler can be used to keep your server from crashing because of
// unrecovered panics.
PanicHandler func(http.ResponseWriter, *http.Request, interface{})

// Go 1.5 introduced the RawPath field in net/url to hold the encoded form of Path.
// The Parse function sets both Path and RawPath in the URL it returns,
// and URL's String method uses RawPath if it is a valid encoding of Path,
// by calling the EncodedPath method.
// This tells the router to use the request.URL.RawPath when parsing the path.
UseRawPath bool
}

// Make sure the Router conforms with the http.Handler interface
Expand All @@ -216,6 +223,7 @@ func New() *Router {
RedirectFixedPath: true,
HandleMethodNotAllowed: true,
HandleOPTIONS: true,
UseRawPath: false,
}
}

Expand Down Expand Up @@ -465,6 +473,10 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {

path := req.URL.Path

if r.UseRawPath && req.URL.RawPath != "" {
path = req.URL.RawPath
}

if root := r.trees[req.Method]; root != nil {
if handle, ps, tsr := root.getValue(path, r.getParams); handle != nil {
if ps != nil {
Expand Down
45 changes: 45 additions & 0 deletions router_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -697,3 +697,48 @@ func TestRouterServeFiles(t *testing.T) {
t.Error("serving file failed")
}
}

func TestRouterUseRawPathSuccess(t *testing.T) {
router := New()
router.UseRawPath = true

routed := false
router.Handle("GET", "/user/:name", func(w http.ResponseWriter, r *http.Request, ps Params) {
routed = true
want := Params{Param{"name", "abc/123"}}
if !reflect.DeepEqual(ps, want) {
t.Fatalf("wrong wildcard values: want %v, got %v", want, ps)
}
})

w := new(mockResponseWriter)

req, _ := http.NewRequest("GET", "/user/abc%2F123", nil)
router.ServeHTTP(w, req)

if !routed {
t.Fatal("routing failed")
}
}

func TestRouterUseRawPathFailure(t *testing.T) {
router := New()

routed := false
router.Handle("GET", "/user/:name", func(w http.ResponseWriter, r *http.Request, ps Params) {
routed = true
want := Params{Param{"name", "abc/123"}}
if !reflect.DeepEqual(ps, want) {
t.Fatalf("wrong wildcard values: want %v, got %v", want, ps)
}
})

w := new(mockResponseWriter)

req, _ := http.NewRequest("GET", "/user/abc%2F123", nil)
router.ServeHTTP(w, req)

if routed {
t.Fatal("routing unexpectedly succeeded")
}
}
12 changes: 10 additions & 2 deletions tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package httprouter

import (
"net/url"
"strings"
"unicode"
"unicode/utf8"
Expand Down Expand Up @@ -368,9 +369,16 @@ walk: // Outer loop for walking the tree
// Expand slice within preallocated capacity
i := len(*ps)
*ps = (*ps)[:i+1]

key := n.path[1:]
value, err := url.PathUnescape(path[:end])
if err != nil {
value = path[:end]
}

(*ps)[i] = Param{
Key: n.path[1:],
Value: path[:end],
Key: key,
Value: value,
}
}

Expand Down
2 changes: 2 additions & 0 deletions tree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ func TestTreeWildcard(t *testing.T) {
{"/files/js/inc/framework.js", false, "/files/:dir/*filepath", Params{Param{"dir", "js"}, Param{"filepath", "/inc/framework.js"}}},
{"/info/gordon/public", false, "/info/:user/public", Params{Param{"user", "gordon"}}},
{"/info/gordon/project/go", false, "/info/:user/project/:project", Params{Param{"user", "gordon"}, Param{"project", "go"}}},
{"/search/something%2Fencoded", false, "/search/:query", Params{Param{"query", "something/encoded"}}},
{"/search/invalid%encoding", false, "/search/:query", Params{Param{"query", "invalid%encoding"}}},
})

checkPriorities(t, tree)
Expand Down