async def _start_tls_connection( self, underlying_transport: asyncio.Transport, req: "ClientRequest", timeout: "ClientTimeout", client_error: Type[Exception] = ClientConnectorError, ) -> Tuple[asyncio.BaseTransport, ResponseHandler]: """Wrap the raw TCP transport with TLS.""" tls_proto = self._factory() # Create a brand new proto for TLS # Safety of the `cast()` call here is based on the fact that # internally `_get_ssl_context()` only returns `None` when # `req.is_ssl()` evaluates to `False` which is never gonna happen # in this code path. Of course, it's rather fragile # maintainability-wise but this is to be solved separately. sslcontext = cast(ssl.SSLContext, self._get_ssl_context(req)) try: async with ceil_timeout( timeout.sock_connect, ceil_threshold=timeout.ceil_threshold ): try: tls_transport = await self._loop.start_tls( underlying_transport, tls_proto, sslcontext, server_hostname=req.host, ssl_handshake_timeout=timeout.total, ) except BaseException: # We need to close the underlying transport since # `start_tls()` probably failed before it had a # chance to do this: underlying_transport.close() raise except cert_errors as exc: raise ClientConnectorCertificateError(req.connection_key, exc) from exc except ssl_errors as exc: raise ClientConnectorSSLError(req.connection_key, exc) from exc except OSError as exc: raise client_error(req.connection_key, exc) from exc except TypeError as type_err: # Example cause looks like this: # TypeError: transport <asyncio.sslproto._SSLProtocolTransport # object at 0x7f760615e460> is not supported by start_tls() raise ClientConnectionError( "Cannot initialize a TLS-in-TLS connection to host " f"{req.host!s}:{req.port:d} through an underlying connection " f"to an HTTPS proxy {req.proxy!s} ssl:{req.ssl or 'default'} " f"[{type_err!s}]" ) from type_err else: tls_proto.connection_made( tls_transport ) # Kick the state machine of the new TLS protocol return tls_transport, tls_proto
def shutdown(_loop: Loop, _transport: asyncio.Transport, _server: Server, executors: List[Executor]): print('shutting down sockets, processes, threads and abort tasks') for task in asyncio.Task.all_tasks(): task.cancel() for executor in executors: executor.shutdown() _transport.close() _server.close() _loop.stop()
def connection_made(self, transport: asyncio.Transport): """Receives a connection and calls the connection callback.""" if self.max_connections is None or (len(self.transports) < self.max_connections): self.transports.append(transport) else: transport.write("Maximum number of connections reached.") transport.close() if self.connection_callback: self.connection_callback(transport)
def connection_made(self, transport: asyncio.Transport): self.transport = transport self.client_cert = transport.get_extra_info("peercert") ssl_context = transport.get_extra_info("ssl_object") if ssl.HAS_ALPN: agreed_protocol = ssl_context.selected_alpn_protocol() else: agreed_protocol = ssl_context.selected_npn_protocol() if agreed_protocol is None: error("Connection error, client does not support HTTP/2") transport.close() else: self.conn.initiate_connection()
async def start_tls( loop: asyncio.AbstractEventLoop, transport: asyncio.Transport, protocol: asyncio.Protocol, sslcontext: ssl.SSLContext, server_side: bool = False, server_hostname: Optional[str] = None, ssl_handshake_timeout: Optional[Union[float, int]] = None, ) -> asyncio.Transport: # We use hasattr here, as uvloop also supports start_tls. if hasattr(loop, "start_tls"): return await loop.start_tls( # type: ignore transport, protocol, sslcontext, server_side=server_side, server_hostname=server_hostname, ssl_handshake_timeout=ssl_handshake_timeout, ) waiter = loop.create_future() ssl_protocol = SSLProtocol(loop, protocol, sslcontext, waiter, server_side, server_hostname) # Pause early so that "ssl_protocol.data_received()" doesn't # have a chance to get called before "ssl_protocol.connection_made()". transport.pause_reading() # Use set_protocol if we can if hasattr(transport, "set_protocol"): transport.set_protocol(ssl_protocol) # type: ignore else: transport._protocol = ssl_protocol # type: ignore conmade_cb = loop.call_soon(ssl_protocol.connection_made, transport) resume_cb = loop.call_soon(transport.resume_reading) try: await asyncio.wait_for(waiter, timeout=ssl_handshake_timeout) except Exception: transport.close() conmade_cb.cancel() resume_cb.cancel() raise return ssl_protocol._app_transport