forked from ctb/cse491-serverz
/
server.py
162 lines (135 loc) · 4.82 KB
/
server.py
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#!/usr/bin/env python
import random
import socket
import time
import argparse
import jinja2
from urlparse import urlparse
from StringIO import StringIO
from wsgiref.validate import validator
from sys import stderr
import quixote
import imageapp
import quotes
import chat
def handle_connection(conn, port, wsgi_app):
"""Takes a socket connection, and serves a WSGI app over it.
Connection is closed when app is served."""
# Start reading in data from the connection
req = conn.recv(1)
count = 0
env = {}
while req[-4:] != '\r\n\r\n':
new = conn.recv(1)
if new == '':
return
else:
req += new
# Parse the headers we've received
req, data = req.split('\r\n',1)
headers = {}
for line in data.split('\r\n')[:-2]:
key, val = line.split(': ', 1)
headers[key.lower()] = val
# Parse the path and related env info
urlInfo = urlparse(req.split(' ', 3)[1])
env['REQUEST_METHOD'] = 'GET'
env['PATH_INFO'] = urlInfo[2]
env['QUERY_STRING'] = urlInfo[4]
env['CONTENT_TYPE'] = 'text/html'
env['CONTENT_LENGTH'] = str(0)
env['SCRIPT_NAME'] = ''
env['SERVER_NAME'] = socket.getfqdn()
env['SERVER_PORT'] = str(port)
env['wsgi.version'] = (1, 0)
env['wsgi.errors'] = stderr
env['wsgi.multithread'] = False
env['wsgi.multiprocess'] = False
env['wsgi.run_once'] = False
env['wsgi.url_scheme'] = 'http'
env['HTTP_COOKIE'] = headers['cookie'] if 'cookie' in headers.keys() else ''
# Start response function for WSGI interface
def start_response(status, response_headers):
"""Send the initial HTTP header, with status code
and any other provided headers"""
# Send HTTP status
conn.send('HTTP/1.0 ')
conn.send(status)
conn.send('\r\n')
# Send the response headers
for pair in response_headers:
key, header = pair
conn.send(key + ': ' + header + '\r\n')
conn.send('\r\n')
# If we received a POST request, collect the rest of the data
content = ''
if req.startswith('POST '):
# Set up extra env variables
env['REQUEST_METHOD'] = 'POST'
env['CONTENT_LENGTH'] = str(headers['content-length'])
env['CONTENT_TYPE'] = headers['content-type']
# Continue receiving content up to content-length
cLen = int(headers['content-length'])
while len(content) < cLen:
content += conn.recv(1)
env['wsgi.input'] = StringIO(content)
if wsgi_app == "image":
from imageapp import create_publisher
imageapp.setup()
try:
p = imageapp.create_publisher()
except RuntimeError:
pass
wsgi_app = quixote.get_wsgi_app()
elif wsgi_app == "myapp":
from app import make_app
wsgi_app = make_app()
elif wsgi_app == "altdemo":
from quixote.demo.altdemo import create_publisher
try:
p = create_publisher()
except RuntimeError:
pass
wsgi_app = quixote.get_wsgi_app()
elif wsgi_app == "quotes":
wsgi_app = quotes.create_quotes_app('./quotes/quotes.txt',
'./quotes/html')
elif wsgi_app == "chat":
wsgi_app = chat.create_chat_app('./chat/html')
## VALIDATION ##
wsgi_app = validator(wsgi_app)
result = wsgi_app(env, start_response)
# Serve the processed data
for data in result:
conn.send(data)
# Close the connection
result.close()
conn.close()
def main():
"""Waits for a connection, then serves a WSGI app using handle_connection"""
# Create a socket object
sock = socket.socket()
# Get local machine name (fully qualified domain name)
host = socket.getfqdn()
parser = argparse.ArgumentParser(description='Choose which app to run.')
parser.add_argument('-A', choices=["image", "myapp", "altdemo", "quotes",
"chat"],
default="myapp", help='app to run')
parser.add_argument('-p', type=int, default=random.randint(8000,9999),
help='the port number to connect on')
args = parser.parse_args()
port = args.p
sock.bind((host, port))
wsgi_app = args.A
print 'Starting server on', host, port
print 'The Web server URL for this would be http://%s:%d/' % (host, port)
# Now wait for client connection.
sock.listen(5)
print 'Entering infinite loop; hit CTRL-C to exit'
while True:
# Establish connection with client.
conn, (client_host, client_port) = sock.accept()
print 'Got connection from', client_host, client_port
handle_connection(conn, port, wsgi_app)
if __name__ == "__main__":
main()