#[non_exhaustive]pub struct Server {
pub app_state: Arc<AppState>,
pub http_addr: Option<SocketAddr>,
pub https_addr: Option<SocketAddr>,
/* private fields */
}Expand description
HTTP(S) server.
Fields (Non-exhaustive)§
This struct is marked as non-exhaustive
Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.app_state: Arc<AppState>RFC 071: shared via Arc, not cloned per request. HTTP and HTTPS
listeners each hold a clone of this Arc (a pointer bump, not a
clone of AppState’s contents) rather than each keeping its own
independent copy of the state as before.
http_addr: Option<SocketAddr>§https_addr: Option<SocketAddr>Implementations§
Source§impl Server
impl Server
Sourcepub async fn new(config: Config) -> ServerResult<Self>
pub async fn new(config: Config) -> ServerResult<Self>
Resolve listener addresses and build the server shell.
Also compiles Rhai middlewares listed in
config.service.middlewares_file_paths. Compilation happens here
(not in the config crate) because the compiled artefact is a
runtime object — see the server-level module docstring.
§TLS material is loaded here, eagerly (RFC 074 S-08)
If [listener.tls] is present, its cert/key are loaded and the
TLS config built as part of this call — not lazily, the first
time bind_https runs. A malformed PEM (the file exists —
apimock_config::Config::new already rejected a missing one —
but doesn’t parse) now fails Server::new itself, which
App::new propagates with ?, which main propagates with
?: the process exits before main ever reaches
app.server.start().await, so no listener binds, HTTP
included. Building this lazily inside bind_https — the
previous behaviour — let https_start log the error and return
while any separately-configured HTTP listener kept serving,
which is exactly the silent HTTP-only degradation this RFC
exists to close.
Sourcepub async fn bind_http(&self) -> ServerResult<Option<TcpListener>>
pub async fn bind_http(&self) -> ServerResult<Option<TcpListener>>
Bind the HTTP listener without accepting connections yet.
Returns Ok(None) if no HTTP listener is configured, Ok(Some(_))
on a successful bind, or Err if the bind itself failed — this is
the piece http_start used to swallow via log::error! + early
return, with no way for a caller to observe it.
Splitting bind from serve exists for callers (namely the
integration-test harness) that need the two to be separate steps:
bind, read back the real port via local_addr() (useful when
[listener].port is 0 and the OS assigns one), then hand the
same listener to Server::serve_http. Because it’s the same
listener throughout, there is no window between “port known” and
“port held” for another process to take it.
Sourcepub async fn serve_http(&self, listener: TcpListener)
pub async fn serve_http(&self, listener: TcpListener)
Accept connections forever on an already-bound HTTP listener.
Sourcepub async fn bind_https(
&self,
) -> ServerResult<Option<(TcpListener, TlsAcceptor)>>
pub async fn bind_https( &self, ) -> ServerResult<Option<(TcpListener, TlsAcceptor)>>
Bind the HTTPS listener without accepting connections yet. See
Server::bind_http for why this is split from serving.
TLS material is already loaded and validated by this point —
see Server::new’s doc comment — so the only failure left
here is the socket bind itself (e.g. the port is in use).
Sourcepub async fn serve_https(&self, listener: TcpListener, acceptor: TlsAcceptor)
pub async fn serve_https(&self, listener: TcpListener, acceptor: TlsAcceptor)
Accept connections forever on an already-bound HTTPS listener.
§RFC 074 S-07: handshake timeout and connection cap
A connection that opens and never completes its TLS handshake is
dropped after handshake_timeout — previously nothing bounded
this, so such a connection held its task (and the OS socket)
forever. Concurrency is bounded by a Semaphore sized to
max_connections: a permit is acquired before spawning the
per-connection task, so once max_connections connections are
in flight, listener.accept() keeps accepting into the kernel
backlog but this loop stops handing new connections to the TLS
handshake until a permit frees — the server recovers as soon as
existing connections close, rather than needing a restart.