-
-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Client attempts to reuse a closed connection if "Connection: keep-alive" header was received #7297
Comments
Thanks for the reproducer. If you have some time, do you think you could turn that into a test and create a PR including it (I think there are some similar tests already)? I think we may have fixed something relating to this recently, so if we're lucky the test may pass on master (but, good to have the test to catch a regression either way). |
I tried running the script on master and it resulted in the same exception. I'm not sure if I can turn this into a unit test very effectively, but feel free to point me to some similar tests. It seems to be something with One interesting thing I found was when making post requests, during the second one, the headers would get written by async def main():
session = aiohttp.ClientSession()
print("making first call...")
res = await session.post("http://localhost:8080", data="data")
print("first call successful")
print("headers:", res.headers)
print("content:", await res.text())
print("-"*20)
print("making second call...")
res = await session.post("http://localhost:8080", data="data")
print("second call successful")
print("headers:", res.headers)
print("content:", await res.text())
print("-"*20)
await session.close() Resulting in
I added these print statements to print("chunk:", chunk)
print("protocol.connected:", bool(self._protocol.connected))
print("transport is None:", self.transport is None)
print("transport.is_cloing():", self.transport.is_closing()) |
There are a load of tests that use a web application in https://github.com/aio-libs/aiohttp/blob/master/tests/test_client_functional.py Maybe it's possible to create a test in a similar manner? |
I added two test cases, one succeeds but the other one fails. Perhaps that could be a lead towards the solution. |
I think the behaviour is correct. When the server sends This is definitely true of the test in your PR as the server and client are running in the same loop, so there is no possible way for the server to execute the code to close the connection until the client code yields to the event loop in the second call. I believe it is probably also true of the original example, as it likely waits until the client has finished reading the response, at which point it becomes a race and the client starts creating a new request before it receives the close. The RFC does suggest that we can automatically retry for idempotent methods (I'd be curious if requests has the same issue with non-idempotent methods): So, maybe we should do this automatically. I've tried it out and got the test passing pretty easily. |
Whats the timeline we are looking to release this fix ? |
Describe the bug
When making requests through a ClientSession, the session will try to reuse connections, where the "Connection: keep-alive" http header was last sent, even when the connection was closed on a lower layer.
Let's say we make a request to server.com. In the response, server.com will include (misleadingly) the header "Connection: keep-alive", but will close the connection, e.g. by closing the socket. When we try to make a second request to server.com,
ClientSession
(or the underlying connector) will reuse this connection, even though it is closed, and the request will thus fail.As far as I'm aware, it is not a violation of protocol to send the "Connection: keep-alive" header and then close the connection, even though it is strange behavior. The
requests
library can deal with this without any problems and I wonder if this type of behavior could cause other issues as well.To Reproduce
Client output:
Expected behavior
Expected output from the client script above is:
Which is what using the
requests
library yields.Logs/tracebacks
Python Version
3.9.2
aiohttp Version
3.8.4
multidict Version
6.0.4
yarl Version
1.8.2
OS
Debian
Related component
Client
Additional context
No response
Code of Conduct
The text was updated successfully, but these errors were encountered: