@@ -4311,3 +4311,128 @@ async def handler(request: web.Request) -> web.Response:
4311
4311
response .raise_for_status ()
4312
4312
4313
4313
assert len (client ._session .connector ._conns ) == 1
4314
+
4315
+
4316
+ async def test_post_content_exception_connection_kept (
4317
+ aiohttp_client : AiohttpClient ,
4318
+ ) -> None :
4319
+ """Test that connections are kept after content.set_exception() with POST."""
4320
+
4321
+ async def handler (request : web .Request ) -> web .Response :
4322
+ await request .read ()
4323
+ return web .Response (
4324
+ body = b"x" * 1000
4325
+ ) # Larger response to ensure it's not pre-buffered
4326
+
4327
+ app = web .Application ()
4328
+ app .router .add_post ("/" , handler )
4329
+ client = await aiohttp_client (app )
4330
+
4331
+ # POST request with body - connection should be closed after content exception
4332
+ resp = await client .post ("/" , data = b"request body" )
4333
+
4334
+ with pytest .raises (RuntimeError ):
4335
+ async with resp :
4336
+ assert resp .status == 200
4337
+ resp .content .set_exception (RuntimeError ("Simulated error" ))
4338
+ await resp .read ()
4339
+
4340
+ assert resp .closed
4341
+
4342
+ # Wait for any pending operations to complete
4343
+ await resp .wait_for_close ()
4344
+
4345
+ assert client ._session .connector is not None
4346
+ # Connection is kept because content.set_exception() is a client-side operation
4347
+ # that doesn't affect the underlying connection state
4348
+ assert len (client ._session .connector ._conns ) == 1
4349
+
4350
+
4351
+ async def test_network_error_connection_closed (
4352
+ aiohttp_client : AiohttpClient ,
4353
+ ) -> None :
4354
+ """Test that connections are closed after network errors."""
4355
+
4356
+ async def handler (request : web .Request ) -> NoReturn :
4357
+ # Read the request body
4358
+ await request .read ()
4359
+
4360
+ # Start sending response but close connection before completing
4361
+ response = web .StreamResponse ()
4362
+ response .content_length = 1000 # Promise 1000 bytes
4363
+ await response .prepare (request )
4364
+
4365
+ # Send partial data then force close the connection
4366
+ await response .write (b"x" * 100 ) # Only send 100 bytes
4367
+ # Force close the transport to simulate network error
4368
+ assert request .transport is not None
4369
+ request .transport .close ()
4370
+ assert False , "Will not return"
4371
+
4372
+ app = web .Application ()
4373
+ app .router .add_post ("/" , handler )
4374
+ client = await aiohttp_client (app )
4375
+
4376
+ # POST request that will fail due to network error
4377
+ with pytest .raises (aiohttp .ClientPayloadError ):
4378
+ resp = await client .post ("/" , data = b"request body" )
4379
+ async with resp :
4380
+ await resp .read () # This should fail
4381
+
4382
+ # Give event loop a chance to process connection cleanup
4383
+ await asyncio .sleep (0 )
4384
+
4385
+ assert client ._session .connector is not None
4386
+ # Connection should be closed due to network error
4387
+ assert len (client ._session .connector ._conns ) == 0
4388
+
4389
+
4390
+ async def test_client_side_network_error_connection_closed (
4391
+ aiohttp_client : AiohttpClient ,
4392
+ ) -> None :
4393
+ """Test that connections are closed after client-side network errors."""
4394
+ handler_done = asyncio .Event ()
4395
+
4396
+ async def handler (request : web .Request ) -> NoReturn :
4397
+ # Read the request body
4398
+ await request .read ()
4399
+
4400
+ # Start sending a large response
4401
+ response = web .StreamResponse ()
4402
+ response .content_length = 10000 # Promise 10KB
4403
+ await response .prepare (request )
4404
+
4405
+ # Send some data
4406
+ await response .write (b"x" * 1000 )
4407
+
4408
+ # Keep the response open - we'll interrupt from client side
4409
+ await asyncio .wait_for (handler_done .wait (), timeout = 5.0 )
4410
+ assert False , "Will not return"
4411
+
4412
+ app = web .Application ()
4413
+ app .router .add_post ("/" , handler )
4414
+ client = await aiohttp_client (app )
4415
+
4416
+ # POST request that will fail due to client-side network error
4417
+ with pytest .raises (aiohttp .ClientPayloadError ):
4418
+ resp = await client .post ("/" , data = b"request body" )
4419
+ async with resp :
4420
+ # Simulate client-side network error by closing the transport
4421
+ # This simulates connection reset, network failure, etc.
4422
+ assert resp .connection is not None
4423
+ assert resp .connection .protocol is not None
4424
+ assert resp .connection .protocol .transport is not None
4425
+ resp .connection .protocol .transport .close ()
4426
+
4427
+ # This should fail with connection error
4428
+ await resp .read ()
4429
+
4430
+ # Signal handler to finish
4431
+ handler_done .set ()
4432
+
4433
+ # Give event loop a chance to process connection cleanup
4434
+ await asyncio .sleep (0 )
4435
+
4436
+ assert client ._session .connector is not None
4437
+ # Connection should be closed due to client-side network error
4438
+ assert len (client ._session .connector ._conns ) == 0
0 commit comments