Skip to main content

Gate

Trait Gate 

Source
pub trait Gate:
    Send
    + Sync
    + 'static {
    type Ticket: Send + 'static;

    // Required methods
    fn admit(
        &self,
        info: &ConnectionInfo,
        stage: AdmitStage,
    ) -> Result<Admitted<Self::Ticket>, Refusal>;
    fn readmit(
        &self,
        ticket: &mut Self::Ticket,
        info: &ConnectionInfo,
    ) -> Result<(), Refusal>;
    fn check(
        &self,
        ticket: &mut Self::Ticket,
        write: &WriteCheck,
    ) -> Result<(), Denial>;

    // Provided method
    fn closed(
        &self,
        ticket: Self::Ticket,
        info: &ConnectionInfo,
        reason: CloseReason,
    ) { ... }
}
Expand description

Decides who may connect and whether bytes may still leave.

net-io calls admit after accept and before any read, readmit after a trusted PROXY header, check before every write system call, and closed exactly once when an admitted connection closes. A method that panics counts as a refusal or a denial (fail closed).

§Examples

use net_io::{Admitted, AdmitStage, CloseReason, ConnectionInfo, Denial, Gate, GateTag, Lane, Refusal, WriteCheck};
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};

/// One global kill switch and a count of open connections.
struct Switch { revoked: AtomicBool, open: AtomicU64 }

impl Gate for Switch {
    type Ticket = ();
    fn admit(&self, info: &ConnectionInfo, _stage: AdmitStage) -> Result<Admitted<()>, Refusal> {
        if self.revoked.load(Ordering::Acquire) {
            return Err(Refusal::Reset { code: 1 });
        }
        let lane = if info.client_addr().is_some_and(|a| a.ip().is_loopback()) { Lane(0) } else { Lane(3) };
        self.open.fetch_add(1, Ordering::Relaxed);
        Ok(Admitted { lane, ticket: (), tag: GateTag(0) })
    }
    fn readmit(&self, _ticket: &mut (), _info: &ConnectionInfo) -> Result<(), Refusal> {
        Ok(())
    }
    fn check(&self, _ticket: &mut (), _write: &WriteCheck) -> Result<(), Denial> {
        if self.revoked.load(Ordering::Acquire) { Err(Denial { code: 503 }) } else { Ok(()) }
    }
    fn closed(&self, _ticket: (), _info: &ConnectionInfo, _reason: CloseReason) {
        self.open.fetch_sub(1, Ordering::Relaxed);
    }
}

let gate = Switch { revoked: AtomicBool::new(false), open: AtomicU64::new(0) };
let info = ConnectionInfo::for_testing("127.0.0.1:9".parse().unwrap());
let admitted = gate.admit(&info, AdmitStage::Accept).unwrap();
assert_eq!(admitted.lane, Lane(0));

Required Associated Types§

Source

type Ticket: Send + 'static

Per-connection state the gate keeps; net-io stores it beside the connection.

Required Methods§

Source

fn admit( &self, info: &ConnectionInfo, stage: AdmitStage, ) -> Result<Admitted<Self::Ticket>, Refusal>

After accept and before any read (Accept), on Server::adopt (Adopt), or when a client connection gets a gate (Dialed).

§Errors

A Refusal closes the connection abortively without reading.

Source

fn readmit( &self, ticket: &mut Self::Ticket, info: &ConnectionInfo, ) -> Result<(), Refusal>

After a trusted PROXY header revealed the real client (info.real_peer is set).

There is no default: a gate that does not care about proxies writes Ok(()) on purpose (decision D-060).

§Errors

A Refusal closes the connection abortively.

Source

fn check( &self, ticket: &mut Self::Ticket, write: &WriteCheck, ) -> Result<(), Denial>

Before every write system call. The path where nothing is revoked should be one atomic load.

§Errors

A Denial wipes pending output, writes the session’s denial if no byte of the current response has left, and resets the connection.

Provided Methods§

Source

fn closed( &self, ticket: Self::Ticket, info: &ConnectionInfo, reason: CloseReason, )

Exactly once per admitted connection, after it closed, with its one close reason.

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§