Skip to content

Commit 821db7b

Browse files
neildpull[bot]
authored andcommitted
net/url: consider an empty base Path as equivalent to / in JoinPath
A Path that starts with / is absolute. A Path that starts with any other character is relative. The meaning of a Path of "" is not defined, but RequestURI converts a "" Path to "/" and an empty Path may represent a URL with just a hostname and no trailing / such as "http://localhost". Handle empty paths in the base URL of JoinPath consistently with RequestURI, so that joining to an empty base produces an absolute path rather than a relative one. u, _ := url.Parse("http://localhost") u = u.JoinPath("x") fmt.Println(u.Path) // "/x", not "x" Fixes #58605 Change-Id: Iacced9c173b0aa693800dd01caf774f3f9a66d56 Reviewed-on: https://go-review.googlesource.com/c/go/+/469935 Reviewed-by: Jonathan Amsterdam <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent ff9bbb6 commit 821db7b

File tree

2 files changed

+114
-73
lines changed

2 files changed

+114
-73
lines changed

src/net/url/url.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1200,7 +1200,12 @@ func (u *URL) UnmarshalBinary(text []byte) error {
12001200
func (u *URL) JoinPath(elem ...string) *URL {
12011201
elem = append([]string{u.EscapedPath()}, elem...)
12021202
var p string
1203-
if !strings.HasPrefix(elem[0], "/") {
1203+
if elem[0] == "" {
1204+
// RequestURI converts an empty Path to /, so do the same
1205+
// here for consistency. See #58605.
1206+
elem[0] = "/"
1207+
p = path.Join(elem...)
1208+
} else if !strings.HasPrefix(elem[0], "/") {
12041209
// Return a relative path if u is relative,
12051210
// but ensure that it contains no ../ elements.
12061211
elem[0] = "/" + elem[0]

src/net/url/url_test.go

Lines changed: 108 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -2066,128 +2066,155 @@ func BenchmarkPathUnescape(b *testing.B) {
20662066

20672067
func TestJoinPath(t *testing.T) {
20682068
tests := []struct {
2069-
base string
2070-
elem []string
2071-
out string
2069+
base string
2070+
elem []string
2071+
out string
2072+
wantPath string
2073+
wantRawPath string
20722074
}{
20732075
{
2074-
base: "https://go.googlesource.com",
2075-
elem: []string{"go"},
2076-
out: "https://go.googlesource.com/go",
2076+
base: "https://go.googlesource.com",
2077+
elem: []string{"go"},
2078+
out: "https://go.googlesource.com/go",
2079+
wantPath: "/go",
20772080
},
20782081
{
2079-
base: "https://go.googlesource.com/a/b/c",
2080-
elem: []string{"../../../go"},
2081-
out: "https://go.googlesource.com/go",
2082+
base: "https://go.googlesource.com/a/b/c",
2083+
elem: []string{"../../../go"},
2084+
out: "https://go.googlesource.com/go",
2085+
wantPath: "/go",
20822086
},
20832087
{
2084-
base: "https://go.googlesource.com/",
2085-
elem: []string{"../go"},
2086-
out: "https://go.googlesource.com/go",
2088+
base: "https://go.googlesource.com/",
2089+
elem: []string{"../go"},
2090+
out: "https://go.googlesource.com/go",
2091+
wantPath: "/go",
20872092
},
20882093
{
2089-
base: "https://go.googlesource.com",
2090-
elem: []string{"../go"},
2091-
out: "https://go.googlesource.com/go",
2094+
base: "https://go.googlesource.com",
2095+
elem: []string{"../go"},
2096+
out: "https://go.googlesource.com/go",
2097+
wantPath: "/go",
20922098
},
20932099
{
2094-
base: "https://go.googlesource.com",
2095-
elem: []string{"../go", "../../go", "../../../go"},
2096-
out: "https://go.googlesource.com/go",
2100+
base: "https://go.googlesource.com",
2101+
elem: []string{"../go", "../../go", "../../../go"},
2102+
out: "https://go.googlesource.com/go",
2103+
wantPath: "/go",
20972104
},
20982105
{
2099-
base: "https://go.googlesource.com/../go",
2100-
elem: nil,
2101-
out: "https://go.googlesource.com/go",
2106+
base: "https://go.googlesource.com/../go",
2107+
elem: nil,
2108+
out: "https://go.googlesource.com/go",
2109+
wantPath: "/go",
21022110
},
21032111
{
2104-
base: "https://go.googlesource.com/",
2105-
elem: []string{"./go"},
2106-
out: "https://go.googlesource.com/go",
2112+
base: "https://go.googlesource.com/",
2113+
elem: []string{"./go"},
2114+
out: "https://go.googlesource.com/go",
2115+
wantPath: "/go",
21072116
},
21082117
{
2109-
base: "https://go.googlesource.com//",
2110-
elem: []string{"/go"},
2111-
out: "https://go.googlesource.com/go",
2118+
base: "https://go.googlesource.com//",
2119+
elem: []string{"/go"},
2120+
out: "https://go.googlesource.com/go",
2121+
wantPath: "/go",
21122122
},
21132123
{
2114-
base: "https://go.googlesource.com//",
2115-
elem: []string{"/go", "a", "b", "c"},
2116-
out: "https://go.googlesource.com/go/a/b/c",
2124+
base: "https://go.googlesource.com//",
2125+
elem: []string{"/go", "a", "b", "c"},
2126+
out: "https://go.googlesource.com/go/a/b/c",
2127+
wantPath: "/go/a/b/c",
21172128
},
21182129
{
21192130
base: "http://[fe80::1%en0]:8080/",
21202131
elem: []string{"/go"},
21212132
},
21222133
{
2123-
base: "https://go.googlesource.com",
2124-
elem: []string{"go/"},
2125-
out: "https://go.googlesource.com/go/",
2134+
base: "https://go.googlesource.com",
2135+
elem: []string{"go/"},
2136+
out: "https://go.googlesource.com/go/",
2137+
wantPath: "/go/",
21262138
},
21272139
{
2128-
base: "https://go.googlesource.com",
2129-
elem: []string{"go//"},
2130-
out: "https://go.googlesource.com/go/",
2140+
base: "https://go.googlesource.com",
2141+
elem: []string{"go//"},
2142+
out: "https://go.googlesource.com/go/",
2143+
wantPath: "/go/",
21312144
},
21322145
{
2133-
base: "https://go.googlesource.com",
2134-
elem: nil,
2135-
out: "https://go.googlesource.com/",
2146+
base: "https://go.googlesource.com",
2147+
elem: nil,
2148+
out: "https://go.googlesource.com/",
2149+
wantPath: "/",
21362150
},
21372151
{
2138-
base: "https://go.googlesource.com/",
2139-
elem: nil,
2140-
out: "https://go.googlesource.com/",
2152+
base: "https://go.googlesource.com/",
2153+
elem: nil,
2154+
out: "https://go.googlesource.com/",
2155+
wantPath: "/",
21412156
},
21422157
{
2143-
base: "https://go.googlesource.com/a%2fb",
2144-
elem: []string{"c"},
2145-
out: "https://go.googlesource.com/a%2fb/c",
2158+
base: "https://go.googlesource.com/a%2fb",
2159+
elem: []string{"c"},
2160+
out: "https://go.googlesource.com/a%2fb/c",
2161+
wantPath: "/a/b/c",
2162+
wantRawPath: "/a%2fb/c",
21462163
},
21472164
{
2148-
base: "https://go.googlesource.com/a%2fb",
2149-
elem: []string{"c%2fd"},
2150-
out: "https://go.googlesource.com/a%2fb/c%2fd",
2165+
base: "https://go.googlesource.com/a%2fb",
2166+
elem: []string{"c%2fd"},
2167+
out: "https://go.googlesource.com/a%2fb/c%2fd",
2168+
wantPath: "/a/b/c/d",
2169+
wantRawPath: "/a%2fb/c%2fd",
21512170
},
21522171
{
2153-
base: "https://go.googlesource.com/a/b",
2154-
elem: []string{"/go"},
2155-
out: "https://go.googlesource.com/a/b/go",
2172+
base: "https://go.googlesource.com/a/b",
2173+
elem: []string{"/go"},
2174+
out: "https://go.googlesource.com/a/b/go",
2175+
wantPath: "/a/b/go",
21562176
},
21572177
{
2158-
base: "/",
2159-
elem: nil,
2160-
out: "/",
2178+
base: "/",
2179+
elem: nil,
2180+
out: "/",
2181+
wantPath: "/",
21612182
},
21622183
{
2163-
base: "a",
2164-
elem: nil,
2165-
out: "a",
2184+
base: "a",
2185+
elem: nil,
2186+
out: "a",
2187+
wantPath: "a",
21662188
},
21672189
{
2168-
base: "a",
2169-
elem: []string{"b"},
2170-
out: "a/b",
2190+
base: "a",
2191+
elem: []string{"b"},
2192+
out: "a/b",
2193+
wantPath: "a/b",
21712194
},
21722195
{
2173-
base: "a",
2174-
elem: []string{"../b"},
2175-
out: "b",
2196+
base: "a",
2197+
elem: []string{"../b"},
2198+
out: "b",
2199+
wantPath: "b",
21762200
},
21772201
{
2178-
base: "a",
2179-
elem: []string{"../../b"},
2180-
out: "b",
2202+
base: "a",
2203+
elem: []string{"../../b"},
2204+
out: "b",
2205+
wantPath: "b",
21812206
},
21822207
{
2183-
base: "",
2184-
elem: []string{"a"},
2185-
out: "a",
2208+
base: "",
2209+
elem: []string{"a"},
2210+
out: "/a",
2211+
wantPath: "/a",
21862212
},
21872213
{
2188-
base: "",
2189-
elem: []string{"../a"},
2190-
out: "a",
2214+
base: "",
2215+
elem: []string{"../a"},
2216+
out: "/a",
2217+
wantPath: "/a",
21912218
},
21922219
}
21932220
for _, tt := range tests {
@@ -2207,5 +2234,14 @@ func TestJoinPath(t *testing.T) {
22072234
if out != tt.out || (err == nil) != (tt.out != "") {
22082235
t.Errorf("Parse(%q).JoinPath(%q) = %q, %v, want %q, %v", tt.base, tt.elem, out, err, tt.out, wantErr)
22092236
}
2237+
if u == nil {
2238+
continue
2239+
}
2240+
if got, want := u.Path, tt.wantPath; got != want {
2241+
t.Errorf("Parse(%q).JoinPath(%q).Path = %q, want %q", tt.base, tt.elem, got, want)
2242+
}
2243+
if got, want := u.RawPath, tt.wantRawPath; got != want {
2244+
t.Errorf("Parse(%q).JoinPath(%q).RawPath = %q, want %q", tt.base, tt.elem, got, want)
2245+
}
22102246
}
22112247
}

0 commit comments

Comments
 (0)