Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐛 Close FormData (uploaded files) after the request is done #5465

Merged
merged 8 commits into from Nov 3, 2022
4 changes: 4 additions & 0 deletions fastapi/routing.py
Expand Up @@ -3,6 +3,7 @@
import email.message
import inspect
import json
from contextlib import AsyncExitStack
from enum import Enum, IntEnum
from typing import (
Any,
Expand Down Expand Up @@ -190,6 +191,9 @@ async def app(request: Request) -> Response:
if body_field:
if is_body_form:
body = await request.form()
stack = request.scope.get("fastapi_astack")
assert isinstance(stack, AsyncExitStack)
stack.push_async_callback(body.close)
else:
body_bytes = await request.body()
if body_bytes:
Expand Down
28 changes: 27 additions & 1 deletion tests/test_datastructures.py
@@ -1,6 +1,10 @@
from pathlib import Path
from typing import List

import pytest
from fastapi import UploadFile
from fastapi import FastAPI, UploadFile
from fastapi.datastructures import Default
from fastapi.testclient import TestClient


def test_upload_file_invalid():
Expand All @@ -20,3 +24,25 @@ def test_default_placeholder_bool():
placeholder_b = Default("")
assert placeholder_a
assert not placeholder_b


def test_upload_file_is_closed(tmp_path: Path):
path = tmp_path / "test.txt"
path.write_bytes(b"<file content>")
app = FastAPI()

testing_file_store: List[UploadFile] = []

@app.post("/uploadfile/")
def create_upload_file(file: UploadFile):
testing_file_store.append(file)
return {"filename": file.filename}

client = TestClient(app)
with path.open("rb") as file:
response = client.post("/uploadfile/", files={"file": file})
assert response.status_code == 200, response.text
assert response.json() == {"filename": "test.txt"}

assert testing_file_store
assert testing_file_store[0].file.closed