diff options
| -rw-r--r-- | main.py | 29 | ||||
| -rw-r--r-- | src/APIv1.py | 22 | ||||
| -rw-r--r-- | src/config.py | 2 | ||||
| -rw-r--r-- | src/request.py | 21 | ||||
| -rw-r--r-- | www/test.html | 11 |
5 files changed, 56 insertions, 29 deletions
diff --git a/main.py b/main.py index fdb0432..db3a716 100644 --- a/main.py +++ b/main.py @@ -4,15 +4,16 @@ The mighty silly webserver written in python for no good reason import ssl -import gzip +# import zlib import time import socket -import brotli +# import brotli import signal import threading from src import APIv1 from src.request import * from src.status_code import * +from src.config import BUFFER_LENGTH from src.minimizer import minimize_html @@ -44,7 +45,7 @@ class HTTPServer: Now uses threading """ - def __init__(self, *, port: int, packet_size: int = 2048): + def __init__(self, *, port: int, packet_size: int = BUFFER_LENGTH): # SSL context context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) context.check_hostname = False @@ -144,27 +145,27 @@ class HTTPServer: response = Response(data, STATUS_CODE_NOT_FOUND) # process header data - if response.headers.get("Content-Encoding") is None and response.compress: - supported_compressions = [x.strip() for x in getattr(request, "Accept-Encoding", "").split(",")] - if "br" in supported_compressions: - response.headers["Content-Encoding"] = "br" - response.data = brotli.compress(response.data) - elif "gzip" in supported_compressions: - response.headers["Content-Encoding"] = "gzip" - response.data = gzip.compress(response.data) + # if response.headers.get("Content-Encoding") is None and response.compress: + # supported_compressions = [x.strip() for x in getattr(request, "Accept-Encoding", "").split(",")] + # if "br" in supported_compressions: + # response.headers["Content-Encoding"] = "br" + # elif "gzip" in supported_compressions: + # response.headers["Content-Encoding"] = "gzip" if response.headers.get("Content-Length") is None: response.headers["Content-Length"] = len(response.data) if response.headers.get("Connection") is None: response.headers["Connection"] = "close" - # generate basic message + # generate basic message message = b'HTTP/1.1 ' + response.status.__bytes__() + b'\r\n' for key, value in response.headers.items(): message += f"{key}: {value}\r\n".encode("ascii") - message += b'\r\n' + response.data + message += b'\r\n' # send message client.sendall(message) + for packet in response.get_data_stream(): + client.sendall(packet) def _handle_get(self, client: ssl.SSLSocket, request: Request) -> Response: """ @@ -231,7 +232,7 @@ class HTTPServer: try: return self.sock.accept()[0] except BlockingIOError: - time.sleep(0.001) + time.sleep(0.005) return None diff --git a/src/APIv1.py b/src/APIv1.py index f163c5b..c396825 100644 --- a/src/APIv1.py +++ b/src/APIv1.py @@ -1,4 +1,5 @@ import random +from ssl import SSLSocket from src.request import * from src.status_code import * @@ -7,20 +8,19 @@ API_FILE_RANDOM_MIN_SIZE_LIMIT = 1 API_FILE_RANDOM_MAX_SIZE_LIMIT = 2**30 * 2 -def random_data_gen(size: int) -> bytes: +def random_data_gen(size: int, chunk_size: int = 65536) -> bytes: """ - Generates SIZE bytes of random data in 64kib chunks + Generates SIZE bytes of random data in CHUNK_SIZE byte chunks :param size: bytes to generate + :param chunk_size: size of each chunk (bytes) :return: random bytes """ - data = bytearray() - int_size = size // 65536 + int_size = size // chunk_size for _ in range(int_size): - data += random.randbytes(65536) - data += random.randbytes((int_size * 65536) - size) - - return data + yield random.randbytes(chunk_size) + if (final_size := (int_size * chunk_size) - size) > 0: + yield random.randbytes(final_size) def decode_size(size: str) -> int: @@ -78,7 +78,11 @@ def api_call(client: SSLSocket, request: Request) -> Response: if size < API_FILE_RANDOM_MIN_SIZE_LIMIT or size > API_FILE_RANDOM_MAX_SIZE_LIMIT: return Response(b'', STATUS_CODE_BAD_REQUEST) - return Response(random_data_gen(size), STATUS_CODE_OK, compress=False) + return Response( + b'', + STATUS_CODE_OK, + headers={"Content-Length": size}, + data_stream=random_data_gen(size)) else: return Response(b'', STATUS_CODE_BAD_REQUEST) else: diff --git a/src/config.py b/src/config.py new file mode 100644 index 0000000..e39d18c --- /dev/null +++ b/src/config.py @@ -0,0 +1,2 @@ +BUFFER_LENGTH = 65536 + diff --git a/src/request.py b/src/request.py index 003783a..a197649 100644 --- a/src/request.py +++ b/src/request.py @@ -1,5 +1,5 @@ -from typing import Any -from ssl import SSLSocket +from typing import Any, Generator +from src.config import BUFFER_LENGTH from src.status_code import StatusCode @@ -72,10 +72,25 @@ class Response: :param data: response data :param status: response status code :param headers: headers to include - :param kwarg: compress - whether to compress data or not + :key compress: compress data or not + :key data_stream: stream of data """ self.data: bytes = data + self.data_stream: Generator[bytes, None, None] | None = kwargs.get("data_stream") self.status: StatusCode = status self.headers: dict[str, Any] = headers if headers is not None else dict() self.compress: bool = kwargs.get("compress", True) + + # check for content-length when using data_stream + if self.data_stream is not None and self.headers.get("Content-Length") is None: + raise Exception("Undefined length for data stream") + + def get_data_stream(self): + if self.data_stream is None: + def generator() -> bytes: + for i in range(0, len(self.data), BUFFER_LENGTH): + yield self.data[i:i+BUFFER_LENGTH] + return generator() + else: + return self.data_stream diff --git a/www/test.html b/www/test.html index f7b7b27..77d376d 100644 --- a/www/test.html +++ b/www/test.html @@ -11,10 +11,15 @@ </header> <div id="section-div"> <section> + <h1> APIv1 Testing page </h1> + <p> You are supposed to see that, it's not a bug </p> + <p> This is a small API / webserver testing page, so feel free to click on downloads to see if they work </p>x + </section> + <section> <h1> File download test </h1> - <p> <a href="/APIv1/file/random?size=128mib" target="_blank">Download 128 MiB file</a> </p> - <p> <a href="/APIv1/file/random?size=512mib" target="_blank">Download 512 MiB file</a> </p> - <p> <a href="/APIv1/file/random?size=1gib" target="_blank">Download 1 GiB file</a> </p> + <p> <a href="/APIv1/file/random?size=128mib" target="_blank">Download random 128 MiB file</a> </p> + <p> <a href="/APIv1/file/random?size=512mib" target="_blank">Download random 512 MiB file</a> </p> + <p> <a href="/APIv1/file/random?size=1gib" target="_blank">Download random 1 GiB file</a> </p> </section> </div> <footer> |