~ubuntu-branches/ubuntu/vivid/golang/vivid

« back to all changes in this revision

Viewing changes to src/pkg/net/url/url.go

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2013-08-20 14:06:23 UTC
  • mfrom: (14.1.23 saucy-proposed)
  • Revision ID: package-import@ubuntu.com-20130820140623-b414jfxi3m0qkmrq
Tags: 2:1.1.2-2ubuntu1
* Merge from Debian unstable (LP: #1211749, #1202027). Remaining changes:
  - 016-armhf-elf-header.patch: Use correct ELF header for armhf binaries.
  - d/control,control.cross: Update Breaks/Replaces for Ubuntu
    versions to ensure smooth upgrades, regenerate control file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
7
7
package url
8
8
 
9
9
import (
 
10
        "bytes"
10
11
        "errors"
 
12
        "sort"
11
13
        "strconv"
12
14
        "strings"
13
15
)
218
220
//
219
221
//      scheme:opaque[?query][#fragment]
220
222
//
 
223
// Note that the Path field is stored in decoded form: /%47%6f%2f becomes /Go/.
 
224
// A consequence is that it is impossible to tell which slashes in the Path were
 
225
// slashes in the raw URL and which were %2f. This distinction is rarely important,
 
226
// but when it is a client must use other routines to parse the raw URL or construct
 
227
// the parsed URL. For example, an HTTP server can consult req.RequestURI, and
 
228
// an HTTP client can use URL{Host: "example.com", Opaque: "//example.com/Go%2f"}
 
229
// instead of URL{Host: "example.com", Path: "/Go/"}.
221
230
type URL struct {
222
231
        Scheme   string
223
232
        Opaque   string    // encoded opaque data
224
233
        User     *Userinfo // username and password information
225
 
        Host     string
 
234
        Host     string    // host or host:port
226
235
        Path     string
227
236
        RawQuery string // encoded query values, without '?'
228
237
        Fragment string // fragment for references, without '#'
308
317
// Maybe s is of the form t c u.
309
318
// If so, return t, c u (or t, u if cutc == true).
310
319
// If not, return s, "".
311
 
func split(s string, c byte, cutc bool) (string, string) {
312
 
        for i := 0; i < len(s); i++ {
313
 
                if s[i] == c {
314
 
                        if cutc {
315
 
                                return s[0:i], s[i+1:]
316
 
                        }
317
 
                        return s[0:i], s[i:]
318
 
                }
319
 
        }
320
 
        return s, ""
 
320
func split(s string, c string, cutc bool) (string, string) {
 
321
        i := strings.Index(s, c)
 
322
        if i < 0 {
 
323
                return s, ""
 
324
        }
 
325
        if cutc {
 
326
                return s[0:i], s[i+len(c):]
 
327
        }
 
328
        return s[0:i], s[i:]
321
329
}
322
330
 
323
331
// Parse parses rawurl into a URL structure.
324
332
// The rawurl may be relative or absolute.
325
333
func Parse(rawurl string) (url *URL, err error) {
326
334
        // Cut off #frag
327
 
        u, frag := split(rawurl, '#', true)
 
335
        u, frag := split(rawurl, "#", true)
328
336
        if url, err = parse(u, false); err != nil {
329
337
                return nil, err
330
338
        }
353
361
func parse(rawurl string, viaRequest bool) (url *URL, err error) {
354
362
        var rest string
355
363
 
356
 
        if rawurl == "" {
 
364
        if rawurl == "" && viaRequest {
357
365
                err = errors.New("empty url")
358
366
                goto Error
359
367
        }
360
368
        url = new(URL)
361
369
 
 
370
        if rawurl == "*" {
 
371
                url.Path = "*"
 
372
                return
 
373
        }
 
374
 
362
375
        // Split off possible leading "http:", "mailto:", etc.
363
376
        // Cannot contain escaped characters.
364
377
        if url.Scheme, rest, err = getscheme(rawurl); err != nil {
365
378
                goto Error
366
379
        }
 
380
        url.Scheme = strings.ToLower(url.Scheme)
367
381
 
368
 
        rest, url.RawQuery = split(rest, '?', true)
 
382
        rest, url.RawQuery = split(rest, "?", true)
369
383
 
370
384
        if !strings.HasPrefix(rest, "/") {
371
385
                if url.Scheme != "" {
379
393
                }
380
394
        }
381
395
 
382
 
        if (url.Scheme != "" || !viaRequest) && strings.HasPrefix(rest, "//") && !strings.HasPrefix(rest, "///") {
 
396
        if (url.Scheme != "" || !viaRequest && !strings.HasPrefix(rest, "///")) && strings.HasPrefix(rest, "//") {
383
397
                var authority string
384
 
                authority, rest = split(rest[2:], '/', false)
 
398
                authority, rest = split(rest[2:], "/", false)
385
399
                url.User, url.Host, err = parseAuthority(authority)
386
400
                if err != nil {
387
401
                        goto Error
413
427
                }
414
428
                user = User(userinfo)
415
429
        } else {
416
 
                username, password := split(userinfo, ':', true)
 
430
                username, password := split(userinfo, ":", true)
417
431
                if username, err = unescape(username, encodeUserPassword); err != nil {
418
432
                        return
419
433
                }
427
441
 
428
442
// String reassembles the URL into a valid URL string.
429
443
func (u *URL) String() string {
430
 
        // TODO: Rewrite to use bytes.Buffer
431
 
        result := ""
 
444
        var buf bytes.Buffer
432
445
        if u.Scheme != "" {
433
 
                result += u.Scheme + ":"
 
446
                buf.WriteString(u.Scheme)
 
447
                buf.WriteByte(':')
434
448
        }
435
449
        if u.Opaque != "" {
436
 
                result += u.Opaque
 
450
                buf.WriteString(u.Opaque)
437
451
        } else {
438
 
                if u.Host != "" || u.User != nil {
439
 
                        result += "//"
 
452
                if u.Scheme != "" || u.Host != "" || u.User != nil {
 
453
                        buf.WriteString("//")
440
454
                        if u := u.User; u != nil {
441
 
                                result += u.String() + "@"
442
 
                        }
443
 
                        result += u.Host
 
455
                                buf.WriteString(u.String())
 
456
                                buf.WriteByte('@')
 
457
                        }
 
458
                        if h := u.Host; h != "" {
 
459
                                buf.WriteString(h)
 
460
                        }
444
461
                }
445
 
                result += escape(u.Path, encodePath)
 
462
                buf.WriteString(escape(u.Path, encodePath))
446
463
        }
447
464
        if u.RawQuery != "" {
448
 
                result += "?" + u.RawQuery
 
465
                buf.WriteByte('?')
 
466
                buf.WriteString(u.RawQuery)
449
467
        }
450
468
        if u.Fragment != "" {
451
 
                result += "#" + escape(u.Fragment, encodeFragment)
 
469
                buf.WriteByte('#')
 
470
                buf.WriteString(escape(u.Fragment, encodeFragment))
452
471
        }
453
 
        return result
 
472
        return buf.String()
454
473
}
455
474
 
456
475
// Values maps a string key to a list of values.
519
538
                }
520
539
                key, err1 := QueryUnescape(key)
521
540
                if err1 != nil {
522
 
                        err = err1
 
541
                        if err == nil {
 
542
                                err = err1
 
543
                        }
523
544
                        continue
524
545
                }
525
546
                value, err1 = QueryUnescape(value)
526
547
                if err1 != nil {
527
 
                        err = err1
 
548
                        if err == nil {
 
549
                                err = err1
 
550
                        }
528
551
                        continue
529
552
                }
530
553
                m[key] = append(m[key], value)
538
561
        if v == nil {
539
562
                return ""
540
563
        }
541
 
        parts := make([]string, 0, len(v)) // will be large enough for most uses
542
 
        for k, vs := range v {
 
564
        var buf bytes.Buffer
 
565
        keys := make([]string, 0, len(v))
 
566
        for k := range v {
 
567
                keys = append(keys, k)
 
568
        }
 
569
        sort.Strings(keys)
 
570
        for _, k := range keys {
 
571
                vs := v[k]
543
572
                prefix := QueryEscape(k) + "="
544
573
                for _, v := range vs {
545
 
                        parts = append(parts, prefix+QueryEscape(v))
 
574
                        if buf.Len() > 0 {
 
575
                                buf.WriteByte('&')
 
576
                        }
 
577
                        buf.WriteString(prefix)
 
578
                        buf.WriteString(QueryEscape(v))
546
579
                }
547
580
        }
548
 
        return strings.Join(parts, "&")
 
581
        return buf.String()
549
582
}
550
583
 
551
584
// resolvePath applies special path segments from refs and applies
552
 
// them to base, per RFC 2396.
553
 
func resolvePath(basepath string, refpath string) string {
554
 
        base := strings.Split(basepath, "/")
555
 
        refs := strings.Split(refpath, "/")
556
 
        if len(base) == 0 {
557
 
                base = []string{""}
558
 
        }
559
 
        for idx, ref := range refs {
560
 
                switch {
561
 
                case ref == ".":
562
 
                        base[len(base)-1] = ""
563
 
                case ref == "..":
564
 
                        newLen := len(base) - 1
565
 
                        if newLen < 1 {
566
 
                                newLen = 1
 
585
// them to base, per RFC 3986.
 
586
func resolvePath(base, ref string) string {
 
587
        var full string
 
588
        if ref == "" {
 
589
                full = base
 
590
        } else if ref[0] != '/' {
 
591
                i := strings.LastIndex(base, "/")
 
592
                full = base[:i+1] + ref
 
593
        } else {
 
594
                full = ref
 
595
        }
 
596
        if full == "" {
 
597
                return ""
 
598
        }
 
599
        var dst []string
 
600
        src := strings.Split(full, "/")
 
601
        for _, elem := range src {
 
602
                switch elem {
 
603
                case ".":
 
604
                        // drop
 
605
                case "..":
 
606
                        if len(dst) > 0 {
 
607
                                dst = dst[:len(dst)-1]
567
608
                        }
568
 
                        base = base[0:newLen]
569
 
                        base[len(base)-1] = ""
570
609
                default:
571
 
                        if idx == 0 || base[len(base)-1] == "" {
572
 
                                base[len(base)-1] = ref
573
 
                        } else {
574
 
                                base = append(base, ref)
575
 
                        }
 
610
                        dst = append(dst, elem)
576
611
                }
577
612
        }
578
 
        return strings.Join(base, "/")
 
613
        if last := src[len(src)-1]; last == "." || last == ".." {
 
614
                // Add final slash to the joined path.
 
615
                dst = append(dst, "")
 
616
        }
 
617
        return "/" + strings.TrimLeft(strings.Join(dst, "/"), "/")
579
618
}
580
619
 
581
620
// IsAbs returns true if the URL is absolute.
595
634
}
596
635
 
597
636
// ResolveReference resolves a URI reference to an absolute URI from
598
 
// an absolute base URI, per RFC 2396 Section 5.2.  The URI reference
 
637
// an absolute base URI, per RFC 3986 Section 5.2.  The URI reference
599
638
// may be relative or absolute.  ResolveReference always returns a new
600
639
// URL instance, even if the returned URL is identical to either the
601
640
// base or reference. If ref is an absolute URL, then ResolveReference
602
641
// ignores base and returns a copy of ref.
603
642
func (u *URL) ResolveReference(ref *URL) *URL {
604
 
        if ref.IsAbs() {
605
 
                url := *ref
 
643
        url := *ref
 
644
        if ref.Scheme == "" {
 
645
                url.Scheme = u.Scheme
 
646
        }
 
647
        if ref.Scheme != "" || ref.Host != "" || ref.User != nil {
 
648
                // The "absoluteURI" or "net_path" cases.
 
649
                url.Path = resolvePath(ref.Path, "")
606
650
                return &url
607
651
        }
608
 
        // relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
609
 
        url := *u
610
 
        url.RawQuery = ref.RawQuery
611
 
        url.Fragment = ref.Fragment
612
652
        if ref.Opaque != "" {
613
 
                url.Opaque = ref.Opaque
614
653
                url.User = nil
615
654
                url.Host = ""
616
655
                url.Path = ""
617
656
                return &url
618
657
        }
619
 
        if ref.Host != "" || ref.User != nil {
620
 
                // The "net_path" case.
621
 
                url.Host = ref.Host
622
 
                url.User = ref.User
623
 
        }
624
 
        if strings.HasPrefix(ref.Path, "/") {
625
 
                // The "abs_path" case.
626
 
                url.Path = ref.Path
627
 
        } else {
628
 
                // The "rel_path" case.
629
 
                path := resolvePath(u.Path, ref.Path)
630
 
                if !strings.HasPrefix(path, "/") {
631
 
                        path = "/" + path
 
658
        if ref.Path == "" {
 
659
                if ref.RawQuery == "" {
 
660
                        url.RawQuery = u.RawQuery
 
661
                        if ref.Fragment == "" {
 
662
                                url.Fragment = u.Fragment
 
663
                        }
632
664
                }
633
 
                url.Path = path
634
665
        }
 
666
        // The "abs_path" or "rel_path" cases.
 
667
        url.Host = u.Host
 
668
        url.User = u.User
 
669
        url.Path = resolvePath(u.Path, ref.Path)
635
670
        return &url
636
671
}
637
672
 
650
685
                if result == "" {
651
686
                        result = "/"
652
687
                }
 
688
        } else {
 
689
                if strings.HasPrefix(result, "//") {
 
690
                        result = u.Scheme + ":" + result
 
691
                }
653
692
        }
654
693
        if u.RawQuery != "" {
655
694
                result += "?" + u.RawQuery