barometer: update DMA's vendoring packages
[barometer.git] / src / dma / vendor / github.com / streadway / amqp / uri.go
1 // Copyright (c) 2012, Sean Treadway, SoundCloud Ltd.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4 // Source code and contact info at http://github.com/streadway/amqp
5
6 package amqp
7
8 import (
9         "errors"
10         "net"
11         "net/url"
12         "strconv"
13         "strings"
14 )
15
16 var errURIScheme = errors.New("AMQP scheme must be either 'amqp://' or 'amqps://'")
17 var errURIWhitespace = errors.New("URI must not contain whitespace")
18
19 var schemePorts = map[string]int{
20         "amqp":  5672,
21         "amqps": 5671,
22 }
23
24 var defaultURI = URI{
25         Scheme:   "amqp",
26         Host:     "localhost",
27         Port:     5672,
28         Username: "guest",
29         Password: "guest",
30         Vhost:    "/",
31 }
32
33 // URI represents a parsed AMQP URI string.
34 type URI struct {
35         Scheme   string
36         Host     string
37         Port     int
38         Username string
39         Password string
40         Vhost    string
41 }
42
43 // ParseURI attempts to parse the given AMQP URI according to the spec.
44 // See http://www.rabbitmq.com/uri-spec.html.
45 //
46 // Default values for the fields are:
47 //
48 //   Scheme: amqp
49 //   Host: localhost
50 //   Port: 5672
51 //   Username: guest
52 //   Password: guest
53 //   Vhost: /
54 //
55 func ParseURI(uri string) (URI, error) {
56         builder := defaultURI
57
58         if strings.Contains(uri, " ") == true {
59                 return builder, errURIWhitespace
60         }
61
62         u, err := url.Parse(uri)
63         if err != nil {
64                 return builder, err
65         }
66
67         defaultPort, okScheme := schemePorts[u.Scheme]
68
69         if okScheme {
70                 builder.Scheme = u.Scheme
71         } else {
72                 return builder, errURIScheme
73         }
74
75         host := u.Hostname()
76         port := u.Port()
77
78         if host != "" {
79                 builder.Host = host
80         }
81
82         if port != "" {
83                 port32, err := strconv.ParseInt(port, 10, 32)
84                 if err != nil {
85                         return builder, err
86                 }
87                 builder.Port = int(port32)
88         } else {
89                 builder.Port = defaultPort
90         }
91
92         if u.User != nil {
93                 builder.Username = u.User.Username()
94                 if password, ok := u.User.Password(); ok {
95                         builder.Password = password
96                 }
97         }
98
99         if u.Path != "" {
100                 if strings.HasPrefix(u.Path, "/") {
101                         if u.Host == "" && strings.HasPrefix(u.Path, "///") {
102                                 // net/url doesn't handle local context authorities and leaves that up
103                                 // to the scheme handler.  In our case, we translate amqp:/// into the
104                                 // default host and whatever the vhost should be
105                                 if len(u.Path) > 3 {
106                                         builder.Vhost = u.Path[3:]
107                                 }
108                         } else if len(u.Path) > 1 {
109                                 builder.Vhost = u.Path[1:]
110                         }
111                 } else {
112                         builder.Vhost = u.Path
113                 }
114         }
115
116         return builder, nil
117 }
118
119 // PlainAuth returns a PlainAuth structure based on the parsed URI's
120 // Username and Password fields.
121 func (uri URI) PlainAuth() *PlainAuth {
122         return &PlainAuth{
123                 Username: uri.Username,
124                 Password: uri.Password,
125         }
126 }
127
128 // AMQPlainAuth returns a PlainAuth structure based on the parsed URI's
129 // Username and Password fields.
130 func (uri URI) AMQPlainAuth() *AMQPlainAuth {
131         return &AMQPlainAuth{
132                 Username: uri.Username,
133                 Password: uri.Password,
134         }
135 }
136
137 func (uri URI) String() string {
138         authority, err := url.Parse("")
139         if err != nil {
140                 return err.Error()
141         }
142
143         authority.Scheme = uri.Scheme
144
145         if uri.Username != defaultURI.Username || uri.Password != defaultURI.Password {
146                 authority.User = url.User(uri.Username)
147
148                 if uri.Password != defaultURI.Password {
149                         authority.User = url.UserPassword(uri.Username, uri.Password)
150                 }
151         }
152
153         authority.Host = net.JoinHostPort(uri.Host, strconv.Itoa(uri.Port))
154
155         if defaultPort, found := schemePorts[uri.Scheme]; !found || defaultPort != uri.Port {
156                 authority.Host = net.JoinHostPort(uri.Host, strconv.Itoa(uri.Port))
157         } else {
158                 // JoinHostPort() automatically add brackets to the host if it's
159                 // an IPv6 address.
160                 //
161                 // If not port is specified, JoinHostPort() return an IP address in the
162                 // form of "[::1]:", so we use TrimSuffix() to remove the extra ":".
163                 authority.Host = strings.TrimSuffix(net.JoinHostPort(uri.Host, ""), ":")
164         }
165
166         if uri.Vhost != defaultURI.Vhost {
167                 // Make sure net/url does not double escape, e.g.
168                 // "%2F" does not become "%252F".
169                 authority.Path = uri.Vhost
170                 authority.RawPath = url.QueryEscape(uri.Vhost)
171         } else {
172                 authority.Path = "/"
173         }
174
175         return authority.String()
176 }