def ssl_wrap_socket(schannel, address, options=None, remote_host=None): # Wrap the socket using the Pyhton SSL socket library schannel._socket = ssl_wrap_socket( socket=schannel._socket, ssl_options=options, server_hostname=remote_host, do_handshake_on_connect=False)
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 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 _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): 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 _handle_connect(self): # When the connection is complete, wrap the socket for SSL # traffic. Note that we do this by overriding _handle_connect # instead of by passing a callback to super().connect because # user callbacks are enqueued asynchronously on the IOLoop, # but since _handle_events calls _handle_connect immediately # followed by _handle_write we need this to be synchronous. self.socket = ssl_wrap_socket(self.socket, self._ssl_options, server_hostname=self._server_hostname, do_handshake_on_connect=False) super(SSLIOStream, self)._handle_connect()
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 _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 _handle_connection(self, connection: socket.socket, address: Any) -> None: 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) if future is not None: 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 _handle_connection(self, connection, address): # Copy-paste of tornado.httpserver.HTTPServer._handle_connection to use # our custom stream class. # # Actually, connection is just a socket. 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): # noqa return connection.close() else: raise try: io_loop = self.io_loop kw = dict(io_loop=io_loop) except AttributeError: # We are on Tornado 5+. Just don't pass ioloop kw = {} io_loop = IOLoop.current() try: stream = EasySSLIOStream( connection, max_buffer_size=self.max_buffer_size, read_chunk_size=self.read_chunk_size, **kw ) future = self.handle_stream(stream, address) if future is not None: io_loop.add_future(future, lambda f: f.result()) except Exception: app_log.error("Error in connection callback", exc_info=True)
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 _handle_connect(self): # When the connection is complete, wrap the socket for SSL # traffic. Note that we do this by overriding _handle_connect # instead of by passing a callback to super().connect because # user callbacks are enqueued asynchronously on the IOLoop, # but since _handle_events calls _handle_connect immediately # followed by _handle_write we need this to be synchronous. # # The IOLoop will get confused if we swap out self.socket while the # fd is registered, so remove it now and re-register after # wrap_socket(). self.io_loop.remove_handler(self.socket) old_state = self._state self._state = None self.socket = ssl_wrap_socket(self.socket, self._ssl_options, server_hostname=self._server_hostname, do_handshake_on_connect=False) self._add_io_state(old_state) super(SSLIOStream, self)._handle_connect()
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 _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) future = self.handle_stream(stream, address) if future is not None: self.io_loop.add_future(future, lambda f: f.result()) except Exception: app_log.error("Error in connection callback", exc_info=True)
def _handle_connection(self, connection, address): # _handle_connection就比较简单了,跳过那些ssl的处理,简化为两句: # stream = IOStream(connection, io_loop=self.io_loop)和 # self.handle_stream()。 # 这里IOStream代表了【IO层】(也就是读写方面的东西),以后再说,反正读写是不愁了。 # 接着是调用handle_stream。我们可以看到,不论应用层是什么协议 # (或者自定义协议),当有新连接到来时走的流程是差不多的,都要经历一番上诉的回调, # 不同之处就在于这个handle_stream方法。这个方法是由【子类自定义覆盖的】, # 它的HTTP实现已经在上一节看过了。 # 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) # 调用handle_stream,传入创建的IOStream对象初始化一个HTTPConnection对象, # HTTPConnection封装了IOStream的一些操作,用于处理HTTPRequest并返回。 # 1.1.0 中的写法: # ====important=====# # HTTPConnection(stream, address, self.request_callback, self.no_keep_alive, self.xheaders) self.handle_stream(stream, address) # 思路是很清晰的,客户端连接在这里被转化成一个IOStream。然后由handle_stream函数处理。 # 这个handle_stream就是我们前面提到过的未直接实现的接口,它是由HTTPServer类实现的。 # def handle_stream(self, stream, address): # HTTPConnection(stream, address, self.request_callback, # self.no_keep_alive, self.xheaders, self.protocol) # 最后,处理流程又回到了HTTPServer类中。可以预见,在HTTConnection这个类中, # stream将和我们注册的RequestHandler协作,一边读客户端请求,一边调用相应的handler处理。 except Exception: app_log.error("Error in connection callback", exc_info=True)
def ssl_wrap_socket(schannel, address, options=None, remote_host=None): # Wrap the socket using the Pyhton SSL socket library schannel._socket = ssl_wrap_socket(socket=schannel._socket, ssl_options=options, server_hostname=remote_host, do_handshake_on_connect=False)