Skip to content

Conversation

@pareshjoshij
Copy link
Contributor

@pareshjoshij pareshjoshij commented Nov 25, 2025

Closes gh-141938

Context:
As reported in gh-141938, when using http.client, if an OSError (such as TimeoutError or ConnectionRefusedError) occurs during _send_request—specifically after the state has transitioned to _CS_REQ_STARTED—the HTTPConnection object remains in a "dirty" state.

Because the state is not reset to _CS_IDLE, the connection object becomes unusable. Any subsequent attempts to use .request(), even after calling .connect(), result in a CannotSendRequest error.

The Fix:

  1. Logic Change in request(): Wrapped _send_request in a try...except OSError block.
    • If an OSError occurs, we check errno.
    • If the error is not errno.EPIPE (Broken Pipe), self.close() is called explicitly. This resets the internal state machine (self.__state) to _CS_IDLE and closes the socket.
    • Note: errno.EPIPE is excluded to preserve existing behavior where a server closes the connection early (e.g., sending a 413 response), allowing the client to still read the response (prevents regression in test_epipe).
  2. Testability Change in __init__(): Changed self._create_connection to use a lambda instead of capturing socket.create_connection directly.
    • This ensures that socket.create_connection is looked up at call time, allowing unit tests to properly mock it for individual requests without the mock being permanently captured by the instance.

Verification:

  • Added HTTPConnectionStateTests to Lib/test/test_httplib.py.
  • Verified that TimeoutError resets state to Idle (previously stuck at Request-sent) and closes the socket.
  • Verified that a subsequent conn.request() call proceeds without raising CannotSendRequest.
  • Verified locally that test_epipe passes, ensuring no regression for broken pipe scenarios.

Handle exceptions during request transmission and close connection on failure.
Handle TimeoutError specifically when sending requests.
Updated the connection creation method to use a lambda for better testability and changed exception handling from TimeoutError to OSError.
Add tests to verify HTTP connection state resets after a timeout and checks state after a successful request.
Handle specific OSError cases to prevent unnecessary connection closure.
@pareshjoshij pareshjoshij marked this pull request as ready for review November 26, 2025 04:54
@pareshjoshij pareshjoshij marked this pull request as draft November 28, 2025 16:25
@picnixz
Copy link
Member

picnixz commented Nov 28, 2025

I will close this PR until we decide what to do in this case. As you can see the test suite is broken with that change. In addition, the PR summary looks AI-generated so please read our policy about this: https://devguide.python.org/getting-started/generative-ai/. I'm also unsure of this weird change.

@picnixz picnixz closed this Nov 28, 2025
@pareshjoshij
Copy link
Contributor Author

@picnixz sir I apologize for the confusion. I actually converted this to a Draft because I realized the code was broken and I was still experimenting. I also understand now that I should have waited for the triage process first.
​One request though: please don't label this as AI. I only used tools to fix my English grammar in the description. I wrote the code myself. Since you are a core developer, your words carry a lot of weight. If you label a beginner's work as 'AI' just because of mistakes, others will believe it, and that puts a permanent stamp on my contribution which is really discouraging

@picnixz
Copy link
Member

picnixz commented Nov 28, 2025

I never said it was AI and apologize if it was understood otherwise. I said it "looked" AI-generated and invited you to read our policy about this. If the code was generated by you, it's fine! however, please do mention when you use AI in the future.

Nonetheless, I am still wondering whether to change the current behavior or not. At least docs could be improved but changing the behavior may break consumer code.

@pareshjoshij
Copy link
Contributor Author

No @picnixz sir no need to apologize! Having your guidance is enough for me. ❤️🙏 I'll make sure to clearly mention any tool usage next time.

​I also understand the concern about breaking consumer code now. It makes sense why we might prefer a documentation update instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

http.client: CannotSendRequest after TimeoutError

2 participants