Skip to content

Commit

Permalink
Fix accidental double-escaping when Router.UseEncodedPath() is enabled
Browse files Browse the repository at this point in the history
  • Loading branch information
nvx committed Sep 7, 2021
1 parent d07530f commit ea5fda2
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 7 deletions.
26 changes: 19 additions & 7 deletions mux.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"errors"
"fmt"
"net/http"
"net/url"
"path"
"regexp"
)
Expand Down Expand Up @@ -172,19 +173,30 @@ func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
// mux.Vars(request).
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
if !r.skipClean {
path := req.URL.Path
urlPath := req.URL.Path
if r.useEncodedPath {
path = req.URL.EscapedPath()
urlPath = req.URL.EscapedPath()
}
// Clean path to canonical form and redirect.
if p := cleanPath(path); p != path {

if p := cleanPath(urlPath); p != urlPath {
// Added 3 lines (Philip Schlump) - It was dropping the query string and #whatever from query.
// This matches with fix in go 1.2 r.c. 4 for same problem. Go Issue:
// http://code.google.com/p/go/issues/detail?id=5252
url := *req.URL
url.Path = p
p = url.String()
reqURL := *req.URL

if r.useEncodedPath {
pURL, err := url.ParseRequestURI(p)
if err != nil {
// This shouldn't be possible, but fall back to old behaviour if some edge case triggers it
reqURL.Path = p
} else {
reqURL.Path = pURL.Path
reqURL.RawPath = pURL.RawPath
}
} else {
reqURL.Path = p
}
p = reqURL.String()

w.Header().Set("Location", p)
w.WriteHeader(http.StatusMovedPermanently)
Expand Down
18 changes: 18 additions & 0 deletions mux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1574,6 +1574,24 @@ func TestUseEncodedPath(t *testing.T) {
}
}

func TestUseEncodedPathEscaping(t *testing.T) {
r := NewRouter()
r.UseEncodedPath()

req, _ := http.NewRequest("GET", "http://localhost/foo/../bar%25", nil)
res := NewRecorder()
r.ServeHTTP(res, req)

if len(res.HeaderMap["Location"]) != 1 {
t.Fatalf("Expected redirect from path clean")
}

expected := "http://localhost/bar%25"
if res.HeaderMap["Location"][0] != expected {
t.Errorf("Expected redirect location to %s, found %s", expected, res.HeaderMap["Location"][0])
}
}

func TestWalkSingleDepth(t *testing.T) {
r0 := NewRouter()
r1 := NewRouter()
Expand Down

0 comments on commit ea5fda2

Please sign in to comment.