Skip to content

feat: add HTTP/1.1 connection reuse - #20

Merged
zuudevs merged 5 commits into
mainfrom
feat/connection-reuse
Sep 15, 2026
Merged

zuudevs merged 5 commits into
mainfrom
feat/connection-reuse

Conversation

@zuudevs

@zuudevs zuudevs commented Sep 15, 2026

Copy link
Copy Markdown
Owner

Summary

Implements the v0.6 roadmap milestone: single-slot HTTP/1.1 connection reuse for the stateful Client.

Behavior

  • retain one eligible TCP connection inside Client
  • reuse only for the same effective host + port
  • skip DNS resolution and TCP connect when reuse is valid
  • close the retained connection before switching origin
  • retain only fully framed responses that the parser marks reusable
  • never retain connections with parser pending bytes
  • honor response Connection: close
  • never reuse close-delimited responses or protocol upgrades
  • honor request Connection: close
  • discard the connection after write/read/protocol failure
  • preserve zero-copy request-body transmission

Ownership design

The public Client remains no-PImpl. Reusable connection state is stored inline as an opaque std::uintptr_t socket token plus owned host/port identity; native Winsock/POSIX socket types remain internal. During request execution the token is adopted back into the existing RAII TcpConnection, and an eligible live handle is released back into the Client slot only after the response is complete.

Client is now explicitly move-only, matching its resource-owning semantics.

Stale keep-alive policy

This PR does not add automatic retries. If a peer has closed an apparently reusable connection, the next request may fail with the normal transport/protocol error; that stale slot is discarded, and the following request reconnects normally. This avoids silently replaying non-idempotent requests and keeps automatic retry policy outside v1 scope.

Tests

Adds dedicated loopback integration coverage for:

  • two sequential requests over one accepted socket
  • Connection: close forcing a reconnect
  • close-delimited response forcing a reconnect
  • port/origin change replacing the retained connection
  • stale keep-alive failure being discarded without hidden retry

All tests are local-only and use bounded accept/read waits to avoid hanging CI.

@zuudevs
zuudevs merged commit 9b00efd into main Sep 15, 2026
6 checks passed
@zuudevs
zuudevs deleted the feat/connection-reuse branch September 15, 2026 00:20

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9bd26b0cdd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

configure_test_timeouts(client);

auto first = client.get(make_url(server.port, "/first"));
ASSERT_TRUE(first);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Ensure the worker is joined before a fatal assertion

If the initial request fails—for example because of a loopback or transport regression—ASSERT_TRUE(first) returns from the test while worker is still joinable. Destroying that std::thread invokes std::terminate, aborting the entire test executable instead of reporting this test failure and continuing; use RAII joining or a nonfatal check with an explicit cleanup path.

Useful? React with 👍 / 👎.

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.

1 participant