97 lines
3.0 KiB
Python
Raw Permalink Normal View History

2024-01-30 20:04:56 +01:00
# Components of HTTP/1.1 responses
#
# Use when manually composing an HTTP response
# Expand as required for your use
#
# For HTTP/1.1 specification see: https://www.ietf.org/rfc/rfc2616.txt
# For MIME types see: https://www.iana.org/assignments/media-types/media-types.xhtml
#
# Copyright 2021 (c) Erik de Lange
# Released under MIT license
from lib.httpserver.sendfile import sendfile
reason = {
200: "OK",
301: "Moved Permanently",
302: "Found",
400: "Bad Request",
404: "Not Found",
418: "I'm a teapot"
}
mimetype = {
"HTML": b"Content-Type: text/html\r\n",
"EVENT_STREAM": b"Content-Type: text/event-stream\r\n",
"X_ICON": b"Content-Type: image/x-icon\r\n",
"JSON": b"Content-Type: application/json\r\n"
}
response_header = {
"CLOSE": b"Connection: close\r\n",
"KEEP_ALIVE": b"Connection: keep-alive\r\n"
}
class HTTPResponse:
def __init__(self, con, status, mimetype=None, close=True, header=None):
""" Create a response object
:param int status: HTTP status code
:param socket con: socket
:param str mimetype: HTTP mime type
:param bool close: if true close connection else keep alive
:param dict header: key,value pairs for HTTP response header fields
"""
self.status = status
self.con = con
self.mimetype = mimetype
self.close = close
if header is None:
self.header = {}
else:
self.header = header
def redirect(self, location):
""" Redirect client """
self.con.write(f"HTTP/1.1 {self.status} {reason.get(self.status, 'NA')}\nLocation: {location}\n")
self.con.write(response_header.get("CLOSE"))
def send_file(self, filepath: str = ""):
""" Send response to stream writer """
self.con.write(f"HTTP/1.1 {self.status} {reason.get(self.status, 'NA')}\n")
if self.mimetype:
self.con.write(mimetype.get(self.mimetype))
if self.close:
self.con.write(response_header.get("CLOSE"))
else:
self.con.write(response_header.get("KEEP_ALIVE"))
if len(self.header) > 0:
for key, value in self.header.items():
self.con.write(f"{key}: {value}\n")
sendfile(self.con, filepath)
def send_raw(self, raw: bytes):
""" Send response to stream writer """
self.con.write(f"HTTP/1.1 {self.status} {reason.get(self.status, 'NA')}\n")
if self.mimetype:
self.con.write(mimetype.get(self.mimetype))
if self.close:
self.con.write(response_header.get("CLOSE"))
else:
self.con.write(response_header.get("KEEP_ALIVE"))
if len(self.header) > 0:
for key, value in self.header.items():
self.con.write(f"{key}: {value};\n")
self.con.write(b'\r\n\r\n')
self.con.write(raw)