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 90 91 92 | #!/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.config import H2Configuration 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 config = H2Configuration(client_side=False) self.conn = H2Connection(config=config) @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() |