Skip to content

Implement async TLS via futures-rustls (BES-27)#13

Merged
fewensa merged 2 commits intorefactorfrom
feat/async-tls
Mar 14, 2026
Merged

Implement async TLS via futures-rustls (BES-27)#13
fewensa merged 2 commits intorefactorfrom
feat/async-tls

Conversation

@fewensa
Copy link
Copy Markdown
Owner

@fewensa fewensa commented Mar 14, 2026

Summary

  • Replaces async-rustls (depends on rustls 0.21) with futures-rustls 0.26 (rustls 0.23 compatible) — the two versions have incompatible types and cannot be used together
  • Implements async_send_https_rustls: wraps TcpStream in AllowStdIo, performs async TLS handshake via TlsConnector::connect().await, then uses existing async_write_stream/async_read_stream
  • Exposes NoCertificateVerification as pub(crate) so it can be imported by async code

API Version Note

futures-rustls 0.26.0 is the direct successor of async-rustls, specifically designed for rustls 0.23+. Both crates share the same TlsConnector::from(Arc<ClientConfig>) + connect(server_name, io).await API pattern. The previous async-rustls 0.4 is deprecated upstream in favor of futures-rustls.

Test

cargo test --features "async,tls-rustls"

All tests pass including test_async_https which now uses a real async TLS handshake.

Notes

This PR also includes async chunked transfer encoding support in async_read_stream and connection_reader.rs (sync path), which was already present in the working tree. All tests pass.

fewensa and others added 2 commits March 14, 2026 03:36
- Replace async-rustls (rustls 0.21) with futures-rustls 0.26 (rustls 0.23 compatible)
- Implement async_send_https_rustls using TlsConnector from futures-rustls
- TLS path wraps TcpStream in AllowStdIo for futures-io compatibility
- Expose NoCertificateVerification as pub(crate) for reuse across modules
- Update tls-rustls feature to depend on futures-rustls instead of async-rustls
- Also includes async chunked transfer support in async_read_stream and
  connection_reader (sync path); all cargo test --features async,tls-rustls pass

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Replace delegation to block_tcp_stream with inline socket2-based
connection setup in async_tcp_stream. This makes the async path own
its socket2 usage directly rather than calling through the sync path,
removing the fake-async delegation and keeping the implementation
consistent with the sync block_tcp_stream.

- Import socket2, ToSocketAddrs, io, time in async_connection.rs
- async_tcp_stream now creates socket, sets timeouts, connects via socket2
- Ready for future async-runtime integration at this single call-site

Co-Authored-By: Paperclip <noreply@paperclip.ing>
@fewensa fewensa merged commit 9ba4b20 into refactor Mar 14, 2026
@fewensa fewensa deleted the feat/async-tls branch March 14, 2026 03:37
fewensa added a commit that referenced this pull request Mar 14, 2026
* format and special toolchain

* refactor raw builder

* ci

* ci

* ci

* ci

* ci

* danger config

* clippy

* lint

* refactor features

* refactor features

* Revert test host

* Migrate async client to futures and socket2 (#2)

* Migrate async client to futures and socket2 (#3)

* Migrate to socket2: update features, async TLS handling, config tests, and CI (#7)

* Update features and CI for socket2 migration

* Fix rustls feature list

* Bump checkout action to v6

* Fix CI branch and relax dependency specs

* Restore checkout v6 in CI (#8)

* Fix build errors: socket2 API, rustls trait impl, async field access, Alphanumeric type (#9)

- connection/mod.rs: remove incorrect #[cfg(feature = "async")] guard on block_connection
- connection/connection.rs: replace socket.into_tcp_stream() with std::net::TcpStream::from(socket)
- connection/connection.rs: implement missing ServerCertVerifier methods and #[derive(Debug)] for NoCertificateVerification
- connection/connection.rs: call .to_owned() on ServerName to fix lifetime issue
- connection/connection.rs: use Display instead of Debug for native-tls HandshakeError
- request/builder/build_body_async.rs: use self.request field directly instead of self.request() method
- request/builder/form_data.rs: cast u8 to char for Alphanumeric distribution output

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix refactor dependency compatibility (#11)

* Fix refactor dependency compatibility\n\nCo-Authored-By: Paperclip <noreply@paperclip.ing>

* Run CI for refactor PRs\n\nCo-Authored-By: Paperclip <noreply@paperclip.ing>

* Apply rustfmt for CI\n\nCo-Authored-By: Paperclip <noreply@paperclip.ing>

* Fix clippy warnings on refactor branch\n\nCo-Authored-By: Paperclip <noreply@paperclip.ing>

* chore: clean up clippy warnings and upgrade workspace resolver (#12)

- Remove unused native_tls::TlsConnector import in block_connection.rs
- Fix block_send_https_native cfg to only compile when tls-native is enabled
  without tls-rustls (avoids dead_code warning)
- Remove unused ToUrl import in async_connection.rs
- Fix unnecessary mut on disposition in build_body_async.rs
- Gate no_request_features behind cfg to suppress unused warning
- Add resolver = "2" to workspace Cargo.toml for edition 2021 compatibility

* Implement async TLS via futures-rustls (BES-27) (#13)

* Implement async TLS via futures-rustls for async_send_https

- Replace async-rustls (rustls 0.21) with futures-rustls 0.26 (rustls 0.23 compatible)
- Implement async_send_https_rustls using TlsConnector from futures-rustls
- TLS path wraps TcpStream in AllowStdIo for futures-io compatibility
- Expose NoCertificateVerification as pub(crate) for reuse across modules
- Update tls-rustls feature to depend on futures-rustls instead of async-rustls
- Also includes async chunked transfer support in async_read_stream and
  connection_reader (sync path); all cargo test --features async,tls-rustls pass

Co-Authored-By: Paperclip <noreply@paperclip.ing>

* feat: use socket2 directly in async_tcp_stream

Replace delegation to block_tcp_stream with inline socket2-based
connection setup in async_tcp_stream. This makes the async path own
its socket2 usage directly rather than calling through the sync path,
removing the fake-async delegation and keeping the implementation
consistent with the sync block_tcp_stream.

- Import socket2, ToSocketAddrs, io, time in async_connection.rs
- async_tcp_stream now creates socket, sets timeouts, connects via socket2
- Ready for future async-runtime integration at this single call-site

Co-Authored-By: Paperclip <noreply@paperclip.ing>

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>

* feat: implement HTTP auth() with Basic and Bearer support (BES-29) (#14)

Add Auth type with Basic and Bearer variants, and implement the
previously-unimplemented auth() method on HttpClient.

- Add types/auth.rs with Auth::basic() and Auth::bearer() constructors
- Auth::header_value() produces correct Authorization header string
- HttpClient::auth() accepts any AsRef<Auth> and sets Authorization header
- Unit tests for Basic/Bearer header encoding in auth.rs
- Integration tests (test_basic_auth, test_bearer_auth) with echo server
- Add spawn_auth_echo_server() to test support module

Co-authored-by: Paperclip <noreply@paperclip.ing>

* chore: remove empty block_stream.rs placeholder file

* Add local SOCKS proxy coverage (#15)

* Align refactor HTTP client behavior

* Add missing async proxy test attribute (#16)

* Remove dead debug code, update CI branches, bump version to 0.2.0 (#17)

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
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