Home | History | Annotate | Download | only in url
      1 // Copyright 2009 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 // Package url parses URLs and implements query escaping.
      6 // See RFC 3986.
      7 package url
      8 
      9 import (
     10 	"bytes"
     11 	"errors"
     12 	"fmt"
     13 	"sort"
     14 	"strconv"
     15 	"strings"
     16 )
     17 
     18 // Error reports an error and the operation and URL that caused it.
     19 type Error struct {
     20 	Op  string
     21 	URL string
     22 	Err error
     23 }
     24 
     25 func (e *Error) Error() string { return e.Op + " " + e.URL + ": " + e.Err.Error() }
     26 
     27 func ishex(c byte) bool {
     28 	switch {
     29 	case '0' <= c && c <= '9':
     30 		return true
     31 	case 'a' <= c && c <= 'f':
     32 		return true
     33 	case 'A' <= c && c <= 'F':
     34 		return true
     35 	}
     36 	return false
     37 }
     38 
     39 func unhex(c byte) byte {
     40 	switch {
     41 	case '0' <= c && c <= '9':
     42 		return c - '0'
     43 	case 'a' <= c && c <= 'f':
     44 		return c - 'a' + 10
     45 	case 'A' <= c && c <= 'F':
     46 		return c - 'A' + 10
     47 	}
     48 	return 0
     49 }
     50 
     51 type encoding int
     52 
     53 const (
     54 	encodePath encoding = 1 + iota
     55 	encodeHost
     56 	encodeUserPassword
     57 	encodeQueryComponent
     58 	encodeFragment
     59 )
     60 
     61 type EscapeError string
     62 
     63 func (e EscapeError) Error() string {
     64 	return "invalid URL escape " + strconv.Quote(string(e))
     65 }
     66 
     67 // Return true if the specified character should be escaped when
     68 // appearing in a URL string, according to RFC 3986.
     69 //
     70 // Please be informed that for now shouldEscape does not check all
     71 // reserved characters correctly. See golang.org/issue/5684.
     72 func shouldEscape(c byte, mode encoding) bool {
     73 	// 2.3 Unreserved characters (alphanum)
     74 	if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' {
     75 		return false
     76 	}
     77 
     78 	if mode == encodeHost {
     79 		// 3.2.2 Host allows
     80 		//	sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
     81 		// as part of reg-name.
     82 		// We add : because we include :port as part of host.
     83 		// We add [ ] because we include [ipv6]:port as part of host
     84 		switch c {
     85 		case '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=', ':', '[', ']':
     86 			return false
     87 		}
     88 	}
     89 
     90 	switch c {
     91 	case '-', '_', '.', '~': // 2.3 Unreserved characters (mark)
     92 		return false
     93 
     94 	case '$', '&', '+', ',', '/', ':', ';', '=', '?', '@': // 2.2 Reserved characters (reserved)
     95 		// Different sections of the URL allow a few of
     96 		// the reserved characters to appear unescaped.
     97 		switch mode {
     98 		case encodePath: // 3.3
     99 			// The RFC allows : @ & = + $ but saves / ; , for assigning
    100 			// meaning to individual path segments. This package
    101 			// only manipulates the path as a whole, so we allow those
    102 			// last two as well. That leaves only ? to escape.
    103 			return c == '?'
    104 
    105 		case encodeUserPassword: // 3.2.1
    106 			// The RFC allows ';', ':', '&', '=', '+', '$', and ',' in
    107 			// userinfo, so we must escape only '@', '/', and '?'.
    108 			// The parsing of userinfo treats ':' as special so we must escape
    109 			// that too.
    110 			return c == '@' || c == '/' || c == '?' || c == ':'
    111 
    112 		case encodeQueryComponent: // 3.4
    113 			// The RFC reserves (so we must escape) everything.
    114 			return true
    115 
    116 		case encodeFragment: // 4.1
    117 			// The RFC text is silent but the grammar allows
    118 			// everything, so escape nothing.
    119 			return false
    120 		}
    121 	}
    122 
    123 	// Everything else must be escaped.
    124 	return true
    125 }
    126 
    127 // QueryUnescape does the inverse transformation of QueryEscape, converting
    128 // %AB into the byte 0xAB and '+' into ' ' (space). It returns an error if
    129 // any % is not followed by two hexadecimal digits.
    130 func QueryUnescape(s string) (string, error) {
    131 	return unescape(s, encodeQueryComponent)
    132 }
    133 
    134 // unescape unescapes a string; the mode specifies
    135 // which section of the URL string is being unescaped.
    136 func unescape(s string, mode encoding) (string, error) {
    137 	// Count %, check that they're well-formed.
    138 	n := 0
    139 	hasPlus := false
    140 	for i := 0; i < len(s); {
    141 		switch s[i] {
    142 		case '%':
    143 			n++
    144 			if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) {
    145 				s = s[i:]
    146 				if len(s) > 3 {
    147 					s = s[:3]
    148 				}
    149 				return "", EscapeError(s)
    150 			}
    151 			i += 3
    152 		case '+':
    153 			hasPlus = mode == encodeQueryComponent
    154 			i++
    155 		default:
    156 			i++
    157 		}
    158 	}
    159 
    160 	if n == 0 && !hasPlus {
    161 		return s, nil
    162 	}
    163 
    164 	t := make([]byte, len(s)-2*n)
    165 	j := 0
    166 	for i := 0; i < len(s); {
    167 		switch s[i] {
    168 		case '%':
    169 			t[j] = unhex(s[i+1])<<4 | unhex(s[i+2])
    170 			j++
    171 			i += 3
    172 		case '+':
    173 			if mode == encodeQueryComponent {
    174 				t[j] = ' '
    175 			} else {
    176 				t[j] = '+'
    177 			}
    178 			j++
    179 			i++
    180 		default:
    181 			t[j] = s[i]
    182 			j++
    183 			i++
    184 		}
    185 	}
    186 	return string(t), nil
    187 }
    188 
    189 // QueryEscape escapes the string so it can be safely placed
    190 // inside a URL query.
    191 func QueryEscape(s string) string {
    192 	return escape(s, encodeQueryComponent)
    193 }
    194 
    195 func escape(s string, mode encoding) string {
    196 	spaceCount, hexCount := 0, 0
    197 	for i := 0; i < len(s); i++ {
    198 		c := s[i]
    199 		if shouldEscape(c, mode) {
    200 			if c == ' ' && mode == encodeQueryComponent {
    201 				spaceCount++
    202 			} else {
    203 				hexCount++
    204 			}
    205 		}
    206 	}
    207 
    208 	if spaceCount == 0 && hexCount == 0 {
    209 		return s
    210 	}
    211 
    212 	t := make([]byte, len(s)+2*hexCount)
    213 	j := 0
    214 	for i := 0; i < len(s); i++ {
    215 		switch c := s[i]; {
    216 		case c == ' ' && mode == encodeQueryComponent:
    217 			t[j] = '+'
    218 			j++
    219 		case shouldEscape(c, mode):
    220 			t[j] = '%'
    221 			t[j+1] = "0123456789ABCDEF"[c>>4]
    222 			t[j+2] = "0123456789ABCDEF"[c&15]
    223 			j += 3
    224 		default:
    225 			t[j] = s[i]
    226 			j++
    227 		}
    228 	}
    229 	return string(t)
    230 }
    231 
    232 // A URL represents a parsed URL (technically, a URI reference).
    233 // The general form represented is:
    234 //
    235 //	scheme://[userinfo@]host/path[?query][#fragment]
    236 //
    237 // URLs that do not start with a slash after the scheme are interpreted as:
    238 //
    239 //	scheme:opaque[?query][#fragment]
    240 //
    241 // Note that the Path field is stored in decoded form: /%47%6f%2f becomes /Go/.
    242 // A consequence is that it is impossible to tell which slashes in the Path were
    243 // slashes in the raw URL and which were %2f. This distinction is rarely important,
    244 // but when it is, code must not use Path directly.
    245 //
    246 // Go 1.5 introduced the RawPath field to hold the encoded form of Path.
    247 // The Parse function sets both Path and RawPath in the URL it returns,
    248 // and URL's String method uses RawPath if it is a valid encoding of Path,
    249 // by calling the EncodedPath method.
    250 //
    251 // In earlier versions of Go, the more indirect workarounds were that an
    252 // HTTP server could consult req.RequestURI and an HTTP client could
    253 // construct a URL struct directly and set the Opaque field instead of Path.
    254 // These still work as well.
    255 type URL struct {
    256 	Scheme   string
    257 	Opaque   string    // encoded opaque data
    258 	User     *Userinfo // username and password information
    259 	Host     string    // host or host:port
    260 	Path     string
    261 	RawPath  string // encoded path hint (Go 1.5 and later only; see EscapedPath method)
    262 	RawQuery string // encoded query values, without '?'
    263 	Fragment string // fragment for references, without '#'
    264 }
    265 
    266 // User returns a Userinfo containing the provided username
    267 // and no password set.
    268 func User(username string) *Userinfo {
    269 	return &Userinfo{username, "", false}
    270 }
    271 
    272 // UserPassword returns a Userinfo containing the provided username
    273 // and password.
    274 // This functionality should only be used with legacy web sites.
    275 // RFC 2396 warns that interpreting Userinfo this way
    276 // ``is NOT RECOMMENDED, because the passing of authentication
    277 // information in clear text (such as URI) has proven to be a
    278 // security risk in almost every case where it has been used.''
    279 func UserPassword(username, password string) *Userinfo {
    280 	return &Userinfo{username, password, true}
    281 }
    282 
    283 // The Userinfo type is an immutable encapsulation of username and
    284 // password details for a URL. An existing Userinfo value is guaranteed
    285 // to have a username set (potentially empty, as allowed by RFC 2396),
    286 // and optionally a password.
    287 type Userinfo struct {
    288 	username    string
    289 	password    string
    290 	passwordSet bool
    291 }
    292 
    293 // Username returns the username.
    294 func (u *Userinfo) Username() string {
    295 	return u.username
    296 }
    297 
    298 // Password returns the password in case it is set, and whether it is set.
    299 func (u *Userinfo) Password() (string, bool) {
    300 	if u.passwordSet {
    301 		return u.password, true
    302 	}
    303 	return "", false
    304 }
    305 
    306 // String returns the encoded userinfo information in the standard form
    307 // of "username[:password]".
    308 func (u *Userinfo) String() string {
    309 	s := escape(u.username, encodeUserPassword)
    310 	if u.passwordSet {
    311 		s += ":" + escape(u.password, encodeUserPassword)
    312 	}
    313 	return s
    314 }
    315 
    316 // Maybe rawurl is of the form scheme:path.
    317 // (Scheme must be [a-zA-Z][a-zA-Z0-9+-.]*)
    318 // If so, return scheme, path; else return "", rawurl.
    319 func getscheme(rawurl string) (scheme, path string, err error) {
    320 	for i := 0; i < len(rawurl); i++ {
    321 		c := rawurl[i]
    322 		switch {
    323 		case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z':
    324 		// do nothing
    325 		case '0' <= c && c <= '9' || c == '+' || c == '-' || c == '.':
    326 			if i == 0 {
    327 				return "", rawurl, nil
    328 			}
    329 		case c == ':':
    330 			if i == 0 {
    331 				return "", "", errors.New("missing protocol scheme")
    332 			}
    333 			return rawurl[:i], rawurl[i+1:], nil
    334 		default:
    335 			// we have encountered an invalid character,
    336 			// so there is no valid scheme
    337 			return "", rawurl, nil
    338 		}
    339 	}
    340 	return "", rawurl, nil
    341 }
    342 
    343 // Maybe s is of the form t c u.
    344 // If so, return t, c u (or t, u if cutc == true).
    345 // If not, return s, "".
    346 func split(s string, c string, cutc bool) (string, string) {
    347 	i := strings.Index(s, c)
    348 	if i < 0 {
    349 		return s, ""
    350 	}
    351 	if cutc {
    352 		return s[:i], s[i+len(c):]
    353 	}
    354 	return s[:i], s[i:]
    355 }
    356 
    357 // Parse parses rawurl into a URL structure.
    358 // The rawurl may be relative or absolute.
    359 func Parse(rawurl string) (url *URL, err error) {
    360 	// Cut off #frag
    361 	u, frag := split(rawurl, "#", true)
    362 	if url, err = parse(u, false); err != nil {
    363 		return nil, err
    364 	}
    365 	if frag == "" {
    366 		return url, nil
    367 	}
    368 	if url.Fragment, err = unescape(frag, encodeFragment); err != nil {
    369 		return nil, &Error{"parse", rawurl, err}
    370 	}
    371 	return url, nil
    372 }
    373 
    374 // ParseRequestURI parses rawurl into a URL structure.  It assumes that
    375 // rawurl was received in an HTTP request, so the rawurl is interpreted
    376 // only as an absolute URI or an absolute path.
    377 // The string rawurl is assumed not to have a #fragment suffix.
    378 // (Web browsers strip #fragment before sending the URL to a web server.)
    379 func ParseRequestURI(rawurl string) (url *URL, err error) {
    380 	return parse(rawurl, true)
    381 }
    382 
    383 // parse parses a URL from a string in one of two contexts.  If
    384 // viaRequest is true, the URL is assumed to have arrived via an HTTP request,
    385 // in which case only absolute URLs or path-absolute relative URLs are allowed.
    386 // If viaRequest is false, all forms of relative URLs are allowed.
    387 func parse(rawurl string, viaRequest bool) (url *URL, err error) {
    388 	var rest string
    389 
    390 	if rawurl == "" && viaRequest {
    391 		err = errors.New("empty url")
    392 		goto Error
    393 	}
    394 	url = new(URL)
    395 
    396 	if rawurl == "*" {
    397 		url.Path = "*"
    398 		return
    399 	}
    400 
    401 	// Split off possible leading "http:", "mailto:", etc.
    402 	// Cannot contain escaped characters.
    403 	if url.Scheme, rest, err = getscheme(rawurl); err != nil {
    404 		goto Error
    405 	}
    406 	url.Scheme = strings.ToLower(url.Scheme)
    407 
    408 	rest, url.RawQuery = split(rest, "?", true)
    409 
    410 	if !strings.HasPrefix(rest, "/") {
    411 		if url.Scheme != "" {
    412 			// We consider rootless paths per RFC 3986 as opaque.
    413 			url.Opaque = rest
    414 			return url, nil
    415 		}
    416 		if viaRequest {
    417 			err = errors.New("invalid URI for request")
    418 			goto Error
    419 		}
    420 	}
    421 
    422 	if (url.Scheme != "" || !viaRequest && !strings.HasPrefix(rest, "///")) && strings.HasPrefix(rest, "//") {
    423 		var authority string
    424 		authority, rest = split(rest[2:], "/", false)
    425 		url.User, url.Host, err = parseAuthority(authority)
    426 		if err != nil {
    427 			goto Error
    428 		}
    429 	}
    430 	if url.Path, err = unescape(rest, encodePath); err != nil {
    431 		goto Error
    432 	}
    433 	// RawPath is a hint as to the encoding of Path to use
    434 	// in url.EncodedPath. If that method already gets the
    435 	// right answer without RawPath, leave it empty.
    436 	// This will help make sure that people don't rely on it in general.
    437 	if url.EscapedPath() != rest && validEncodedPath(rest) {
    438 		url.RawPath = rest
    439 	}
    440 	return url, nil
    441 
    442 Error:
    443 	return nil, &Error{"parse", rawurl, err}
    444 }
    445 
    446 func parseAuthority(authority string) (user *Userinfo, host string, err error) {
    447 	i := strings.LastIndex(authority, "@")
    448 	if i < 0 {
    449 		host, err = parseHost(authority)
    450 	} else {
    451 		host, err = parseHost(authority[i+1:])
    452 	}
    453 	if err != nil {
    454 		return nil, "", err
    455 	}
    456 	if i < 0 {
    457 		return nil, host, nil
    458 	}
    459 	userinfo := authority[:i]
    460 	if strings.Index(userinfo, ":") < 0 {
    461 		if userinfo, err = unescape(userinfo, encodeUserPassword); err != nil {
    462 			return nil, "", err
    463 		}
    464 		user = User(userinfo)
    465 	} else {
    466 		username, password := split(userinfo, ":", true)
    467 		if username, err = unescape(username, encodeUserPassword); err != nil {
    468 			return nil, "", err
    469 		}
    470 		if password, err = unescape(password, encodeUserPassword); err != nil {
    471 			return nil, "", err
    472 		}
    473 		user = UserPassword(username, password)
    474 	}
    475 	return user, host, nil
    476 }
    477 
    478 // parseHost parses host as an authority without user
    479 // information. That is, as host[:port].
    480 func parseHost(host string) (string, error) {
    481 	litOrName := host
    482 	if strings.HasPrefix(host, "[") {
    483 		// Parse an IP-Literal in RFC 3986 and RFC 6874.
    484 		// E.g., "[fe80::1], "[fe80::1%25en0]"
    485 		//
    486 		// RFC 4007 defines "%" as a delimiter character in
    487 		// the textual representation of IPv6 addresses.
    488 		// Per RFC 6874, in URIs that "%" is encoded as "%25".
    489 		i := strings.LastIndex(host, "]")
    490 		if i < 0 {
    491 			return "", errors.New("missing ']' in host")
    492 		}
    493 		colonPort := host[i+1:]
    494 		if !validOptionalPort(colonPort) {
    495 			return "", fmt.Errorf("invalid port %q after host", colonPort)
    496 		}
    497 		// Parse a host subcomponent without a ZoneID in RFC
    498 		// 6874 because the ZoneID is allowed to use the
    499 		// percent encoded form.
    500 		j := strings.Index(host[:i], "%25")
    501 		if j < 0 {
    502 			litOrName = host[1:i]
    503 		} else {
    504 			litOrName = host[1:j]
    505 		}
    506 	}
    507 
    508 	// A URI containing an IP-Literal without a ZoneID or
    509 	// IPv4address in RFC 3986 and RFC 6847 must not be
    510 	// percent-encoded.
    511 	//
    512 	// A URI containing a DNS registered name in RFC 3986 is
    513 	// allowed to be percent-encoded, though we don't use it for
    514 	// now to avoid messing up with the gap between allowed
    515 	// characters in URI and allowed characters in DNS.
    516 	// See golang.org/issue/7991.
    517 	if strings.Contains(litOrName, "%") {
    518 		return "", errors.New("percent-encoded characters in host")
    519 	}
    520 	var err error
    521 	if host, err = unescape(host, encodeHost); err != nil {
    522 		return "", err
    523 	}
    524 	return host, nil
    525 }
    526 
    527 // EscapedPath returns the escaped form of u.Path.
    528 // In general there are multiple possible escaped forms of any path.
    529 // EscapedPath returns u.RawPath when it is a valid escaping of u.Path.
    530 // Otherwise EscapedPath ignores u.RawPath and computes an escaped
    531 // form on its own.
    532 // The String and RequestURI methods use EscapedPath to construct
    533 // their results.
    534 // In general, code should call EscapedPath instead of
    535 // reading u.RawPath directly.
    536 func (u *URL) EscapedPath() string {
    537 	if u.RawPath != "" && validEncodedPath(u.RawPath) {
    538 		p, err := unescape(u.RawPath, encodePath)
    539 		if err == nil && p == u.Path {
    540 			return u.RawPath
    541 		}
    542 	}
    543 	if u.Path == "*" {
    544 		return "*" // don't escape (Issue 11202)
    545 	}
    546 	return escape(u.Path, encodePath)
    547 }
    548 
    549 // validEncodedPath reports whether s is a valid encoded path.
    550 // It must not contain any bytes that require escaping during path encoding.
    551 func validEncodedPath(s string) bool {
    552 	for i := 0; i < len(s); i++ {
    553 		// RFC 3986, Appendix A.
    554 		// pchar = unreserved / pct-encoded / sub-delims / ":" / "@".
    555 		// shouldEscape is not quite compliant with the RFC,
    556 		// so we check the sub-delims ourselves and let
    557 		// shouldEscape handle the others.
    558 		switch s[i] {
    559 		case '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=', ':', '@':
    560 			// ok
    561 		case '[', ']':
    562 			// ok - not specified in RFC 3986 but left alone by modern browsers
    563 		case '%':
    564 			// ok - percent encoded, will decode
    565 		default:
    566 			if shouldEscape(s[i], encodePath) {
    567 				return false
    568 			}
    569 		}
    570 	}
    571 	return true
    572 }
    573 
    574 // validOptionalPort reports whether port is either an empty string
    575 // or matches /^:\d+$/
    576 func validOptionalPort(port string) bool {
    577 	if port == "" {
    578 		return true
    579 	}
    580 	if port[0] != ':' || len(port) == 1 {
    581 		return false
    582 	}
    583 	for _, b := range port[1:] {
    584 		if b < '0' || b > '9' {
    585 			return false
    586 		}
    587 	}
    588 	return true
    589 }
    590 
    591 // String reassembles the URL into a valid URL string.
    592 // The general form of the result is one of:
    593 //
    594 //	scheme:opaque?query#fragment
    595 //	scheme://userinfo@host/path?query#fragment
    596 //
    597 // If u.Opaque is non-empty, String uses the first form;
    598 // otherwise it uses the second form.
    599 // To obtain the path, String uses u.EncodedPath().
    600 //
    601 // In the second form, the following rules apply:
    602 //	- if u.Scheme is empty, scheme: is omitted.
    603 //	- if u.User is nil, userinfo@ is omitted.
    604 //	- if u.Host is empty, host/ is omitted.
    605 //	- if u.Scheme and u.Host are empty and u.User is nil,
    606 //	   the entire scheme://userinfo@host/ is omitted.
    607 //	- if u.Host is non-empty and u.Path begins with a /,
    608 //	   the form host/path does not add its own /.
    609 //	- if u.RawQuery is empty, ?query is omitted.
    610 //	- if u.Fragment is empty, #fragment is omitted.
    611 func (u *URL) String() string {
    612 	var buf bytes.Buffer
    613 	if u.Scheme != "" {
    614 		buf.WriteString(u.Scheme)
    615 		buf.WriteByte(':')
    616 	}
    617 	if u.Opaque != "" {
    618 		buf.WriteString(u.Opaque)
    619 	} else {
    620 		if u.Scheme != "" || u.Host != "" || u.User != nil {
    621 			buf.WriteString("//")
    622 			if ui := u.User; ui != nil {
    623 				buf.WriteString(ui.String())
    624 				buf.WriteByte('@')
    625 			}
    626 			if h := u.Host; h != "" {
    627 				buf.WriteString(escape(h, encodeHost))
    628 			}
    629 		}
    630 		path := u.EscapedPath()
    631 		if path != "" && path[0] != '/' && u.Host != "" {
    632 			buf.WriteByte('/')
    633 		}
    634 		buf.WriteString(path)
    635 	}
    636 	if u.RawQuery != "" {
    637 		buf.WriteByte('?')
    638 		buf.WriteString(u.RawQuery)
    639 	}
    640 	if u.Fragment != "" {
    641 		buf.WriteByte('#')
    642 		buf.WriteString(escape(u.Fragment, encodeFragment))
    643 	}
    644 	return buf.String()
    645 }
    646 
    647 // Values maps a string key to a list of values.
    648 // It is typically used for query parameters and form values.
    649 // Unlike in the http.Header map, the keys in a Values map
    650 // are case-sensitive.
    651 type Values map[string][]string
    652 
    653 // Get gets the first value associated with the given key.
    654 // If there are no values associated with the key, Get returns
    655 // the empty string. To access multiple values, use the map
    656 // directly.
    657 func (v Values) Get(key string) string {
    658 	if v == nil {
    659 		return ""
    660 	}
    661 	vs, ok := v[key]
    662 	if !ok || len(vs) == 0 {
    663 		return ""
    664 	}
    665 	return vs[0]
    666 }
    667 
    668 // Set sets the key to value. It replaces any existing
    669 // values.
    670 func (v Values) Set(key, value string) {
    671 	v[key] = []string{value}
    672 }
    673 
    674 // Add adds the value to key. It appends to any existing
    675 // values associated with key.
    676 func (v Values) Add(key, value string) {
    677 	v[key] = append(v[key], value)
    678 }
    679 
    680 // Del deletes the values associated with key.
    681 func (v Values) Del(key string) {
    682 	delete(v, key)
    683 }
    684 
    685 // ParseQuery parses the URL-encoded query string and returns
    686 // a map listing the values specified for each key.
    687 // ParseQuery always returns a non-nil map containing all the
    688 // valid query parameters found; err describes the first decoding error
    689 // encountered, if any.
    690 func ParseQuery(query string) (m Values, err error) {
    691 	m = make(Values)
    692 	err = parseQuery(m, query)
    693 	return
    694 }
    695 
    696 func parseQuery(m Values, query string) (err error) {
    697 	for query != "" {
    698 		key := query
    699 		if i := strings.IndexAny(key, "&;"); i >= 0 {
    700 			key, query = key[:i], key[i+1:]
    701 		} else {
    702 			query = ""
    703 		}
    704 		if key == "" {
    705 			continue
    706 		}
    707 		value := ""
    708 		if i := strings.Index(key, "="); i >= 0 {
    709 			key, value = key[:i], key[i+1:]
    710 		}
    711 		key, err1 := QueryUnescape(key)
    712 		if err1 != nil {
    713 			if err == nil {
    714 				err = err1
    715 			}
    716 			continue
    717 		}
    718 		value, err1 = QueryUnescape(value)
    719 		if err1 != nil {
    720 			if err == nil {
    721 				err = err1
    722 			}
    723 			continue
    724 		}
    725 		m[key] = append(m[key], value)
    726 	}
    727 	return err
    728 }
    729 
    730 // Encode encodes the values into ``URL encoded'' form
    731 // ("bar=baz&foo=quux") sorted by key.
    732 func (v Values) Encode() string {
    733 	if v == nil {
    734 		return ""
    735 	}
    736 	var buf bytes.Buffer
    737 	keys := make([]string, 0, len(v))
    738 	for k := range v {
    739 		keys = append(keys, k)
    740 	}
    741 	sort.Strings(keys)
    742 	for _, k := range keys {
    743 		vs := v[k]
    744 		prefix := QueryEscape(k) + "="
    745 		for _, v := range vs {
    746 			if buf.Len() > 0 {
    747 				buf.WriteByte('&')
    748 			}
    749 			buf.WriteString(prefix)
    750 			buf.WriteString(QueryEscape(v))
    751 		}
    752 	}
    753 	return buf.String()
    754 }
    755 
    756 // resolvePath applies special path segments from refs and applies
    757 // them to base, per RFC 3986.
    758 func resolvePath(base, ref string) string {
    759 	var full string
    760 	if ref == "" {
    761 		full = base
    762 	} else if ref[0] != '/' {
    763 		i := strings.LastIndex(base, "/")
    764 		full = base[:i+1] + ref
    765 	} else {
    766 		full = ref
    767 	}
    768 	if full == "" {
    769 		return ""
    770 	}
    771 	var dst []string
    772 	src := strings.Split(full, "/")
    773 	for _, elem := range src {
    774 		switch elem {
    775 		case ".":
    776 			// drop
    777 		case "..":
    778 			if len(dst) > 0 {
    779 				dst = dst[:len(dst)-1]
    780 			}
    781 		default:
    782 			dst = append(dst, elem)
    783 		}
    784 	}
    785 	if last := src[len(src)-1]; last == "." || last == ".." {
    786 		// Add final slash to the joined path.
    787 		dst = append(dst, "")
    788 	}
    789 	return "/" + strings.TrimLeft(strings.Join(dst, "/"), "/")
    790 }
    791 
    792 // IsAbs reports whether the URL is absolute.
    793 func (u *URL) IsAbs() bool {
    794 	return u.Scheme != ""
    795 }
    796 
    797 // Parse parses a URL in the context of the receiver.  The provided URL
    798 // may be relative or absolute.  Parse returns nil, err on parse
    799 // failure, otherwise its return value is the same as ResolveReference.
    800 func (u *URL) Parse(ref string) (*URL, error) {
    801 	refurl, err := Parse(ref)
    802 	if err != nil {
    803 		return nil, err
    804 	}
    805 	return u.ResolveReference(refurl), nil
    806 }
    807 
    808 // ResolveReference resolves a URI reference to an absolute URI from
    809 // an absolute base URI, per RFC 3986 Section 5.2.  The URI reference
    810 // may be relative or absolute.  ResolveReference always returns a new
    811 // URL instance, even if the returned URL is identical to either the
    812 // base or reference. If ref is an absolute URL, then ResolveReference
    813 // ignores base and returns a copy of ref.
    814 func (u *URL) ResolveReference(ref *URL) *URL {
    815 	url := *ref
    816 	if ref.Scheme == "" {
    817 		url.Scheme = u.Scheme
    818 	}
    819 	if ref.Scheme != "" || ref.Host != "" || ref.User != nil {
    820 		// The "absoluteURI" or "net_path" cases.
    821 		url.Path = resolvePath(ref.Path, "")
    822 		return &url
    823 	}
    824 	if ref.Opaque != "" {
    825 		url.User = nil
    826 		url.Host = ""
    827 		url.Path = ""
    828 		return &url
    829 	}
    830 	if ref.Path == "" {
    831 		if ref.RawQuery == "" {
    832 			url.RawQuery = u.RawQuery
    833 			if ref.Fragment == "" {
    834 				url.Fragment = u.Fragment
    835 			}
    836 		}
    837 	}
    838 	// The "abs_path" or "rel_path" cases.
    839 	url.Host = u.Host
    840 	url.User = u.User
    841 	url.Path = resolvePath(u.Path, ref.Path)
    842 	return &url
    843 }
    844 
    845 // Query parses RawQuery and returns the corresponding values.
    846 func (u *URL) Query() Values {
    847 	v, _ := ParseQuery(u.RawQuery)
    848 	return v
    849 }
    850 
    851 // RequestURI returns the encoded path?query or opaque?query
    852 // string that would be used in an HTTP request for u.
    853 func (u *URL) RequestURI() string {
    854 	result := u.Opaque
    855 	if result == "" {
    856 		result = u.EscapedPath()
    857 		if result == "" {
    858 			result = "/"
    859 		}
    860 	} else {
    861 		if strings.HasPrefix(result, "//") {
    862 			result = u.Scheme + ":" + result
    863 		}
    864 	}
    865 	if u.RawQuery != "" {
    866 		result += "?" + u.RawQuery
    867 	}
    868 	return result
    869 }
    870