OLD | NEW |
(Empty) | |
| 1 from __future__ import absolute_import |
| 2 import socket |
| 3 from .wait import wait_for_read |
| 4 from .selectors import HAS_SELECT, SelectorError |
| 5 |
| 6 |
| 7 def 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. |
| 36 def 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 le
ts |
| 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 |
| 88 def _set_socket_options(sock, options): |
| 89 if options is None: |
| 90 return |
| 91 |
| 92 for opt in options: |
| 93 sock.setsockopt(*opt) |
| 94 |
| 95 |
| 96 def 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 |
| 107 def _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 |
| 130 HAS_IPV6 = _has_ipv6('::1') |
OLD | NEW |