Tornado Example ServerΒΆ
This example is a basic HTTP/2 server written using the Tornado asynchronous networking library.
The server returns the request headers as a JSON document to the caller, just like the example from the Getting Started: Writing Your Own HTTP/2 Server document.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | #!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
tornado-server.py
~~~~~~~~~~~~~~~~~
A fully-functional HTTP/2 server written for Tornado.
"""
import collections
import json
import ssl
import tornado.gen
import tornado.ioloop
import tornado.iostream
import tornado.tcpserver
from h2.connection import H2Connection
from h2.events import RequestReceived, DataReceived
def create_ssl_context(certfile, keyfile):
ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
ssl_context.options |= (
ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1 | ssl.OP_NO_COMPRESSION
)
ssl_context.set_ciphers("ECDHE+AESGCM")
ssl_context.load_cert_chain(certfile=certfile, keyfile=keyfile)
ssl_context.set_alpn_protocols(["h2"])
return ssl_context
class H2Server(tornado.tcpserver.TCPServer):
@tornado.gen.coroutine
def handle_stream(self, stream, address):
handler = EchoHeadersHandler(stream)
yield handler.handle()
class EchoHeadersHandler(object):
def __init__(self, stream):
self.stream = stream
self.conn = H2Connection(client_side=False)
@tornado.gen.coroutine
def handle(self):
self.conn.initiate_connection()
yield self.stream.write(self.conn.data_to_send())
while True:
try:
data = yield self.stream.read_bytes(65535, partial=True)
if not data:
break
events = self.conn.receive_data(data)
for event in events:
if isinstance(event, RequestReceived):
self.request_received(event.headers, event.stream_id)
elif isinstance(event, DataReceived):
self.conn.reset_stream(event.stream_id)
yield self.stream.write(self.conn.data_to_send())
except tornado.iostream.StreamClosedError:
break
def request_received(self, headers, stream_id):
headers = collections.OrderedDict(headers)
data = json.dumps({'headers': headers}, indent=4).encode('utf-8')
response_headers = (
(':status', '200'),
('content-type', 'application/json'),
('content-length', str(len(data))),
('server', 'tornado-h2'),
)
self.conn.send_headers(stream_id, response_headers)
self.conn.send_data(stream_id, data, end_stream=True)
if __name__ == '__main__':
ssl_context = create_ssl_context('server.crt', 'server.key')
server = H2Server(ssl_options=ssl_context)
server.listen(8888)
io_loop = tornado.ioloop.IOLoop.current()
io_loop.start()
|