facebook/tornado — pull request #533 by alekstorm (2012-06-08 07:26:46+00:00)
Title: Refactor TCPServer and HTTPServer to support TLS NPN

* TLS NPN means that one of many protocols can be selected after a TCP connection is established. A layer of indirection was added to `TCPServer` to allow it to delegate handling of a TCP connection to whichever protocol handler was negotiated. If the `npn_protocols` parameter (a list of `(name, handler)` tuples in order of preference) was passed to the constructor, the connection is over TLS, and NPN succeeded, the handler for the chosen name will be called. Otherwise, the `protocol` constructor parameter will be called. For example, `SPDYServer` is essentially:

```
class SPDYServer(TCPServer):
def __init__(self, request_callback):
http_protocol = HTTPServerProtocol(request_callback)
TCPServer.__init__(self, http_protocol,
npn_protocols=[
('spdy/2', SPDYServerProtocol(request_callback)),
('http/1.1', http_protocol)])
```

* `TCPServer` was moved from `netutil` to its own module, `tcpserver`.

* Since utilizing NPN support in Python 3.3 requires the `ssl.SSLContext` class, which isn't available in Python 2.x, the `wrap_socket()` top-level function was added to `netutil` to abstract away these details. In addition, the `SUPPORTS_NPN` constant was added as a convenience for determining if the system supported NPN.

* Previously, `web.RequestHandler` formatted the HTTP response itself and wrote it directly to the `IOStream`. This responsibility has been moved to the `HTTPRequest.connection` object, which must provide the `write_preamble()` and `write()` methods - the former writes the response status line and headers, while the latter writes a chunk of the response body.

* Although `IOStream.connect()` already takes a callback parameter, in `SSLIOStream` it's not called until the SSL handshake is completed (which contains TLS NPN) - and `TCPServer`, which doesn't call `connect()`, won't know which protocol handler to execute until that happens. To fix this, a `set_connect_callback` method was added to `IOStream`.

* Snippets that conditionally imported `BytesIO` and `ssl` were moved into `util` and `netutil`, respectively. These symbols are now imported from there.

From the SPDY fork