Skip to content

Commit 0228de0

Browse files
committed
Fix accidental double-escaping when Router.UseEncodedPath() is enabled
1 parent 91708ff commit 0228de0

File tree

2 files changed

+37
-7
lines changed

2 files changed

+37
-7
lines changed

mux.go

+19-7
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"errors"
1010
"fmt"
1111
"net/http"
12+
"net/url"
1213
"path"
1314
"regexp"
1415
)
@@ -174,19 +175,30 @@ func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
174175
// mux.Vars(request).
175176
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
176177
if !r.skipClean {
177-
path := req.URL.Path
178+
urlPath := req.URL.Path
178179
if r.useEncodedPath {
179-
path = req.URL.EscapedPath()
180+
urlPath = req.URL.EscapedPath()
180181
}
181182
// Clean path to canonical form and redirect.
182-
if p := cleanPath(path); p != path {
183-
183+
if p := cleanPath(urlPath); p != urlPath {
184184
// Added 3 lines (Philip Schlump) - It was dropping the query string and #whatever from query.
185185
// This matches with fix in go 1.2 r.c. 4 for same problem. Go Issue:
186186
// http://code.google.com/p/go/issues/detail?id=5252
187-
url := *req.URL
188-
url.Path = p
189-
p = url.String()
187+
reqURL := *req.URL
188+
189+
if r.useEncodedPath {
190+
pURL, err := url.ParseRequestURI(p)
191+
if err != nil {
192+
// This shouldn't be possible, but fall back to old behaviour if some edge case triggers it
193+
reqURL.Path = p
194+
} else {
195+
reqURL.Path = pURL.Path
196+
reqURL.RawPath = pURL.RawPath
197+
}
198+
} else {
199+
reqURL.Path = p
200+
}
201+
p = reqURL.String()
190202

191203
w.Header().Set("Location", p)
192204
w.WriteHeader(http.StatusMovedPermanently)

mux_test.go

+18
Original file line numberDiff line numberDiff line change
@@ -1574,6 +1574,24 @@ func TestUseEncodedPath(t *testing.T) {
15741574
}
15751575
}
15761576

1577+
func TestUseEncodedPathEscaping(t *testing.T) {
1578+
r := NewRouter()
1579+
r.UseEncodedPath()
1580+
1581+
req, _ := http.NewRequest("GET", "http://localhost/foo/../bar%25", nil)
1582+
res := NewRecorder()
1583+
r.ServeHTTP(res, req)
1584+
1585+
if len(res.HeaderMap["Location"]) != 1 {
1586+
t.Fatalf("Expected redirect from path clean")
1587+
}
1588+
1589+
expected := "http://localhost/bar%25"
1590+
if res.HeaderMap["Location"][0] != expected {
1591+
t.Errorf("Expected redirect location to %s, found %s", expected, res.HeaderMap["Location"][0])
1592+
}
1593+
}
1594+
15771595
func TestWalkSingleDepth(t *testing.T) {
15781596
r0 := NewRouter()
15791597
r1 := NewRouter()

0 commit comments

Comments
 (0)