Imported Upstream version 4.8.1
[platform/upstream/gcc48.git] / libgo / go / net / url / url.go
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         "sort"
13         "strconv"
14         "strings"
15 )
16
17 // Error reports an error and the operation and URL that caused it.
18 type Error struct {
19         Op  string
20         URL string
21         Err error
22 }
23
24 func (e *Error) Error() string { return e.Op + " " + e.URL + ": " + e.Err.Error() }
25
26 func ishex(c byte) bool {
27         switch {
28         case '0' <= c && c <= '9':
29                 return true
30         case 'a' <= c && c <= 'f':
31                 return true
32         case 'A' <= c && c <= 'F':
33                 return true
34         }
35         return false
36 }
37
38 func unhex(c byte) byte {
39         switch {
40         case '0' <= c && c <= '9':
41                 return c - '0'
42         case 'a' <= c && c <= 'f':
43                 return c - 'a' + 10
44         case 'A' <= c && c <= 'F':
45                 return c - 'A' + 10
46         }
47         return 0
48 }
49
50 type encoding int
51
52 const (
53         encodePath encoding = 1 + iota
54         encodeUserPassword
55         encodeQueryComponent
56         encodeFragment
57 )
58
59 type EscapeError string
60
61 func (e EscapeError) Error() string {
62         return "invalid URL escape " + strconv.Quote(string(e))
63 }
64
65 // Return true if the specified character should be escaped when
66 // appearing in a URL string, according to RFC 3986.
67 // When 'all' is true the full range of reserved characters are matched.
68 func shouldEscape(c byte, mode encoding) bool {
69         // §2.3 Unreserved characters (alphanum)
70         if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' {
71                 return false
72         }
73
74         switch c {
75         case '-', '_', '.', '~': // §2.3 Unreserved characters (mark)
76                 return false
77
78         case '$', '&', '+', ',', '/', ':', ';', '=', '?', '@': // §2.2 Reserved characters (reserved)
79                 // Different sections of the URL allow a few of
80                 // the reserved characters to appear unescaped.
81                 switch mode {
82                 case encodePath: // §3.3
83                         // The RFC allows : @ & = + $ but saves / ; , for assigning
84                         // meaning to individual path segments. This package
85                         // only manipulates the path as a whole, so we allow those
86                         // last two as well. That leaves only ? to escape.
87                         return c == '?'
88
89                 case encodeUserPassword: // §3.2.2
90                         // The RFC allows ; : & = + $ , in userinfo, so we must escape only @ and /.
91                         // The parsing of userinfo treats : as special so we must escape that too.
92                         return c == '@' || c == '/' || c == ':'
93
94                 case encodeQueryComponent: // §3.4
95                         // The RFC reserves (so we must escape) everything.
96                         return true
97
98                 case encodeFragment: // §4.1
99                         // The RFC text is silent but the grammar allows
100                         // everything, so escape nothing.
101                         return false
102                 }
103         }
104
105         // Everything else must be escaped.
106         return true
107 }
108
109 // QueryUnescape does the inverse transformation of QueryEscape, converting
110 // %AB into the byte 0xAB and '+' into ' ' (space). It returns an error if
111 // any % is not followed by two hexadecimal digits.
112 func QueryUnescape(s string) (string, error) {
113         return unescape(s, encodeQueryComponent)
114 }
115
116 // unescape unescapes a string; the mode specifies
117 // which section of the URL string is being unescaped.
118 func unescape(s string, mode encoding) (string, error) {
119         // Count %, check that they're well-formed.
120         n := 0
121         hasPlus := false
122         for i := 0; i < len(s); {
123                 switch s[i] {
124                 case '%':
125                         n++
126                         if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) {
127                                 s = s[i:]
128                                 if len(s) > 3 {
129                                         s = s[0:3]
130                                 }
131                                 return "", EscapeError(s)
132                         }
133                         i += 3
134                 case '+':
135                         hasPlus = mode == encodeQueryComponent
136                         i++
137                 default:
138                         i++
139                 }
140         }
141
142         if n == 0 && !hasPlus {
143                 return s, nil
144         }
145
146         t := make([]byte, len(s)-2*n)
147         j := 0
148         for i := 0; i < len(s); {
149                 switch s[i] {
150                 case '%':
151                         t[j] = unhex(s[i+1])<<4 | unhex(s[i+2])
152                         j++
153                         i += 3
154                 case '+':
155                         if mode == encodeQueryComponent {
156                                 t[j] = ' '
157                         } else {
158                                 t[j] = '+'
159                         }
160                         j++
161                         i++
162                 default:
163                         t[j] = s[i]
164                         j++
165                         i++
166                 }
167         }
168         return string(t), nil
169 }
170
171 // QueryEscape escapes the string so it can be safely placed
172 // inside a URL query.
173 func QueryEscape(s string) string {
174         return escape(s, encodeQueryComponent)
175 }
176
177 func escape(s string, mode encoding) string {
178         spaceCount, hexCount := 0, 0
179         for i := 0; i < len(s); i++ {
180                 c := s[i]
181                 if shouldEscape(c, mode) {
182                         if c == ' ' && mode == encodeQueryComponent {
183                                 spaceCount++
184                         } else {
185                                 hexCount++
186                         }
187                 }
188         }
189
190         if spaceCount == 0 && hexCount == 0 {
191                 return s
192         }
193
194         t := make([]byte, len(s)+2*hexCount)
195         j := 0
196         for i := 0; i < len(s); i++ {
197                 switch c := s[i]; {
198                 case c == ' ' && mode == encodeQueryComponent:
199                         t[j] = '+'
200                         j++
201                 case shouldEscape(c, mode):
202                         t[j] = '%'
203                         t[j+1] = "0123456789ABCDEF"[c>>4]
204                         t[j+2] = "0123456789ABCDEF"[c&15]
205                         j += 3
206                 default:
207                         t[j] = s[i]
208                         j++
209                 }
210         }
211         return string(t)
212 }
213
214 // A URL represents a parsed URL (technically, a URI reference).
215 // The general form represented is:
216 //
217 //      scheme://[userinfo@]host/path[?query][#fragment]
218 //
219 // URLs that do not start with a slash after the scheme are interpreted as:
220 //
221 //      scheme:opaque[?query][#fragment]
222 //
223 type URL struct {
224         Scheme   string
225         Opaque   string    // encoded opaque data
226         User     *Userinfo // username and password information
227         Host     string    // host or host:port
228         Path     string
229         RawQuery string // encoded query values, without '?'
230         Fragment string // fragment for references, without '#'
231 }
232
233 // User returns a Userinfo containing the provided username
234 // and no password set.
235 func User(username string) *Userinfo {
236         return &Userinfo{username, "", false}
237 }
238
239 // UserPassword returns a Userinfo containing the provided username
240 // and password.
241 // This functionality should only be used with legacy web sites.
242 // RFC 2396 warns that interpreting Userinfo this way
243 // ``is NOT RECOMMENDED, because the passing of authentication
244 // information in clear text (such as URI) has proven to be a
245 // security risk in almost every case where it has been used.''
246 func UserPassword(username, password string) *Userinfo {
247         return &Userinfo{username, password, true}
248 }
249
250 // The Userinfo type is an immutable encapsulation of username and
251 // password details for a URL. An existing Userinfo value is guaranteed
252 // to have a username set (potentially empty, as allowed by RFC 2396),
253 // and optionally a password.
254 type Userinfo struct {
255         username    string
256         password    string
257         passwordSet bool
258 }
259
260 // Username returns the username.
261 func (u *Userinfo) Username() string {
262         return u.username
263 }
264
265 // Password returns the password in case it is set, and whether it is set.
266 func (u *Userinfo) Password() (string, bool) {
267         if u.passwordSet {
268                 return u.password, true
269         }
270         return "", false
271 }
272
273 // String returns the encoded userinfo information in the standard form
274 // of "username[:password]".
275 func (u *Userinfo) String() string {
276         s := escape(u.username, encodeUserPassword)
277         if u.passwordSet {
278                 s += ":" + escape(u.password, encodeUserPassword)
279         }
280         return s
281 }
282
283 // Maybe rawurl is of the form scheme:path.
284 // (Scheme must be [a-zA-Z][a-zA-Z0-9+-.]*)
285 // If so, return scheme, path; else return "", rawurl.
286 func getscheme(rawurl string) (scheme, path string, err error) {
287         for i := 0; i < len(rawurl); i++ {
288                 c := rawurl[i]
289                 switch {
290                 case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z':
291                 // do nothing
292                 case '0' <= c && c <= '9' || c == '+' || c == '-' || c == '.':
293                         if i == 0 {
294                                 return "", rawurl, nil
295                         }
296                 case c == ':':
297                         if i == 0 {
298                                 return "", "", errors.New("missing protocol scheme")
299                         }
300                         return rawurl[0:i], rawurl[i+1:], nil
301                 default:
302                         // we have encountered an invalid character,
303                         // so there is no valid scheme
304                         return "", rawurl, nil
305                 }
306         }
307         return "", rawurl, nil
308 }
309
310 // Maybe s is of the form t c u.
311 // If so, return t, c u (or t, u if cutc == true).
312 // If not, return s, "".
313 func split(s string, c byte, cutc bool) (string, string) {
314         for i := 0; i < len(s); i++ {
315                 if s[i] == c {
316                         if cutc {
317                                 return s[0:i], s[i+1:]
318                         }
319                         return s[0:i], s[i:]
320                 }
321         }
322         return s, ""
323 }
324
325 // Parse parses rawurl into a URL structure.
326 // The rawurl may be relative or absolute.
327 func Parse(rawurl string) (url *URL, err error) {
328         // Cut off #frag
329         u, frag := split(rawurl, '#', true)
330         if url, err = parse(u, false); err != nil {
331                 return nil, err
332         }
333         if frag == "" {
334                 return url, nil
335         }
336         if url.Fragment, err = unescape(frag, encodeFragment); err != nil {
337                 return nil, &Error{"parse", rawurl, err}
338         }
339         return url, nil
340 }
341
342 // ParseRequestURI parses rawurl into a URL structure.  It assumes that
343 // rawurl was received in an HTTP request, so the rawurl is interpreted
344 // only as an absolute URI or an absolute path.
345 // The string rawurl is assumed not to have a #fragment suffix.
346 // (Web browsers strip #fragment before sending the URL to a web server.)
347 func ParseRequestURI(rawurl string) (url *URL, err error) {
348         return parse(rawurl, true)
349 }
350
351 // parse parses a URL from a string in one of two contexts.  If
352 // viaRequest is true, the URL is assumed to have arrived via an HTTP request,
353 // in which case only absolute URLs or path-absolute relative URLs are allowed.
354 // If viaRequest is false, all forms of relative URLs are allowed.
355 func parse(rawurl string, viaRequest bool) (url *URL, err error) {
356         var rest string
357
358         if rawurl == "" {
359                 err = errors.New("empty url")
360                 goto Error
361         }
362         url = new(URL)
363
364         if rawurl == "*" {
365                 url.Path = "*"
366                 return
367         }
368
369         // Split off possible leading "http:", "mailto:", etc.
370         // Cannot contain escaped characters.
371         if url.Scheme, rest, err = getscheme(rawurl); err != nil {
372                 goto Error
373         }
374
375         rest, url.RawQuery = split(rest, '?', true)
376
377         if !strings.HasPrefix(rest, "/") {
378                 if url.Scheme != "" {
379                         // We consider rootless paths per RFC 3986 as opaque.
380                         url.Opaque = rest
381                         return url, nil
382                 }
383                 if viaRequest {
384                         err = errors.New("invalid URI for request")
385                         goto Error
386                 }
387         }
388
389         if (url.Scheme != "" || !viaRequest && !strings.HasPrefix(rest, "///")) && strings.HasPrefix(rest, "//") {
390                 var authority string
391                 authority, rest = split(rest[2:], '/', false)
392                 url.User, url.Host, err = parseAuthority(authority)
393                 if err != nil {
394                         goto Error
395                 }
396                 if strings.Contains(url.Host, "%") {
397                         err = errors.New("hexadecimal escape in host")
398                         goto Error
399                 }
400         }
401         if url.Path, err = unescape(rest, encodePath); err != nil {
402                 goto Error
403         }
404         return url, nil
405
406 Error:
407         return nil, &Error{"parse", rawurl, err}
408 }
409
410 func parseAuthority(authority string) (user *Userinfo, host string, err error) {
411         i := strings.LastIndex(authority, "@")
412         if i < 0 {
413                 host = authority
414                 return
415         }
416         userinfo, host := authority[:i], authority[i+1:]
417         if strings.Index(userinfo, ":") < 0 {
418                 if userinfo, err = unescape(userinfo, encodeUserPassword); err != nil {
419                         return
420                 }
421                 user = User(userinfo)
422         } else {
423                 username, password := split(userinfo, ':', true)
424                 if username, err = unescape(username, encodeUserPassword); err != nil {
425                         return
426                 }
427                 if password, err = unescape(password, encodeUserPassword); err != nil {
428                         return
429                 }
430                 user = UserPassword(username, password)
431         }
432         return
433 }
434
435 // String reassembles the URL into a valid URL string.
436 func (u *URL) String() string {
437         var buf bytes.Buffer
438         if u.Scheme != "" {
439                 buf.WriteString(u.Scheme)
440                 buf.WriteByte(':')
441         }
442         if u.Opaque != "" {
443                 buf.WriteString(u.Opaque)
444         } else {
445                 if u.Scheme != "" || u.Host != "" || u.User != nil {
446                         buf.WriteString("//")
447                         if u := u.User; u != nil {
448                                 buf.WriteString(u.String())
449                                 buf.WriteByte('@')
450                         }
451                         if h := u.Host; h != "" {
452                                 buf.WriteString(h)
453                         }
454                 }
455                 buf.WriteString(escape(u.Path, encodePath))
456         }
457         if u.RawQuery != "" {
458                 buf.WriteByte('?')
459                 buf.WriteString(u.RawQuery)
460         }
461         if u.Fragment != "" {
462                 buf.WriteByte('#')
463                 buf.WriteString(escape(u.Fragment, encodeFragment))
464         }
465         return buf.String()
466 }
467
468 // Values maps a string key to a list of values.
469 // It is typically used for query parameters and form values.
470 // Unlike in the http.Header map, the keys in a Values map
471 // are case-sensitive.
472 type Values map[string][]string
473
474 // Get gets the first value associated with the given key.
475 // If there are no values associated with the key, Get returns
476 // the empty string. To access multiple values, use the map
477 // directly.
478 func (v Values) Get(key string) string {
479         if v == nil {
480                 return ""
481         }
482         vs, ok := v[key]
483         if !ok || len(vs) == 0 {
484                 return ""
485         }
486         return vs[0]
487 }
488
489 // Set sets the key to value. It replaces any existing
490 // values.
491 func (v Values) Set(key, value string) {
492         v[key] = []string{value}
493 }
494
495 // Add adds the key to value. It appends to any existing
496 // values associated with key.
497 func (v Values) Add(key, value string) {
498         v[key] = append(v[key], value)
499 }
500
501 // Del deletes the values associated with key.
502 func (v Values) Del(key string) {
503         delete(v, key)
504 }
505
506 // ParseQuery parses the URL-encoded query string and returns
507 // a map listing the values specified for each key.
508 // ParseQuery always returns a non-nil map containing all the
509 // valid query parameters found; err describes the first decoding error
510 // encountered, if any.
511 func ParseQuery(query string) (m Values, err error) {
512         m = make(Values)
513         err = parseQuery(m, query)
514         return
515 }
516
517 func parseQuery(m Values, query string) (err error) {
518         for query != "" {
519                 key := query
520                 if i := strings.IndexAny(key, "&;"); i >= 0 {
521                         key, query = key[:i], key[i+1:]
522                 } else {
523                         query = ""
524                 }
525                 if key == "" {
526                         continue
527                 }
528                 value := ""
529                 if i := strings.Index(key, "="); i >= 0 {
530                         key, value = key[:i], key[i+1:]
531                 }
532                 key, err1 := QueryUnescape(key)
533                 if err1 != nil {
534                         if err == nil {
535                                 err = err1
536                         }
537                         continue
538                 }
539                 value, err1 = QueryUnescape(value)
540                 if err1 != nil {
541                         if err == nil {
542                                 err = err1
543                         }
544                         continue
545                 }
546                 m[key] = append(m[key], value)
547         }
548         return err
549 }
550
551 // Encode encodes the values into ``URL encoded'' form.
552 // e.g. "foo=bar&bar=baz"
553 func (v Values) Encode() string {
554         if v == nil {
555                 return ""
556         }
557         var buf bytes.Buffer
558         keys := make([]string, 0, len(v))
559         for k := range v {
560                 keys = append(keys, k)
561         }
562         sort.Strings(keys)
563         for _, k := range keys {
564                 vs := v[k]
565                 prefix := QueryEscape(k) + "="
566                 for _, v := range vs {
567                         if buf.Len() > 0 {
568                                 buf.WriteByte('&')
569                         }
570                         buf.WriteString(prefix)
571                         buf.WriteString(QueryEscape(v))
572                 }
573         }
574         return buf.String()
575 }
576
577 // resolvePath applies special path segments from refs and applies
578 // them to base, per RFC 2396.
579 func resolvePath(basepath string, refpath string) string {
580         base := strings.Split(basepath, "/")
581         refs := strings.Split(refpath, "/")
582         if len(base) == 0 {
583                 base = []string{""}
584         }
585
586         rm := true
587         for idx, ref := range refs {
588                 switch {
589                 case ref == ".":
590                         if idx == 0 {
591                                 base[len(base)-1] = ""
592                                 rm = true
593                         } else {
594                                 rm = false
595                         }
596                 case ref == "..":
597                         newLen := len(base) - 1
598                         if newLen < 1 {
599                                 newLen = 1
600                         }
601                         base = base[0:newLen]
602                         if rm {
603                                 base[len(base)-1] = ""
604                         }
605                 default:
606                         if idx == 0 || base[len(base)-1] == "" {
607                                 base[len(base)-1] = ref
608                         } else {
609                                 base = append(base, ref)
610                         }
611                         rm = false
612                 }
613         }
614         return strings.Join(base, "/")
615 }
616
617 // IsAbs returns true if the URL is absolute.
618 func (u *URL) IsAbs() bool {
619         return u.Scheme != ""
620 }
621
622 // Parse parses a URL in the context of the receiver.  The provided URL
623 // may be relative or absolute.  Parse returns nil, err on parse
624 // failure, otherwise its return value is the same as ResolveReference.
625 func (u *URL) Parse(ref string) (*URL, error) {
626         refurl, err := Parse(ref)
627         if err != nil {
628                 return nil, err
629         }
630         return u.ResolveReference(refurl), nil
631 }
632
633 // ResolveReference resolves a URI reference to an absolute URI from
634 // an absolute base URI, per RFC 2396 Section 5.2.  The URI reference
635 // may be relative or absolute.  ResolveReference always returns a new
636 // URL instance, even if the returned URL is identical to either the
637 // base or reference. If ref is an absolute URL, then ResolveReference
638 // ignores base and returns a copy of ref.
639 func (u *URL) ResolveReference(ref *URL) *URL {
640         if ref.IsAbs() {
641                 url := *ref
642                 return &url
643         }
644         // relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
645         url := *u
646         url.RawQuery = ref.RawQuery
647         url.Fragment = ref.Fragment
648         if ref.Opaque != "" {
649                 url.Opaque = ref.Opaque
650                 url.User = nil
651                 url.Host = ""
652                 url.Path = ""
653                 return &url
654         }
655         if ref.Host != "" || ref.User != nil {
656                 // The "net_path" case.
657                 url.Host = ref.Host
658                 url.User = ref.User
659         }
660         if strings.HasPrefix(ref.Path, "/") {
661                 // The "abs_path" case.
662                 url.Path = ref.Path
663         } else {
664                 // The "rel_path" case.
665                 path := resolvePath(u.Path, ref.Path)
666                 if !strings.HasPrefix(path, "/") {
667                         path = "/" + path
668                 }
669                 url.Path = path
670         }
671         return &url
672 }
673
674 // Query parses RawQuery and returns the corresponding values.
675 func (u *URL) Query() Values {
676         v, _ := ParseQuery(u.RawQuery)
677         return v
678 }
679
680 // RequestURI returns the encoded path?query or opaque?query
681 // string that would be used in an HTTP request for u.
682 func (u *URL) RequestURI() string {
683         result := u.Opaque
684         if result == "" {
685                 result = escape(u.Path, encodePath)
686                 if result == "" {
687                         result = "/"
688                 }
689         }
690         if u.RawQuery != "" {
691                 result += "?" + u.RawQuery
692         }
693         return result
694 }