-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.py
160 lines (133 loc) · 5.22 KB
/
main.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
from urllib.parse import unquote
import socket
import sys
import os
DEFAULT_PORT = 8000
ADDRESS_FAMILY = socket.AF_INET
SOCKET_TYPE = socket.SOCK_STREAM
REQUEST_QUEUE_SIZE = 5
def open_socket():
"""Creates an open listening socket"""
port = int(sys.argv[1]) if len(sys.argv) > 1 and sys.argv[1].isdigit() else DEFAULT_PORT
listen_socket = socket.socket(ADDRESS_FAMILY, SOCKET_TYPE)
# Allow to reuse the same address
listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# Bind
listen_socket.bind(('', port))
# Activate
listen_socket.listen(REQUEST_QUEUE_SIZE)
print('Serving HTTP on port {port} ...'.format(port=port))
return listen_socket
def add_headers(response_without_headers):
"""Add headers to response"""
headers = 'HTTP/1.1 200 OK\r\nServer: MyServer v0.1\r\n\r\n'
try:
return headers + response_without_headers
except TypeError:
return headers.encode('utf-8') + response_without_headers
def convert_to_proper_unicode(*args):
"""Convert multiple byte-coded strings to readable Unicode strings"""
return [unquote(arg.decode('utf-8')) for arg in args]
def styles():
"""Add some styles to the HTML"""
style = """
<style>
body{
background: #000000;
background: -webkit-linear-gradient(to left, #000000 , #434343);
background: linear-gradient(to left, #000000 , #434343);
}
ul{
font-size: 20px;
}
li, a{
color: white;
}
li{
transition: font-size 0.3s;
}
li:hover{
font-size: 25px;
}
</style>
"""
return style
def return_index_html(path='/'):
"""Returns the content of index.html, with HTTP-headers"""
with open(os.path.join(path if path != '/' else '', 'index.html'), 'rb') as f:
response = f.read()
response = add_headers(response)
return response
def return_directory_html(path):
"""Return an HTML-page displaying list of directory contents + styles"""
response = '<html><head><meta charset="UTF-8">\
<title>{}</title></head><body><ul>'.format(path if path == '/' else '/' + path)
all_dir_content = os.listdir(os.getcwd() if path == '/' else path)
for el in all_dir_content:
if path == '/':
response += '<li><a href="{0}">{0}</a></li>'.format(el)
else:
response += '<li><a href="{0}/{1}">{1}</a></li>'.format(path, el)
response += '</ul></body></html>'
response += styles()
return response
def parse_request(request_data):
"""Parse the request data, return the request line"""
request_line = request_data.splitlines()[0]
return request_line.rstrip().split()
def send_response(client_connection, response, raw=False):
"""Sends response to an accepted connection and closes it"""
if raw:
client_connection.sendall(response)
else:
try:
client_connection.sendall(bytes(add_headers(response), 'utf-8'))
except TypeError:
client_connection.sendall(add_headers(response))
client_connection.close()
def send_error_response(client_connection):
"""Sends a simple response saying there was an error"""
response = '<h1>Sorry, but there was some kind of error(</h1>'
send_response(client_connection, response)
def serve():
"""Accept HTTP-requests and return HTTP-responses"""
listen_socket = open_socket()
while True:
client_connection, client_address = listen_socket.accept()
request_data = client_connection.recv(1024)
# Parse the request
try:
request_method, path, request_version = parse_request(request_data)
except IndexError:
send_error_response(client_connection)
continue
# Print the request line
print(*convert_to_proper_unicode(request_method, path, request_version))
# Convert path to proper Unicode
path = convert_to_proper_unicode(path)[0]
# Delete the starting slash to work properly
path = path if path == '/' else path[1:]
# If there is an 'index.html' file - display it's content
if os.path.isfile('index.html'):
response = return_index_html()
send_response(client_connection, response, raw=True)
continue
# If requested a file - send it's content
if os.path.isfile(path):
with open(path, 'rb') as file:
response = file.read()
# If requested a directory - send an HTML-page displaying a list of directory contents
elif os.path.isdir(path):
# If there is an 'index.html' file in directory - display it's content
if 'index.html' in os.listdir(path):
response = return_index_html(path)
send_response(client_connection, response, raw=True)
continue
response = return_directory_html(path)
else:
send_error_response(client_connection)
continue
# Send the response data and close the connection
send_response(client_connection, response)
if __name__ == '__main__':
serve()