Skip to main content

Server

Struct Server 

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

The main Actus server.

Implementations§

Source§

impl Server

Source

pub fn new(router: Router) -> Self

Create a server for router with default settings: no middleware, no CORS, the default body cap, and no DoS limits. Configure it with the with_* builder methods, then call run.

Source

pub fn with_middleware(self, middleware: impl Middleware + 'static) -> Self

Adds a middleware to the server’s request processing chain.

Source

pub fn with_cors(self, cors: CorsLayer) -> Self

Enables CORS with the given policy. The server then answers preflight (OPTIONS) requests itself and adds the Access-Control-* headers to every cross-origin response (including error responses). See CorsLayer.

Source

pub fn with_compression(self, layer: CompressionLayer) -> Self

Enables response compression (gzip / brotli). For each response Actus picks an encoding from the request’s Accept-Encoding and compresses buffered, compressible bodies above the layer’s size threshold. See CompressionLayer. (Requires the compression feature.)

Source

pub fn with_max_body_bytes(self, max: usize) -> Self

Caps the request body Actus will buffer (default DEFAULT_MAX_BODY_BYTES = 2 MiB). A larger body is rejected with 413 Payload Too Large before it can exhaust memory — the limit bounds buffered bytes, so it also covers chunked bodies that lie about (or omit) Content-Length.

0 is accepted and means “reject every non-empty body” — typically only useful on a strictly-GET surface that should never see a body.

Source

pub fn with_request_timeout(self, d: Duration) -> Self

Cap the total time any single request may take — body parse, middleware before, handler, middleware after, and finalization combined. An over-budget request is aborted (the handler’s future is dropped) and the client gets 504 Gateway Timeout. No timeout is set by default.

Scope. The timer covers the request/response exchange. A WebSocket upgrade succeeds inside the timer (the 101 is the response); the post-upgrade conversation runs in its own task and is not bound by this timeout.

Effect of an over-budget request. When the timer elapses the in-flight future is dropped, which cancels whatever the handler was awaiting (DB query, channel recv, etc.). The 504 reply is one-shot — the after-chain doesn’t run on it (by definition, some component upstream was unresponsive; running more risks hanging again).

Source

pub fn with_drain_deadline(self, d: Duration) -> Self

Override the grace period for in-flight connections after a shutdown signal (default DEFAULT_DRAIN_DEADLINE = 30 s). Anything still running at the deadline is hard-aborted via JoinSet::shutdown. Use a longer value for surfaces that hold long-lived connections (large file downloads, WebSockets); a shorter value for fast-iteration dev workflows. Duration::ZERO aborts every in-flight task immediately.

Source

pub fn with_max_connections(self, n: usize) -> Self

Cap concurrent connection tasks at n. While the cap is held, the accept loop pauses on permit acquisition; new SYNs queue in the kernel’s accept backlog and (once that fills, governed by SOMAXCONN) get dropped at the OS level. No userland reject / no-503-per-conn cost — the kernel handles the spillover.

Each connection task holds its permit until it ends, including the post-handshake WebSocket conversation. Size accordingly: a with_max_connections(N) server can hold N long-lived WebSockets before it stops accepting new connections of any kind.

Unbounded by default (no semaphore installed).

Source

pub fn with_max_inflight_body_bytes(self, n: usize) -> Self

Cap the total bytes being buffered across all in-flight body reads at n. Each request reserves its per-request cap (see with_max_body_bytes) from this global budget upfront; if the budget is exhausted, the request is refused with 503 Service Unavailable (via WebError::Busy) and a short Retry-After.

Together with Self::with_max_connections this puts a hard ceiling on the framework’s memory under adversarial load: with_max_connections(C) * with_max_body_bytes(B) is the worst case absent this knob; with it, the ceiling is min(C * B, this value).

Pre-reserving the per-request cap over-counts (a 1 KB request reserves up to its full cap); the alternative — incremental per-chunk byte accounting — is more code for the same effective ceiling, and a request that has already started buffering can’t be sensibly aborted partway through anyway.

n is clamped to u32::MAX internally (Tokio’s Semaphore permit count uses u32); for practical deployments this is no limit (4 GiB).

Unbounded by default.

Source

pub fn with_header_read_timeout(self, d: Duration) -> Self

Bound how long after starting to read request headers we’ll wait before dropping the connection. Forwards to hyper’s http1::Builder::header_read_timeout. Catches slowloris (sending headers one byte at a time) and clients that TCP-connect-and-send- nothing — the most common file-descriptor-exhaustion attack on a keep-alive HTTP server.

Note: hyper 1.x doesn’t have a separate “idle between requests” timeout (after a complete request, an idle keep-alive connection stays open until either side closes or the OS-level TCP keep-alive fires). If that matters for your deployment, either disable keep-alive entirely upstream of Actus or rely on the OS knobs.

No timeout by default (hyper’s default).

Source

pub async fn run(self, port: u16) -> Result<(), ServerError>

Runs the server on 127.0.0.1:port (loopback only). For a different bind address — e.g. 0.0.0.0:port to accept connections from other hosts in a container — use Server::run_on.

Listens for SIGTERM/SIGINT (Unix) or Ctrl-C (cross-platform) and shuts down gracefully: stops accepting new connections, signals in-flight connections to finish, and waits up to 30 seconds for them to drain before returning.

Source

pub async fn run_on(self, addr: SocketAddr) -> Result<(), ServerError>

Like Server::run but binds an arbitrary address. Pass 0.0.0.0:port (or [::]:port) to accept connections from other hosts.

Source

pub async fn run_with_shutdown( self, port: u16, shutdown: impl Future<Output = ()> + Send + 'static, ) -> Result<(), ServerError>

Like Server::run but with a custom shutdown trigger (a future that, when it resolves, starts the graceful drain). Binds 127.0.0.1:port; see Server::run_with_shutdown_on for a custom bind address. Useful for tests or for embedding the server in a larger supervision tree.

Source

pub async fn run_with_shutdown_on( self, addr: SocketAddr, shutdown: impl Future<Output = ()> + Send + 'static, ) -> Result<(), ServerError>

The general form: bind addr, serve until shutdown resolves, then drain. Server::run, Server::run_on, and Server::run_with_shutdown are thin wrappers over this.

Drain bound. Once shutdown resolves the server stops accepting and signals every in-flight connection to wind down. The drain deadline defaults to DEFAULT_DRAIN_DEADLINE (30 s); override with Server::with_drain_deadline. Anything still running at the deadline is hard-aborted via JoinSet::shutdown. In particular, long-lived connections (WebSockets, slow downloads, kept-alive idle clients) and any connection task that raced the shutdown notification and missed it both get aborted at the deadline rather than draining gracefully.

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.

Source§

impl<T> Instrument for T

Source§

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

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

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> Same for T

Source§

type Output = T

Should always be Self
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.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

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
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

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