]> Cypherpunks repositories - gostls13.git/commitdiff
net/url: consistently remove ../ elements in JoinPath
authorDamien Neil <dneil@google.com>
Fri, 12 Aug 2022 23:21:09 +0000 (16:21 -0700)
committerDamien Neil <dneil@google.com>
Tue, 23 Aug 2022 22:01:05 +0000 (22:01 +0000)
JoinPath would fail to remove relative elements from the start of
the path when the first path element is "".

In addition, JoinPath would return the original path unmodified
when provided with no elements to join, violating the documented
behavior of always cleaning the resulting path.

Correct both these cases.

    JoinPath("http://go.dev", "../go")
    // before: http://go.dev/../go
    // after:  http://go.dev/go

    JoinPath("http://go.dev/../go")
    // before: http://go.dev/../go
    // after:  http://go.dev/go

Fixes #54385.

Change-Id: I6d22cd160d097c50703dd96e4f453c6c118fd5d9
Reviewed-on: https://go-review.googlesource.com/c/go/+/423514
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Alan Donovan <adonovan@google.com>
src/net/url/url.go
src/net/url/url_test.go

index a21af7e47958b0be1d525513f3d6d0f6aaa55c4b..d530a50d40d19fe2467e021308a808e009877d41 100644 (file)
@@ -1194,17 +1194,23 @@ func (u *URL) UnmarshalBinary(text []byte) error {
 // any existing path and the resulting path cleaned of any ./ or ../ elements.
 // Any sequences of multiple / characters will be reduced to a single /.
 func (u *URL) JoinPath(elem ...string) *URL {
-       url := *u
-       if len(elem) > 0 {
-               elem = append([]string{u.EscapedPath()}, elem...)
-               p := path.Join(elem...)
-               // path.Join will remove any trailing slashes.
-               // Preserve at least one.
-               if strings.HasSuffix(elem[len(elem)-1], "/") && !strings.HasSuffix(p, "/") {
-                       p += "/"
-               }
-               url.setPath(p)
+       elem = append([]string{u.EscapedPath()}, elem...)
+       var p string
+       if !strings.HasPrefix(elem[0], "/") {
+               // Return a relative path if u is relative,
+               // but ensure that it contains no ../ elements.
+               elem[0] = "/" + elem[0]
+               p = path.Join(elem...)[1:]
+       } else {
+               p = path.Join(elem...)
        }
+       // path.Join will remove any trailing slashes.
+       // Preserve at least one.
+       if strings.HasSuffix(elem[len(elem)-1], "/") && !strings.HasSuffix(p, "/") {
+               p += "/"
+       }
+       url := *u
+       url.setPath(p)
        return &url
 }
 
index 263eddffcf35d821bd3df4758f466bf17945faf6..577cf631c835e1986ff65107dc1cd9fc32651cd3 100644 (file)
@@ -2080,6 +2080,26 @@ func TestJoinPath(t *testing.T) {
                        elem: []string{"../../../go"},
                        out:  "https://go.googlesource.com/go",
                },
+               {
+                       base: "https://go.googlesource.com/",
+                       elem: []string{"../go"},
+                       out:  "https://go.googlesource.com/go",
+               },
+               {
+                       base: "https://go.googlesource.com",
+                       elem: []string{"../go"},
+                       out:  "https://go.googlesource.com/go",
+               },
+               {
+                       base: "https://go.googlesource.com",
+                       elem: []string{"../go", "../../go", "../../../go"},
+                       out:  "https://go.googlesource.com/go",
+               },
+               {
+                       base: "https://go.googlesource.com/../go",
+                       elem: nil,
+                       out:  "https://go.googlesource.com/go",
+               },
                {
                        base: "https://go.googlesource.com/",
                        elem: []string{"./go"},
@@ -2112,7 +2132,7 @@ func TestJoinPath(t *testing.T) {
                {
                        base: "https://go.googlesource.com",
                        elem: nil,
-                       out:  "https://go.googlesource.com",
+                       out:  "https://go.googlesource.com/",
                },
                {
                        base: "https://go.googlesource.com/",
@@ -2129,11 +2149,46 @@ func TestJoinPath(t *testing.T) {
                        elem: []string{"c%2fd"},
                        out:  "https://go.googlesource.com/a%2fb/c%2fd",
                },
+               {
+                       base: "https://go.googlesource.com/a/b",
+                       elem: []string{"/go"},
+                       out:  "https://go.googlesource.com/a/b/go",
+               },
                {
                        base: "/",
                        elem: nil,
                        out:  "/",
                },
+               {
+                       base: "a",
+                       elem: nil,
+                       out:  "a",
+               },
+               {
+                       base: "a",
+                       elem: []string{"b"},
+                       out:  "a/b",
+               },
+               {
+                       base: "a",
+                       elem: []string{"../b"},
+                       out:  "b",
+               },
+               {
+                       base: "a",
+                       elem: []string{"../../b"},
+                       out:  "b",
+               },
+               {
+                       base: "",
+                       elem: []string{"a"},
+                       out:  "a",
+               },
+               {
+                       base: "",
+                       elem: []string{"../a"},
+                       out:  "a",
+               },
        }
        for _, tt := range tests {
                wantErr := "nil"