]> Cypherpunks repositories - gostls13.git/commitdiff
net/url: support query string without values
authorRick Arnold <rickarnoldjr@gmail.com>
Fri, 26 Feb 2016 03:24:07 +0000 (22:24 -0500)
committerBrad Fitzpatrick <bradfitz@golang.org>
Fri, 26 Feb 2016 16:13:26 +0000 (16:13 +0000)
Previously, RawQuery was used to indicate the presence of a query
string in url.URL. However, this approach was not able to differentiate
between URLs that have no query string at all (http://foo.bar/) and
those that have a query with no values (http://foo.bar/?).

Add a ForceQuery field to indicate the latter form of URL and use it
in URL.String to create a matching URL with a trailing '?'.

Fixes #13488

Change-Id: Ifac663c73d35759bc6c33a00f84ab116b9b81684
Reviewed-on: https://go-review.googlesource.com/19931
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

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

index b3513a85a3f9f26f7c1aa7b443dd341bb249a9e6..48119f4a5dc35c342c727939b7f98c69d1939ac8 100644 (file)
@@ -307,14 +307,15 @@ func escape(s string, mode encoding) string {
 // construct a URL struct directly and set the Opaque field instead of Path.
 // These still work as well.
 type URL struct {
-       Scheme   string
-       Opaque   string    // encoded opaque data
-       User     *Userinfo // username and password information
-       Host     string    // host or host:port
-       Path     string
-       RawPath  string // encoded path hint (Go 1.5 and later only; see EscapedPath method)
-       RawQuery string // encoded query values, without '?'
-       Fragment string // fragment for references, without '#'
+       Scheme     string
+       Opaque     string    // encoded opaque data
+       User       *Userinfo // username and password information
+       Host       string    // host or host:port
+       Path       string
+       RawPath    string // encoded path hint (Go 1.5 and later only; see EscapedPath method)
+       ForceQuery bool   // append a query ('?') even if RawQuery is empty
+       RawQuery   string // encoded query values, without '?'
+       Fragment   string // fragment for references, without '#'
 }
 
 // User returns a Userinfo containing the provided username
@@ -459,7 +460,12 @@ func parse(rawurl string, viaRequest bool) (url *URL, err error) {
        }
        url.Scheme = strings.ToLower(url.Scheme)
 
-       rest, url.RawQuery = split(rest, "?", true)
+       if strings.HasSuffix(rest, "?") {
+               url.ForceQuery = true
+               rest = rest[:len(rest)-1]
+       } else {
+               rest, url.RawQuery = split(rest, "?", true)
+       }
 
        if !strings.HasPrefix(rest, "/") {
                if url.Scheme != "" {
@@ -684,7 +690,7 @@ func (u *URL) String() string {
                }
                buf.WriteString(path)
        }
-       if u.RawQuery != "" {
+       if u.ForceQuery || u.RawQuery != "" {
                buf.WriteByte('?')
                buf.WriteString(u.RawQuery)
        }
@@ -913,7 +919,7 @@ func (u *URL) RequestURI() string {
                        result = u.Scheme + ":" + result
                }
        }
-       if u.RawQuery != "" {
+       if u.ForceQuery || u.RawQuery != "" {
                result += "?" + u.RawQuery
        }
        return result
index d3f8487bd7c0addb96f8e7329f98619308589540..a3088ec0a3867d9b48eaba46b3bda98d915bbd9d 100644 (file)
@@ -72,6 +72,17 @@ var urltests = []URLTest{
                },
                "ftp://john%20doe@www.google.com/",
        },
+       // empty query
+       {
+               "http://www.google.com/?",
+               &URL{
+                       Scheme:     "http",
+                       Host:       "www.google.com",
+                       Path:       "/",
+                       ForceQuery: true,
+               },
+               "",
+       },
        // query
        {
                "http://www.google.com/?q=go+language",
@@ -874,11 +885,13 @@ var resolveReferenceTests = []struct {
        // Absolute URL references
        {"http://foo.com?a=b", "https://bar.com/", "https://bar.com/"},
        {"http://foo.com/", "https://bar.com/?a=b", "https://bar.com/?a=b"},
+       {"http://foo.com/", "https://bar.com/?", "https://bar.com/?"},
        {"http://foo.com/bar", "mailto:foo@example.com", "mailto:foo@example.com"},
 
        // Path-absolute references
        {"http://foo.com/bar", "/baz", "http://foo.com/baz"},
        {"http://foo.com/bar?a=b#f", "/baz", "http://foo.com/baz"},
+       {"http://foo.com/bar?a=b", "/baz?", "http://foo.com/baz?"},
        {"http://foo.com/bar?a=b", "/baz?c=d", "http://foo.com/baz?c=d"},
 
        // Scheme-relative
@@ -1217,6 +1230,15 @@ var requritests = []RequestURITest{
                },
                "//foo",
        },
+       {
+               &URL{
+                       Scheme:     "http",
+                       Host:       "example.com",
+                       Path:       "/foo",
+                       ForceQuery: true,
+               },
+               "/foo?",
+       },
 }
 
 func TestRequestURI(t *testing.T) {