From 211ed1537428c094dc9aff4fa29453c378f543b5 Mon Sep 17 00:00:00 2001 From: Jesse Rosalia Date: Thu, 23 Jul 2026 14:44:13 -0700 Subject: [PATCH 1/4] Fix intermittent Windows test flake in async httpx integration tests BaseHTTPRequestHandler defaults to protocol_version "HTTP/1.0", which sets close_connection=True after every response. On Windows, the socket close can race with the async httpx client reading the response body, causing ReadError (Windows discards buffered TCP data on RST more aggressively than Linux). Setting protocol_version to "HTTP/1.1" keeps the connection alive, eliminating the race. The 30s timeout is a backstop against the handler blocking on readline if the client never closes the connection. Co-Authored-By: Claude Opus 4.6 Committed-By-Agent: claude --- tests/test_integration.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test_integration.py b/tests/test_integration.py index ca1acdf1b..8ab6d132a 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -27,6 +27,9 @@ class MyTestHandler(BaseHTTPRequestHandler): + protocol_version = "HTTP/1.1" + timeout = 30 + num_requests = 0 requests = defaultdict(Queue) From d88669712fee019c71d43f71963422e5d054e551 Mon Sep 17 00:00:00 2001 From: Jesse Rosalia Date: Thu, 23 Jul 2026 17:31:37 -0700 Subject: [PATCH 2/4] Drain request body in mock handler for HTTP/1.1 keep-alive With protocol_version set to HTTP/1.1, the server keeps the connection alive and reads the next request from the same socket. If the POST body isn't consumed, those bytes remain in the buffer and get misinterpreted as the next HTTP request line. Co-Authored-By: Claude Opus 4.6 Committed-By-Agent: claude --- tests/test_integration.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/test_integration.py b/tests/test_integration.py index 8ab6d132a..e40f36281 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -55,6 +55,12 @@ def do_POST(self): return self._do_request() def _do_request(self): + # Drain the request body so it doesn't pollute the next request + # on the keep-alive connection. + content_length = int(self.headers.get("Content-Length", 0)) + if content_length: + self.rfile.read(content_length) + n = self.__class__.num_requests self.__class__.num_requests += 1 self._add_request(self) From 11caa6caa50ffddc7b55beb6cbaf08db312c6dba Mon Sep 17 00:00:00 2001 From: Jesse Rosalia Date: Fri, 24 Jul 2026 09:19:50 -0700 Subject: [PATCH 3/4] Snapshot request attributes for HTTP/1.1 keep-alive handler reuse With keep-alive, multiple requests are handled by the same BaseHTTPRequestHandler instance. Storing `self` in the queue meant all entries shared the same mutable object whose .headers/.path/.command reflect only the last request. Capture a snapshot at handle time instead. Co-Authored-By: Claude Opus 4.6 Committed-By-Agent: claude --- tests/test_integration.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/tests/test_integration.py b/tests/test_integration.py index e40f36281..c1df0ff10 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -26,6 +26,19 @@ MOCK_HOST = os.environ.get("STRIPE_MOCK_HOST", "localhost") +class RequestSnapshot: + """Snapshot of request attributes, captured at handle time. + + With HTTP/1.1 keep-alive, multiple requests reuse the same handler + instance whose attributes get overwritten on each request. + """ + + def __init__(self, handler): + self.command = handler.command + self.path = handler.path + self.headers = handler.headers + + class MyTestHandler(BaseHTTPRequestHandler): protocol_version = "HTTP/1.1" timeout = 30 @@ -37,10 +50,10 @@ class MyTestHandler(BaseHTTPRequestHandler): @classmethod def _add_request(cls, req): q = cls.requests[id(cls)] - q.put(req) + q.put(RequestSnapshot(req)) @classmethod - def get_requests(cls, n) -> List[BaseHTTPRequestHandler]: + def get_requests(cls, n) -> List[RequestSnapshot]: reqs = [] for _ in range(n): reqs.append(cls.requests[id(cls)].get(False)) From 89c012698ef7257710176905f6948442e6e8165a Mon Sep 17 00:00:00 2001 From: Jesse Rosalia Date: Fri, 24 Jul 2026 11:03:05 -0700 Subject: [PATCH 4/4] Add type hint to RequestSnapshot.__init__ Co-Authored-By: Claude Opus 4.6 Committed-By-Agent: claude --- tests/test_integration.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_integration.py b/tests/test_integration.py index c1df0ff10..bf80daf9f 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -33,7 +33,7 @@ class RequestSnapshot: instance whose attributes get overwritten on each request. """ - def __init__(self, handler): + def __init__(self, handler: BaseHTTPRequestHandler): self.command = handler.command self.path = handler.path self.headers = handler.headers