mirror of
https://github.com/golang/go
synced 2024-09-25 05:20:13 -06:00
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>
This commit is contained in:
parent
1d1a0277de
commit
1040626c0c
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user