-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhttp_response.py
133 lines (106 loc) · 4.16 KB
/
http_response.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
import mimetypes
import os
import re
class HTTPResponse:
def __init__(self, method, uri, body):
self.redirect_paths = dict()
self.forbidden_paths = set()
self.load_config()
if method == 'GET':
self.data = self.get(uri)
elif method == 'POST':
self.data = self.post(uri, body)
else:
self.data = self.not_implemented()
def load_config(self):
# loads forbidden file paths and redirects
with open('config.txt', 'r') as file:
config_data = file.read()
config_lines = config_data.split('\n')
for line in config_lines:
if line[0] == '#':
# if line begins with a hash, treat it as a comment
continue
config_parts = line.split(' ')
if config_parts[0] == '301':
self.redirect_paths[config_parts[1]] = config_parts[2]
elif config_parts[0] == '403':
self.forbidden_paths.add(config_parts[1])
def get(self, uri):
file = self.read_file(uri)
if file == 'Not Found':
return self.not_found()
elif file == 'Forbidden':
return self.forbidden(uri)
elif file == 'Redirect':
return self.redirect(uri)
elif file:
file_contents, content_type = file
response = b'HTTP/1.1 200 OK \r\n'
response += b'Content-Type: '
response += content_type.encode()
response += b'\r\n\r\n'
response += file_contents
else:
response = self.not_found()
return response
def post(self, uri, body):
file = self.read_file(uri)
if file:
file_contents, content_type = file
file_contents = file_contents.decode()
for field, value in body.items():
# display POST values in page
match = '{{' + field + '}}'
file_contents = re.sub(match, value, file_contents)
response = b'HTTP/1.1 200 OK \r\n'
response += b'Content-Type: '
response += content_type.encode()
response += b'\r\n\r\n'
response += file_contents.encode()
else:
response = self.not_found()
return response
def read_file(self, uri):
relative_path = uri.lstrip('/')
absolute_path = 'site/' + relative_path
if relative_path in self.forbidden_paths:
return 'Forbidden'
elif relative_path in self.redirect_paths:
return 'Redirect'
elif os.path.exists(absolute_path):
with open(absolute_path, 'rb') as file:
file_contents = file.read()
content_type = mimetypes.guess_type(absolute_path)[0]
if not content_type:
content_type = 'text/html'
return file_contents, content_type
else:
return 'Not Found'
def redirect(self, uri):
file_path = uri.lstrip('/')
response = 'HTTP/1.1 301 Moved Permanently\r\n'
response += f'Location: {self.redirect_paths[file_path]}\r\n\r\n'
return response.encode()
def forbidden(self, uri):
file_path = uri.lstrip('/')
response = 'HTTP/1.1 403 Forbidden\r\n'
response += 'Content-Type: text/html'
response += '\r\n\r\n'
response += '<h1>403 Forbidden</h1>'
response += f'<p>You are forbidden from accessing the following page: <code>{file_path}</code>.</p>'
return response.encode()
def not_implemented(self, method):
response = 'HTTP/1.1 501 Not Implemented\r\n'
response += 'Content-Type: text/html'
response += '\r\n\r\n'
response += '<h1>501 Not Implemented</h1>'
response += f'<p>The method {method} has not been implemented yet.</p>'
return response.encode()
def not_found(self):
response = b'HTTP/1.1 404 Not Found \r\n'
response += b'Content-Type: text/html'
response += b'\r\n\r\n'
response += b'<h1>404 Not Found</h1>'
response += b'<p>The page you requested could not be found.'
return response