Skip to content

Feature/grpc tunneling#100

Merged
MitulShah1 merged 5 commits intomainfrom
feature/grpc-tunneling
Mar 13, 2026
Merged

Feature/grpc tunneling#100
MitulShah1 merged 5 commits intomainfrom
feature/grpc-tunneling

Conversation

@MitulShah1
Copy link
Collaborator

fix #98

- Detect Content-Type: application/grpc* in ingress and tag stream as
  Protocol::GRPC (variant was already reserved in the protocol crate)
- Use hyper::client::conn::http2::handshake over VirtualStream for gRPC
  streams so HTTP/2 framing and trailers are preserved end-to-end
- Add use_h2 field + with_pool_h2() to LocalProxyService; h2 path calls
  pool.acquire_h2() instead of acquire_h1()
- Add HttpProxy::handle_grpc_stream() that serves VirtualStream via
  hyper::server::conn::http2::Builder with a prefer_h2 pool
- CLI StreamHandler::handle dispatches Protocol::GRPC to handle_grpc_stream
  automatically — no new flags required
- Integration tests: test_grpc_tunnel (end-to-end) and
  test_non_grpc_not_classified_as_grpc (regression guard for HTTP path)
- Example: examples/basic/grpc_tunnel.rs
- Update CHANGELOG.md (Unreleased v1.0.5) and ROADMAP.md
)

rustls 0.23 requires rustls::crypto::ring::default_provider().install_default()
to be called before any ClientConfig/ServerConfig is built. The feature flag makes
the provider available but does NOT auto-install it.

The test suite already calls this in test helpers, so tests passed. The release
binary did not, causing a panic on the first TLS connection attempt in a tokio
worker thread.

Add the install_default() call at the top of main() and add rustls as a direct
dependency of ferrotunnel-cli so the call compiles without relying on a
transitive re-export.

Closes #98
Copilot AI review requested due to automatic review settings March 13, 2026 06:59
@chatgpt-codex-connector
Copy link

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses issue #98 (rustls 0.23 CryptoProvider panic in the CLI) and adds end-to-end gRPC tunneling support by detecting gRPC requests at the HTTP ingress and proxying them over HTTP/2 through the tunnel.

Changes:

  • Fix CLI TLS panic by explicitly installing rustls’s ring CryptoProvider at startup and adding rustls as a direct CLI dependency.
  • Add gRPC detection (Content-Type: application/grpc*) and an HTTP/2 forwarding path to preserve gRPC trailer semantics end-to-end.
  • Add a gRPC example and integration tests; bump workspace/crate versions to 1.0.6.

Reviewed changes

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

Show a summary per file
File Description
tools/soak/Cargo.toml Bumps ferrotunnel dependency version to align with workspace versioning.
tests/integration/mod.rs Registers new gRPC integration test module.
tests/integration/grpc_test.rs Adds end-to-end gRPC tunneling tests (currently not asserting trailers).
ferrotunnel/Cargo.toml Updates internal crate dependency versions to 1.0.6.
ferrotunnel-observability/Cargo.toml Updates dependency version to 1.0.6.
ferrotunnel-http/src/proxy.rs Adds HTTP/2 local forwarding mode + handle_grpc_stream() for tunnel streams.
ferrotunnel-http/src/ingress.rs Detects gRPC and uses HTTP/2 client handshake over VirtualStream when detected.
ferrotunnel-http/Cargo.toml Updates internal crate dependency versions to 1.0.6.
ferrotunnel-core/Cargo.toml Updates internal crate dependency versions to 1.0.6.
ferrotunnel-cli/src/main.rs Installs rustls ring CryptoProvider early to prevent TLS panic.
ferrotunnel-cli/src/commands/client.rs Dispatches Protocol::GRPC streams to the new HTTP/2 handling path.
ferrotunnel-cli/Cargo.toml Bumps internal deps to 1.0.6 and adds direct rustls dependency.
examples/basic/grpc_tunnel.rs Adds a runnable gRPC tunneling example.
examples/Cargo.toml Registers the new grpc_tunnel example.
ROADMAP.md Updates roadmap items to reference v1.0.6 (contains duplicate v1.0.6 headings).
Cargo.toml Bumps workspace version to 1.0.6 and updates workspace dependency version pinning.
CHANGELOG.md Adds 1.0.6 “Unreleased” notes; updates compare links (currently inconsistent for an unreleased tag).

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

Comment on lines 154 to 156
let is_ws = is_websocket_upgrade(req.headers());
let is_grpc = is_grpc(req.headers());

Comment on lines +326 to +330
let grpc_pool = Arc::new(ConnectionPool::new(
self.target_addr.clone(),
PoolConfig {
prefer_h2: true,
..PoolConfig::default()
Comment on lines +19 to +24
/// Accepts any POST request and responds with:
/// - status 200
/// - `content-type: application/grpc`
/// - body: empty gRPC message frame (5-byte prefix + 0 bytes)
/// - trailer: `grpc-status: 0`
async fn start_grpc_server(addr: SocketAddr) -> tokio::task::JoinHandle<()> {
ROADMAP.md Outdated
Comment on lines +49 to +53
- **v1.0.6** - gRPC Support (in development)
- Native gRPC tunneling over HTTP/2 with automatic detection and trailer preservation
- **Target Audience**: Enterprise and microservices developers

- **v1.0.5** - QUIC Transport (HTTP/3)
- **v1.0.6** - QUIC Transport (HTTP/3)
CHANGELOG.md Outdated
| `ferrotunnel-common` | Shared types and errors |

[Unreleased]: https://github.com/ferro-labs/ferrotunnel/compare/v1.0.4...HEAD
[Unreleased]: https://github.com/ferro-labs/ferrotunnel/compare/v1.0.6...HEAD
- ingress: recompute is_grpc from parts.headers after plugin request
  hooks, so plugins that modify Content-Type are respected
- ingress: reconstruct absolute HTTP/2 URI (scheme + authority) from
  the Host header when the forwarded request has a path-only URI —
  hyper's h2 client requires :scheme/:authority pseudo-headers
  (User(MissingUriSchemeAndAuthority) was causing 502 in tests)
- client (library): dispatch Protocol::GRPC streams to
  handle_grpc_stream() instead of always calling handle_stream();
  fixes the integration test 502 and mirrors the CLI dispatch logic
- proxy: remove unused prefer_h2:true from handle_grpc_stream's
  PoolConfig (PoolConfig::prefer_h2 is not wired into acquire routing);
  update doc comment accordingly
- grpc_test: mock server now emits a real grpc-status:0 HTTP/2
  trailer via StreamBody; test asserts the trailer is preserved
  end-to-end through the tunnel
- ROADMAP: disambiguate duplicate v1.0.6 entries — QUIC → v1.0.7,
  Multi-region → v1.0.8, Custom Domains → v1.0.9
- CHANGELOG: restore [Unreleased] compare link to v1.0.4...HEAD until
  the v1.0.6 tag is published
- Add ### gRPC Tunneling section after HTTP/2 & Connection Pooling
- Add gRPC row to features table
- Remove examples/basic/grpc_tunnel.rs and its Cargo.toml entry
- Fix clippy::map_unwrap_or lint in ferrotunnel-http/src/ingress.rs
@MitulShah1 MitulShah1 merged commit e63806d into main Mar 13, 2026
15 checks passed
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.

TLS CryptoProvider panic: rustls 0.23 requires explicit install_default() in CLI binary

2 participants