///|
/// The bounds a server applies to each connection and request. Build them
/// from `ServerLimits::default()` with a record update; `validate` refuses
/// values that would disable a bound.
///
/// ```mbt check
/// test {
/// let limits = { ..@h1server.ServerLimits::default(), max_body_bytes: 4096, }
/// limits.validate()
/// assert_eq(limits.max_header_bytes, 16384)
/// }
/// ```
#derive(Eq, Debug)
pub(all) struct ServerLimits {
/// Request body bytes after transfer framing; a larger Content-Length is
/// refused with 413 before the handler runs, and a chunked body fails at
/// the chunk that crosses it. At least 0.
max_body_bytes : Int32
/// Waiting for a request head and reading it, from the end of the
/// previous exchange (or the start of the connection). At least 1.
header_timeout_ms : Int32
/// Reading one request body, from its first pull to its end, and each
/// write of the response and each read of a streamed response body. At
/// least 1.
body_timeout_ms : Int32
/// One request head, the start line, empty lines before it and the final
/// CRLF CRLF included. At least 1.
max_header_bytes : Int32
/// Accepted connections the listener adapter may serve at once. The
/// adapter enforces this across calls to `serve_conn`. At least 1.
max_connections : Int32
/// Unread request body bytes the server reads and discards after the
/// response so the connection can serve the next request; a longer rest
/// closes the connection instead. At least 0.
drain_max_bytes : Int32
/// Running the handler, until it returns the response; `None` sets no
/// limit. At least 1 when set.
handler_timeout_ms : Int32?
/// How long the listener adapter lets running exchanges and background
/// work finish after a stop before it cancels them. At least 0.
drain_ms : Int32
}
///|
/// Compares limits field by field.
pub extend ServerLimits with Eq::{equal, not_equal}
///|
/// Formats limits for diagnostics.
pub extend ServerLimits with @debug.Debug::{to_repr}
///|
/// 1 MiB bodies, five-second header and body budgets, 16 KiB heads, 256
/// connections, 64 KiB of unread body drained, no handler deadline and ten
/// seconds to drain at shutdown.
pub fn ServerLimits::default() -> ServerLimits {
{
max_body_bytes: 1048576,
header_timeout_ms: 5000,
body_timeout_ms: 5000,
max_header_bytes: 16384,
max_connections: 256,
drain_max_bytes: 65536,
handler_timeout_ms: None,
drain_ms: 10000,
}
}
///|
/// Settings refused before any connection is served.
#derive(Debug)
pub(all) suberror ServerConfigError {
InvalidMaxBodyBytes(value~ : Int32)
InvalidBodyTimeoutMs(value~ : Int32)
InvalidHeaderTimeoutMs(value~ : Int32)
InvalidMaxConnections(value~ : Int32)
InvalidMaxHeaderBytes(value~ : Int32)
InvalidDrainMaxBytes(value~ : Int32)
InvalidHandlerTimeoutMs(value~ : Int32)
InvalidDrainMs(value~ : Int32)
}
///|
/// Formats the refused setting for diagnostics.
pub extend ServerConfigError with @debug.Debug::{to_repr}
///|
/// Refuses limits that would disable a bound, naming the first invalid
/// field.
pub fn ServerLimits::validate(
self : ServerLimits,
) -> Unit raise ServerConfigError {
if self.max_body_bytes < 0 {
raise InvalidMaxBodyBytes(value=self.max_body_bytes)
}
if self.header_timeout_ms <= 0 {
raise InvalidHeaderTimeoutMs(value=self.header_timeout_ms)
}
if self.body_timeout_ms <= 0 {
raise InvalidBodyTimeoutMs(value=self.body_timeout_ms)
}
if self.max_header_bytes < 1 {
raise InvalidMaxHeaderBytes(value=self.max_header_bytes)
}
if self.max_connections < 1 {
raise InvalidMaxConnections(value=self.max_connections)
}
if self.drain_max_bytes < 0 {
raise InvalidDrainMaxBytes(value=self.drain_max_bytes)
}
if self.handler_timeout_ms is Some(value) && value <= 0 {
raise InvalidHandlerTimeoutMs(value~)
}
if self.drain_ms < 0 {
raise InvalidDrainMs(value=self.drain_ms)
}
}