-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrequest.py
103 lines (85 loc) · 3.06 KB
/
request.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
import zlib
import logging
import os
import util
import codecs
import datetime
class Request:
'''
Object for all HTTP requests
'''
def __init__(self, filename, method, host, port, root='/website'):
# Routing scheme requires that everything be in absolute path format
if filename == '/' or filename.endswith(root):
self.__filename = util.create_path(root, '/index.html')
elif not filename.startswith('/website'):
self.__filename = util.create_path(root, filename)
else:
self.__filename = util.create_path(filename)
self.__host = host
self.__port = port
self.__method = method
self.__methods = {
'GET' : self.do_get,
'HEAD' : self.do_head
}
self.__status = self.get_status()
self.__content = None
logging.basicConfig(filename='server.log',level=logging.DEBUG,format='%(asctime)s %(message)s')
def get_status(self):
'''
Returns the HTTP status for the specified file
'''
if os.path.exists(self.__filename):
if os.stat(self.__filename).st_mode == 33188:
# group has read access => 200
return 200
else:
# group does not have read access => 403
return 403
else:
# Page doesn't exist => 404
return 404
def do_request(self):
'''
Executes the HTTP method and returns the results as a string
'''
logging.info('(%s, %s) - "%s %s" %s', self.__host, self.__port, self.__method, self.__filename, self.__status)
resp = self.__methods.get(self.__method, '405 Method Not Allowed')()
return resp
def do_get(self):
'''
Invokes HTTP GET and returns the source code for @self.__filename as a string
'''
# Get the header for the requested file
# Content of file will come from do_head because of finding the content-length
header = self.do_head()
# Return the file requested (with the appropriate header)
return header + self.__content # extra header needed to separate from body per HTTP standards (RFC 2616)
def do_head(self):
'''
Invokes HTTP HEAD and returns the header for @self.__filename as a string
'''
crlf = '\r\n'
self.__content = self.get_content() # save the content of in case GET is next
# Build the header
header = 'HTTP/1.1 ' + util.resp_codes.get(self.__status, '') + crlf
header += 'Date: ' + datetime.datetime.now().strftime('%a, %d %b %Y %H:%M:%S CST') + crlf
header += 'Content-Type: ' + util.get_content_type(self.__filename) + '; charset=UTF-8' + crlf
header += 'Content-Length: %d' % len(self.__content) + crlf
header += 'Content-Encoding: gzip' + crlf
header += 'Server: Nishad HTTP (Unix)' + crlf
return header + crlf # end of header denoted by empty field
def get_content(self):
'''
Return content of @self.__filename
'''
# Serve templated files in case there isn't an OK HTTP response
if self.__status != 200:
self.__filename = util.create_path('/resp_files', '/'+str(self.__status)+'.html')
with open(self.__filename, 'rb') as f:
src = f.read()
# Compress the source code using gzip
z = zlib.compressobj(-1, zlib.DEFLATED, 31) # -1 = middle compression level, 31 = gzip compression
compressed = z.compress(src) + z.flush()
return compressed