Skip to content

Fix HTTP connect_timeout enforcement - #413

Merged
Coldwings merged 2 commits into
mainfrom
fix/http-connect-timeout
Jul 10, 2026
Merged

Fix HTTP connect_timeout enforcement#413
Coldwings merged 2 commits into
mainfrom
fix/http-connect-timeout

Conversation

@Coldwings

Copy link
Copy Markdown
Owner

Description

Enforce the shared HTTP client connect_timeout during TCP connection setup and TLS handshake. This fixes clients that could hang in connection setup even though base_client_config::connect_timeout advertised a timeout.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Performance improvement (optimization that improves speed/memory usage)
  • Documentation (changes to documentation, comments, or examples)
  • Refactoring (code changes that neither fix bugs nor add features)
  • Tests (adding or modifying tests)
  • Build/CI (changes to build system, CI configuration, or dependencies)

Related Issues

Closes #412

Changes Made

Core Changes

  • Add cancellable net::tcp_connect overloads backed by cancel_token.
  • Add a cancellable TLS handshake overload that uses cancellable TCP readiness polling.
  • Enforce base_client_config::connect_timeout in the shared client_connect path used by HTTP/1, WebSocket, and SSE clients.
  • Preserve specific connection setup errors such as ETIMEDOUT instead of always mapping acquire failure to ECONNREFUSED.
  • Update API and networking wiki docs for the enforced timeout semantics.

API Changes (if applicable)

Before:

// connect_timeout existed in base_client_config, but HTTP/1 connection setup
// did not pass a cancellation path into TCP connect or TLS handshake.

After:

// connect_timeout now bounds TCP connect plus TLS handshake for the shared
// HTTP/1, WebSocket, and SSE connection path. Values <= 0 disable it.

Migration Guide (if breaking change)

N/A. This enforces existing configuration rather than changing the public configuration surface.

Testing

Unit Tests

  • Added new tests for the changes
  • Updated existing tests if needed
  • All tests pass locally

Integration Tests

  • Tested with existing examples
  • Tested in real-world scenarios (if applicable)

Sanitizer Testing

  • Tested with ASAN (AddressSanitizer)
  • Tested with TSAN (ThreadSanitizer)
  • No new warnings or errors in the local debug build

Test Results

cmake --build /tmp/elio-fix-412-build --target elio_tests --parallel 2
/tmp/elio-fix-412-build/tests/elio_tests "[http][client]"
timeout 120s /tmp/elio-fix-412-build/tests/elio_tests "[http2][timeout]"
timeout 120s /tmp/elio-fix-412-build/tests/elio_tests "[io][cancel]"
timeout 120s /tmp/elio-fix-412-build/tests/elio_tests "[websocket]"
timeout 120s /tmp/elio-fix-412-build/tests/elio_tests "[sse]"
git diff --check

Checklist

Code Quality

  • My code follows the project's coding standards
  • I have added/updated comments for complex logic
  • I have removed any debug code, TODOs, or commented-out code
  • My changes generate no new warnings

Documentation

  • I have updated documentation (wiki, README, code comments)
  • I have added examples for new features (if applicable)
  • I have updated API documentation (if applicable)

Testing

  • I have added tests that prove my fix is effective or my feature works
  • New and existing unit tests pass locally with my changes
  • I have tested with ASAN and TSAN

Compatibility

  • My changes are backward compatible (or I've documented breaking changes)
  • I have considered the impact on existing users
  • I have updated CHANGELOG.md (if applicable)

Performance (if applicable)

  • I have considered the performance impact
  • I have added benchmarks for performance-critical changes

Screenshots / Diagrams

N/A.

Additional Notes

Full ctest was not run because this configuration includes NOT_BUILT sanitizer/RDMA placeholder tests; the targeted executable-level tests above were run instead.

Reviewer Guidance

Areas requiring special attention:

  • Cancellation and fd ownership in the new cancellable tcp_connect path.
  • Timeout error preservation from client_connect through http::client::send_request.
  • Documentation distinction between HTTP/1/WebSocket/SSE timeout behavior and the existing HTTP/2 reserved connect_timeout note.

Questions for reviewers:

  • None.

Copilot AI review requested due to automatic review settings July 10, 2026 16:30

Copilot AI 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.

Pull request overview

Enforces HTTP connection timeouts across TCP setup and TLS handshakes for HTTP, WebSocket, and SSE clients.

Changes:

  • Adds cancellable TCP connect and TLS handshake APIs.
  • Applies shared connection deadlines while preserving setup errors.
  • Adds TLS timeout coverage and updates documentation.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
wiki/Networking.md Documents client timeout configuration.
wiki/API-Reference.md Clarifies timeout semantics.
tests/unit/test_http_client.cpp Tests stalled TLS handshake timeout.
include/elio/tls/tls_stream.hpp Adds cancellable TLS handshaking.
include/elio/net/tcp.hpp Adds cancellable TCP connection overloads.
include/elio/http/websocket_client.hpp Passes WebSocket connection timeout.
include/elio/http/sse_client.hpp Passes SSE connection timeout.
include/elio/http/http_client.hpp Enforces timeout through connection pooling.
include/elio/http/client_base.hpp Implements shared connection watchdog.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread include/elio/http/client_base.hpp
Comment thread include/elio/net/tcp.hpp Outdated
Comment thread include/elio/net/tcp.hpp Outdated
Comment thread include/elio/net/tcp.hpp Outdated
Comment thread include/elio/net/tcp.hpp
@Coldwings

Copy link
Copy Markdown
Owner Author

@copilot Please re-review the latest changes only. Do not push commits or make direct modifications.

Copilot AI commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

@copilot Please re-review the latest changes only. Do not push commits or make direct modifications.

Reviewed commit 97947cf. All four concerns from the prior review are addressed:

errno preservation (client_base.hpp):
stop_watchdog_preserving_errno saves errno into saved_errno (a coroutine-frame local) before awaiting, then restores it after — correct across scheduler-worker migrations. The all-addresses-failed paths use the same pattern (connect_errno saved before co_await stop_watchdog(), restored after). One minor observation: errno ? errno : ECONNREFUSED is defensive but reasonable since errno should be set by the last failed tcp_connect attempt.

API ambiguity (tcp.hpp):
The constrained template requires std::is_same_v<std::remove_cvref_t<Token>, coro::cancel_token> is the right fix. Braced-init-list {} cannot be used for template argument deduction, so it never selects the cancellable overload; the non-template tcp_options overload wins unambiguously. The added compilation test confirms this.

Constructor reorder (tcp_connect_awaitable):
The (addr, opts, token) order matches the new factory-function signature and removes the previous mismatch.

Cancellation tests:
Both tests are sound. The already-cancelled-token test cleanly exercises the await_suspend early-return path. The pending-connect test uses 192.0.2.1 (RFC 5737 TEST-NET) sensibly, handles the "platform refused before cancellation" race with a graceful early SUCCEED, and the fd check (after_fds < pending_fds) is correct given both counts use the same helper (the DIR fd is consistently included in both and closed before returning).

@Coldwings
Coldwings merged commit 4e0e2c1 into main Jul 10, 2026
10 checks passed
@Coldwings
Coldwings deleted the fix/http-connect-timeout branch July 10, 2026 16:58
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.

[Contract] HTTP connect_timeout is not enforced during connection setup

3 participants