Coverage for tests / test_custom_middleware_exception.py: 100%
50 statements
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-21 17:29 +0000
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-21 17:29 +0000
1from pathlib import Path 1ghij
3from fastapi import APIRouter, FastAPI, File, UploadFile 1ghij
4from fastapi.exceptions import HTTPException 1ghij
5from fastapi.testclient import TestClient 1ghij
7app = FastAPI() 1ghij
9router = APIRouter() 1ghij
12class ContentSizeLimitMiddleware: 1ghij
13 """Content size limiting middleware for ASGI applications
14 Args:
15 app (ASGI application): ASGI application
16 max_content_size (optional): the maximum content size allowed in bytes, None for no limit
17 """
19 def __init__(self, app: APIRouter, max_content_size: int | None = None): 1ghij
20 self.app = app 1abc
21 self.max_content_size = max_content_size 1abc
23 def receive_wrapper(self, receive): 1ghij
24 received = 0 1adbecf
26 async def inner(): 1adbecf
27 nonlocal received
28 message = await receive() 1adbecf
29 if message["type"] != "http.request": 1adbecf
30 return message # pragma: no cover
32 body_len = len(message.get("body", b"")) 1adbecf
33 received += body_len 1adbecf
34 if received > self.max_content_size: 1adbecf
35 raise HTTPException( 1abc
36 422,
37 detail={
38 "name": "ContentSizeLimitExceeded",
39 "code": 999,
40 "message": "File limit exceeded",
41 },
42 )
43 return message 1def
45 return inner 1adbecf
47 async def __call__(self, scope, receive, send): 1ghij
48 if scope["type"] != "http" or self.max_content_size is None: 1adbecf
49 await self.app(scope, receive, send) 1adbecf
50 return 1adbecf
52 wrapper = self.receive_wrapper(receive) 1adbecf
53 await self.app(scope, wrapper, send) 1adbecf
56@router.post("/middleware") 1ghij
57def run_middleware(file: UploadFile = File(..., description="Big File")): 1ghij
58 return {"message": "OK"} 1def
61app.include_router(router) 1ghij
62app.add_middleware(ContentSizeLimitMiddleware, max_content_size=2**8) 1ghij
65client = TestClient(app) 1ghij
68def test_custom_middleware_exception(tmp_path: Path): 1ghij
69 default_pydantic_max_size = 2**16 1abc
70 path = tmp_path / "test.txt" 1abc
71 path.write_bytes(b"x" * (default_pydantic_max_size + 1)) 1abc
73 with client: 1abc
74 with open(path, "rb") as file: 1abc
75 response = client.post("/middleware", files={"file": file}) 1abc
76 assert response.status_code == 422, response.text 1abc
77 assert response.json() == { 1abc
78 "detail": {
79 "name": "ContentSizeLimitExceeded",
80 "code": 999,
81 "message": "File limit exceeded",
82 }
83 }
86def test_custom_middleware_exception_not_raised(tmp_path: Path): 1ghij
87 path = tmp_path / "test.txt" 1def
88 path.write_bytes(b"<file content>") 1def
90 with client: 1def
91 with open(path, "rb") as file: 1def
92 response = client.post("/middleware", files={"file": file}) 1def
93 assert response.status_code == 200, response.text 1def
94 assert response.json() == {"message": "OK"} 1def