From 9f4ceab9a42507d02f48961f7facd64e051f5e1f Mon Sep 17 00:00:00 2001 From: AliveDevil Date: Tue, 29 Oct 2024 12:55:10 +0100 Subject: [PATCH 1/5] Overwrite FileResponse Content-Type with application/octet-stream for all files in /store --- asu/fastapi/StaticFiles.py | 41 ++++++++++++++++++++++++++++++++++++++ asu/main.py | 3 ++- 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 asu/fastapi/StaticFiles.py diff --git a/asu/fastapi/StaticFiles.py b/asu/fastapi/StaticFiles.py new file mode 100644 index 00000000..566cca83 --- /dev/null +++ b/asu/fastapi/StaticFiles.py @@ -0,0 +1,41 @@ +import os + +from fastapi.responses import FileResponse, Response +from fastapi.staticfiles import StaticFiles as FastApiStaticFiles + +from starlette.staticfiles import PathLike +from starlette.types import Scope + +class StaticFiles(FastApiStaticFiles): + def __init__( + self, + *, + directory: PathLike | None = None, + packages: list[str | tuple[str, str]] | None = None, + html: bool = False, + check_dir: bool = True, + follow_symlink: bool = False, + ) -> None: + super().__init__( + directory=directory, + packages=packages, + html=html, + check_dir=check_dir, + follow_symlink=follow_symlink + ) + + def file_response( + self, + full_path: PathLike, + stat_result: os.stat_result, + scope: Scope, + status_code: int = 200, + ) -> Response: + response = super().file_response( + full_path, + stat_result, + scope, + status_code) + if isinstance(response, FileResponse): + response.headers["Content-Type"] = "application/octet-stream" + return response; diff --git a/asu/main.py b/asu/main.py index 9a45f929..c1e34559 100644 --- a/asu/main.py +++ b/asu/main.py @@ -15,6 +15,7 @@ from asu.config import settings from asu.routers import api from asu.util import get_redis_client, parse_feeds_conf, parse_packages_file +from asu.fastapi.StaticFiles import StaticFiles as AsuStaticFiles logging.basicConfig(encoding="utf-8", level=settings.log_level) @@ -36,7 +37,7 @@ async def lifespan(app: FastAPI): (settings.public_path / "json").mkdir(parents=True, exist_ok=True) (settings.public_path / "store").mkdir(parents=True, exist_ok=True) -app.mount("/store", StaticFiles(directory=settings.public_path / "store"), name="store") +app.mount("/store", AsuStaticFiles(directory=settings.public_path / "store"), name="store") app.mount("/static", StaticFiles(directory=base_path / "static"), name="static") templates = Jinja2Templates(directory=base_path / "templates") From aca55fec7fac7c591629a621463319b7b98653bf Mon Sep 17 00:00:00 2001 From: AliveDevil Date: Tue, 29 Oct 2024 13:33:18 +0100 Subject: [PATCH 2/5] Lint fix --- asu/fastapi/StaticFiles.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/asu/fastapi/StaticFiles.py b/asu/fastapi/StaticFiles.py index 566cca83..0ed1be2c 100644 --- a/asu/fastapi/StaticFiles.py +++ b/asu/fastapi/StaticFiles.py @@ -38,4 +38,4 @@ def file_response( status_code) if isinstance(response, FileResponse): response.headers["Content-Type"] = "application/octet-stream" - return response; + return response From 122d701799570882d089c820056913748e3da3c3 Mon Sep 17 00:00:00 2001 From: AliveDevil Date: Tue, 29 Oct 2024 13:46:44 +0100 Subject: [PATCH 3/5] Format --- asu/fastapi/StaticFiles.py | 19 ++++++++----------- asu/main.py | 4 +++- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/asu/fastapi/StaticFiles.py b/asu/fastapi/StaticFiles.py index 0ed1be2c..96cfa4a2 100644 --- a/asu/fastapi/StaticFiles.py +++ b/asu/fastapi/StaticFiles.py @@ -6,6 +6,7 @@ from starlette.staticfiles import PathLike from starlette.types import Scope + class StaticFiles(FastApiStaticFiles): def __init__( self, @@ -17,13 +18,13 @@ def __init__( follow_symlink: bool = False, ) -> None: super().__init__( - directory=directory, - packages=packages, - html=html, - check_dir=check_dir, - follow_symlink=follow_symlink + directory=directory, + packages=packages, + html=html, + check_dir=check_dir, + follow_symlink=follow_symlink, ) - + def file_response( self, full_path: PathLike, @@ -31,11 +32,7 @@ def file_response( scope: Scope, status_code: int = 200, ) -> Response: - response = super().file_response( - full_path, - stat_result, - scope, - status_code) + response = super().file_response(full_path, stat_result, scope, status_code) if isinstance(response, FileResponse): response.headers["Content-Type"] = "application/octet-stream" return response diff --git a/asu/main.py b/asu/main.py index c1e34559..1cab0dd4 100644 --- a/asu/main.py +++ b/asu/main.py @@ -37,7 +37,9 @@ async def lifespan(app: FastAPI): (settings.public_path / "json").mkdir(parents=True, exist_ok=True) (settings.public_path / "store").mkdir(parents=True, exist_ok=True) -app.mount("/store", AsuStaticFiles(directory=settings.public_path / "store"), name="store") +app.mount( + "/store", AsuStaticFiles(directory=settings.public_path / "store"), name="store" +) app.mount("/static", StaticFiles(directory=base_path / "static"), name="static") templates = Jinja2Templates(directory=base_path / "templates") From 3cbf8548520526a40f6bba0710973ee72c1539d2 Mon Sep 17 00:00:00 2001 From: AliveDevil Date: Tue, 29 Oct 2024 16:08:41 +0100 Subject: [PATCH 4/5] Add tests for code-coverage --- .../{StaticFiles.py => staticfiles.py} | 0 asu/main.py | 2 +- tests/test_store.py | 36 +++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) rename asu/fastapi/{StaticFiles.py => staticfiles.py} (100%) create mode 100644 tests/test_store.py diff --git a/asu/fastapi/StaticFiles.py b/asu/fastapi/staticfiles.py similarity index 100% rename from asu/fastapi/StaticFiles.py rename to asu/fastapi/staticfiles.py diff --git a/asu/main.py b/asu/main.py index 1cab0dd4..4dcff09d 100644 --- a/asu/main.py +++ b/asu/main.py @@ -15,7 +15,7 @@ from asu.config import settings from asu.routers import api from asu.util import get_redis_client, parse_feeds_conf, parse_packages_file -from asu.fastapi.StaticFiles import StaticFiles as AsuStaticFiles +from asu.fastapi.staticfiles import StaticFiles as AsuStaticFiles logging.basicConfig(encoding="utf-8", level=settings.log_level) diff --git a/tests/test_store.py b/tests/test_store.py new file mode 100644 index 00000000..fa1fc3a2 --- /dev/null +++ b/tests/test_store.py @@ -0,0 +1,36 @@ +from asu.config import settings +from asu.fastapi.staticfiles import FileResponse + +store_path = settings.public_path / "store" + +def test_store_content_type_img(client): + store_path.mkdir(parents=True, exist_ok=True) + with open(store_path / "test_store_content_type.img", "w+b"): + pass + response = client.head("/store/test_store_content_type.img") + + assert response.status_code == 200 + + headers = response.headers + assert headers["Content-Type"] == "application/octet-stream" + + +def test_store_content_type_imggz(client): + store_path.mkdir(parents=True, exist_ok=True) + with open(store_path / "test_store_content_type.img.gz", "w+b"): + pass + response = client.head("/store/test_store_content_type.img.gz") + + assert response.status_code == 200 + + headers = response.headers + assert headers["Content-Type"] == "application/octet-stream" + + +def test_store_file_missing(client): + response = client.head("/store/test_store_file_missing.bin") + + assert response.status_code == 404 + + headers = response.headers + assert headers["Content-Type"] != "application/octet-stream" From 702fcfbf7937ab1e8117082c433427adfdf4b47e Mon Sep 17 00:00:00 2001 From: AliveDevil Date: Tue, 29 Oct 2024 16:16:21 +0100 Subject: [PATCH 5/5] Lint & Format --- tests/test_store.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_store.py b/tests/test_store.py index fa1fc3a2..5cb0b586 100644 --- a/tests/test_store.py +++ b/tests/test_store.py @@ -1,8 +1,8 @@ from asu.config import settings -from asu.fastapi.staticfiles import FileResponse store_path = settings.public_path / "store" + def test_store_content_type_img(client): store_path.mkdir(parents=True, exist_ok=True) with open(store_path / "test_store_content_type.img", "w+b"):