Skip to content

net/url: Path and RawPath are hard to use #17340

@theory

Description

@theory

Please answer these questions before submitting your issue. Thanks!

What version of Go are you using (go version)?

go version go1.6 darwin/amd64

What operating system and processor architecture are you using (go env)?

GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/david/dev/go"
GORACE=""
GOROOT="/usr/local/go"
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GO15VENDOREXPERIMENT="1"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fno-common"
CXX="clang++"
CGO_ENABLED="1"

What did you do?

I wanted to create a URL where a path segment had an encoded slash. This is because usernames in our system are allowed to contain any valid UTF-8 character, and usernames are used in URLs. But getting the url package to properly encode the slash is tricky. Sample code:

username := "foo/bar"
url := url.URL{
    Scheme: "https",
    Host:   "example.com",
    Path:   "/user/" + username,
}
println(url.String())

What did you expect to see?

https://example.com/user/foo%2Fbar

What did you see instead?

https://example.com/user/foo/bar

Of course I understand that it's impossible for this example to know that "foo/bar" is a single path segment, instead of two. But I tried also supplying a raw path:

username := "foo/bar"
url := url.URL{
    Scheme:  "https",
    Host:    "example.com",
    Path:    "/user/" + username,
    RawPath: "user/" + strings.Replace(username, "/", "%2F", -1),
}
println(url.String())

But the output was the same. The only way I've been able to figure out how to get it to know that "foo/bar" is a single segment is by manually encoding each segment myself and then having the url package parse it:

username := "foo/bar"
raw := "https://example.com/user/" + strings.Replace(
    (&url.URL{Path: username}).String(),
    "/", "%2F", -1,
)

url, err := url.Parse(raw)
if err != nil {
    panic(err)
}
println(url.String())

This outputs the correct value:

https://example.com/user/foo%2Fbar

However, since the whole point of constructing a URL from its parts it to generate a string representation (e.g., to pass to http.Get()), this kind of defeats the whole purpose: I can simply use the raw variable.

I'd like a way to be able to specify the path as a slice of segments, so that the url package knows which parts are directory segments and which aren't. Something like:

url := url.URL{
    Scheme:  "https",
    Host:    "example.com",
    Segments: []string{"user", username}
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions