""" websocket - WebSocket client library for Python Copyright (C) 2010 Hiroki Ohtani(liris) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA """ import os import socket import struct from six.moves.urllib.parse import urlparse __all__ = ["parse_url", "get_proxy_info"] def parse_url(url): """ parse url and the result is tuple of (hostname, port, resource path and the flag of secure mode) url: url string. """ if ":" not in url: raise ValueError("url is invalid") scheme, url = url.split(":", 1) parsed = urlparse(url, scheme="ws") if parsed.hostname: hostname = parsed.hostname else: raise ValueError("hostname is invalid") port = 0 if parsed.port: port = parsed.port is_secure = False if scheme == "ws": if not port: port = 80 elif scheme == "wss": is_secure = True if not port: port = 443 else: raise ValueError("scheme %s is invalid" % scheme) if parsed.path: resource = parsed.path else: resource = "/" if parsed.query: resource += "?" + parsed.query return hostname, port, resource, is_secure DEFAULT_NO_PROXY_HOST = ["localhost", "127.0.0.1"] def _is_ip_address(addr): try: socket.inet_aton(addr) except socket.error: return False else: return True def _is_subnet_address(hostname): try: addr, netmask = hostname.split("/") return _is_ip_address(addr) and 0 <= int(netmask) < 32 except ValueError: return False def _is_address_in_network(ip, net): ipaddr = struct.unpack('I', socket.inet_aton(ip))[0] netaddr, bits = net.split('/') netmask = struct.unpack('I', socket.inet_aton(netaddr))[0] & ((2 << int(bits) - 1) - 1) return ipaddr & netmask == netmask def _is_no_proxy_host(hostname, no_proxy): if not no_proxy: v = os.environ.get("no_proxy", "").replace(" ", "") no_proxy = v.split(",") if not no_proxy: no_proxy = DEFAULT_NO_PROXY_HOST if hostname in no_proxy: return True elif _is_ip_address(hostname): return any([_is_address_in_network(hostname, subnet) for subnet in no_proxy if _is_subnet_address(subnet)]) return False def get_proxy_info( hostname, is_secure, proxy_host=None, proxy_port=0, proxy_auth=None, no_proxy=None, proxy_type='http'): """ try to retrieve proxy host and port from environment if not provided in options. result is (proxy_host, proxy_port, proxy_auth). proxy_auth is tuple of username and password of proxy authentication information. hostname: websocket server name. is_secure: is the connection secure? (wss) looks for "https_proxy" in env before falling back to "http_proxy" options: "http_proxy_host" - http proxy host name. "http_proxy_port" - http proxy port. "http_no_proxy" - host names, which doesn't use proxy. "http_proxy_auth" - http proxy auth information. tuple of username and password. default is None "proxy_type" - if set to "socks5" PySocks wrapper will be used in place of a http proxy. default is "http" """ if _is_no_proxy_host(hostname, no_proxy): return None, 0, None if proxy_host: port = proxy_port auth = proxy_auth return proxy_host, port, auth env_keys = ["http_proxy"] if is_secure: env_keys.insert(0, "https_proxy") for key in env_keys: value = os.environ.get(key, None) if value: proxy = urlparse(value) auth = (proxy.username, proxy.password) if proxy.username else None return proxy.hostname, proxy.port, auth return None, 0, None