-
Notifications
You must be signed in to change notification settings - Fork 172
Expand file tree
/
Copy patheventlet-server.py
More file actions
102 lines (81 loc) · 2.78 KB
/
eventlet-server.py
File metadata and controls
102 lines (81 loc) · 2.78 KB
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
93
94
95
96
97
98
99
100
101
102
# -*- coding: utf-8 -*-
"""
eventlet-server.py
~~~~~~~~~~~~~~~~~~
A fully-functional HTTP/2 server written for Eventlet.
"""
import collections
import json
import eventlet
from eventlet.green.OpenSSL import SSL, crypto
from h2.config import H2Configuration
from h2.connection import H2Connection
from h2.events import RequestReceived, DataReceived
class ConnectionManager(object):
"""
An object that manages a single HTTP/2 connection.
"""
def __init__(self, sock):
config = H2Configuration(client_side=False)
self.sock = sock
self.conn = H2Connection(config=config)
def run_forever(self):
self.conn.initiate_connection()
self.sock.sendall(self.conn.data_to_send())
while True:
data = self.sock.recv(65535)
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)
self.sock.sendall(self.conn.data_to_send())
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', 'eventlet-h2'),
)
self.conn.send_headers(stream_id, response_headers)
self.conn.send_data(stream_id, data, end_stream=True)
def alpn_callback(conn, protos):
if b'h2' in protos:
return b'h2'
raise RuntimeError("No acceptable protocol offered!")
def npn_advertise_cb(conn):
return [b'h2']
# Let's set up SSL. This is a lot of work in PyOpenSSL.
options = (
SSL.OP_NO_COMPRESSION |
SSL.OP_NO_SSLv2 |
SSL.OP_NO_SSLv3 |
SSL.OP_NO_TLSv1 |
SSL.OP_NO_TLSv1_1
)
context = SSL.Context(SSL.SSLv23_METHOD)
context.set_options(options)
context.set_verify(SSL.VERIFY_NONE, lambda *args: True)
context.use_privatekey_file('server.key')
context.use_certificate_file('server.crt')
context.set_npn_advertise_callback(npn_advertise_cb)
context.set_alpn_select_callback(alpn_callback)
context.set_cipher_list(
"ECDHE+AESGCM"
)
context.set_tmp_ecdh(crypto.get_elliptic_curve(u'prime256v1'))
server = eventlet.listen(('0.0.0.0', 443))
server = SSL.Connection(context, server)
pool = eventlet.GreenPool()
while True:
try:
new_sock, _ = server.accept()
manager = ConnectionManager(new_sock)
pool.spawn_n(manager.run_forever)
except (SystemExit, KeyboardInterrupt):
break