def connect(self): self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) self.stream = SSLIOStream(self.s, ssl_options=dict(certfile=self.certfile)) self.stream.connect(self.host, self._on_connect) self.stream.read_until_close(self._on_close, streaming_callback=self._on_read)
def _handle_connection(self, connection, address): if self.ssl_options is not None: assert ssl, "Python 2.6+ and OpenSSL required for SSL" try: connection = ssl_wrap_socket(connection, self.ssl_options, server_side=True, do_handshake_on_connect=False) except ssl.SSLError as err: if err.args[0] == ssl.SSL_ERROR_EOF: return connection.close() else: raise except socket.error as err: if errno_from_exception(err) in (errno.ECONNABORTED, errno.EINVAL): return connection.close() else: raise try: if self.ssl_options is not None: stream = SSLIOStream(connection, io_loop=self.io_loop, max_buffer_size=self.max_buffer_size, read_chunk_size=self.read_chunk_size) else: stream = IOStream(connection, io_loop=self.io_loop, max_buffer_size=self.max_buffer_size, read_chunk_size=self.read_chunk_size) self.handle_stream(stream, address) except Exception: self.handle_exception(sys.exc_info())
def on_client_read(self, data): self.flush() request_info = self.on_request(data) logger.debug( "[%s] Got request for %s://%s:%s", self._client_address, request_info.scheme, request_info.target_host, request_info.target_port, ) if self._server_stream is None: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) stream = ( SSLIOStream(s, ssl_options={}) if request_info.scheme == "https" else IOStream(s) ) stream.connect( (request_info.target_host, request_info.target_port), self.on_server_connect, server_hostname=request_info.target_host, ) self._server_stream = StreamWrapper(stream, self.on_server_close, True) self._server_stream.write(request_info.data)
def connect_to_server(self, server_cls): server = client = None try: sock, port = bind_unused_port() server = server_cls(ssl_options=_server_ssl_options()) server.add_socket(sock) ssl_ctx = ssl.create_default_context(ssl.Purpose.SERVER_AUTH) ssl_ctx.check_hostname = False ssl_ctx.verify_mode = ssl.CERT_NONE # These tests fail with ConnectionAbortedErrors with TLS # 1.3 on windows python 3.7.4 (which includes an upgrade # to openssl 1.1.c. Other platforms might be affected with # newer openssl too). Disable it until we figure out # what's up. # Update 2021-12-28: Still happening with Python 3.10 on # Windows. OP_NO_TLSv1_3 now raises a DeprecationWarning. with ignore_deprecation(): ssl_ctx.options |= getattr(ssl, "OP_NO_TLSv1_3", 0) client = SSLIOStream(socket.socket(), ssl_options=ssl_ctx) yield client.connect(("127.0.0.1", port)) self.assertIsNotNone(client.socket.cipher()) finally: if server is not None: server.stop() if client is not None: client.close()
def __init__(self, io_loop, request, callback): self.start_time = time.time() self.io_loop = io_loop self.request = request self.callback = callback self.code = None self.headers = None self.chunks = None self._decompressor = None # Timeout handle returned by IOLoop.add_timeout self._timeout = None with stack_context.StackContext(self.cleanup): parsed = urlparse.urlsplit(self.request.url) if ":" in parsed.netloc: host, _, port = parsed.netloc.partition(":") port = int(port) else: host = parsed.netloc port = 443 if parsed.scheme == "https" else 80 if parsed.scheme == "https": # TODO: cert verification, etc self.stream = SSLIOStream(socket.socket(), io_loop=self.io_loop) else: self.stream = IOStream(socket.socket(), io_loop=self.io_loop) timeout = min(request.connect_timeout, request.request_timeout) if timeout: self._connect_timeout = self.io_loop.add_timeout( self.start_time + timeout, self._on_timeout) self.stream.connect((host, port), functools.partial(self._on_connect, parsed))
def _handle_connection(self, connection, address): if self.ssl_options is not None: assert ssl, "Python 2.6+ and OpenSSL required for SSL" try: connection = ssl.wrap_socket(connection, server_side=True, do_handshake_on_connect=False, **self.ssl_options) except ssl.SSLError as err: if err.args[0] == ssl.SSL_ERROR_EOF: return connection.close() else: raise except socket.error as err: if err.args[0] == errno.ECONNABORTED: return connection.close() else: raise try: if self.ssl_options is not None: stream = SSLIOStream(connection, io_loop=self.io_loop) else: stream = IOStream(connection, io_loop=self.io_loop) self.handle_stream(stream, address) except Exception: logging.error("Error in connection callback", exc_info=True)
def _make_server_iostream(self, connection, **kwargs): connection = ssl.wrap_socket( connection, server_side=True, do_handshake_on_connect=False, **_server_ssl_options() ) return SSLIOStream(connection, **kwargs)
def _make_server_iostream(self, connection, **kwargs): ssl_ctx = ssl_options_to_context(_server_ssl_options(), server_side=True) connection = ssl_ctx.wrap_socket( connection, server_side=True, do_handshake_on_connect=False, ) return SSLIOStream(connection, **kwargs)
def _make_server_iostream(self, connection, **kwargs): context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) context.load_cert_chain( os.path.join(os.path.dirname(__file__), 'test.crt'), os.path.join(os.path.dirname(__file__), 'test.key')) connection = ssl_wrap_socket(connection, context, server_side=True, do_handshake_on_connect=False) return SSLIOStream(connection, io_loop=self.io_loop, **kwargs)
def _make_server_iostream(self, connection, **kwargs): ssl_options = dict( certfile=os.path.join(os.path.dirname(__file__), 'test.crt'), keyfile=os.path.join(os.path.dirname(__file__), 'test.key'), ) connection = ssl.wrap_socket(connection, server_side=True, do_handshake_on_connect=False, **ssl_options) return SSLIOStream(connection, io_loop=self.io_loop, **kwargs)
def _on_resolve(self, addrinfo): af, sockaddr = addrinfo[0] if self.parsed.scheme == "https": ssl_options = {} if self.request.validate_cert: ssl_options["cert_reqs"] = ssl.CERT_REQUIRED if self.request.ca_certs is not None: ssl_options["ca_certs"] = self.request.ca_certs else: ssl_options["ca_certs"] = _DEFAULT_CA_CERTS if self.request.client_key is not None: ssl_options["keyfile"] = self.request.client_key if self.request.client_cert is not None: ssl_options["certfile"] = self.request.client_cert # SSL interoperability is tricky. We want to disable # SSLv2 for security reasons; it wasn't disabled by default # until openssl 1.0. The best way to do this is to use # the SSL_OP_NO_SSLv2, but that wasn't exposed to python # until 3.2. Python 2.7 adds the ciphers argument, which # can also be used to disable SSLv2. As a last resort # on python 2.6, we set ssl_version to SSLv3. This is # more narrow than we'd like since it also breaks # compatibility with servers configured for TLSv1 only, # but nearly all servers support SSLv3: # http://blog.ivanristic.com/2011/09/ssl-survey-protocol-support.html if sys.version_info >= (2, 7): ssl_options["ciphers"] = "DEFAULT:!SSLv2" else: # This is really only necessary for pre-1.0 versions # of openssl, but python 2.6 doesn't expose version # information. ssl_options["ssl_version"] = ssl.PROTOCOL_SSLv3 self.stream = SSLIOStream(socket.socket(af), io_loop=self.io_loop, ssl_options=ssl_options, max_buffer_size=self.max_buffer_size) else: self.stream = IOStream(socket.socket(af), io_loop=self.io_loop, max_buffer_size=self.max_buffer_size) timeout = min(self.request.connect_timeout, self.request.request_timeout) if timeout: self._timeout = self.io_loop.add_timeout( self.start_time + timeout, stack_context.wrap(self._on_timeout)) self.stream.set_close_callback(self._on_close) # ipv6 addresses are broken (in self.parsed.hostname) until # 2.7, here is correctly parsed value calculated in __init__ self.stream.connect(sockaddr, self._on_connect, server_hostname=self.parsed_hostname)
def _make_server_iostream(self, connection, **kwargs): context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) context.load_cert_chain( os.path.join(os.path.dirname(__file__), "test.crt"), os.path.join(os.path.dirname(__file__), "test.key"), ) connection = ssl_wrap_socket(connection, context, server_side=True, do_handshake_on_connect=False) return SSLIOStream(connection, **kwargs)
def connect(self): self.__stream = SSLIOStream( socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0), io_loop=self.__io_loop, ssl_options={ 'ssl_version': ssl.PROTOCOL_TLSv1, # 'ca_certs': path.join(CERT_ROOT, 'entrust_root_ca.pem'), 'certfile': self.__cert, # 'cert_reqs': ssl.CERT_REQUIRED }) self.__stream.set_close_callback(self._on_close) self.__stream.connect(self.__svr_addr, self.__on_connect)
def _handle_connection(self, connection: socket.socket, address: Any) -> None: # 此处获取到的是sock.accept() 返回的两个数据, 也就是request和address嘛 # 每当有用户建立连接, 都会进入此处 if self.ssl_options is not None: assert ssl, "Python 2.6+ and OpenSSL required for SSL" try: connection = ssl_wrap_socket( connection, self.ssl_options, server_side=True, do_handshake_on_connect=False, ) except ssl.SSLError as err: if err.args[0] == ssl.SSL_ERROR_EOF: return connection.close() else: raise except socket.error as err: # If the connection is closed immediately after it is created # (as in a port scan), we can get one of several errors. # wrap_socket makes an internal call to getpeername, # which may return either EINVAL (Mac OS X) or ENOTCONN # (Linux). If it returns ENOTCONN, this error is # silently swallowed by the ssl module, so we need to # catch another error later on (AttributeError in # SSLIOStream._do_ssl_handshake). # To test this behavior, try nmap with the -sT flag. # https://github.com/tornadoweb/tornado/pull/750 if errno_from_exception(err) in (errno.ECONNABORTED, errno.EINVAL): return connection.close() else: raise try: if self.ssl_options is not None: stream = SSLIOStream( connection, max_buffer_size=self.max_buffer_size, read_chunk_size=self.read_chunk_size, ) # type: IOStream else: stream = IOStream( connection, max_buffer_size=self.max_buffer_size, read_chunk_size=self.read_chunk_size, ) future = self.handle_stream(stream, address) # 会注册一个未来对象到loop里面 if future is not None: # 也就是说一个http连接到了这之后接结束了, 剩下的事都在loop中 IOLoop.current().add_future( gen.convert_yielded(future), lambda f: f.result() ) except Exception: app_log.error("Error in connection callback", exc_info=True)
def _create_stream(self, host, ssl_options, max_buffer_size, af, addr): # TODO: we should connect in plaintext mode and start the # ssl handshake only after stopping the _Connector. if ssl_options is None: stream = IOStream(socket.socket(af), io_loop=self.io_loop, max_buffer_size=max_buffer_size) else: stream = SSLIOStream(socket.socket(af), io_loop=self.io_loop, ssl_options=ssl_options, max_buffer_size=max_buffer_size) return stream.connect(addr, server_hostname=host)
def __init__(self, uid, port): super(Client, self).__init__('client') self.uid = uid self.port = port self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.conn = SSLIOStream(self.sock, ssl_options={ 'ca_certs': SERVER_CRT_PATH, 'cert_reqs': ssl.CERT_REQUIRED }) self.conn.connect(('127.0.0.1', self.port), self.on_connect)
def _handle_connection(self, connection, address): # 如果可以的话,启用ssl # address = ('127.0.0.1', 63959) # connection : socket object if self.ssl_options is not None: assert ssl, "Python 2.6+ and OpenSSL required for SSL" try: connection = ssl_wrap_socket(connection, self.ssl_options, server_side=True, do_handshake_on_connect=False) except ssl.SSLError as err: if err.args[0] == ssl.SSL_ERROR_EOF: return connection.close() else: raise except socket.error as err: # If the connection is closed immediately after it is created # (as in a port scan), we can get one of several errors. # wrap_socket makes an internal call to getpeername, # which may return either EINVAL (Mac OS X) or ENOTCONN # (Linux). If it returns ENOTCONN, this error is # silently swallowed by the ssl module, so we need to # catch another error later on (AttributeError in # SSLIOStream._do_ssl_handshake). # To test this behavior, try nmap with the -sT flag. # https://github.com/tornadoweb/tornado/pull/750 if errno_from_exception(err) in (errno.ECONNABORTED, errno.EINVAL): return connection.close() else: raise try: if self.ssl_options is not None: stream = SSLIOStream(connection, io_loop=self.io_loop, max_buffer_size=self.max_buffer_size, read_chunk_size=self.read_chunk_size) else: # 根据connection获得一个IOStream的对象,便于数据的读取 stream = IOStream(connection, io_loop=self.io_loop, max_buffer_size=self.max_buffer_size, read_chunk_size=self.read_chunk_size) # 开始处理进来的数据连接 self.handle_stream(stream, address) except Exception: app_log.error("Error in connection callback", exc_info=True)
def connect_to_server(self, server_cls): server = client = None try: sock, port = bind_unused_port() server = server_cls(ssl_options=_server_ssl_options()) server.add_socket(sock) client = SSLIOStream(socket.socket(), ssl_options=dict(cert_reqs=ssl.CERT_NONE)) yield client.connect(("10.0.0.7", port)) self.assertIsNotNone(client.socket.cipher()) finally: if server is not None: server.stop() if client is not None: client.close()
def _create_stream(self, addrinfo): af = addrinfo[0][0] if self.parsed.scheme == "https": ssl_options = {} if self.request.validate_cert: ssl_options["cert_reqs"] = ssl.CERT_REQUIRED if self.request.ca_certs is not None: ssl_options["ca_certs"] = self.request.ca_certs else: ssl_options["ca_certs"] = _DEFAULT_CA_CERTS if self.request.client_key is not None: ssl_options["keyfile"] = self.request.client_key if self.request.client_cert is not None: ssl_options["certfile"] = self.request.client_cert # SSL interoperability is tricky. We want to disable # SSLv2 for security reasons; it wasn't disabled by default # until openssl 1.0. The best way to do this is to use # the SSL_OP_NO_SSLv2, but that wasn't exposed to python # until 3.2. Python 2.7 adds the ciphers argument, which # can also be used to disable SSLv2. As a last resort # on python 2.6, we set ssl_version to TLSv1. This is # more narrow than we'd like since it also breaks # compatibility with servers configured for SSLv3 only, # but nearly all servers support both SSLv3 and TLSv1: # http://blog.ivanristic.com/2011/09/ssl-survey-protocol-support.html if sys.version_info >= (2, 7): # In addition to disabling SSLv2, we also exclude certain # classes of insecure ciphers. ssl_options["ciphers"] = "DEFAULT:!SSLv2:!EXPORT:!DES" else: # This is really only necessary for pre-1.0 versions # of openssl, but python 2.6 doesn't expose version # information. ssl_options["ssl_version"] = ssl.PROTOCOL_TLSv1 return SSLIOStream(socket.socket(af), io_loop=self.io_loop, ssl_options=ssl_options, max_buffer_size=self.max_buffer_size) else: return IOStream(socket.socket(af), io_loop=self.io_loop, max_buffer_size=self.max_buffer_size)
def __init__(self, io_loop, client, request, callback): self.start_time = time.time() self.io_loop = io_loop self.client = client self.request = request self.callback = callback self.code = None self.headers = None self.chunks = None self._decompressor = None # Timeout handle returned by IOLoop.add_timeout self._timeout = None with stack_context.StackContext(self.cleanup): parsed = urlparse.urlsplit(self.request.url) if ":" in parsed.netloc: host, _, port = parsed.netloc.partition(":") port = int(port) else: host = parsed.netloc port = 443 if parsed.scheme == "https" else 80 if self.client.hostname_mapping is not None: host = self.client.hostname_mapping.get(host, host) if parsed.scheme == "https": ssl_options = {} if request.validate_cert: ssl_options["cert_reqs"] = ssl.CERT_REQUIRED if request.ca_certs is not None: ssl_options["ca_certs"] = request.ca_certs else: ssl_options["ca_certs"] = _DEFAULT_CA_CERTS self.stream = SSLIOStream(socket.socket(), io_loop=self.io_loop, ssl_options=ssl_options) else: self.stream = IOStream(socket.socket(), io_loop=self.io_loop) timeout = min(request.connect_timeout, request.request_timeout) if timeout: self._connect_timeout = self.io_loop.add_timeout( self.start_time + timeout, self._on_timeout) self.stream.set_close_callback(self._on_close) self.stream.connect((host, port), functools.partial(self._on_connect, parsed))
def _handle_connection(self, connection, address): if self.ssl_options is not None: assert ssl, "Python 2.6+ and OpenSSL required for SSL" try: connection = ssl_wrap_socket(connection, self.ssl_options, server_side=True, do_handshake_on_connect=False) except ssl.SSLError as err: if err.args[0] == ssl.SSL_ERROR_EOF: return connection.close() else: raise except socket.error as err: # If the connection is closed immediately after it is created # (as in a port scan), we can get one of several errors. # wrap_socket makes an internal call to getpeername, # which may return either EINVAL (Mac OS X) or ENOTCONN # (Linux). If it returns ENOTCONN, this error is # silently swallowed by the ssl module, so we need to # catch another error later on (AttributeError in # SSLIOStream._do_ssl_handshake). # To test this behavior, try nmap with the -sT flag. # https://github.com/facebook/tornado/pull/750 if err.args[0] in (errno.ECONNABORTED, errno.EINVAL): return connection.close() else: raise try: if self.ssl_options is not None: stream = SSLIOStream(connection, io_loop=self.io_loop, max_buffer_size=self.max_buffer_size) else: stream = IOStream(connection, io_loop=self.io_loop, max_buffer_size=self.max_buffer_size) self.handle_stream(stream, address) # 这个_handle_conntion基本是用在底层iostream的处理上面, # 而路由的分发,我猜测应该是在生成request对象那个时候才开始的 except Exception: app_log.error("Error in connection callback", exc_info=True)
def _Connect(self): try: ssl_options = { 'certfile': secrets.GetSecretFile(self._settings['certfile']) } self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) self._stream = SSLIOStream(self._sock, io_loop=self._io_loop, ssl_options=ssl_options) self._stream.set_close_callback(self._OnClose) self._stream.connect(self._host, self._OnConnect) except KeyError: logging.warning( 'failed to initialize connection to APN service at %s:%d ' 'whose certificate is missing from secrets/%s' % (self._host[0], self._host[1], self._settings['certfile'])) return except: self._stream = None raise
def _make_iostream(self, s): assert ssl, "Python 2.6+ and OpenSSL required for SSL" try: s = ssl.wrap_socket(s, server_side=True, do_handshake_on_connect=False, **self.ssl_options) except ssl.SSLError as err: if err.args[0] == ssl.SSL_ERROR_EOF: s.close() return else: raise except socket.error as err: if err.args[0] == errno.ECONNABORTED: s.close() return else: raise return SSLIOStream(s)
def connect(self, host, port): self.authority = host s = socket.socket() self.io_stream = SSLIOStream(s, ssl_options=self.ssl_context) yield self.io_stream.connect((host, port), server_hostname=host) logger.debug("Connected!") self.known_proto = self.io_stream.socket.selected_alpn_protocol() assert self.known_proto == self.ALPN_HTTP2_PROTOCOL, "ALPN protocol was not h2, was {} instead".format( self.known_proto) self.io_stream.set_close_callback(self.connection_lost) logger.debug("Talking to a valid HTTP2 server! Sending preamble") self.conn.initiate_connection() self.io_stream.read_until_close(streaming_callback=self.data_received) data = self.conn.data_to_send() yield self.io_stream.write(data) logger.debug("Preamble Sent! Should be connected now")
def _make_client_iostream(self, connection, **kwargs): context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) return SSLIOStream(connection, io_loop=self.io_loop, ssl_options=context, **kwargs)
def _make_client_iostream(self, connection, **kwargs): return SSLIOStream(connection, io_loop=self.io_loop, **kwargs)
def _make_client_iostream(self): return SSLIOStream(socket.socket(), io_loop=self.io_loop)
def __init__(self, io_loop, client, request, release_callback, final_callback, max_buffer_size): self.start_time = time.time() self.io_loop = io_loop self.client = client self.request = request self.release_callback = release_callback self.final_callback = final_callback self.code = None self.headers = None self.chunks = None self._decompressor = None # Timeout handle returned by IOLoop.add_timeout self._timeout = None with stack_context.StackContext(self.cleanup): parsed = urlparse.urlsplit(_unicode(self.request.url)) if ssl is None and parsed.scheme == "https": raise ValueError("HTTPS requires either python2.6+ or " "curl_httpclient") if parsed.scheme not in ("http", "https"): raise ValueError("Unsupported url scheme: %s" % self.request.url) # urlsplit results have hostname and port results, but they # didn't support ipv6 literals until python 2.7. netloc = parsed.netloc if "@" in netloc: userpass, _, netloc = netloc.rpartition("@") match = re.match(r'^(.+):(\d+)$', netloc) if match: host = match.group(1) port = int(match.group(2)) else: host = netloc port = 443 if parsed.scheme == "https" else 80 if re.match(r'^\[.*\]$', host): # raw ipv6 addresses in urls are enclosed in brackets host = host[1:-1] if self.client.hostname_mapping is not None: host = self.client.hostname_mapping.get(host, host) if request.allow_ipv6: af = socket.AF_UNSPEC else: # We only try the first IP we get from getaddrinfo, # so restrict to ipv4 by default. af = socket.AF_INET addrinfo = socket.getaddrinfo(host, port, af, socket.SOCK_STREAM, 0, 0) af, socktype, proto, canonname, sockaddr = addrinfo[0] if parsed.scheme == "https": ssl_options = {} if request.validate_cert: ssl_options["cert_reqs"] = ssl.CERT_REQUIRED if request.ca_certs is not None: ssl_options["ca_certs"] = request.ca_certs else: ssl_options["ca_certs"] = _DEFAULT_CA_CERTS if request.client_key is not None: ssl_options["keyfile"] = request.client_key if request.client_cert is not None: ssl_options["certfile"] = request.client_cert self.stream = SSLIOStream(socket.socket(af, socktype, proto), io_loop=self.io_loop, ssl_options=ssl_options, max_buffer_size=max_buffer_size) else: self.stream = IOStream(socket.socket(af, socktype, proto), io_loop=self.io_loop, max_buffer_size=max_buffer_size) timeout = min(request.connect_timeout, request.request_timeout) if timeout: self._timeout = self.io_loop.add_timeout( self.start_time + timeout, self._on_timeout) self.stream.set_close_callback(self._on_close) self.stream.connect(sockaddr, functools.partial(self._on_connect, parsed))
server_side=True, do_handshake_on_connect=False, **self.ssl_options) except ssl.SSLError, err: if err.args[0] == ssl.SSL_ERROR_EOF: return connection.close() else: raise except socket.error, err: if err.args[0] == errno.ECONNABORTED: return connection.close() else: raise try: if self.ssl_options is not None: stream = SSLIOStream(connection, io_loop=self.io_loop) else: stream = IOStream(connection, io_loop=self.io_loop) self.handle_stream(stream, address) except Exception: app_log.error("Error in connection callback", exc_info=True) def bind_sockets(port, address=None, family=socket.AF_UNSPEC, backlog=128, flags=None): """Creates listening sockets bound to the given port and address. Returns a list of socket objects (multiple sockets are returned if the given address maps to multiple IP addresses, which is most common for mixed IPv4 and IPv6 use). Address may be either an IP address or hostname. If it's a hostname,
def __init__(self, io_loop, client, request, release_callback, final_callback, max_buffer_size): self.start_time = time.time() self.io_loop = io_loop self.client = client self.request = request self.release_callback = release_callback self.final_callback = final_callback self.code = None self.headers = None self.chunks = None self._decompressor = None # Timeout handle returned by IOLoop.add_timeout self._timeout = None with stack_context.StackContext(self.cleanup): parsed = urlparse.urlsplit(_unicode(self.request.url)) if ssl is None and parsed.scheme == "https": raise ValueError("HTTPS requires either python2.6+ or " "curl_httpclient") if parsed.scheme not in ("http", "https"): raise ValueError("Unsupported url scheme: %s" % self.request.url) # urlsplit results have hostname and port results, but they # didn't support ipv6 literals until python 2.7. netloc = parsed.netloc if "@" in netloc: userpass, _, netloc = netloc.rpartition("@") match = re.match(r'^(.+):(\d+)$', netloc) if match: host = match.group(1) port = int(match.group(2)) else: host = netloc port = 443 if parsed.scheme == "https" else 80 if re.match(r'^\[.*\]$', host): # raw ipv6 addresses in urls are enclosed in brackets host = host[1:-1] if self.client.hostname_mapping is not None: host = self.client.hostname_mapping.get(host, host) if request.allow_ipv6: af = socket.AF_UNSPEC else: # We only try the first IP we get from getaddrinfo, # so restrict to ipv4 by default. af = socket.AF_INET addrinfo = socket.getaddrinfo(host, port, af, socket.SOCK_STREAM, 0, 0) af, socktype, proto, canonname, sockaddr = addrinfo[0] if parsed.scheme == "https": ssl_options = {} if request.validate_cert: ssl_options["cert_reqs"] = ssl.CERT_REQUIRED if request.ca_certs is not None: ssl_options["ca_certs"] = request.ca_certs else: ssl_options["ca_certs"] = _DEFAULT_CA_CERTS if request.client_key is not None: ssl_options["keyfile"] = request.client_key if request.client_cert is not None: ssl_options["certfile"] = request.client_cert # SSL interoperability is tricky. We want to disable # SSLv2 for security reasons; it wasn't disabled by default # until openssl 1.0. The best way to do this is to use # the SSL_OP_NO_SSLv2, but that wasn't exposed to python # until 3.2. Python 2.7 adds the ciphers argument, which # can also be used to disable SSLv2. As a last resort # on python 2.6, we set ssl_version to SSLv3. This is # more narrow than we'd like since it also breaks # compatibility with servers configured for TLSv1 only, # but nearly all servers support SSLv3: # http://blog.ivanristic.com/2011/09/ssl-survey-protocol-support.html if sys.version_info >= (2, 7): ssl_options["ciphers"] = "DEFAULT:!SSLv2" else: # This is really only necessary for pre-1.0 versions # of openssl, but python 2.6 doesn't expose version # information. ssl_options["ssl_version"] = ssl.PROTOCOL_SSLv3 self.stream = SSLIOStream(socket.socket(af, socktype, proto), io_loop=self.io_loop, ssl_options=ssl_options, max_buffer_size=max_buffer_size) else: self.stream = IOStream(socket.socket(af, socktype, proto), io_loop=self.io_loop, max_buffer_size=max_buffer_size) timeout = min(request.connect_timeout, request.request_timeout) if timeout: self._timeout = self.io_loop.add_timeout( self.start_time + timeout, self._on_timeout) self.stream.set_close_callback(self._on_close) self.stream.connect(sockaddr, functools.partial(self._on_connect, parsed))