server: Server::with_connection_extensions — populate ConnectionInfo once per connection - #304
Merged
Merged
Conversation
rpb-ant
force-pushed
the
rpb/connection-extensions
branch
from
September 15, 2026 17:28
2dc4d79 to
a967b1f
Compare
ConnectionInfo, with_connection_extensions)Server::with_connection_extensions — populate ConnectionInfo once per connection
rpb-ant
force-pushed
the
rpb/connection-extensions
branch
from
September 16, 2026 03:20
a967b1f to
09887c0
Compare
rpb-ant
changed the base branch from
rpb/server-layers
to
rpb/c-serve-connection
September 16, 2026 03:20
iainmcgin
force-pushed
the
rpb/connection-extensions
branch
from
September 17, 2026 04:48
09887c0 to
7e75d33
Compare
iainmcgin
force-pushed
the
rpb/c-serve-connection
branch
from
September 17, 2026 04:48
4da9e4a to
7648589
Compare
iainmcgin
force-pushed
the
rpb/c-serve-connection
branch
from
September 18, 2026 05:41
7648589 to
f4cfeac
Compare
iainmcgin
force-pushed
the
rpb/connection-extensions
branch
2 times, most recently
from
September 18, 2026 05:49
6dbe05b to
6eb8c6c
Compare
iainmcgin
force-pushed
the
rpb/c-serve-connection
branch
from
September 18, 2026 05:49
f4cfeac to
86f528e
Compare
…fo` once per connection The built-in accept loop gains one optional step between the handshake and `serve_connection`: a `Fn(&mut ConnectionInfo) + Send + Sync` registered with `with_connection_extensions` on `Server`, `BoundServer` or `connectrpc::axum::Serve` (one code path, the shared accept loop; `Server::serve_connection` applies it too). It runs once per accepted connection, on that connection's task, and whatever it puts in `extensions_mut()` rides into every request — the same thing a custom loop does by hand, now available without writing one. `PeerAddr` / `PeerCerts` still always come from the transport. The function is held in a crate-private newtype that asserts unwind safety so the holders keep their auto traits. The mtls-identity example parses the client certificate into a `PeerIdentity` once per connection instead of per request. Tests: runs once per connection across unary and streaming requests on one HTTP/2 connection and again for the next; absent when unset; sees the verified chain over mTLS and cannot forge `PeerCerts` or `PeerAddr`; `Server::serve_connection` applies it; parity through `axum::serve_tls`. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BgcfmMV1ECyzhbqGvUV1a7 Signed-off-by: Ryan Brewster <rpb@anthropic.com>
…nInfo The function registered with `with_connection_extensions` took `&mut ConnectionInfo`, and `ConnectionInfo` is `Default` with public `with_peer_addr` / `with_peer_certs`, so `*conn = std::mem::take(conn).with_peer_addr(spoof)` replaced the peer the transport observed, although the docs promise the function cannot change the peer. The signature is now `Fn(&ConnectionInfo, &mut http::Extensions)`: the function reads the connection (including extensions a custom loop inserted) and whatever it inserts joins the connection's extensions. Changing this after release would be breaking. The `UnwindSafe` rationale now names the holder the assertion preserves (`BoundServer` without `server-tls`). A panic in the function is now caught and logged: the connection is dropped, and `Server::serve_connection` reports `CloseReason::Error` instead of the panic escaping its future. Signed-off-by: Iain McGinniss <309153+iainmcgin@users.noreply.github.com>
iainmcgin
force-pushed
the
rpb/connection-extensions
branch
from
September 18, 2026 05:58
6eb8c6c to
7cceb7a
Compare
iainmcgin
marked this pull request as ready for review
September 18, 2026 05:58
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Per-connection facts, such as an identity parsed from the client certificate, are computed once after the handshake instead of on every request:
Server,BoundServerandconnectrpc::axum::Serve:with_connection_extensions(impl Fn(&ConnectionInfo, &mut http::Extensions) + Send + Sync + 'static). The function reads the connection and fills an empty map, whose entries join the connection's extensions. It cannot remove an entry or change the peer:PeerAddr/PeerCertsstill come only from theConnectionInfopeer fields. It is synchronous and cannot refuse a connection; a custom loop aroundServer::serve_connectiondoes that.Server::serve_connection's future. The freeserver::serve_connectiondoes not run it. A panic in it is logged and drops only that connection, whichServer::serve_connectionreports asCloseReason::Error; underpanic = "abort"it aborts the process.UnwindSafe/RefUnwindSafe, soServer,BoundServerandaxum::Servekeep their auto traits.