This commit is contained in:
2018-05-03 17:46:29 +02:00
commit 464f2c16f3
2 changed files with 115 additions and 0 deletions

8
README.md Normal file
View File

@@ -0,0 +1,8 @@
# serve
My Python port of the webserver Gary Bernhardt built in [this
screencast](https://www.destroyallsoftware.com/screencasts/catalog/http-server-from-scratch).
It is not spec-compliant, serves files from disk, is vulnerable to directory
traversal, and if those files are executable, executes them. Its as terrible
as it sounds!

107
serve.py Normal file
View File

@@ -0,0 +1,107 @@
#!/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()