-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathserver.py
More file actions
92 lines (83 loc) · 2.26 KB
/
server.py
File metadata and controls
92 lines (83 loc) · 2.26 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
import logging
import asyncio
import urllib.parse
import app
import argparse
logging.basicConfig(level=logging.INFO)
log = logging.getLogger('server')
class Request():
def start_response(self, code, msg=''):
self.writer.write(f'HTTP/1.0 {code} {msg}\r\n'.encode())
def send_header(self, key, val):
self.writer.write(f'{key}: {val}\r\n'.encode())
def end_headers(self):
self.writer.write(b'\r\n')
def detach(self):
r = self.reader
w = self.writer
self.reader = None
self.writer = None
return r, w
def close(self):
if self.writer:
self.writer.close()
def parsequery(path):
i = path.find(' ')
if i == -1:
raise ValueError('invalid query line')
method = path[:i]
path = path[i+1:]
i = path.find(' ')
path = path[:i]
return method, urllib.parse.urlparse(path)
async def handle_tcp(reader, writer):
try:
query = await reader.readline()
method, url = parsequery(query.decode()[:-1])
log.info(f'HTTP method:{method!r} {url}')
f = app.HTTP_HANDLERS.get(method+' '+url.path, app.handle_default)
r = Request()
r.writer = writer
r.reader = reader
r.headers = {}
r.method = method
r.url = url
r.params = {}
for k, v in urllib.parse.parse_qsl(r.url.query):
r.params[k] = v
while True:
line = await reader.readline()
if line == b'\r\n':
break
line = line.decode()
if line[-1] == '\n':
line = line[:-1]
i = line.find(': ')
key = line[:i].lower()
value = line[i+2:]
r.headers[key] = value
await f(r)
r.close()
except Exception as e:
print(e)
writer.write(b'HTTP/1.0 400 No\r\nContent-Type: text/html\r\n\r\n<h2>No</h2>\njust no')
writer.close()
raise e
argp = argparse.ArgumentParser()
argp.add_argument('--bind', default='0.0.0.0', help='Address to bind to')
argp.add_argument('--port', type=int, default=4999, help='Port to bind to')
args = argp.parse_args()
loop = asyncio.get_event_loop()
coro = asyncio.start_server(handle_tcp, args.bind, args.port, loop=loop)
server = loop.run_until_complete(coro)
# Serve requests until Ctrl+c is pressed
log.info(f'Serving on {server.sockets[0].getsockname()}')
try:
loop.run_forever()
except KeyboardInterrupt:
pass
# Close the server
server.close()
log.info('Waiting for connections to close...')
loop.run_until_complete(server.wait_closed())
loop.close()