Skip to content

Commit ea5fda2

Browse files
committed
Fix accidental double-escaping when Router.UseEncodedPath() is enabled
1 parent d07530f commit ea5fda2

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
)
@@ -172,19 +173,30 @@ func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
172173
// mux.Vars(request).
173174
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
174175
if !r.skipClean {
175-
path := req.URL.Path
176+
urlPath := req.URL.Path
176177
if r.useEncodedPath {
177-
path = req.URL.EscapedPath()
178+
urlPath = req.URL.EscapedPath()
178179
}
179180
// Clean path to canonical form and redirect.
180-
if p := cleanPath(path); p != path {
181-
181+
if p := cleanPath(urlPath); p != urlPath {
182182
// Added 3 lines (Philip Schlump) - It was dropping the query string and #whatever from query.
183183
// This matches with fix in go 1.2 r.c. 4 for same problem. Go Issue:
184184
// http://code.google.com/p/go/issues/detail?id=5252
185-
url := *req.URL
186-
url.Path = p
187-
p = url.String()
185+
reqURL := *req.URL
186+
187+
if r.useEncodedPath {
188+
pURL, err := url.ParseRequestURI(p)
189+
if err != nil {
190+
// This shouldn't be possible, but fall back to old behaviour if some edge case triggers it
191+
reqURL.Path = p
192+
} else {
193+
reqURL.Path = pURL.Path
194+
reqURL.RawPath = pURL.RawPath
195+
}
196+
} else {
197+
reqURL.Path = p
198+
}
199+
p = reqURL.String()
188200

189201
w.Header().Set("Location", p)
190202
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)