Permalink
Browse files

net/url: escape URL.RawQuery on Parse if it contains invalid characters

Fixes #22907

Change-Id: I7abcf53ab92768514e13ce2554a6c25dcde8218e
Reviewed-on: https://go-review.googlesource.com/99135
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
  • Loading branch information...
octo authored and bradfitz committed Mar 7, 2018
1 parent 1d1a027 commit 1040626c0ce4a1bc2b312aa0866ffeb2ff53c1ab
Showing with 61 additions and 1 deletion.
  1. +50 −1 src/net/url/url.go
  2. +11 −0 src/net/url/url_test.go
View
@@ -515,7 +515,13 @@ func parse(rawurl string, viaRequest bool) (*URL, error) {
url.ForceQuery = true
rest = rest[:len(rest)-1]
} else {
rest, url.RawQuery = split(rest, "?", true)
var q string
rest, q = split(rest, "?", true)
if validQuery(q) {
url.RawQuery = q
} else {
url.RawQuery = QueryEscape(q)
}
}
if !strings.HasPrefix(rest, "/") {
@@ -1114,3 +1120,46 @@ func validUserinfo(s string) bool {
}
return true
}
// validQuery reports whether s is a valid query string per RFC 3986
// Section 3.4:
// query = *( pchar / "/" / "?" )
// pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
// unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
// sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
// / "*" / "+" / "," / ";" / "="
func validQuery(s string) bool {
pctEnc := 0
for _, r := range s {
if pctEnc > 0 {
if uint32(r) > 255 || !ishex(byte(r)) {
return false
}
pctEnc--
continue
} else if r == '%' {
pctEnc = 2
continue
}
if 'A' <= r && r <= 'Z' {
continue
}
if 'a' <= r && r <= 'z' {
continue
}
if '0' <= r && r <= '9' {
continue
}
switch r {
case '-', '.', '_', '~', '!', '$', '&', '\'', '(', ')',
'*', '+', ',', ';', '=', ':', '@', '/', '?':
continue
default:
return false
}
}
return true
}
View
@@ -590,6 +590,16 @@ var urltests = []URLTest{
},
"mailto:?subject=hi",
},
{
"https://example.com/search?q=Фотки собак&source=lnms",
&URL{
Scheme: "https",
Host: "example.com",
Path: "/search",
RawQuery: "q%3D%D0%A4%D0%BE%D1%82%D0%BA%D0%B8+%D1%81%D0%BE%D0%B1%D0%B0%D0%BA%26source%3Dlnms",
},
"https://example.com/search?q%3D%D0%A4%D0%BE%D1%82%D0%BA%D0%B8+%D1%81%D0%BE%D0%B1%D0%B0%D0%BA%26source%3Dlnms",
},
}
// more useful string for debugging than fmt's struct printer
@@ -1439,6 +1449,7 @@ func TestParseErrors(t *testing.T) {
{"cache_object:foo", true},
{"cache_object:foo/bar", true},
{"cache_object/:foo/bar", false},
{"https://example.com/search?q=Фотки собак&source=lnms", false},
}
for _, tt := range tests {
u, err := Parse(tt.in)

0 comments on commit 1040626

Please sign in to comment.