eventlet-server.py (2851B)
1 # -*- coding: utf-8 -*- 2 """ 3 eventlet-server.py 4 ~~~~~~~~~~~~~~~~~~ 5 6 A fully-functional HTTP/2 server written for Eventlet. 7 """ 8 import collections 9 import json 10 11 import eventlet 12 13 from eventlet.green.OpenSSL import SSL, crypto 14 from h2.config import H2Configuration 15 from h2.connection import H2Connection 16 from h2.events import RequestReceived, DataReceived 17 18 19 class ConnectionManager(object): 20 """ 21 An object that manages a single HTTP/2 connection. 22 """ 23 def __init__(self, sock): 24 config = H2Configuration(client_side=False) 25 self.sock = sock 26 self.conn = H2Connection(config=config) 27 28 def run_forever(self): 29 self.conn.initiate_connection() 30 self.sock.sendall(self.conn.data_to_send()) 31 32 while True: 33 data = self.sock.recv(65535) 34 if not data: 35 break 36 37 events = self.conn.receive_data(data) 38 39 for event in events: 40 if isinstance(event, RequestReceived): 41 self.request_received(event.headers, event.stream_id) 42 elif isinstance(event, DataReceived): 43 self.conn.reset_stream(event.stream_id) 44 45 self.sock.sendall(self.conn.data_to_send()) 46 47 def request_received(self, headers, stream_id): 48 headers = collections.OrderedDict(headers) 49 data = json.dumps({'headers': headers}, indent=4).encode('utf-8') 50 51 response_headers = ( 52 (':status', '200'), 53 ('content-type', 'application/json'), 54 ('content-length', str(len(data))), 55 ('server', 'eventlet-h2'), 56 ) 57 self.conn.send_headers(stream_id, response_headers) 58 self.conn.send_data(stream_id, data, end_stream=True) 59 60 61 def alpn_callback(conn, protos): 62 if b'h2' in protos: 63 return b'h2' 64 65 raise RuntimeError("No acceptable protocol offered!") 66 67 68 def npn_advertise_cb(conn): 69 return [b'h2'] 70 71 72 # Let's set up SSL. This is a lot of work in PyOpenSSL. 73 options = ( 74 SSL.OP_NO_COMPRESSION | 75 SSL.OP_NO_SSLv2 | 76 SSL.OP_NO_SSLv3 | 77 SSL.OP_NO_TLSv1 | 78 SSL.OP_NO_TLSv1_1 79 ) 80 context = SSL.Context(SSL.SSLv23_METHOD) 81 context.set_options(options) 82 context.set_verify(SSL.VERIFY_NONE, lambda *args: True) 83 context.use_privatekey_file('server.key') 84 context.use_certificate_file('server.crt') 85 context.set_npn_advertise_callback(npn_advertise_cb) 86 context.set_alpn_select_callback(alpn_callback) 87 context.set_cipher_list( 88 "ECDHE+AESGCM" 89 ) 90 context.set_tmp_ecdh(crypto.get_elliptic_curve(u'prime256v1')) 91 92 server = eventlet.listen(('0.0.0.0', 443)) 93 server = SSL.Connection(context, server) 94 pool = eventlet.GreenPool() 95 96 while True: 97 try: 98 new_sock, _ = server.accept() 99 manager = ConnectionManager(new_sock) 100 pool.spawn_n(manager.run_forever) 101 except (SystemExit, KeyboardInterrupt): 102 break