From c5ccbdd22bdbdc43d541b7e7d4ed66ceb559030e Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 20 Oct 2016 16:53:49 -0400 Subject: [PATCH] net/url: reject colon in first segment of relative path in Parse MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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/31582 Reviewed-by: Quentin Smith --- src/net/url/url.go | 13 +++++++++++++ src/net/url/url_test.go | 8 ++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/net/url/url.go b/src/net/url/url.go index 0931296468..42a514bbc1 100644 --- a/src/net/url/url.go +++ b/src/net/url/url.go @@ -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, "//") { diff --git a/src/net/url/url_test.go b/src/net/url/url_test.go index eebc1112c1..6c3bb21d20 100644 --- a/src/net/url/url_test.go +++ b/src/net/url/url_test.go @@ -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) -- 2.48.1