108 lines
2.5 KiB
Python
108 lines
2.5 KiB
Python
#!/usr/bin/env python3
|
|
|
|
import os
|
|
import socket
|
|
import subprocess
|
|
|
|
class Connection():
|
|
def __init__(self, sock):
|
|
self.sock = sock
|
|
self.buffer = ""
|
|
|
|
def read_until(self, sep):
|
|
while sep not in self.buffer:
|
|
self.buffer += self.sock.recv(4096)
|
|
res, self.buffer = self.buffer.split(sep, 1)
|
|
return res
|
|
|
|
def read_line(self):
|
|
return self.read_until("\r\n")
|
|
|
|
def read_request(self):
|
|
request_line = self.read_line()
|
|
method, path, version = request_line.split(" ", 3)
|
|
|
|
headers = {}
|
|
|
|
line = self.read_line()
|
|
while len(line):
|
|
k, v = line.split(":", 1)
|
|
headers[k] = v.strip()
|
|
line = self.read_line()
|
|
|
|
# we do not read the body
|
|
|
|
return Request(method, path, headers)
|
|
|
|
|
|
class Request():
|
|
def __init__(self, method, path, headers):
|
|
self.method = method
|
|
self.path = path
|
|
self.headers = headers
|
|
|
|
def __str__(self):
|
|
return "Request(method='{}' path='{}' headers='{}')".format(self.method,
|
|
self.path,
|
|
self.headers)
|
|
|
|
|
|
MSGS = {
|
|
200: "OK",
|
|
400: "Bad Request",
|
|
401: "Unauthorized",
|
|
403: "Forbidden",
|
|
404: "Not Found",
|
|
500: "Internal Server Error",
|
|
}
|
|
|
|
|
|
def respond(conn, status_code, content):
|
|
conn.send("HTTP/1.1 {} {}\r\n".format(status_code, MSGS[status_code]), 0)
|
|
conn.send("Content-Length: {}\r\n".format(len(content)))
|
|
conn.send("\r\n", 0)
|
|
conn.send(content, 0)
|
|
|
|
|
|
def respond_to(conn, req):
|
|
content = ""
|
|
try:
|
|
path = os.getcwd() + req.path
|
|
if os.path.exists(path):
|
|
if os.access(path, os.X_OK):
|
|
content = subprocess.check_output([path])
|
|
else:
|
|
with open(path, 'r') as f:
|
|
content = f.read()
|
|
status_code = 200
|
|
else:
|
|
status_code = 404
|
|
except Exception as e:
|
|
content = str(e)
|
|
status_code = 500
|
|
respond(conn, status_code, content)
|
|
|
|
|
|
def accept(s):
|
|
conn, addr_info = s.accept()
|
|
connection = Connection(conn)
|
|
req = connection.read_request()
|
|
respond_to(conn, req)
|
|
|
|
|
|
def accept_loop(s):
|
|
while True:
|
|
accept(s)
|
|
|
|
|
|
def listen():
|
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
|
|
s.bind(('', 8080))
|
|
s.listen(5)
|
|
|
|
accept_loop(s)
|
|
|
|
if __name__ == '__main__':
|
|
listen()
|