Skip to main content

Connection

Struct Connection 

Source
pub struct Connection { /* private fields */ }
Expand description

An accepted HTTP/3 connection.

Implementations§

Source§

impl Connection

Source

pub async fn handshake( quic: Connection, within: Duration, dropped_datagrams: Arc<AtomicU64>, ) -> Result<Self, ConnectionError>

Performs the HTTP/3 handshake on an established QUIC connection.

The SETTINGS this sends are not a preference but a requirement: Surge validates SETTINGS_ENABLE_CONNECT_PROTOCOL and SETTINGS_H3_DATAGRAM during setup and disconnects if either is missing.

The two QPACK streams are opened even though RFC 9204 §4.2 permits omitting them (“An endpoint MAY avoid creating an encoder stream if it will not be used”). Nothing is ever written to them; they exist because every deployed stack opens them, and interoperating with one particular client is this server’s whole purpose.

§The deadline

within bounds all of that, and it has to: opening three unidirectional streams is the peer’s decision, not this endpoint’s. Transport parameters that allow fewer than three of them – or no data on them – park the handshake with no way out, and the QUIC idle timeout is no backstop, because crate::quic enables a keep-alive whose PINGs the peer’s stack answers without any application ever being involved. Each such connection would hold a max_connections slot for as long as the peer cares to keep the socket open.

One idle timeout is the bound the caller passes, and it is generous by construction: a peer that cannot complete a three-stream handshake in the time it is allowed to say nothing at all is not going to complete it.

dropped_datagrams is where this connection counts every inbound HTTP Datagram it drops rather than delivers. The caller supplies it, keeping a clone of its own, because the count is read for the connection’s closing log line – which is written after everything constructed here is gone.

Source

pub fn peer_datagrams(&self) -> Arc<AtomicBool>

A live view of whether the peer advertised SETTINGS_H3_DATAGRAM = 1.

RFC 9297 §2.1.1 forbids sending HTTP Datagrams before this is true, and a CONNECT-UDP session falls back to capsules on the request stream while it is not. The flag is handed out rather than sampled, for the reason the module documentation gives.

Until the peer’s SETTINGS arrive it reads false, which is the safe direction to be wrong in.

Source

pub async fn accept(&mut self) -> Result<Option<Resolver>, ConnectionError>

Waits for the next request stream.

Cancel-safe: [quinn::Connection::accept_bi] leaves an unaccepted stream queued, so a caller may poll this inside a select!.

Ok(None) would mean “the peer will send no further requests”, and this server never reports it. The only thing that could say so is a GOAWAY from the client, which promises nothing about the requests already in flight – while the caller reads Ok(None) as permission to drop the connection, and dropping it would cut those requests off mid-tunnel. A connection therefore ends when the peer closes it or the idle timeout fires, both of which arrive here as Err.

Source

pub async fn shutdown(&mut self) -> Result<(), ConnectionError>

Starts a graceful shutdown by sending GOAWAY (RFC 9114 §5.2).

The identifier is the first request this connection will not serve – four past the last one accepted, or zero if none was – so everything already in flight is untouched and the client knows to take new work elsewhere. Requests arriving past it are rejected in Self::accept with H3_REQUEST_REJECTED, the code a client may safely retry on.

Note what this does not do: it does not wait for anything, and the connection stays usable afterwards. Deciding when the existing tunnels are done is the caller’s job.

Source

pub fn close_quietly(&self, reason: &'static str) -> ConnectionError

Ends the connection because this endpoint is done with it, not because anything went wrong.

The counterpart of the violation close: the same mechanism – RFC 9114 §8 makes a CONNECTION_CLOSE carrying an HTTP/3 code be the connection error – with the code §8.1 defines for having nothing to report:

reason reaches the peer in the CONNECTION_CLOSE frame and comes back in the returned error, which crate::h3api::benign_close grades as a routine ending rather than a fault – so the caller can break on it and let the connection’s closing line stay at the level an idle timeout gets. Returning the error rather than logging here is what keeps that grading in one place (D50).

Trait Implementations§

Source§

impl Drop for Connection

Source§

fn drop(&mut self)

Closes the QUIC connection and stops reading the peer’s streams and datagrams.

H3_NO_ERROR is RFC 9114 §8.1’s code for when “the connection or stream needs to be closed, but there is no error to signal”. quic.rs depends on this happening: it is why quinn::Connection::close_reason() cannot be used to grade a connection’s closing log line, and why the error value returned by conn::handle is graded instead.

Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more