perf: optimize url upload with async i/o
Replaced synchronous `requests.get` and `open().write` in the `process_url` endpoint with `httpx.AsyncClient` and `aiofiles.open`. This prevents the FastAPI event loop from blocking during large file downloads. Updated test suite in `tests/test_url_upload.py` to use `AsyncMock` to mock `httpx.AsyncClient.stream` contexts and async generators properly, covering all original conditions and HTTP error handling paths. Added dependencies `aiofiles` and `types-aiofiles` to resolve MyPy typing CI failures, and mitigated CodeQL security alerts regarding user-provided path extensions by leveraging `os.path.basename` around the generated target file paths. Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
This commit is contained in:
@@ -187,10 +187,11 @@ async def process_url(request: Request, url_request: URLUploadRequest):
|
||||
# Generate unique filename
|
||||
unique_id = str(uuid.uuid4())
|
||||
if "." in safe_filename:
|
||||
file_extension = safe_filename.rsplit(".", 1)[1]
|
||||
target_filename = f"{unique_id}.{file_extension}"
|
||||
# Sanitize extension to prevent path traversal (CodeQL alert)
|
||||
file_extension = os.path.basename(safe_filename.rsplit(".", 1)[1])
|
||||
target_filename = os.path.basename(f"{unique_id}.{file_extension}")
|
||||
else:
|
||||
target_filename = unique_id
|
||||
target_filename = os.path.basename(unique_id)
|
||||
|
||||
target_path = os.path.join(settings.workdir, target_filename)
|
||||
|
||||
|
||||
@@ -37,3 +37,4 @@ pip-licenses==5.5.1 # For license compliance checking
|
||||
|
||||
# Release automation
|
||||
python-semantic-release>=9.0.0
|
||||
types-aiofiles>=23.2.0.20240106
|
||||
|
||||
@@ -58,3 +58,4 @@ sentry-sdk[fastapi,celery,sqlalchemy]>=2.20.0,<3.0.0
|
||||
|
||||
# GraphQL API
|
||||
strawberry-graphql[fastapi]>=0.243.0,<1.0.0
|
||||
aiofiles>=23.2.1
|
||||
|
||||
Reference in New Issue
Block a user