]> git.ipfire.org Git - thirdparty/fastapi/fastapi.git/commitdiff
🐛 Close FormData (uploaded files) after the request is done (#5465)
authorAdrian Garcia Badaracco <1755071+adriangb@users.noreply.github.com>
Thu, 3 Nov 2022 12:06:52 +0000 (07:06 -0500)
committerGitHub <noreply@github.com>
Thu, 3 Nov 2022 12:06:52 +0000 (13:06 +0100)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
fastapi/routing.py
tests/test_datastructures.py

index 7caf018b552324aee9c1bf5df700951d5e395cbc..8c0bec5e612bf2e62ae13d2fc719f419a953a11c 100644 (file)
@@ -3,6 +3,7 @@ import dataclasses
 import email.message
 import inspect
 import json
+from contextlib import AsyncExitStack
 from enum import Enum, IntEnum
 from typing import (
     Any,
@@ -190,6 +191,9 @@ def get_request_handler(
             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:
index 43f1a116cb55a76db37f80d4b8906ffae6de694c..2e6217d34eb08999abc567005554f1ec7deb402a 100644 (file)
@@ -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():
@@ -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