src/net/url/url.go | 18 ++++++++++++++++-- src/net/url/url_test.go | 24 +++++++++++++++++++++++- diff --git a/src/net/url/url.go b/src/net/url/url.go index efbb4c36e9bf0419619d4dfdffc26d578a8a0f9a..8ffad663d5cf062e96055131a48a5c51cab66434 100644 --- a/src/net/url/url.go +++ b/src/net/url/url.go @@ -550,8 +550,22 @@ // validEncodedPath reports whether s is a valid encoded path. // It must not contain any bytes that require escaping during path encoding. func validEncodedPath(s string) bool { for i := 0; i < len(s); i++ { - if s[i] != '%' && shouldEscape(s[i], encodePath) { - return false + // RFC 3986, Appendix A. + // pchar = unreserved / pct-encoded / sub-delims / ":" / "@". + // shouldEscape is not quite compliant with the RFC, + // so we check the sub-delims ourselves and let + // shouldEscape handle the others. + switch s[i] { + case '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=', ':', '@': + // ok + case '[', ']': + // ok - not specified in RFC 3986 but left alone by modern browsers + case '%': + // ok - percent encoded, will decode + default: + if shouldEscape(s[i], encodePath) { + return false + } } } return true diff --git a/src/net/url/url_test.go b/src/net/url/url_test.go index 80a2b80efad32e80994f54a2fa1a05db9750c930..ff6e9e4541a7b6b524f74e02808bedfc5f464406 100644 --- a/src/net/url/url_test.go +++ b/src/net/url/url_test.go @@ -392,13 +392,35 @@ Path: "/bar", }, "", }, - // worst case host + // worst case host, still round trips { "scheme://!$&'()*+,;=hello!:port/path", &URL{ Scheme: "scheme", Host: "!$&'()*+,;=hello!:port", Path: "/path", + }, + "", + }, + // worst case path, still round trips + { + "http://host/!$&'()*+,;=:@[hello]", + &URL{ + Scheme: "http", + Host: "host", + Path: "/!$&'()*+,;=:@[hello]", + RawPath: "/!$&'()*+,;=:@[hello]", + }, + "", + }, + // golang.org/issue/5684 + { + "http://example.com/oid/[order_id]", + &URL{ + Scheme: "http", + Host: "example.com", + Path: "/oid/[order_id]", + RawPath: "/oid/[order_id]", }, "", },