Package proton :: Module _url
[frames] | no frames]

Source Code for Module proton._url

  1  # 
  2  # Licensed to the Apache Software Foundation (ASF) under one 
  3  # or more contributor license agreements.  See the NOTICE file 
  4  # distributed with this work for additional information 
  5  # regarding copyright ownership.  The ASF licenses this file 
  6  # to you under the Apache License, Version 2.0 (the 
  7  # "License"); you may not use this file except in compliance 
  8  # with the License.  You may obtain a copy of the License at 
  9  # 
 10  #   http://www.apache.org/licenses/LICENSE-2.0 
 11  # 
 12  # Unless required by applicable law or agreed to in writing, 
 13  # software distributed under the License is distributed on an 
 14  # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
 15  # KIND, either express or implied.  See the License for the 
 16  # specific language governing permissions and limitations 
 17  # under the License. 
 18  # 
 19   
 20  from __future__ import absolute_import 
 21   
 22  import socket 
 23  from ._compat import urlparse, urlunparse, quote, unquote 
24 25 26 -class Url(object):
27 """ 28 Simple URL parser/constructor, handles URLs of the form: 29 30 <scheme>://<user>:<password>@<host>:<port>/<path> 31 32 All components can be None if not specified in the URL string. 33 34 The port can be specified as a service name, e.g. 'amqp' in the 35 URL string but Url.port always gives the integer value. 36 37 Warning: The placement of user and password in URLs is not 38 recommended. It can result in credentials leaking out in program 39 logs. Use connection configuration attributes instead. 40 41 @ivar scheme: Url scheme e.g. 'amqp' or 'amqps' 42 @ivar user: Username 43 @ivar password: Password 44 @ivar host: Host name, ipv6 literal or ipv4 dotted quad. 45 @ivar port: Integer port. 46 @ivar host_port: Returns host:port 47 """ 48 49 AMQPS = "amqps" 50 AMQP = "amqp" 51
52 - class Port(int):
53 """An integer port number that can be constructed from a service name string""" 54
55 - def __new__(cls, value):
56 """@param value: integer port number or string service name.""" 57 port = super(Url.Port, cls).__new__(cls, cls._port_int(value)) 58 setattr(port, 'name', str(value)) 59 return port
60
61 - def __eq__(self, x):
62 return str(self) == x or int(self) == x
63
64 - def __ne__(self, x):
65 return not self == x
66
67 - def __str__(self):
68 return str(self.name)
69 70 @staticmethod
71 - def _port_int(value):
72 """Convert service, an integer or a service name, into an integer port number.""" 73 try: 74 return int(value) 75 except ValueError: 76 try: 77 return socket.getservbyname(value) 78 except socket.error: 79 # Not every system has amqp/amqps defined as a service 80 if value == Url.AMQPS: 81 return 5671 82 elif value == Url.AMQP: 83 return 5672 84 else: 85 raise ValueError("Not a valid port number or service name: '%s'" % value)
86
87 - def __init__(self, url=None, defaults=True, **kwargs):
88 """ 89 @param url: URL string to parse. 90 @param defaults: If true, fill in missing default values in the URL. 91 If false, you can fill them in later by calling self.defaults() 92 @param kwargs: scheme, user, password, host, port, path. 93 If specified, replaces corresponding part in url string. 94 """ 95 if isinstance(url, Url): 96 self.scheme = url.scheme 97 self.username = url.username 98 self.password = url.password 99 self.host = url.host 100 self._port = url._port 101 self._path = url._path 102 self._params = url._params 103 self._query = url._query 104 self._fragment = url._fragment 105 elif url: 106 if not url.startswith('//'): 107 p = url.partition(':') 108 if '/' in p[0] or not p[2].startswith('//'): 109 url = '//' + url 110 u = urlparse(url) 111 if not u: raise ValueError("Invalid URL '%s'" % url) 112 self.scheme = None if not u.scheme else u.scheme 113 self.username = u.username and unquote(u.username) 114 self.password = u.password and unquote(u.password) 115 self.host = None if not u.hostname else u.hostname 116 self._port = self._parse_port(u.netloc) 117 self._path = None if not u.path else u.path 118 self._params = u.params 119 self._query = u.query 120 self._fragment = u.fragment 121 else: 122 self.scheme = None 123 self.username = None 124 self.password = None 125 self.host = None 126 self._port = None 127 self._path = None 128 self._params = None 129 self._query = None 130 self._fragment = None 131 for k in kwargs: # Let kwargs override values parsed from url 132 getattr(self, k) # Check for invalid kwargs 133 setattr(self, k, kwargs[k]) 134 if defaults: self.defaults()
135 136 @staticmethod
137 - def _parse_port(nl):
138 netloc = nl.split('@')[-1].split(']')[-1] 139 if ':' in netloc: 140 port = netloc.split(':')[1] 141 if port: 142 return port 143 return None
144 145 @property
146 - def path(self):
147 return self._path if not self._path or self._path[0] != '/' else self._path[1:]
148 149 @path.setter
150 - def path(self, p):
151 self._path = p if p[0] == '/' else '/' + p
152 153 @property
154 - def port(self):
155 return self._port and Url.Port(self._port)
156 157 @port.setter
158 - def port(self, p):
159 self._port = p
160 161 @property
162 - def _netloc(self):
163 hostport = '' 164 if self.host: 165 hostport = self.host 166 if self._port: 167 hostport += ':' 168 hostport += str(self._port) 169 userpart = '' 170 if self.username: 171 userpart += quote(self.username) 172 if self.password: 173 userpart += ':' 174 userpart += quote(self.password) 175 if self.username or self.password: 176 userpart += '@' 177 return userpart + hostport
178
179 - def __str__(self):
180 if self.scheme \ 181 and not self._netloc and not self._path \ 182 and not self._params and not self._query and not self._fragment: 183 return self.scheme + '://' 184 return urlunparse((self.scheme or '', self._netloc or '', self._path or '', 185 self._params or '', self._query or '', self._fragment or ''))
186
187 - def __repr__(self):
188 return "Url('%s')" % self
189
190 - def __eq__(self, x):
191 return str(self) == str(x)
192
193 - def __ne__(self, x):
194 return not self == x
195
196 - def defaults(self):
197 """ 198 Fill in missing values (scheme, host or port) with defaults 199 @return: self 200 """ 201 self.scheme = self.scheme or self.AMQP 202 self.host = self.host or '0.0.0.0' 203 self._port = self._port or self.Port(self.scheme) 204 return self
205