diff --git a/Dockerfile b/Dockerfile index 06d3a43..f91f945 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,6 +8,7 @@ ENV HOST=localhost ENV PORT=8080 ENV BIND=0.0.0.0 ENV DATA_DIR=/data +ENV MAX_SIZE=2000000 RUN PIP_ROOT_USER_ACTION=ignore python3 -m pip install uv diff --git a/README.md b/README.md index 973f9da..cac6c25 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Stapler ```txt -usage: stapler [-h] [-p PORT] [--host HOST] [-d DATA_DIR] [-b BIND] [-t TOKEN] +usage: stapler [-h] [-p PORT] [--host HOST] [-d DATA_DIR] -t TOKEN [--max-size-bytes MAX_SIZE_BYTES] [-b BIND] Static pages as simple as a gzip file @@ -11,8 +11,10 @@ options: --host HOST server default host (default: localhost) (env var: HOST) -d, --data-dir DATA_DIR directory where files are/will be stored (default: ./data) (env var: DATA_DIR) - -b, --bind BIND server bind address (default: 0.0.0.0) (env var: BIND) -t, --token TOKEN secret token for update requests (env var: TOKEN) + --max-size-bytes MAX_SIZE_BYTES + max size of accepted archives (in bytes) (default: 2000000 -> 2MB) (env var: MAX_SIZE) + -b, --bind BIND server bind address (default: 0.0.0.0) (env var: BIND) ``` ## Endpoints @@ -51,7 +53,7 @@ curl -X DELETE \ - [x] env instead of args when available - [x] PUT gzip data into /data/xxx - [x] DELETE request -- [ ] max file size +- [x] max file size - [ ] CNAME in /data/xxx can be translated as host in GET / - [ ] header to setup CNAME file instead of in archive - [ ] cerbot install in container + path env/arg diff --git a/src/params.py b/src/params.py index f40a253..dfb3784 100644 --- a/src/params.py +++ b/src/params.py @@ -13,6 +13,7 @@ class Parameters: data_dir: str bind: str token: str + max_size_bytes: int @classmethod def from_namespace(cls, args: argparse.Namespace) -> "Parameters": @@ -54,12 +55,6 @@ def parse_parameters() -> Parameters: default=__get_env_str("DATA_DIR", os.path.join(os.getcwd(), "data")), help="directory where files are/will be stored (default: ./data) (env var: DATA_DIR)", ) - parser.add_argument( - "-b", - "--bind", - default=__get_env_str("BIND", "0.0.0.0"), - help="server bind address (default: 0.0.0.0) (env var: BIND)", - ) parser.add_argument( "-t", "--token", @@ -67,5 +62,17 @@ def parse_parameters() -> Parameters: default=os.getenv("TOKEN"), help="secret token for update requests (env var: TOKEN)", ) + parser.add_argument( + "--max-size-bytes", + type=int, + default=__get_env_int("MAX_SIZE", 2000000), + help="max size of accepted archives (in bytes) (default: 2000000 -> 2MB) (env var: MAX_SIZE)", + ) + parser.add_argument( + "-b", + "--bind", + default=__get_env_str("BIND", "0.0.0.0"), + help="server bind address (default: 0.0.0.0) (env var: BIND)", + ) args = parser.parse_args() return Parameters.from_namespace(args) diff --git a/src/server.py b/src/server.py index 6352e17..72dde92 100644 --- a/src/server.py +++ b/src/server.py @@ -17,6 +17,7 @@ class _StaplerRequestHandler(http.server.SimpleHTTPRequestHandler): self.default_host = params.host self.token = params.token self.data_dir = params.data_dir + self.max_size_bytes = params.max_size_bytes super().__init__(*args, directory=params.data_dir, **kwargs) def list_directory(self, *_, **__): @@ -36,6 +37,8 @@ class _StaplerRequestHandler(http.server.SimpleHTTPRequestHandler): content_length = int(self.headers["Content-Length"]) if content_length == 0: return self.send_error(http.HTTPStatus.LENGTH_REQUIRED, "No body found") + if content_length > self.max_size_bytes: + return self.send_error(http.HTTPStatus.CONTENT_TOO_LARGE, "Archive too large") try: file_bytes = io.BytesIO(self.rfile.read(content_length)) target_path = os.path.join(self.data_dir, sub_path)