]> Cypherpunks repositories - gostls13.git/commitdiff
net/url: add OmitHost bool to url.URL
authorUzondu Enudeme <uzondu@orijtech.com>
Wed, 9 Mar 2022 23:08:52 +0000 (00:08 +0100)
committerEmmanuel Odeke <emmanuel@orijtech.com>
Mon, 14 Mar 2022 09:19:01 +0000 (09:19 +0000)
Previously, myscheme:/path and myscheme:///path were treated as the same URL
although materially different. The distinction made clear by RFC 3986 sec. 5.3 where
a different recomposition behavior is expected when a URI reference has an undefined
host(authority) as in myscheme:/path vs. one with an empty host(authority)
as in myscheme:///path.

This change fixes the Parse/String roundtrip limitation for URLs with an undefined
host and a single slash.

Fixes #46059

Change-Id: I1b8d6042135513616374ff8c8dfb1cdb640f8efe
Reviewed-on: https://go-review.googlesource.com/c/go/+/391294
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Emmanuel Odeke <emmanuel@orijtech.com>
Run-TryBot: Emmanuel Odeke <emmanuel@orijtech.com>
TryBot-Result: Gopher Robot <gobot@golang.org>

src/net/url/url.go
src/net/url/url_test.go

index 1571bf728ba9145fc62a256fd812719799e49027..ecfd1d9e94b84619b80500d7b9d4fc9c0fc81a3c 100644 (file)
@@ -363,6 +363,7 @@ type URL struct {
        Host        string    // host or host:port
        Path        string    // path (relative paths may omit leading slash)
        RawPath     string    // encoded path hint (see EscapedPath method)
+       OmitHost    bool      // do not emit empty host (authority)
        ForceQuery  bool      // append a query ('?') even if RawQuery is empty
        RawQuery    string    // encoded query values, without '?'
        Fragment    string    // fragment for references, without '#'
@@ -556,7 +557,12 @@ func parse(rawURL string, viaRequest bool) (*URL, error) {
                if err != nil {
                        return nil, err
                }
+       } else if url.Scheme != "" && strings.HasPrefix(rest, "/") {
+               // OmitHost is set to true when rawURL has an empty host (authority).
+               // See golang.org/issue/46059.
+               url.OmitHost = true
        }
+
        // Set Path and, optionally, RawPath.
        // RawPath is a hint of the encoding of Path. We don't want to set it if
        // the default escaping of Path is equivalent, to help make sure that people
@@ -806,15 +812,19 @@ func (u *URL) String() string {
                buf.WriteString(u.Opaque)
        } else {
                if u.Scheme != "" || u.Host != "" || u.User != nil {
-                       if u.Host != "" || u.Path != "" || u.User != nil {
-                               buf.WriteString("//")
-                       }
-                       if ui := u.User; ui != nil {
-                               buf.WriteString(ui.String())
-                               buf.WriteByte('@')
-                       }
-                       if h := u.Host; h != "" {
-                               buf.WriteString(escape(h, encodeHost))
+                       if u.OmitHost && u.Host == "" && u.User == nil {
+                               // omit empty host
+                       } else {
+                               if u.Host != "" || u.Path != "" || u.User != nil {
+                                       buf.WriteString("//")
+                               }
+                               if ui := u.User; ui != nil {
+                                       buf.WriteString(ui.String())
+                                       buf.WriteByte('@')
+                               }
+                               if h := u.Host; h != "" {
+                                       buf.WriteString(escape(h, encodeHost))
+                               }
                        }
                }
                path := u.EscapedPath()
index 84dba45c3c1366872f2e2d152d84ce53ea169d73..18aa5f8a1c55a8abcdac3839bab3c559eb2cb3e4 100644 (file)
@@ -163,14 +163,15 @@ var urltests = []URLTest{
                },
                "http:%2f%2fwww.google.com/?q=go+language",
        },
-       // non-authority with path
+       // non-authority with path; see golang.org/issue/46059
        {
                "mailto:/webmaster@golang.org",
                &URL{
-                       Scheme: "mailto",
-                       Path:   "/webmaster@golang.org",
+                       Scheme:   "mailto",
+                       Path:     "/webmaster@golang.org",
+                       OmitHost: true,
                },
-               "mailto:///webmaster@golang.org", // unfortunate compromise
+               "",
        },
        // non-authority
        {
@@ -625,8 +626,8 @@ func ufmt(u *URL) string {
                        pass = p
                }
        }
-       return fmt.Sprintf("opaque=%q, scheme=%q, user=%#v, pass=%#v, host=%q, path=%q, rawpath=%q, rawq=%q, frag=%q, rawfrag=%q, forcequery=%v",
-               u.Opaque, u.Scheme, user, pass, u.Host, u.Path, u.RawPath, u.RawQuery, u.Fragment, u.RawFragment, u.ForceQuery)
+       return fmt.Sprintf("opaque=%q, scheme=%q, user=%#v, pass=%#v, host=%q, path=%q, rawpath=%q, rawq=%q, frag=%q, rawfrag=%q, forcequery=%v, omithost=%t",
+               u.Opaque, u.Scheme, user, pass, u.Host, u.Path, u.RawPath, u.RawQuery, u.Fragment, u.RawFragment, u.ForceQuery, u.OmitHost)
 }
 
 func BenchmarkString(b *testing.B) {