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