// 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
}
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"},
{
base: "https://go.googlesource.com",
elem: nil,
- out: "https://go.googlesource.com",
+ out: "https://go.googlesource.com/",
},
{
base: "https://go.googlesource.com/",
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"