1from __future__ import absolute_import 2import socket 3from .wait import wait_for_read 4from .selectors import HAS_SELECT, SelectorError 5 6 7def is_connection_dropped(conn): # Platform-specific 8 """ 9 Returns True if the connection is dropped and should be closed. 10 11 :param conn: 12 :class:`httplib.HTTPConnection` object. 13 14 Note: For platforms like AppEngine, this will always return ``False`` to 15 let the platform handle connection recycling transparently for us. 16 """ 17 sock = getattr(conn, 'sock', False) 18 if sock is False: # Platform-specific: AppEngine 19 return False 20 if sock is None: # Connection already closed (such as by httplib). 21 return True 22 23 if not HAS_SELECT: 24 return False 25 26 try: 27 return bool(wait_for_read(sock, timeout=0.0)) 28 except SelectorError: 29 return True 30 31 32# This function is copied from socket.py in the Python 2.7 standard 33# library test suite. Added to its signature is only `socket_options`. 34# One additional modification is that we avoid binding to IPv6 servers 35# discovered in DNS if the system doesn't have IPv6 functionality. 36def create_connection(address, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, 37 source_address=None, socket_options=None): 38 """Connect to *address* and return the socket object. 39 40 Convenience function. Connect to *address* (a 2-tuple ``(host, 41 port)``) and return the socket object. Passing the optional 42 *timeout* parameter will set the timeout on the socket instance 43 before attempting to connect. If no *timeout* is supplied, the 44 global default timeout setting returned by :func:`getdefaulttimeout` 45 is used. If *source_address* is set it must be a tuple of (host, port) 46 for the socket to bind as a source address before making the connection. 47 An host of '' or port 0 tells the OS to use the default. 48 """ 49 50 host, port = address 51 if host.startswith('['): 52 host = host.strip('[]') 53 err = None 54 55 # Using the value from allowed_gai_family() in the context of getaddrinfo lets 56 # us select whether to work with IPv4 DNS records, IPv6 records, or both. 57 # The original create_connection function always returns all records. 58 family = allowed_gai_family() 59 60 for res in socket.getaddrinfo(host, port, family, socket.SOCK_STREAM): 61 af, socktype, proto, canonname, sa = res 62 sock = None 63 try: 64 sock = socket.socket(af, socktype, proto) 65 66 # If provided, set socket level options before connecting. 67 _set_socket_options(sock, socket_options) 68 69 if timeout is not socket._GLOBAL_DEFAULT_TIMEOUT: 70 sock.settimeout(timeout) 71 if source_address: 72 sock.bind(source_address) 73 sock.connect(sa) 74 return sock 75 76 except socket.error as e: 77 err = e 78 if sock is not None: 79 sock.close() 80 sock = None 81 82 if err is not None: 83 raise err 84 85 raise socket.error("getaddrinfo returns an empty list") 86 87 88def _set_socket_options(sock, options): 89 if options is None: 90 return 91 92 for opt in options: 93 sock.setsockopt(*opt) 94 95 96def allowed_gai_family(): 97 """This function is designed to work in the context of 98 getaddrinfo, where family=socket.AF_UNSPEC is the default and 99 will perform a DNS search for both IPv6 and IPv4 records.""" 100 101 family = socket.AF_INET 102 if HAS_IPV6: 103 family = socket.AF_UNSPEC 104 return family 105 106 107def _has_ipv6(host): 108 """ Returns True if the system can bind an IPv6 address. """ 109 sock = None 110 has_ipv6 = False 111 112 if socket.has_ipv6: 113 # has_ipv6 returns true if cPython was compiled with IPv6 support. 114 # It does not tell us if the system has IPv6 support enabled. To 115 # determine that we must bind to an IPv6 address. 116 # https://github.com/shazow/urllib3/pull/611 117 # https://bugs.python.org/issue658327 118 try: 119 sock = socket.socket(socket.AF_INET6) 120 sock.bind((host, 0)) 121 has_ipv6 = True 122 except Exception: 123 pass 124 125 if sock: 126 sock.close() 127 return has_ipv6 128 129 130HAS_IPV6 = _has_ipv6('::1') 131