Skip to content

Commit 4c99d66

Browse files
committed
allow router to use request.URL.RawPath
1 parent 975b5c4 commit 4c99d66

4 files changed

Lines changed: 65 additions & 1 deletion

File tree

router.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,13 @@ type Router struct {
159159
// The handler can be used to keep your server from crashing because of
160160
// unrecovered panics.
161161
PanicHandler func(http.ResponseWriter, *http.Request, interface{})
162+
163+
// Go 1.5 introduced the RawPath field in net/url to hold the encoded form of Path.
164+
// The Parse function sets both Path and RawPath in the URL it returns,
165+
// and URL's String method uses RawPath if it is a valid encoding of Path,
166+
// by calling the EncodedPath method.
167+
// This tells the router to use the request.URL.RawPath when parsing the path.
168+
UseRawPath bool
162169
}
163170

164171
// Make sure the Router conforms with the http.Handler interface
@@ -172,6 +179,7 @@ func New() *Router {
172179
RedirectFixedPath: true,
173180
HandleMethodNotAllowed: true,
174181
HandleOPTIONS: true,
182+
UseRawPath: false,
175183
}
176184
}
177185

@@ -339,6 +347,10 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
339347

340348
path := req.URL.Path
341349

350+
if r.UseRawPath {
351+
path = req.URL.RawPath
352+
}
353+
342354
if root := r.trees[req.Method]; root != nil {
343355
if handle, ps, tsr := root.getValue(path); handle != nil {
344356
handle(w, req, ps)

router_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,3 +528,48 @@ func TestRouterServeFiles(t *testing.T) {
528528
t.Error("serving file failed")
529529
}
530530
}
531+
532+
func TestRouterUseRawPathSuccess(t *testing.T) {
533+
router := New()
534+
router.UseRawPath = true
535+
536+
routed := false
537+
router.Handle("GET", "/user/:name", func(w http.ResponseWriter, r *http.Request, ps Params) {
538+
routed = true
539+
want := Params{Param{"name", "abc/123"}}
540+
if !reflect.DeepEqual(ps, want) {
541+
t.Fatalf("wrong wildcard values: want %v, got %v", want, ps)
542+
}
543+
})
544+
545+
w := new(mockResponseWriter)
546+
547+
req, _ := http.NewRequest("GET", "/user/abc%2F123", nil)
548+
router.ServeHTTP(w, req)
549+
550+
if !routed {
551+
t.Fatal("routing failed")
552+
}
553+
}
554+
555+
func TestRouterUseRawPathFailure(t *testing.T) {
556+
router := New()
557+
558+
routed := false
559+
router.Handle("GET", "/user/:name", func(w http.ResponseWriter, r *http.Request, ps Params) {
560+
routed = true
561+
want := Params{Param{"name", "abc/123"}}
562+
if !reflect.DeepEqual(ps, want) {
563+
t.Fatalf("wrong wildcard values: want %v, got %v", want, ps)
564+
}
565+
})
566+
567+
w := new(mockResponseWriter)
568+
569+
req, _ := http.NewRequest("GET", "/user/abc%2F123", nil)
570+
router.ServeHTTP(w, req)
571+
572+
if routed {
573+
t.Fatal("routing unexpectedly succeeded")
574+
}
575+
}

tree.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package httprouter
66

77
import (
8+
"net/url"
89
"strings"
910
"unicode"
1011
"unicode/utf8"
@@ -371,7 +372,12 @@ walk: // outer loop for walking the tree
371372
i := len(p)
372373
p = p[:i+1] // expand slice within preallocated capacity
373374
p[i].Key = n.path[1:]
374-
p[i].Value = path[:end]
375+
376+
value, err := url.PathUnescape(path[:end])
377+
if err != nil {
378+
return
379+
}
380+
p[i].Value = value
375381

376382
// we need to go deeper!
377383
if end < len(path) {

tree_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ func TestTreeWildcard(t *testing.T) {
193193
{"/files/js/inc/framework.js", false, "/files/:dir/*filepath", Params{Param{"dir", "js"}, Param{"filepath", "/inc/framework.js"}}},
194194
{"/info/gordon/public", false, "/info/:user/public", Params{Param{"user", "gordon"}}},
195195
{"/info/gordon/project/go", false, "/info/:user/project/:project", Params{Param{"user", "gordon"}, Param{"project", "go"}}},
196+
{"/search/something%2Fencoded", false, "/search/:query", Params{Param{"query", "something/encoded"}}},
196197
})
197198

198199
checkPriorities(t, tree)

0 commit comments

Comments
 (0)