Commit c5ccbdd2 authored by Russ Cox's avatar Russ Cox

net/url: reject colon in first segment of relative path in Parse

RFC 3986 §3.3 disallows relative URL paths in which the first segment
contains a colon, presumably to avoid confusion with scheme:foo syntax,
which is exactly what happened in #16822.

Fixes #16822.

Change-Id: Ie4449e1dd21c5e56e3b126e086c3a0b05da7ff24
Reviewed-on: https://go-review.googlesource.com/31582Reviewed-by: 's avatarQuentin Smith <quentin@golang.org>
parent afe675c2
......@@ -503,6 +503,19 @@ func parse(rawurl string, viaRequest bool) (*URL, error) {
if viaRequest {
return nil, errors.New("invalid URI for request")
}
// Avoid confusion with malformed schemes, like cache_object:foo/bar.
// See golang.org/issue/16822.
//
// RFC 3986, §3.3:
// In addition, a URI reference (Section 4.1) may be a relative-path reference,
// in which case the first path segment cannot contain a colon (":") character.
colon := strings.Index(rest, ":")
slash := strings.Index(rest, "/")
if colon >= 0 && (slash < 0 || colon < slash) {
// First path segment has colon. Not allowed in relative URL.
return nil, errors.New("first path segment in URL cannot contain colon")
}
}
if (url.Scheme != "" || !viaRequest && !strings.HasPrefix(rest, "///")) && strings.HasPrefix(rest, "//") {
......
......@@ -1385,7 +1385,7 @@ func TestParseFailure(t *testing.T) {
}
}
func TestParseAuthority(t *testing.T) {
func TestParseErrors(t *testing.T) {
tests := []struct {
in string
wantErr bool
......@@ -1405,9 +1405,13 @@ func TestParseAuthority(t *testing.T) {
{"http://%41:8080/", true}, // not allowed: % encoding only for non-ASCII
{"mysql://x@y(z:123)/foo", false}, // golang.org/issue/12023
{"mysql://x@y(1.2.3.4:123)/foo", false},
{"mysql://x@y([2001:db8::1]:123)/foo", false},
{"http://[]%20%48%54%54%50%2f%31%2e%31%0a%4d%79%48%65%61%64%65%72%3a%20%31%32%33%0a%0a/", true}, // golang.org/issue/11208
{"http://a b.com/", true}, // no space in host name please
{"cache_object://foo", true}, // scheme cannot have _, relative path cannot have : in first segment
{"cache_object:foo", true},
{"cache_object:foo/bar", true},
{"cache_object/:foo/bar", false},
}
for _, tt := range tests {
u, err := Parse(tt.in)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment