diff --git a/backend/config/__init__.py b/backend/config/__init__.py index 0293bdcba..af698d32e 100644 --- a/backend/config/__init__.py +++ b/backend/config/__init__.py @@ -13,8 +13,7 @@ GUNICORN_WORKERS: Final = int(os.environ.get("GUNICORN_WORKERS", 2)) # PATHS ROMM_BASE_PATH: Final = os.environ.get("ROMM_BASE_PATH", "/romm") -LIBRARY_PATH_SUFFIX: Final = "/library" -LIBRARY_BASE_PATH: Final = f"{ROMM_BASE_PATH}{LIBRARY_PATH_SUFFIX}" +LIBRARY_BASE_PATH: Final = f"{ROMM_BASE_PATH}/library" RESOURCES_BASE_PATH: Final = f"{ROMM_BASE_PATH}/resources" ASSETS_BASE_PATH: Final = f"{ROMM_BASE_PATH}/assets" FRONTEND_RESOURCES_PATH: Final = "/assets/romm/resources" diff --git a/backend/endpoints/rom.py b/backend/endpoints/rom.py index d4868d8a0..c0a7dd72b 100644 --- a/backend/endpoints/rom.py +++ b/backend/endpoints/rom.py @@ -9,7 +9,6 @@ from anyio import Path, open_file from config import ( DISABLE_DOWNLOAD_ENDPOINT_AUTH, LIBRARY_BASE_PATH, - LIBRARY_PATH_SUFFIX, RESOURCES_BASE_PATH, ) from decorators.auth import protected_route @@ -23,7 +22,7 @@ from endpoints.responses.rom import ( ) from exceptions.endpoint_exceptions import RomNotFoundInDatabaseException from exceptions.fs_exceptions import RomAlreadyExistsException -from fastapi import File, HTTPException, Query, Request, Response, UploadFile, status +from fastapi import File, HTTPException, Query, Request, UploadFile, status from fastapi.responses import FileResponse from handler.database import db_platform_handler, db_rom_handler from handler.filesystem import fs_resource_handler, fs_rom_handler @@ -174,8 +173,19 @@ def head_rom_content(request: Request, id: int, file_name: str): rom_path = f"{LIBRARY_BASE_PATH}/{rom.full_path}" + if not rom.multi: + return FileResponse( + path=rom_path, + filename=rom.file_name, + headers={ + "Content-Disposition": f'attachment; filename="{quote(rom.file_name)}"', + "Content-Type": "application/octet-stream", + "Content-Length": str(rom.file_size_bytes), + }, + ) + return FileResponse( - path=rom_path if not rom.multi else f'{rom_path}/{rom.files[0]["filename"]}', + path=f'{rom_path}/{rom.files[0]["filename"]}', filename=file_name, headers={ "Content-Disposition": f'attachment; filename="{quote(rom.name)}.zip"', @@ -211,28 +221,31 @@ async def get_rom_content( if not rom: raise RomNotFoundInDatabaseException(id) + rom_path = f"{LIBRARY_BASE_PATH}/{rom.full_path}" files_to_download = files or [r["filename"] for r in rom.files] if not rom.multi: - return Response( + return FileResponse( + path=rom_path, + filename=rom.file_name, headers={ "Content-Disposition": f'attachment; filename="{quote(rom.file_name)}"', "Content-Type": "application/octet-stream", - "X-Accel-Redirect": f"{LIBRARY_PATH_SUFFIX}/{rom.full_path}", + "X-Accel-Redirect": f"/library/{rom.full_path}", }, ) if len(files_to_download) == 1: - return Response( + return FileResponse( + path=f"{rom_path}/{files_to_download[0]}", + filename=files_to_download[0], headers={ "Content-Disposition": f'attachment; filename="{quote(files_to_download[0])}"', "Content-Type": "application/octet-stream", - "X-Accel-Redirect": f"{LIBRARY_PATH_SUFFIX}/{rom.full_path}/{files_to_download[0]}", + "X-Accel-Redirect": f"/library/{rom.full_path}/{files_to_download[0]}", }, ) - rom_path = f"{LIBRARY_BASE_PATH}/{rom.full_path}" - # Builds a generator of tuples for each member file async def local_files() -> AsyncIterator[AsyncMemberFile]: async def contents(filename: str) -> AsyncIterator[bytes]: diff --git a/backend/main.py b/backend/main.py index 8f3eb38b1..c810f870d 100644 --- a/backend/main.py +++ b/backend/main.py @@ -32,7 +32,6 @@ from endpoints import ( ) from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware -from fastapi.middleware.gzip import GZipMiddleware from handler.auth.base_handler import ALGORITHM from handler.auth.hybrid_auth import HybridAuthBackend from handler.auth.middleware import CustomCSRFMiddleware, SessionMiddleware @@ -68,9 +67,6 @@ if not IS_PYTEST_RUN and not DISABLE_CSRF_PROTECTION: exempt_urls=[re.compile(r"^/token.*"), re.compile(r"^/ws")], ) -# Enable GZip compression for responses -app.add_middleware(GZipMiddleware, minimum_size=1024) - # Handles both basic and oauth authentication app.add_middleware( AuthenticationMiddleware, diff --git a/docker/nginx/default.conf b/docker/nginx/default.conf index a93592c08..87896c31f 100644 --- a/docker/nginx/default.conf +++ b/docker/nginx/default.conf @@ -14,9 +14,14 @@ http { scgi_temp_path /tmp/scgi; sendfile on; + client_body_buffer_size 128k; client_max_body_size 0; + client_header_buffer_size 1k; + large_client_header_buffers 4 16k; + send_timeout 60s; + keepalive_timeout 65s; tcp_nopush on; - # types_hash_max_size 2048; + tcp_nodelay on; include /etc/nginx/mime.types; default_type application/octet-stream; @@ -41,6 +46,13 @@ http { error_log /dev/stderr; gzip on; + gzip_proxied any; + gzip_vary on; + gzip_comp_level 6; + gzip_buffers 16 8k; + gzip_min_length 1024; + gzip_http_version 1.1; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; # include /etc/nginx/conf.d/*.conf; # include /etc/nginx/sites-enabled/*; @@ -88,7 +100,7 @@ http { proxy_set_header Connection "upgrade"; } - # Library files + # Internally redirect download requests location /library { internal; alias /romm/library;