esgd/esgd.py

170 lines
4.4 KiB
Python
Raw Normal View History

2021-07-18 23:24:08 -05:00
import socketserver
2021-07-19 15:11:31 -05:00
import subprocess
2021-07-18 23:24:08 -05:00
import os
2021-07-19 17:15:39 -05:00
host = "localhost"
port = 70
2021-07-18 23:24:08 -05:00
class GopherError(BaseException): pass
class RequestError(GopherError): pass
2021-07-19 16:17:45 -05:00
class GopherLine:
def __init__(self, line):
self.item = "i"
self.text = ""
self.location = "null"
self.host = "null.host"
self.port = "0"
self.line = line
self.parse()
def parse(self):
split = self.line.rstrip().split('\t')
location = False
if len(split) == 1:
self.text = split[0]
return
try: self.item = split[0][0]
except IndexError: pass
try: self.text = split[0][1:]
except IndexError: pass
try:
self.location = split[1]
location = True
except IndexError: pass
try: self.host = split[2]
except IndexError:
2021-07-19 17:15:39 -05:00
if location == True: self.host = host
2021-07-19 16:17:45 -05:00
try: self.port = split[3]
except IndexError:
2021-07-19 17:15:39 -05:00
if location == True: self.port = str(port)
2021-07-19 16:17:45 -05:00
def render(self):
return "{}{}\t{}\t{}\t{}".format(
self.item,
self.text,
self.location,
self.host,
self.port
)
2021-07-18 23:24:08 -05:00
def recieveRequest(context):
2021-07-19 16:16:54 -05:00
data = b""
while data[-2:] != b"\r\n":
2021-07-18 23:24:08 -05:00
data += context.request.recv(1)
2021-07-19 16:16:54 -05:00
decoded = data[:-2].decode("utf-8")
2021-07-18 23:24:08 -05:00
return decoded
def requestParser(request):
2021-07-19 16:16:54 -05:00
if ".." in request: raise RequestError
2021-07-18 23:24:08 -05:00
try:
2021-07-19 16:16:54 -05:00
if request[0] == "/": request = request[1:]
2021-07-18 23:24:08 -05:00
except IndexError: pass
2021-07-19 16:16:54 -05:00
request = request.replace("?", "\t").split("\t")
2021-07-18 23:24:08 -05:00
try: return (request[0], request[1])
except IndexError: return (request[0], "")
def returnRelative(file):
gph = False
if file == "":
ret = "gophermap"
gph = True
elif os.path.isdir(file):
ret = file + "/gophermap"
gph = True
elif os.path.isfile(file): ret = file
2021-07-19 16:16:54 -05:00
else: raise RequestError("unreachable state")
2021-07-18 23:24:08 -05:00
return (ret, gph)
def fileSendable(file): return os.access(file, os.F_OK|os.R_OK)
def fileCGI(file):
return os.access(file, os.F_OK|os.R_OK|os.X_OK)
def notFound(context):
context.request.sendall(b"3error: file not found!\r\n.\r\n")
2021-07-19 15:11:31 -05:00
def invalid(context):
context.request.sendall(b"3error: selector contains '..'!\r\n.\r\n")
2021-07-18 23:24:08 -05:00
def sendFile(file, context):
with open(file, "r") as fd:
sendFileArray(fd.readlines(), context)
def sendFileArray(arr, context):
[context.request.sendall(
(i.rstrip() + "\r\n").encode("utf-8")
) for i in arr]
context.request.sendall(b".\r\n")
2021-07-18 23:24:08 -05:00
2021-07-19 15:11:31 -05:00
def cgi(file, query, context):
env = {}
2021-07-19 16:16:54 -05:00
env["QUERY_STRING"] = query
env["SCRIPT_NAME"] = "/" + file
env["REMOTE_ADDR"] = context.client_address[0]
2021-07-19 15:11:31 -05:00
proc = subprocess.Popen(
[os.getcwd() + "/" + file],
stdout = subprocess.PIPE,
env = env
)
try: out, err = proc.communicate(timeout=10)
except TimeoutExpired:
proc.kill()
out, err = proc.communicate()
2021-07-19 16:16:54 -05:00
return out.decode("utf-8").replace("\r", "").split("\n")
2021-07-19 15:11:31 -05:00
2021-07-19 17:15:39 -05:00
def gopherRenderer(fileArray):
gopherlines = []
for i in fileArray:
gopherlines.append(GopherLine(i))
returned = []
for i in gopherlines:
returned.append(i.render())
return returned
2021-07-18 23:24:08 -05:00
class gopherHandler(socketserver.BaseRequestHandler):
def handle(self):
decoded = recieveRequest(self)
2021-07-19 15:11:31 -05:00
try:
parsed = requestParser(decoded)
except RequestError:
invalid(self)
return
2021-07-18 23:24:08 -05:00
try: file = returnRelative(parsed[0])
except RequestError:
notFound(self)
return
2021-07-19 15:11:31 -05:00
if fileCGI(file[0]):
2021-07-19 17:15:39 -05:00
if not file[1]:
sendFileArray(
cgi(file[0], parsed[1], self), self
)
else:
sendFileArray(
gopherRenderer(
cgi(
file[0], parsed[1], self
)
), self
)
elif fileSendable(file[0]):
if not file[1]: sendFile(file[0], self)
else:
sendFileArray(
gopherRenderer(
[i.rstrip() for i in open(file[0]).readlines()]
), self
)
2021-07-18 23:24:08 -05:00
else: notFound(self)
if __name__ == "__main__":
with socketserver.TCPServer((host, port), gopherHandler) as server:
2021-07-18 23:24:08 -05:00
server.serve_forever()