summaryrefslogtreecommitdiffstats
path: root/llgo/third_party/gofrontend/libgo/go/net/url/url.go
diff options
context:
space:
mode:
Diffstat (limited to 'llgo/third_party/gofrontend/libgo/go/net/url/url.go')
-rw-r--r--llgo/third_party/gofrontend/libgo/go/net/url/url.go200
1 files changed, 175 insertions, 25 deletions
diff --git a/llgo/third_party/gofrontend/libgo/go/net/url/url.go b/llgo/third_party/gofrontend/libgo/go/net/url/url.go
index f167408faba..8ffad663d5c 100644
--- a/llgo/third_party/gofrontend/libgo/go/net/url/url.go
+++ b/llgo/third_party/gofrontend/libgo/go/net/url/url.go
@@ -9,6 +9,7 @@ package url
import (
"bytes"
"errors"
+ "fmt"
"sort"
"strconv"
"strings"
@@ -51,6 +52,7 @@ type encoding int
const (
encodePath encoding = 1 + iota
+ encodeHost
encodeUserPassword
encodeQueryComponent
encodeFragment
@@ -64,12 +66,27 @@ func (e EscapeError) Error() string {
// Return true if the specified character should be escaped when
// appearing in a URL string, according to RFC 3986.
+//
+// Please be informed that for now shouldEscape does not check all
+// reserved characters correctly. See golang.org/issue/5684.
func shouldEscape(c byte, mode encoding) bool {
// §2.3 Unreserved characters (alphanum)
if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' {
return false
}
+ if mode == encodeHost {
+ // §3.2.2 Host allows
+ // sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
+ // as part of reg-name.
+ // We add : because we include :port as part of host.
+ // We add [ ] because we include [ipv6]:port as part of host
+ switch c {
+ case '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=', ':', '[', ']':
+ return false
+ }
+ }
+
switch c {
case '-', '_', '.', '~': // §2.3 Unreserved characters (mark)
return false
@@ -127,7 +144,7 @@ func unescape(s string, mode encoding) (string, error) {
if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) {
s = s[i:]
if len(s) > 3 {
- s = s[0:3]
+ s = s[:3]
}
return "", EscapeError(s)
}
@@ -224,16 +241,24 @@ func escape(s string, mode encoding) string {
// Note that the Path field is stored in decoded form: /%47%6f%2f becomes /Go/.
// A consequence is that it is impossible to tell which slashes in the Path were
// slashes in the raw URL and which were %2f. This distinction is rarely important,
-// but when it is a client must use other routines to parse the raw URL or construct
-// the parsed URL. For example, an HTTP server can consult req.RequestURI, and
-// an HTTP client can use URL{Host: "example.com", Opaque: "//example.com/Go%2f"}
-// instead of URL{Host: "example.com", Path: "/Go/"}.
+// but when it is, code must not use Path directly.
+//
+// Go 1.5 introduced the RawPath field to hold the encoded form of Path.
+// The Parse function sets both Path and RawPath in the URL it returns,
+// and URL's String method uses RawPath if it is a valid encoding of Path,
+// by calling the EncodedPath method.
+//
+// In earlier versions of Go, the more indirect workarounds were that an
+// HTTP server could consult req.RequestURI and an HTTP client could
+// 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 '#'
}
@@ -305,7 +330,7 @@ func getscheme(rawurl string) (scheme, path string, err error) {
if i == 0 {
return "", "", errors.New("missing protocol scheme")
}
- return rawurl[0:i], rawurl[i+1:], nil
+ return rawurl[:i], rawurl[i+1:], nil
default:
// we have encountered an invalid character,
// so there is no valid scheme
@@ -324,9 +349,9 @@ func split(s string, c string, cutc bool) (string, string) {
return s, ""
}
if cutc {
- return s[0:i], s[i+len(c):]
+ return s[:i], s[i+len(c):]
}
- return s[0:i], s[i:]
+ return s[:i], s[i:]
}
// Parse parses rawurl into a URL structure.
@@ -401,14 +426,17 @@ func parse(rawurl string, viaRequest bool) (url *URL, err error) {
if err != nil {
goto Error
}
- if strings.Contains(url.Host, "%") {
- err = errors.New("hexadecimal escape in host")
- goto Error
- }
}
if url.Path, err = unescape(rest, encodePath); err != nil {
goto Error
}
+ // RawPath is a hint as to the encoding of Path to use
+ // in url.EncodedPath. If that method already gets the
+ // right answer without RawPath, leave it empty.
+ // This will help make sure that people don't rely on it in general.
+ if url.EscapedPath() != rest && validEncodedPath(rest) {
+ url.RawPath = rest
+ }
return url, nil
Error:
@@ -418,36 +446,157 @@ Error:
func parseAuthority(authority string) (user *Userinfo, host string, err error) {
i := strings.LastIndex(authority, "@")
if i < 0 {
- host = authority
- return
+ host, err = parseHost(authority)
+ } else {
+ host, err = parseHost(authority[i+1:])
}
- userinfo, host := authority[:i], authority[i+1:]
+ if err != nil {
+ return nil, "", err
+ }
+ if i < 0 {
+ return nil, host, nil
+ }
+ userinfo := authority[:i]
if strings.Index(userinfo, ":") < 0 {
if userinfo, err = unescape(userinfo, encodeUserPassword); err != nil {
- return
+ return nil, "", err
}
user = User(userinfo)
} else {
username, password := split(userinfo, ":", true)
if username, err = unescape(username, encodeUserPassword); err != nil {
- return
+ return nil, "", err
}
if password, err = unescape(password, encodeUserPassword); err != nil {
- return
+ return nil, "", err
}
user = UserPassword(username, password)
}
- return
+ return user, host, nil
+}
+
+// parseHost parses host as an authority without user
+// information. That is, as host[:port].
+func parseHost(host string) (string, error) {
+ litOrName := host
+ if strings.HasPrefix(host, "[") {
+ // Parse an IP-Literal in RFC 3986 and RFC 6874.
+ // E.g., "[fe80::1], "[fe80::1%25en0]"
+ //
+ // RFC 4007 defines "%" as a delimiter character in
+ // the textual representation of IPv6 addresses.
+ // Per RFC 6874, in URIs that "%" is encoded as "%25".
+ i := strings.LastIndex(host, "]")
+ if i < 0 {
+ return "", errors.New("missing ']' in host")
+ }
+ colonPort := host[i+1:]
+ if !validOptionalPort(colonPort) {
+ return "", fmt.Errorf("invalid port %q after host", colonPort)
+ }
+ // Parse a host subcomponent without a ZoneID in RFC
+ // 6874 because the ZoneID is allowed to use the
+ // percent encoded form.
+ j := strings.Index(host[:i], "%25")
+ if j < 0 {
+ litOrName = host[1:i]
+ } else {
+ litOrName = host[1:j]
+ }
+ }
+
+ // A URI containing an IP-Literal without a ZoneID or
+ // IPv4address in RFC 3986 and RFC 6847 must not be
+ // percent-encoded.
+ //
+ // A URI containing a DNS registered name in RFC 3986 is
+ // allowed to be percent-encoded, though we don't use it for
+ // now to avoid messing up with the gap between allowed
+ // characters in URI and allowed characters in DNS.
+ // See golang.org/issue/7991.
+ if strings.Contains(litOrName, "%") {
+ return "", errors.New("percent-encoded characters in host")
+ }
+ var err error
+ if host, err = unescape(host, encodeHost); err != nil {
+ return "", err
+ }
+ return host, nil
+}
+
+// EscapedPath returns the escaped form of u.Path.
+// In general there are multiple possible escaped forms of any path.
+// EscapedPath returns u.RawPath when it is a valid escaping of u.Path.
+// Otherwise EscapedPath ignores u.RawPath and computes an escaped
+// form on its own.
+// The String and RequestURI methods use EscapedPath to construct
+// their results.
+// In general, code should call EscapedPath instead of
+// reading u.RawPath directly.
+func (u *URL) EscapedPath() string {
+ if u.RawPath != "" && validEncodedPath(u.RawPath) {
+ p, err := unescape(u.RawPath, encodePath)
+ if err == nil && p == u.Path {
+ return u.RawPath
+ }
+ }
+ if u.Path == "*" {
+ return "*" // don't escape (Issue 11202)
+ }
+ return escape(u.Path, encodePath)
+}
+
+// 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++ {
+ // 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
+}
+
+// validOptionalPort reports whether port is either an empty string
+// or matches /^:\d+$/
+func validOptionalPort(port string) bool {
+ if port == "" {
+ return true
+ }
+ if port[0] != ':' || len(port) == 1 {
+ return false
+ }
+ for _, b := range port[1:] {
+ if b < '0' || b > '9' {
+ return false
+ }
+ }
+ return true
}
// String reassembles the URL into a valid URL string.
// The general form of the result is one of:
//
-// scheme:opaque
+// scheme:opaque?query#fragment
// scheme://userinfo@host/path?query#fragment
//
// If u.Opaque is non-empty, String uses the first form;
// otherwise it uses the second form.
+// To obtain the path, String uses u.EncodedPath().
//
// In the second form, the following rules apply:
// - if u.Scheme is empty, scheme: is omitted.
@@ -475,13 +624,14 @@ func (u *URL) String() string {
buf.WriteByte('@')
}
if h := u.Host; h != "" {
- buf.WriteString(h)
+ buf.WriteString(escape(h, encodeHost))
}
}
- if u.Path != "" && u.Path[0] != '/' && u.Host != "" {
+ path := u.EscapedPath()
+ if path != "" && path[0] != '/' && u.Host != "" {
buf.WriteByte('/')
}
- buf.WriteString(escape(u.Path, encodePath))
+ buf.WriteString(path)
}
if u.RawQuery != "" {
buf.WriteByte('?')
@@ -639,7 +789,7 @@ func resolvePath(base, ref string) string {
return "/" + strings.TrimLeft(strings.Join(dst, "/"), "/")
}
-// IsAbs returns true if the URL is absolute.
+// IsAbs reports whether the URL is absolute.
func (u *URL) IsAbs() bool {
return u.Scheme != ""
}
@@ -703,7 +853,7 @@ func (u *URL) Query() Values {
func (u *URL) RequestURI() string {
result := u.Opaque
if result == "" {
- result = escape(u.Path, encodePath)
+ result = u.EscapedPath()
if result == "" {
result = "/"
}
OpenPOWER on IntegriCloud