-
Notifications
You must be signed in to change notification settings - Fork 17.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
net/url: JoinPath generates bad path if initial url path is empty string #58605
Comments
The issue here is that before the call to |
Yes, I think so. It's a sort of unfortunate fact about url.URL.Path that |
Hmm, a quick and dirty attempt at fixing it causes these test errors:
I'm not sure what I think the output should be here. |
I'm sort of thinking empty path might only be the same as / if the hostname is not empty. If it's empty then it's a relative url, right? I'd probably just special case this...
|
diff --git a/src/net/url/url.go b/src/net/url/url.go
index d530a50d40..bdc85ef6fa 100644
--- a/src/net/url/url.go
+++ b/src/net/url/url.go
@@ -1209,6 +1209,9 @@ func (u *URL) JoinPath(elem ...string) *URL {
if strings.HasSuffix(elem[len(elem)-1], "/") && !strings.HasSuffix(p, "/") {
p += "/"
}
+ if p != "" && p[0] != '/' && u.Host != "" {
+ p = "/" + p
+ }
url := *u
url.setPath(p)
return &url
diff --git a/src/net/url/url_test.go b/src/net/url/url_test.go
index 577cf631c8..df7f9dea9c 100644
--- a/src/net/url/url_test.go
+++ b/src/net/url/url_test.go
@@ -2202,6 +2202,9 @@ func TestJoinPath(t *testing.T) {
u, err := Parse(tt.base)
if err == nil {
u = u.JoinPath(tt.elem...)
+ if u.Path != "" && u.Path[0] != '/' && u.Host != "" {
+ t.Errorf("Parse(%q).JoinPath(%q).Path = %q", tt.base, tt.elem, u.Path)
+ }
out = u.String()
}
if out != tt.out || (err == nil) != (tt.out != "") { This changes it to add a slash if the hostname is not empty, and it passes tests, but like I said, I'm not sure what the correct behavior is here. |
The doc for
This implies absolute paths must not omit the leading slash, but I think the most consistent behavior here would be for |
How about this then: diff --git a/src/net/url/url.go b/src/net/url/url.go
index d530a50d40..c7415897e2 100644
--- a/src/net/url/url.go
+++ b/src/net/url/url.go
@@ -1200,7 +1200,10 @@ func (u *URL) JoinPath(elem ...string) *URL {
// Return a relative path if u is relative,
// but ensure that it contains no ../ elements.
elem[0] = "/" + elem[0]
- p = path.Join(elem...)[1:]
+ p = path.Join(elem...)
+ if elem[0] != "/" || u.Host == "" {
+ p = p[1:]
+ }
} else {
p = path.Join(elem...)
} |
Change https://go.dev/cl/469935 mentions this issue: |
That's still handling the case where https://go.dev/cl/469935 takes that approach. What do you think? |
Not sure if I'm supposed to be pushing this in any kind of manner. If so, consider yourselves pushed. :) |
URL.JoinPath, is buggy: golang/go#58605. By setting the path to '/' when it's empty we work around the issue and can still use JoinPath.
Note that currently the value of I'd argue that this might be considered to also be a bug in |
https://go.dev/play/p/l7jfSgP24id |
Glad I caught this in a unit test before updating my client lib from http.NewRequest. Easy enough to workaround though - set Path to "/" on the base url.URL type if empty before calling JoinPath - if you know the right-hand-side arg is non-empty. |
This change broke a variety of tests inside Google, indicating that it would probably break a variety of tests and potentially real-world uses outside Google as well. I rolled back the change. If we roll it forward again we should probably put it behind a GODEBUG, like urljoinpathslash=0 to go back to the old behavior. |
I think this is a case where if we would want to add a GODEBUG, that's sufficient evidence that we just shouldn't make the change. |
What were the broken tests at Google testing? |
Two cases of non-test code, and one case of test code doing variations on:
I think this is clearly a misuse of One case of non-test code doing this and relying on the result:
I don't understand why you'd do this, but it's not wrong. One case of non-test code doing this and a test relying on the result when
I think that this might be a case where the production code will always use an absolute |
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (
go env
)?go env
OutputWhat did you do?
https://go.dev/play/p/wXMvYKC1FSY
What did you expect to see?
200 OK
What did you see instead?
400 Bad Request
The request sent to the server starts with
GET api/endpoint
. It should beGET /api/endpoint
. The former generates a 400 error in url.ParseRequestURI.The text was updated successfully, but these errors were encountered: