lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

server.rs (80674B)


      1 //! Bounded HTTP/1.1 administration server over an owned Unix listener.
      2 
      3 use core::fmt;
      4 use serde::{Deserialize, Deserializer, Serialize, de, de::DeserializeOwned};
      5 use serde_json::value::RawValue;
      6 use std::collections::{BTreeMap, BTreeSet};
      7 use std::convert::Infallible;
      8 use std::error::Error;
      9 use std::future::Future;
     10 use std::io;
     11 use std::pin::Pin;
     12 use std::sync::{Arc, Mutex};
     13 
     14 use bytes::Bytes;
     15 use http::header::{CONTENT_TYPE, HeaderMap, HeaderValue};
     16 use http::{Method, Request, Response, StatusCode, Version};
     17 use http_body_util::{BodyExt, Full, LengthLimitError, Limited};
     18 use hyper::body::Incoming;
     19 use hyper::server::conn::http1;
     20 use hyper::service::service_fn;
     21 use hyper_util::rt::{TokioIo, TokioTimer};
     22 use tokio::sync::Semaphore;
     23 use tokio::task::JoinSet;
     24 
     25 #[cfg(test)]
     26 use super::test_support;
     27 use super::{
     28     ADMIN_CONTRACT_VERSION, AdminCorrelationId, AdminError, AdminErrorCode, AdminErrorMessage,
     29     AdminFailureResponse, AdminMutationRequest, AdminTransportLimits, UnixAdminSocketBinding,
     30 };
     31 use crate::{CancellationToken, EntropySource, SystemEntropy};
     32 
     33 /// Smallest configured response cap that can always carry a safe v1 failure envelope.
     34 pub const ADMIN_MIN_RESPONSE_BODY_UTF8_BYTES: u32 = 512;
     35 
     36 pub const ADMIN_ROUTE_PATH_MAX_UTF8_BYTES: usize = 256;
     37 pub const ADMIN_ROUTE_PARAMETER_NAME_MAX_UTF8_BYTES: usize = 64;
     38 pub const ADMIN_ROUTE_PARAMETER_VALUE_MAX_UTF8_BYTES: usize = 128;
     39 const HTTP_MINIMUM_MAX_BUFFER_SIZE: usize = 8 * 1024;
     40 const JSON_CONTENT_TYPE: &str = "application/json";
     41 const FALLBACK_CORRELATION_ID: &str = "correlation-unavailable";
     42 
     43 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
     44 pub enum AdminHttpMethod {
     45     Get,
     46     Post,
     47 }
     48 
     49 impl AdminHttpMethod {
     50     fn from_http(method: &Method) -> Option<Self> {
     51         if method == Method::GET {
     52             Some(Self::Get)
     53         } else if method == Method::POST {
     54             Some(Self::Post)
     55         } else {
     56             None
     57         }
     58     }
     59 }
     60 
     61 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
     62 pub enum AdminRoutePathError {
     63     Empty,
     64     TooLong,
     65     WrongVersionPrefix,
     66     InvalidCharacter,
     67     EmptySegment,
     68     InvalidParameter,
     69     DuplicateParameter,
     70 }
     71 
     72 impl fmt::Display for AdminRoutePathError {
     73     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
     74         formatter.write_str("admin route path is not a canonical v1 route")
     75     }
     76 }
     77 
     78 impl Error for AdminRoutePathError {}
     79 
     80 #[derive(Clone, Debug, PartialEq, Eq)]
     81 pub struct AdminRoutePath {
     82     canonical: String,
     83     segments: Vec<AdminRouteSegment>,
     84     literal_count: usize,
     85 }
     86 
     87 #[derive(Clone, Debug, PartialEq, Eq)]
     88 enum AdminRouteSegment {
     89     Literal(String),
     90     Parameter(String),
     91 }
     92 
     93 impl AdminRoutePath {
     94     pub fn new(value: impl AsRef<str>) -> Result<Self, AdminRoutePathError> {
     95         let value = value.as_ref();
     96         if value.is_empty() {
     97             return Err(AdminRoutePathError::Empty);
     98         }
     99         if value.len() > ADMIN_ROUTE_PATH_MAX_UTF8_BYTES {
    100             return Err(AdminRoutePathError::TooLong);
    101         }
    102         if !value.starts_with("/v1/") || value.ends_with('/') {
    103             return Err(AdminRoutePathError::WrongVersionPrefix);
    104         }
    105         let mut parameter_names = BTreeSet::new();
    106         let mut literal_count = 0;
    107         for segment in value[1..].split('/') {
    108             if segment.is_empty() {
    109                 return Err(AdminRoutePathError::EmptySegment);
    110             }
    111             if let Some(parameter) = segment
    112                 .strip_prefix('{')
    113                 .and_then(|segment| segment.strip_suffix('}'))
    114             {
    115                 if !valid_parameter_name(parameter) {
    116                     return Err(AdminRoutePathError::InvalidParameter);
    117                 }
    118                 if !parameter_names.insert(parameter) {
    119                     return Err(AdminRoutePathError::DuplicateParameter);
    120                 }
    121             } else {
    122                 if !segment
    123                     .bytes()
    124                     .all(|byte| matches!(byte, b'a'..=b'z' | b'0'..=b'9' | b'_' | b'-'))
    125                 {
    126                     return Err(AdminRoutePathError::InvalidCharacter);
    127                 }
    128                 literal_count += 1;
    129             }
    130         }
    131         let segments = value[1..]
    132             .split('/')
    133             .map(|segment| {
    134                 segment
    135                     .strip_prefix('{')
    136                     .and_then(|segment| segment.strip_suffix('}'))
    137                     .map_or_else(
    138                         || AdminRouteSegment::Literal(segment.to_owned()),
    139                         |parameter| AdminRouteSegment::Parameter(parameter.to_owned()),
    140                     )
    141             })
    142             .collect();
    143         Ok(Self {
    144             canonical: value.to_owned(),
    145             segments,
    146             literal_count,
    147         })
    148     }
    149 
    150     #[must_use]
    151     pub fn as_str(&self) -> &str {
    152         &self.canonical
    153     }
    154 
    155     fn overlaps(&self, other: &Self) -> bool {
    156         self.segments.len() == other.segments.len()
    157             && self
    158                 .segments
    159                 .iter()
    160                 .zip(&other.segments)
    161                 .all(|(left, right)| match (left, right) {
    162                     (AdminRouteSegment::Literal(left), AdminRouteSegment::Literal(right)) => {
    163                         left == right
    164                     }
    165                     _ => true,
    166                 })
    167     }
    168 
    169     fn match_path(&self, path: &str) -> Option<BTreeMap<String, String>> {
    170         if !path.starts_with('/') || path.ends_with('/') || path.contains("//") {
    171             return None;
    172         }
    173         let raw_segments = path[1..].split('/').collect::<Vec<_>>();
    174         if raw_segments.len() != self.segments.len() {
    175             return None;
    176         }
    177         let mut parameters = BTreeMap::new();
    178         for (pattern, raw) in self.segments.iter().zip(raw_segments) {
    179             match pattern {
    180                 AdminRouteSegment::Literal(literal) if literal != raw => return None,
    181                 AdminRouteSegment::Literal(_) => {}
    182                 AdminRouteSegment::Parameter(name) => {
    183                     parameters.insert(name.clone(), decode_route_parameter(raw)?);
    184                 }
    185             }
    186         }
    187         Some(parameters)
    188     }
    189 }
    190 
    191 fn valid_parameter_name(value: &str) -> bool {
    192     value.len() <= ADMIN_ROUTE_PARAMETER_NAME_MAX_UTF8_BYTES
    193         && matches!(value.as_bytes().first(), Some(b'a'..=b'z'))
    194         && value
    195             .bytes()
    196             .all(|byte| matches!(byte, b'a'..=b'z' | b'0'..=b'9' | b'_'))
    197 }
    198 
    199 fn decode_route_parameter(raw: &str) -> Option<String> {
    200     if raw.is_empty() {
    201         return None;
    202     }
    203     let raw = raw.as_bytes();
    204     let mut decoded = Vec::with_capacity(raw.len().min(ADMIN_ROUTE_PARAMETER_VALUE_MAX_UTF8_BYTES));
    205     let mut index = 0;
    206     while index < raw.len() {
    207         let byte = if raw[index] == b'%' {
    208             let high = *raw.get(index + 1)?;
    209             let low = *raw.get(index + 2)?;
    210             index += 3;
    211             (hex_nibble(high)? << 4) | hex_nibble(low)?
    212         } else {
    213             let byte = raw[index];
    214             index += 1;
    215             byte
    216         };
    217         if byte == b'/' || byte == b'\\' || byte == 0 || byte.is_ascii_control() {
    218             return None;
    219         }
    220         if decoded.len() == ADMIN_ROUTE_PARAMETER_VALUE_MAX_UTF8_BYTES {
    221             return None;
    222         }
    223         decoded.push(byte);
    224     }
    225     String::from_utf8(decoded)
    226         .ok()
    227         .filter(|value| !value.is_empty())
    228 }
    229 
    230 fn hex_nibble(value: u8) -> Option<u8> {
    231     match value {
    232         b'0'..=b'9' => Some(value - b'0'),
    233         b'a'..=b'f' => Some(value - b'a' + 10),
    234         b'A'..=b'F' => Some(value - b'A' + 10),
    235         _ => None,
    236     }
    237 }
    238 
    239 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
    240 pub enum AdminRouteRegistrationError {
    241     InvalidPath(AdminRoutePathError),
    242     Duplicate,
    243     Ambiguous,
    244 }
    245 
    246 impl fmt::Display for AdminRouteRegistrationError {
    247     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    248         formatter.write_str("admin route registration is invalid")
    249     }
    250 }
    251 
    252 impl Error for AdminRouteRegistrationError {}
    253 
    254 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
    255 pub enum AdminRequestDecodeError {
    256     Empty,
    257     Malformed,
    258 }
    259 
    260 impl fmt::Display for AdminRequestDecodeError {
    261     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    262         formatter.write_str("admin request body is not valid JSON")
    263     }
    264 }
    265 
    266 impl Error for AdminRequestDecodeError {}
    267 
    268 /// Validated request metadata and a bounded raw JSON body.
    269 pub struct AdminRequest {
    270     method: AdminHttpMethod,
    271     path: AdminRoutePath,
    272     query: Option<String>,
    273     correlation_id: AdminCorrelationId,
    274     parameters: BTreeMap<String, String>,
    275     body: Bytes,
    276     response_body_limit: usize,
    277 }
    278 
    279 impl AdminRequest {
    280     #[must_use]
    281     pub const fn method(&self) -> AdminHttpMethod {
    282         self.method
    283     }
    284 
    285     #[must_use]
    286     pub const fn path(&self) -> &AdminRoutePath {
    287         &self.path
    288     }
    289 
    290     #[must_use]
    291     pub fn query(&self) -> Option<&str> {
    292         self.query.as_deref()
    293     }
    294 
    295     #[must_use]
    296     pub const fn correlation_id(&self) -> &AdminCorrelationId {
    297         &self.correlation_id
    298     }
    299 
    300     #[must_use]
    301     pub fn parameter(&self, name: &str) -> Option<&str> {
    302         self.parameters.get(name).map(String::as_str)
    303     }
    304 
    305     #[must_use]
    306     pub fn body(&self) -> &[u8] {
    307         &self.body
    308     }
    309 
    310     pub fn decode_json<T>(&self) -> Result<T, AdminRequestDecodeError>
    311     where
    312         T: DeserializeOwned,
    313     {
    314         if self.body.is_empty() {
    315             return Err(AdminRequestDecodeError::Empty);
    316         }
    317         serde_json::from_slice(&self.body).map_err(|_| AdminRequestDecodeError::Malformed)
    318     }
    319 
    320     pub fn success<T>(&self, result: &T) -> Result<AdminRouteOutcome, AdminRouteOutcomeError>
    321     where
    322         T: Serialize,
    323     {
    324         let encoded =
    325             encode_bounded(result, self.response_body_limit).map_err(|error| match error {
    326                 BoundedEncodingError::Limit => AdminRouteOutcomeError::ResponseLimit,
    327                 BoundedEncodingError::Encoding => AdminRouteOutcomeError::Encoding,
    328             })?;
    329         let _: StrictJsonPayload =
    330             serde_json::from_slice(&encoded).map_err(|_| AdminRouteOutcomeError::InvalidPayload)?;
    331         let encoded =
    332             String::from_utf8(encoded).expect("serde_json output must always be valid UTF-8");
    333         let result =
    334             RawValue::from_string(encoded).map_err(|_| AdminRouteOutcomeError::Encoding)?;
    335         Ok(AdminRouteOutcome(AdminRouteOutcomeKind::Success(result)))
    336     }
    337 }
    338 
    339 impl fmt::Debug for AdminRequest {
    340     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    341         formatter
    342             .debug_struct("AdminRequest")
    343             .field("method", &self.method)
    344             .field("path", &self.path)
    345             .field("query", &self.query.as_ref().map(|_| "[redacted]"))
    346             .field("correlation_id", &self.correlation_id)
    347             .field(
    348                 "parameter_names",
    349                 &self.parameters.keys().collect::<Vec<_>>(),
    350             )
    351             .field("body", &"[redacted]")
    352             .finish()
    353     }
    354 }
    355 
    356 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
    357 pub enum AdminRouteOutcomeError {
    358     Encoding,
    359     InvalidPayload,
    360     ResponseLimit,
    361 }
    362 
    363 impl fmt::Display for AdminRouteOutcomeError {
    364     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    365         formatter.write_str(match self {
    366             Self::Encoding => "admin route result could not be encoded",
    367             Self::InvalidPayload => "admin route result violates the JSON payload contract",
    368             Self::ResponseLimit => "admin route result exceeds the response limit",
    369         })
    370     }
    371 }
    372 
    373 impl Error for AdminRouteOutcomeError {}
    374 
    375 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
    376 pub enum AdminRouteFailureStatus {
    377     BadRequest,
    378     NotFound,
    379     Conflict,
    380     Unavailable,
    381     Internal,
    382 }
    383 
    384 impl AdminRouteFailureStatus {
    385     const fn http_status(self) -> StatusCode {
    386         match self {
    387             Self::BadRequest => StatusCode::BAD_REQUEST,
    388             Self::NotFound => StatusCode::NOT_FOUND,
    389             Self::Conflict => StatusCode::CONFLICT,
    390             Self::Unavailable => StatusCode::SERVICE_UNAVAILABLE,
    391             Self::Internal => StatusCode::INTERNAL_SERVER_ERROR,
    392         }
    393     }
    394 }
    395 
    396 #[derive(Clone, Debug, PartialEq, Eq)]
    397 pub struct AdminRouteFailure {
    398     status: AdminRouteFailureStatus,
    399     error: AdminError,
    400 }
    401 
    402 impl AdminRouteFailure {
    403     #[must_use]
    404     pub const fn new(status: AdminRouteFailureStatus, error: AdminError) -> Self {
    405         Self { status, error }
    406     }
    407 
    408     #[must_use]
    409     pub const fn status(&self) -> AdminRouteFailureStatus {
    410         self.status
    411     }
    412 
    413     #[must_use]
    414     pub const fn error(&self) -> &AdminError {
    415         &self.error
    416     }
    417 }
    418 
    419 enum AdminRouteOutcomeKind {
    420     Success(Box<RawValue>),
    421     Failure(AdminRouteFailure),
    422 }
    423 
    424 pub struct AdminRouteOutcome(AdminRouteOutcomeKind);
    425 
    426 impl AdminRouteOutcome {
    427     #[must_use]
    428     pub const fn failure(failure: AdminRouteFailure) -> Self {
    429         Self(AdminRouteOutcomeKind::Failure(failure))
    430     }
    431 }
    432 
    433 impl fmt::Debug for AdminRouteOutcome {
    434     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    435         match &self.0 {
    436             AdminRouteOutcomeKind::Success(_) => {
    437                 formatter.write_str("AdminRouteOutcome::Success(<redacted>)")
    438             }
    439             AdminRouteOutcomeKind::Failure(failure) => {
    440                 formatter.debug_tuple("Failure").field(failure).finish()
    441             }
    442         }
    443     }
    444 }
    445 
    446 #[derive(Serialize)]
    447 struct ServerSuccessEnvelope<'a> {
    448     contract_version: u32,
    449     ok: bool,
    450     correlation_id: &'a AdminCorrelationId,
    451     result: &'a RawValue,
    452 }
    453 
    454 #[derive(Clone, Copy)]
    455 struct StrictJsonPayload;
    456 
    457 impl Serialize for StrictJsonPayload {
    458     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    459     where
    460         S: serde::Serializer,
    461     {
    462         serializer.serialize_bool(true)
    463     }
    464 }
    465 
    466 impl<'de> Deserialize<'de> for StrictJsonPayload {
    467     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    468     where
    469         D: Deserializer<'de>,
    470     {
    471         deserializer.deserialize_any(StrictJsonVisitor)
    472     }
    473 }
    474 
    475 struct StrictJsonVisitor;
    476 
    477 impl<'de> de::Visitor<'de> for StrictJsonVisitor {
    478     type Value = StrictJsonPayload;
    479 
    480     fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    481         formatter.write_str("JSON without duplicate object keys or null values")
    482     }
    483 
    484     fn visit_bool<E>(self, _value: bool) -> Result<Self::Value, E> {
    485         Ok(StrictJsonPayload)
    486     }
    487 
    488     fn visit_i64<E>(self, _value: i64) -> Result<Self::Value, E> {
    489         Ok(StrictJsonPayload)
    490     }
    491 
    492     fn visit_u64<E>(self, _value: u64) -> Result<Self::Value, E> {
    493         Ok(StrictJsonPayload)
    494     }
    495 
    496     fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E>
    497     where
    498         E: de::Error,
    499     {
    500         if value.is_finite() {
    501             Ok(StrictJsonPayload)
    502         } else {
    503             Err(E::custom("non-finite JSON number"))
    504         }
    505     }
    506 
    507     fn visit_str<E>(self, _value: &str) -> Result<Self::Value, E> {
    508         Ok(StrictJsonPayload)
    509     }
    510 
    511     fn visit_borrowed_str<E>(self, value: &'de str) -> Result<Self::Value, E>
    512     where
    513         E: de::Error,
    514     {
    515         self.visit_str(value)
    516     }
    517 
    518     fn visit_string<E>(self, _value: String) -> Result<Self::Value, E> {
    519         Ok(StrictJsonPayload)
    520     }
    521 
    522     fn visit_none<E>(self) -> Result<Self::Value, E>
    523     where
    524         E: de::Error,
    525     {
    526         Err(E::custom("JSON null is forbidden"))
    527     }
    528 
    529     fn visit_unit<E>(self) -> Result<Self::Value, E>
    530     where
    531         E: de::Error,
    532     {
    533         Err(E::custom("JSON null is forbidden"))
    534     }
    535 
    536     fn visit_seq<A>(self, mut sequence: A) -> Result<Self::Value, A::Error>
    537     where
    538         A: de::SeqAccess<'de>,
    539     {
    540         while sequence.next_element::<StrictJsonPayload>()?.is_some() {}
    541         Ok(StrictJsonPayload)
    542     }
    543 
    544     fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
    545     where
    546         A: de::MapAccess<'de>,
    547     {
    548         let mut keys = BTreeSet::new();
    549         while let Some(key) = map.next_key::<String>()? {
    550             if !keys.insert(key) {
    551                 return Err(de::Error::custom("duplicate JSON object key"));
    552             }
    553             map.next_value::<StrictJsonPayload>()?;
    554         }
    555         Ok(StrictJsonPayload)
    556     }
    557 }
    558 
    559 type AdminRouteFuture = Pin<Box<dyn Future<Output = AdminRouteOutcome> + Send + 'static>>;
    560 
    561 trait AdminRouteHandler: Send + Sync {
    562     fn handle(&self, request: AdminRequest) -> AdminRouteFuture;
    563 }
    564 
    565 struct FunctionRouteHandler<F>(F);
    566 
    567 // This impl only boxes and forwards a service-owned handler future. End-to-end dispatch remains
    568 // covered by the server tests; generic closure instantiations add no host policy branches.
    569 #[cfg_attr(coverage_nightly, coverage(off))]
    570 impl<F, Fut> AdminRouteHandler for FunctionRouteHandler<F>
    571 where
    572     F: Fn(AdminRequest) -> Fut + Send + Sync + 'static,
    573     Fut: Future<Output = AdminRouteOutcome> + Send + 'static,
    574 {
    575     fn handle(&self, request: AdminRequest) -> AdminRouteFuture {
    576         Box::pin((self.0)(request))
    577     }
    578 }
    579 
    580 struct RegisteredRoute {
    581     method: AdminHttpMethod,
    582     path: AdminRoutePath,
    583     handler: Arc<dyn AdminRouteHandler>,
    584 }
    585 
    586 /// Method/path registry supplied by the consuming service.
    587 #[derive(Default)]
    588 pub struct AdminRouter {
    589     routes: Vec<RegisteredRoute>,
    590 }
    591 
    592 impl AdminRouter {
    593     #[must_use]
    594     pub fn new() -> Self {
    595         Self::default()
    596     }
    597 
    598     pub fn route<F, Fut>(
    599         &mut self,
    600         method: AdminHttpMethod,
    601         path: impl AsRef<str>,
    602         handler: F,
    603     ) -> Result<(), AdminRouteRegistrationError>
    604     where
    605         F: Fn(AdminRequest) -> Fut + Send + Sync + 'static,
    606         Fut: Future<Output = AdminRouteOutcome> + Send + 'static,
    607     {
    608         let path = AdminRoutePath::new(path).map_err(AdminRouteRegistrationError::InvalidPath)?;
    609         if self
    610             .routes
    611             .iter()
    612             .any(|route| route.method == method && route.path == path)
    613         {
    614             return Err(AdminRouteRegistrationError::Duplicate);
    615         }
    616         if self.routes.iter().any(|route| {
    617             route.method == method
    618                 && route.path.literal_count == path.literal_count
    619                 && route.path.overlaps(&path)
    620         }) {
    621             return Err(AdminRouteRegistrationError::Ambiguous);
    622         }
    623         self.routes.push(RegisteredRoute {
    624             method,
    625             path,
    626             handler: Arc::new(FunctionRouteHandler(handler)),
    627         });
    628         Ok(())
    629     }
    630 }
    631 
    632 impl fmt::Debug for AdminRouter {
    633     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    634         formatter
    635             .debug_struct("AdminRouter")
    636             .field("route_count", &self.routes.len())
    637             .finish()
    638     }
    639 }
    640 
    641 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
    642 pub enum AdminServerConfigError {
    643     NoRoutes,
    644     ResponseLimitTooSmall,
    645 }
    646 
    647 impl fmt::Display for AdminServerConfigError {
    648     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    649         formatter.write_str("admin server configuration is invalid")
    650     }
    651 }
    652 
    653 impl Error for AdminServerConfigError {}
    654 
    655 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
    656 pub enum AdminServerError {
    657     ListenerClone { kind: io::ErrorKind },
    658     ListenerRegistration { kind: io::ErrorKind },
    659     Accept { kind: io::ErrorKind },
    660     ConnectionTaskPanicked,
    661 }
    662 
    663 impl fmt::Display for AdminServerError {
    664     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    665         formatter.write_str("bounded admin server failed")
    666     }
    667 }
    668 
    669 impl Error for AdminServerError {}
    670 
    671 struct AdminServerState {
    672     routes: Vec<RegisteredRoute>,
    673     limits: AdminTransportLimits,
    674     entropy: Arc<dyn EntropySource>,
    675 }
    676 
    677 /// One bounded HTTP/1.1 server that can only consume a Unix admin binding.
    678 pub struct AdminServer {
    679     state: Arc<AdminServerState>,
    680 }
    681 
    682 impl fmt::Debug for AdminServer {
    683     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    684         formatter
    685             .debug_struct("AdminServer")
    686             .field("route_count", &self.state.routes.len())
    687             .field("limits", &self.state.limits)
    688             .field("entropy", &"[injected]")
    689             .finish()
    690     }
    691 }
    692 
    693 impl AdminServer {
    694     pub fn new<E>(
    695         router: AdminRouter,
    696         limits: AdminTransportLimits,
    697         entropy: E,
    698     ) -> Result<Self, AdminServerConfigError>
    699     where
    700         E: EntropySource + 'static,
    701     {
    702         if router.routes.is_empty() {
    703             return Err(AdminServerConfigError::NoRoutes);
    704         }
    705         if limits.response_body_utf8_bytes() < ADMIN_MIN_RESPONSE_BODY_UTF8_BYTES {
    706             return Err(AdminServerConfigError::ResponseLimitTooSmall);
    707         }
    708         Ok(Self {
    709             state: Arc::new(AdminServerState {
    710                 routes: router.routes,
    711                 limits,
    712                 entropy: Arc::new(entropy),
    713             }),
    714         })
    715     }
    716 
    717     pub fn with_system_entropy(
    718         router: AdminRouter,
    719         limits: AdminTransportLimits,
    720     ) -> Result<Self, AdminServerConfigError> {
    721         Self::new(router, limits, SystemEntropy)
    722     }
    723 
    724     /// Serves until cancellation, then stops admission and drains every bounded connection task.
    725     pub async fn serve(
    726         self,
    727         binding: UnixAdminSocketBinding,
    728         cancellation: CancellationToken,
    729     ) -> Result<(), AdminServerError> {
    730         let listener = binding
    731             .listener()
    732             .try_clone()
    733             .map_err(|error| AdminServerError::ListenerClone { kind: error.kind() })?;
    734         listener
    735             .set_nonblocking(true)
    736             .map_err(|error| AdminServerError::ListenerRegistration { kind: error.kind() })?;
    737         let listener = tokio::net::UnixListener::from_std(listener)
    738             .map_err(|error| AdminServerError::ListenerRegistration { kind: error.kind() })?;
    739         let peer_authorizer = binding.peer_authorizer();
    740         let permits = Arc::new(Semaphore::new(
    741             self.state.limits.concurrent_connections() as usize
    742         ));
    743         let mut tasks = JoinSet::new();
    744 
    745         let mut result = loop {
    746             tokio::select! {
    747                 biased;
    748                 () = cancellation.cancelled() => break Ok(()),
    749                 joined = tasks.join_next(), if !tasks.is_empty() => {
    750                     if joined.is_some_and(|result| result.is_err()) {
    751                         cancellation.cancel();
    752                         break Err(AdminServerError::ConnectionTaskPanicked);
    753                     }
    754                 }
    755                 accepted = listener.accept() => {
    756                     let (stream, _) = match accepted {
    757                         Ok(accepted) => accepted,
    758                         Err(error) => {
    759                             cancellation.cancel();
    760                             break Err(AdminServerError::Accept { kind: error.kind() });
    761                         }
    762                     };
    763                     if peer_authorizer.authorize(&stream).is_err() {
    764                         drop(stream);
    765                         continue;
    766                     }
    767                     let Ok(permit) = Arc::clone(&permits).try_acquire_owned() else {
    768                         drop(stream);
    769                         continue;
    770                     };
    771                     let state = Arc::clone(&self.state);
    772                     let connection_cancellation = cancellation.clone();
    773                     tasks.spawn(async move {
    774                         let _permit = permit;
    775                         serve_connection(stream, state, connection_cancellation).await;
    776                     });
    777                 }
    778             }
    779         };
    780 
    781         while let Some(joined) = tasks.join_next().await {
    782             if joined.is_err() {
    783                 result = Err(AdminServerError::ConnectionTaskPanicked);
    784             }
    785         }
    786         drop(binding);
    787         result
    788     }
    789 }
    790 
    791 async fn serve_connection(
    792     stream: tokio::net::UnixStream,
    793     state: Arc<AdminServerState>,
    794     cancellation: CancellationToken,
    795 ) {
    796     let service_state = Arc::clone(&state);
    797     let service = service_fn(move |request| {
    798         let state = Arc::clone(&service_state);
    799         async move { Ok::<_, Infallible>(serve_request(request, state).await) }
    800     });
    801 
    802     let mut builder = http1::Builder::new();
    803     builder
    804         .keep_alive(false)
    805         .auto_date_header(false)
    806         .max_headers(state.limits.header_count() as usize)
    807         .max_buf_size((state.limits.header_bytes() as usize).max(HTTP_MINIMUM_MAX_BUFFER_SIZE))
    808         .header_read_timeout(state.limits.idle_timeout())
    809         .timer(TokioTimer::new());
    810 
    811     let mut connection = Box::pin(builder.serve_connection(TokioIo::new(stream), service));
    812     let connection_deadline = state
    813         .limits
    814         .request_deadline()
    815         .checked_add(state.limits.idle_timeout())
    816         .unwrap_or(state.limits.idle_timeout());
    817     tokio::select! {
    818         biased;
    819         () = cancellation.cancelled() => {
    820             connection.as_mut().graceful_shutdown();
    821             let _ = tokio::time::timeout(connection_deadline, connection).await;
    822         }
    823         _ = tokio::time::timeout(connection_deadline, &mut connection) => {}
    824     }
    825 }
    826 
    827 async fn serve_request(
    828     request: Request<Incoming>,
    829     state: Arc<AdminServerState>,
    830 ) -> Response<Full<Bytes>> {
    831     let (initial_correlation, deferred_entropy_failure) =
    832         match generated_correlation(&*state.entropy) {
    833             Ok(correlation) => (correlation, None),
    834             Err(error) => (fallback_correlation(), Some(error)),
    835         };
    836     let correlation = Arc::new(CorrelationSlot::new(initial_correlation));
    837     let deadline = state.limits.request_deadline();
    838     match tokio::time::timeout(
    839         deadline,
    840         process_request(
    841             request,
    842             Arc::clone(&state),
    843             Arc::clone(&correlation),
    844             deferred_entropy_failure,
    845         ),
    846     )
    847     .await
    848     {
    849         Ok(response) => response,
    850         Err(_) => failure_response(
    851             StatusCode::GATEWAY_TIMEOUT,
    852             correlation.current(),
    853             known_error("request_timeout", "admin request deadline elapsed"),
    854             state.limits,
    855         ),
    856     }
    857 }
    858 
    859 async fn process_request(
    860     request: Request<Incoming>,
    861     state: Arc<AdminServerState>,
    862     correlation: Arc<CorrelationSlot>,
    863     deferred_entropy_failure: Option<AdminError>,
    864 ) -> Response<Full<Bytes>> {
    865     let correlation_id = correlation.current();
    866     if request.version() != Version::HTTP_11 {
    867         return failure_response(
    868             StatusCode::HTTP_VERSION_NOT_SUPPORTED,
    869             correlation_id,
    870             known_error(
    871                 "http_version_unsupported",
    872                 "admin transport requires HTTP/1.1",
    873             ),
    874             state.limits,
    875         );
    876     }
    877     if header_bytes(request.headers()) > u64::from(state.limits.header_bytes())
    878         || request.headers().len() > state.limits.header_count() as usize
    879     {
    880         return failure_response(
    881             StatusCode::REQUEST_HEADER_FIELDS_TOO_LARGE,
    882             correlation_id,
    883             known_error(
    884                 "request_headers_too_large",
    885                 "admin request headers exceed the limit",
    886             ),
    887             state.limits,
    888         );
    889     }
    890     if query_item_count(request.uri().query()) > state.limits.query_items() as usize {
    891         return failure_response(
    892             StatusCode::BAD_REQUEST,
    893             correlation_id,
    894             known_error("query_limit_exceeded", "admin query exceeds the item limit"),
    895             state.limits,
    896         );
    897     }
    898 
    899     if unknown_major_version(request.uri().path()) {
    900         let response = AdminFailureResponse::unsupported_contract_version(correlation_id.clone());
    901         return bounded_json_response(
    902             StatusCode::BAD_REQUEST,
    903             &response,
    904             correlation_id,
    905             state.limits,
    906         );
    907     }
    908     let Some(method) = AdminHttpMethod::from_http(request.method()) else {
    909         return failure_response(
    910             StatusCode::NOT_FOUND,
    911             correlation_id,
    912             known_error("route_not_found", "admin route was not found"),
    913             state.limits,
    914         );
    915     };
    916     let route = state
    917         .routes
    918         .iter()
    919         .filter(|route| route.method == method)
    920         .filter_map(|route| {
    921             route
    922                 .path
    923                 .match_path(request.uri().path())
    924                 .map(|parameters| {
    925                     (
    926                         route.path.literal_count,
    927                         route.path.clone(),
    928                         parameters,
    929                         Arc::clone(&route.handler),
    930                     )
    931                 })
    932         })
    933         .max_by_key(|(literal_count, _, _, _)| *literal_count);
    934     let Some((_, path, parameters, handler)) = route else {
    935         return failure_response(
    936             StatusCode::NOT_FOUND,
    937             correlation_id,
    938             known_error("route_not_found", "admin route was not found"),
    939             state.limits,
    940         );
    941     };
    942 
    943     if method == AdminHttpMethod::Post && !is_json_content_type(request.headers()) {
    944         return failure_response(
    945             StatusCode::UNSUPPORTED_MEDIA_TYPE,
    946             correlation_id,
    947             known_error(
    948                 "content_type_required",
    949                 "admin mutation requires JSON content type",
    950             ),
    951             state.limits,
    952         );
    953     }
    954     let query = request.uri().query().map(str::to_owned);
    955     let body = match Limited::new(
    956         request.into_body(),
    957         state.limits.request_body_utf8_bytes() as usize,
    958     )
    959     .collect()
    960     .await
    961     {
    962         Ok(collected) => collected.to_bytes(),
    963         Err(error) if error.downcast_ref::<LengthLimitError>().is_some() => {
    964             return failure_response(
    965                 StatusCode::PAYLOAD_TOO_LARGE,
    966                 correlation_id,
    967                 known_error(
    968                     "request_body_too_large",
    969                     "admin request body exceeds the limit",
    970                 ),
    971                 state.limits,
    972             );
    973         }
    974         Err(_) => {
    975             return failure_response(
    976                 StatusCode::BAD_REQUEST,
    977                 correlation_id,
    978                 known_error(
    979                     "request_body_unavailable",
    980                     "admin request body is unavailable",
    981                 ),
    982                 state.limits,
    983             );
    984         }
    985     };
    986     if method == AdminHttpMethod::Get && !body.is_empty() {
    987         return failure_response(
    988             StatusCode::BAD_REQUEST,
    989             correlation_id,
    990             known_error("malformed_json", "admin request body is not valid JSON"),
    991             state.limits,
    992         );
    993     }
    994 
    995     if method == AdminHttpMethod::Post {
    996         let envelope =
    997             match serde_json::from_slice::<AdminMutationRequest<StrictJsonPayload>>(&body) {
    998                 Ok(envelope) => envelope,
    999                 Err(_) => {
   1000                     return failure_response(
   1001                         StatusCode::BAD_REQUEST,
   1002                         correlation.current(),
   1003                         known_error("malformed_json", "admin request body is not valid JSON"),
   1004                         state.limits,
   1005                     );
   1006                 }
   1007             };
   1008         if let Some(caller_correlation) = envelope.correlation_id().cloned() {
   1009             correlation.replace(caller_correlation);
   1010         } else if let Some(error) = deferred_entropy_failure {
   1011             return failure_response(
   1012                 StatusCode::INTERNAL_SERVER_ERROR,
   1013                 correlation.current(),
   1014                 error,
   1015                 state.limits,
   1016             );
   1017         }
   1018         if envelope.validate_contract_version().is_err() {
   1019             let correlation_id = correlation.current();
   1020             let response =
   1021                 AdminFailureResponse::unsupported_contract_version(correlation_id.clone());
   1022             return bounded_json_response(
   1023                 StatusCode::BAD_REQUEST,
   1024                 &response,
   1025                 correlation_id,
   1026                 state.limits,
   1027             );
   1028         }
   1029     } else if let Some(error) = deferred_entropy_failure {
   1030         return failure_response(
   1031             StatusCode::INTERNAL_SERVER_ERROR,
   1032             correlation.current(),
   1033             error,
   1034             state.limits,
   1035         );
   1036     }
   1037     let correlation_id = correlation.current();
   1038 
   1039     let request = AdminRequest {
   1040         method,
   1041         path,
   1042         query,
   1043         correlation_id: correlation_id.clone(),
   1044         parameters,
   1045         body,
   1046         response_body_limit: state.limits.response_body_utf8_bytes() as usize,
   1047     };
   1048     match handler.handle(request).await.0 {
   1049         AdminRouteOutcomeKind::Success(result) => {
   1050             let envelope = ServerSuccessEnvelope {
   1051                 contract_version: ADMIN_CONTRACT_VERSION,
   1052                 ok: true,
   1053                 correlation_id: &correlation_id,
   1054                 result: &result,
   1055             };
   1056             bounded_json_response(
   1057                 StatusCode::OK,
   1058                 &envelope,
   1059                 correlation_id.clone(),
   1060                 state.limits,
   1061             )
   1062         }
   1063         AdminRouteOutcomeKind::Failure(failure) => failure_response(
   1064             failure.status.http_status(),
   1065             correlation_id,
   1066             failure.error,
   1067             state.limits,
   1068         ),
   1069     }
   1070 }
   1071 
   1072 fn generated_correlation(entropy: &dyn EntropySource) -> Result<AdminCorrelationId, AdminError> {
   1073     let mut bytes = [0_u8; 16];
   1074     if entropy.fill_bytes(&mut bytes).is_err() {
   1075         return Err(known_error(
   1076             "correlation_unavailable",
   1077             "admin correlation identity is unavailable",
   1078         ));
   1079     }
   1080     let value = bytes
   1081         .iter()
   1082         .map(|byte| format!("{byte:02x}"))
   1083         .collect::<String>();
   1084     Ok(AdminCorrelationId::new(value).expect("hex correlation must be valid"))
   1085 }
   1086 
   1087 fn fallback_correlation() -> AdminCorrelationId {
   1088     AdminCorrelationId::new(FALLBACK_CORRELATION_ID)
   1089         .expect("static correlation fallback must be valid")
   1090 }
   1091 
   1092 fn unknown_major_version(path: &str) -> bool {
   1093     path.strip_prefix('/')
   1094         .and_then(|path| path.split('/').next())
   1095         .is_some_and(|segment| {
   1096             segment != "v1"
   1097                 && segment.strip_prefix('v').is_some_and(|version| {
   1098                     !version.is_empty() && version.bytes().all(|byte| byte.is_ascii_digit())
   1099                 })
   1100         })
   1101 }
   1102 
   1103 struct CorrelationSlot(Mutex<AdminCorrelationId>);
   1104 
   1105 impl CorrelationSlot {
   1106     fn new(correlation_id: AdminCorrelationId) -> Self {
   1107         Self(Mutex::new(correlation_id))
   1108     }
   1109 
   1110     fn current(&self) -> AdminCorrelationId {
   1111         self.0
   1112             .lock()
   1113             .unwrap_or_else(std::sync::PoisonError::into_inner)
   1114             .clone()
   1115     }
   1116 
   1117     fn replace(&self, correlation_id: AdminCorrelationId) {
   1118         *self
   1119             .0
   1120             .lock()
   1121             .unwrap_or_else(std::sync::PoisonError::into_inner) = correlation_id;
   1122     }
   1123 }
   1124 
   1125 fn header_bytes(headers: &HeaderMap) -> u64 {
   1126     headers.iter().fold(0_u64, |total, (name, value)| {
   1127         total
   1128             .saturating_add(name.as_str().len() as u64)
   1129             .saturating_add(value.as_bytes().len() as u64)
   1130     })
   1131 }
   1132 
   1133 fn query_item_count(query: Option<&str>) -> usize {
   1134     match query {
   1135         None | Some("") => 0,
   1136         Some(query) => query.split('&').count(),
   1137     }
   1138 }
   1139 
   1140 fn is_json_content_type(headers: &HeaderMap) -> bool {
   1141     headers
   1142         .get(CONTENT_TYPE)
   1143         .and_then(|value| value.to_str().ok())
   1144         .is_some_and(|value| {
   1145             value == JSON_CONTENT_TYPE || value == "application/json; charset=utf-8"
   1146         })
   1147 }
   1148 
   1149 fn failure_response(
   1150     status: StatusCode,
   1151     correlation_id: AdminCorrelationId,
   1152     error: AdminError,
   1153     limits: AdminTransportLimits,
   1154 ) -> Response<Full<Bytes>> {
   1155     let envelope = AdminFailureResponse::new(correlation_id.clone(), error);
   1156     bounded_json_response(status, &envelope, correlation_id, limits)
   1157 }
   1158 
   1159 fn bounded_json_response<T>(
   1160     status: StatusCode,
   1161     value: &T,
   1162     correlation_id: AdminCorrelationId,
   1163     limits: AdminTransportLimits,
   1164 ) -> Response<Full<Bytes>>
   1165 where
   1166     T: Serialize,
   1167 {
   1168     let limit = limits.response_body_utf8_bytes() as usize;
   1169     if let Ok(encoded) = encode_bounded(value, limit) {
   1170         return json_response(status, encoded);
   1171     }
   1172     let fallback = AdminFailureResponse::new(
   1173         correlation_id,
   1174         known_error(
   1175             "response_body_too_large",
   1176             "admin response body exceeds the limit",
   1177         ),
   1178     );
   1179     match encode_bounded(&fallback, limit) {
   1180         Ok(encoded) => json_response(StatusCode::INTERNAL_SERVER_ERROR, encoded),
   1181         Err(_) => json_response(
   1182             StatusCode::INTERNAL_SERVER_ERROR,
   1183             br#"{"contract_version":1,"ok":false,"correlation_id":"correlation-unavailable","error":{"code":"response_body_too_large","message":"admin response body exceeds the limit"}}"#.to_vec(),
   1184         ),
   1185     }
   1186 }
   1187 
   1188 enum BoundedEncodingError {
   1189     Limit,
   1190     Encoding,
   1191 }
   1192 
   1193 struct CappedWriter {
   1194     bytes: Vec<u8>,
   1195     limit: usize,
   1196     exceeded: bool,
   1197 }
   1198 
   1199 impl CappedWriter {
   1200     fn new(limit: usize) -> Self {
   1201         Self {
   1202             bytes: Vec::with_capacity(limit.min(4096)),
   1203             limit,
   1204             exceeded: false,
   1205         }
   1206     }
   1207 }
   1208 
   1209 impl io::Write for CappedWriter {
   1210     fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
   1211         if bytes.len() > self.limit.saturating_sub(self.bytes.len()) {
   1212             self.exceeded = true;
   1213             return Err(io::Error::other("bounded JSON output limit exceeded"));
   1214         }
   1215         self.bytes.extend_from_slice(bytes);
   1216         Ok(bytes.len())
   1217     }
   1218 
   1219     fn flush(&mut self) -> io::Result<()> {
   1220         Ok(())
   1221     }
   1222 }
   1223 
   1224 fn encode_bounded<T>(value: &T, limit: usize) -> Result<Vec<u8>, BoundedEncodingError>
   1225 where
   1226     T: Serialize,
   1227 {
   1228     let mut writer = CappedWriter::new(limit);
   1229     match serde_json::to_writer(&mut writer, value) {
   1230         Ok(()) => Ok(writer.bytes),
   1231         Err(_) if writer.exceeded => Err(BoundedEncodingError::Limit),
   1232         Err(_) => Err(BoundedEncodingError::Encoding),
   1233     }
   1234 }
   1235 
   1236 fn json_response(status: StatusCode, body: Vec<u8>) -> Response<Full<Bytes>> {
   1237     let mut response = Response::new(Full::new(Bytes::from(body)));
   1238     *response.status_mut() = status;
   1239     response
   1240         .headers_mut()
   1241         .insert(CONTENT_TYPE, HeaderValue::from_static(JSON_CONTENT_TYPE));
   1242     response
   1243 }
   1244 
   1245 fn known_error(code: &'static str, message: &'static str) -> AdminError {
   1246     AdminError::new(
   1247         AdminErrorCode::new(code).expect("static admin error code must be valid"),
   1248         AdminErrorMessage::new(message).expect("static admin error message must be valid"),
   1249     )
   1250 }
   1251 
   1252 #[cfg(test)]
   1253 mod tests {
   1254     use super::*;
   1255     use serde::{Deserialize, Serialize};
   1256     use std::sync::atomic::{AtomicUsize, Ordering};
   1257     use tokio::io::{AsyncReadExt, AsyncWriteExt};
   1258     use tokio::sync::Notify;
   1259 
   1260     #[derive(Clone, Copy)]
   1261     struct FixedEntropy(u8);
   1262 
   1263     impl EntropySource for FixedEntropy {
   1264         fn fill_bytes(&self, destination: &mut [u8]) -> Result<(), crate::EntropyError> {
   1265             destination.fill(self.0);
   1266             Ok(())
   1267         }
   1268     }
   1269 
   1270     struct FailingEntropy;
   1271 
   1272     impl EntropySource for FailingEntropy {
   1273         fn fill_bytes(&self, _destination: &mut [u8]) -> Result<(), crate::EntropyError> {
   1274             Err(crate::EntropyError::Unavailable)
   1275         }
   1276     }
   1277 
   1278     struct CountingFailingEntropy(Arc<AtomicUsize>);
   1279 
   1280     impl EntropySource for CountingFailingEntropy {
   1281         fn fill_bytes(&self, _destination: &mut [u8]) -> Result<(), crate::EntropyError> {
   1282             self.0.fetch_add(1, Ordering::SeqCst);
   1283             Err(crate::EntropyError::Unavailable)
   1284         }
   1285     }
   1286 
   1287     #[derive(Debug, Deserialize, Serialize)]
   1288     #[serde(deny_unknown_fields)]
   1289     struct EchoRequest {
   1290         value: String,
   1291     }
   1292 
   1293     fn echo_router() -> AdminRouter {
   1294         let mut router = AdminRouter::new();
   1295         router
   1296             .route(AdminHttpMethod::Post, "/v1/echo", |request| async move {
   1297                 match request.decode_json::<AdminMutationRequest<EchoRequest>>() {
   1298                     Ok(envelope) => {
   1299                         let request_body = envelope.into_request();
   1300                         request
   1301                             .success(&serde_json::json!({"value": request_body.value}))
   1302                             .expect("echo result should encode")
   1303                     }
   1304                     Err(_) => AdminRouteOutcome::failure(AdminRouteFailure::new(
   1305                         AdminRouteFailureStatus::BadRequest,
   1306                         known_error("malformed_echo", "echo request is malformed"),
   1307                     )),
   1308                 }
   1309             })
   1310             .expect("echo route");
   1311         router
   1312     }
   1313 
   1314     fn limits_with(
   1315         request_body: u32,
   1316         concurrency: u32,
   1317         deadline: std::time::Duration,
   1318     ) -> AdminTransportLimits {
   1319         let mut values = AdminTransportLimits::DEFAULT.values();
   1320         values.request_body_utf8_bytes = request_body;
   1321         values.concurrent_connections = concurrency;
   1322         values.request_deadline = deadline;
   1323         AdminTransportLimits::new(values).expect("test limits")
   1324     }
   1325 
   1326     async fn binding(
   1327         directory: &tempfile::TempDir,
   1328     ) -> (std::path::PathBuf, UnixAdminSocketBinding) {
   1329         let socket = directory.path().join("admin.sock");
   1330         let authority = super::super::UnixAdminSocketWriterAuthority::acquire(directory.path())
   1331             .expect("writer authority");
   1332         let binding = UnixAdminSocketBinding::bind(authority, &socket)
   1333             .await
   1334             .expect("socket binding");
   1335         (socket, binding)
   1336     }
   1337 
   1338     async fn exchange(socket: &std::path::Path, request: &[u8]) -> Vec<u8> {
   1339         let mut stream = tokio::net::UnixStream::connect(socket)
   1340             .await
   1341             .expect("connect admin server");
   1342         stream.write_all(request).await.expect("write request");
   1343         let mut response = Vec::new();
   1344         stream
   1345             .read_to_end(&mut response)
   1346             .await
   1347             .expect("read response");
   1348         response
   1349     }
   1350 
   1351     async fn exchange_allowing_reset(socket: &std::path::Path, request: &[u8]) -> Vec<u8> {
   1352         let mut stream = tokio::net::UnixStream::connect(socket)
   1353             .await
   1354             .expect("connect admin server");
   1355         stream.write_all(request).await.expect("write request");
   1356         let mut response = Vec::new();
   1357         match stream.read_to_end(&mut response).await {
   1358             Ok(_) => response,
   1359             Err(error) if error.kind() == std::io::ErrorKind::ConnectionReset => response,
   1360             Err(error) => panic!("read response: {error}"),
   1361         }
   1362     }
   1363 
   1364     #[tokio::test]
   1365     async fn serves_valid_json_with_exact_caller_correlation_and_no_web_headers() {
   1366         let directory = super::test_support::short_tempdir();
   1367         let (socket, binding) = binding(&directory).await;
   1368         let server = AdminServer::new(
   1369             echo_router(),
   1370             AdminTransportLimits::DEFAULT,
   1371             FixedEntropy(7),
   1372         )
   1373         .expect("admin server");
   1374         let cancellation = CancellationToken::new();
   1375         let task_cancellation = cancellation.clone();
   1376         let task = tokio::spawn(server.serve(binding, task_cancellation));
   1377 
   1378         let body = r#"{"contract_version":1,"operation_id":"echo-01","correlation_id":"caller-01","request":{"value":"ok"}}"#;
   1379         let request = format!(
   1380             "POST /v1/echo HTTP/1.1\r\nHost: local\r\nContent-Type: application/json\r\nContent-Length: {}\r\n\r\n{body}",
   1381             body.len()
   1382         );
   1383         let response = exchange(&socket, request.as_bytes()).await;
   1384         let text = String::from_utf8(response).expect("UTF-8 response");
   1385         assert!(text.starts_with("HTTP/1.1 200 OK\r\n"), "{text}");
   1386         assert!(text.contains("content-type: application/json"));
   1387         assert!(!text.to_ascii_lowercase().contains("access-control-allow"));
   1388         assert!(text.ends_with(
   1389             r#"{"contract_version":1,"ok":true,"correlation_id":"caller-01","result":{"value":"ok"}}"#
   1390         ));
   1391 
   1392         let unsupported =
   1393             exchange(&socket, b"GET /v2/status HTTP/1.1\r\nHost: local\r\n\r\n").await;
   1394         let unsupported = String::from_utf8(unsupported).expect("unsupported response");
   1395         assert!(unsupported.starts_with("HTTP/1.1 400 Bad Request\r\n"));
   1396         assert!(unsupported.contains("unsupported_contract_version"));
   1397         assert!(unsupported.contains("07070707070707070707070707070707"));
   1398 
   1399         cancellation.cancel();
   1400         task.await.expect("server task").expect("server shutdown");
   1401         assert!(!socket.exists());
   1402     }
   1403 
   1404     #[tokio::test]
   1405     async fn rejects_oversized_and_malformed_json_before_the_handler() {
   1406         let directory = super::test_support::short_tempdir();
   1407         let (socket, binding) = binding(&directory).await;
   1408         let calls = Arc::new(AtomicUsize::new(0));
   1409         let handler_calls = Arc::clone(&calls);
   1410         let mut router = AdminRouter::new();
   1411         router
   1412             .route(AdminHttpMethod::Post, "/v1/test", move |request| {
   1413                 let calls = Arc::clone(&handler_calls);
   1414                 async move {
   1415                     calls.fetch_add(1, Ordering::SeqCst);
   1416                     request
   1417                         .success(&serde_json::json!({"ok": true}))
   1418                         .expect("test result")
   1419                 }
   1420             })
   1421             .expect("test route");
   1422         let server = AdminServer::new(
   1423             router,
   1424             limits_with(8, 4, std::time::Duration::from_secs(1)),
   1425             FixedEntropy(8),
   1426         )
   1427         .expect("admin server");
   1428         let cancellation = CancellationToken::new();
   1429         let task = tokio::spawn(server.serve(binding, cancellation.clone()));
   1430 
   1431         let oversized = exchange(
   1432             &socket,
   1433             b"POST /v1/test HTTP/1.1\r\nHost: local\r\nContent-Type: application/json\r\nContent-Length: 9\r\n\r\n123456789",
   1434         )
   1435         .await;
   1436         assert!(
   1437             String::from_utf8(oversized)
   1438                 .expect("response")
   1439                 .contains("request_body_too_large")
   1440         );
   1441         let malformed = exchange(
   1442             &socket,
   1443             b"POST /v1/test HTTP/1.1\r\nHost: local\r\nContent-Type: application/json\r\nContent-Length: 1\r\n\r\n{",
   1444         )
   1445         .await;
   1446         assert!(
   1447             String::from_utf8(malformed)
   1448                 .expect("response")
   1449                 .contains("malformed_json")
   1450         );
   1451         assert_eq!(calls.load(Ordering::SeqCst), 0);
   1452 
   1453         cancellation.cancel();
   1454         task.await.expect("server task").expect("server shutdown");
   1455     }
   1456 
   1457     #[tokio::test]
   1458     async fn rejects_invalid_mutation_envelopes_duplicates_and_nested_null_before_dispatch() {
   1459         let directory = super::test_support::short_tempdir();
   1460         let (socket, binding) = binding(&directory).await;
   1461         let calls = Arc::new(AtomicUsize::new(0));
   1462         let handler_calls = Arc::clone(&calls);
   1463         let mut router = AdminRouter::new();
   1464         router
   1465             .route(AdminHttpMethod::Post, "/v1/test", move |request| {
   1466                 let calls = Arc::clone(&handler_calls);
   1467                 async move {
   1468                     calls.fetch_add(1, Ordering::SeqCst);
   1469                     request.success(&true).expect("test result")
   1470                 }
   1471             })
   1472             .expect("test route");
   1473         let server = AdminServer::new(router, AdminTransportLimits::DEFAULT, FixedEntropy(0x21))
   1474             .expect("admin server");
   1475         let cancellation = CancellationToken::new();
   1476         let task = tokio::spawn(server.serve(binding, cancellation.clone()));
   1477 
   1478         for body in [
   1479             r#"{"operation_id":"missing-version","request":{"value":true}}"#,
   1480             r#"{"contract_version":1,"operation_id":"missing-request"}"#,
   1481             r#"{"contract_version":1,"operation_id":"duplicate-correlation","correlation_id":"first","correlation_id":"second","request":{"value":true}}"#,
   1482             r#"{"contract_version":1,"operation_id":"nested-duplicate","request":{"value":true,"value":false}}"#,
   1483             r#"{"contract_version":1,"operation_id":"nested-null","request":{"nested":[true,null]}}"#,
   1484         ] {
   1485             let request = format!(
   1486                 "POST /v1/test HTTP/1.1\r\nHost: local\r\nContent-Type: application/json\r\nContent-Length: {}\r\n\r\n{body}",
   1487                 body.len()
   1488             );
   1489             let response = String::from_utf8(exchange(&socket, request.as_bytes()).await)
   1490                 .expect("invalid envelope response");
   1491             assert!(response.contains("malformed_json"), "{response}");
   1492         }
   1493 
   1494         let body = r#"{"contract_version":2,"operation_id":"future-version","correlation_id":"caller-v2","request":{"value":true}}"#;
   1495         let request = format!(
   1496             "POST /v1/test HTTP/1.1\r\nHost: local\r\nContent-Type: application/json\r\nContent-Length: {}\r\n\r\n{body}",
   1497             body.len()
   1498         );
   1499         let response = String::from_utf8(exchange(&socket, request.as_bytes()).await)
   1500             .expect("version response");
   1501         assert!(response.contains("unsupported_contract_version"));
   1502         assert!(response.contains("caller-v2"));
   1503         assert_eq!(calls.load(Ordering::SeqCst), 0);
   1504 
   1505         cancellation.cancel();
   1506         task.await.expect("server task").expect("server shutdown");
   1507     }
   1508 
   1509     #[tokio::test]
   1510     async fn parameterized_routes_percent_decode_bounded_values_without_service_authority() {
   1511         let directory = super::test_support::short_tempdir();
   1512         let (socket, binding) = binding(&directory).await;
   1513         let calls = Arc::new(AtomicUsize::new(0));
   1514         let handler_calls = Arc::clone(&calls);
   1515         let mut router = AdminRouter::new();
   1516         router
   1517             .route(
   1518                 AdminHttpMethod::Post,
   1519                 "/v1/connections/{connection_id}/approve",
   1520                 move |request| {
   1521                     let calls = Arc::clone(&handler_calls);
   1522                     async move {
   1523                         calls.fetch_add(1, Ordering::SeqCst);
   1524                         let parameter = request
   1525                             .parameter("connection_id")
   1526                             .expect("decoded route parameter")
   1527                             .to_owned();
   1528                         request
   1529                             .success(&serde_json::json!({"connection_id": parameter}))
   1530                             .expect("parameter response")
   1531                     }
   1532                 },
   1533             )
   1534             .expect("parameterized route");
   1535         let server = AdminServer::new(router, AdminTransportLimits::DEFAULT, FixedEntropy(0x22))
   1536             .expect("admin server");
   1537         let cancellation = CancellationToken::new();
   1538         let task = tokio::spawn(server.serve(binding, cancellation.clone()));
   1539         let body =
   1540             r#"{"contract_version":1,"operation_id":"approve-01","request":{"approve":true}}"#;
   1541 
   1542         let request = format!(
   1543             "POST /v1/connections/farm%2D01/approve HTTP/1.1\r\nHost: local\r\nContent-Type: application/json\r\nContent-Length: {}\r\n\r\n{body}",
   1544             body.len()
   1545         );
   1546         let response = String::from_utf8(exchange(&socket, request.as_bytes()).await)
   1547             .expect("parameter response");
   1548         assert!(response.starts_with("HTTP/1.1 200 OK"), "{response}");
   1549         assert!(response.contains(r#""connection_id":"farm-01""#));
   1550 
   1551         for path in [
   1552             "/v1/connections/farm%2/approve",
   1553             "/v1/connections/farm%2F01/approve",
   1554             &format!(
   1555                 "/v1/connections/{}/approve",
   1556                 "x".repeat(ADMIN_ROUTE_PARAMETER_VALUE_MAX_UTF8_BYTES + 1)
   1557             ),
   1558         ] {
   1559             let request = format!(
   1560                 "POST {path} HTTP/1.1\r\nHost: local\r\nContent-Type: application/json\r\nContent-Length: {}\r\n\r\n{body}",
   1561                 body.len()
   1562             );
   1563             let response = String::from_utf8(exchange(&socket, request.as_bytes()).await)
   1564                 .expect("invalid parameter response");
   1565             assert!(response.contains("route_not_found"), "{response}");
   1566         }
   1567         assert_eq!(calls.load(Ordering::SeqCst), 1);
   1568 
   1569         cancellation.cancel();
   1570         task.await.expect("server task").expect("server shutdown");
   1571     }
   1572 
   1573     #[tokio::test]
   1574     async fn caller_correlation_precedes_entropy_and_survives_timeout_handoff() {
   1575         let directory = super::test_support::short_tempdir();
   1576         let (socket, binding) = binding(&directory).await;
   1577         let entropy_calls = Arc::new(AtomicUsize::new(0));
   1578         let mut router = AdminRouter::new();
   1579         router
   1580             .route(AdminHttpMethod::Post, "/v1/slow", |request| async move {
   1581                 tokio::time::sleep(std::time::Duration::from_secs(60)).await;
   1582                 request.success(&true).expect("slow result")
   1583             })
   1584             .expect("slow route");
   1585         let server = AdminServer::new(
   1586             router,
   1587             limits_with(1024, 4, std::time::Duration::from_millis(20)),
   1588             CountingFailingEntropy(Arc::clone(&entropy_calls)),
   1589         )
   1590         .expect("admin server");
   1591         let cancellation = CancellationToken::new();
   1592         let task = tokio::spawn(server.serve(binding, cancellation.clone()));
   1593 
   1594         let body = r#"{"contract_version":1,"operation_id":"slow-01","correlation_id":"caller-timeout","request":{"wait":true}}"#;
   1595         let request = format!(
   1596             "POST /v1/slow HTTP/1.1\r\nHost: local\r\nContent-Type: application/json\r\nContent-Length: {}\r\n\r\n{body}",
   1597             body.len()
   1598         );
   1599         let response = String::from_utf8(exchange(&socket, request.as_bytes()).await)
   1600             .expect("timeout response");
   1601         assert!(response.starts_with("HTTP/1.1 504 Gateway Timeout"));
   1602         assert!(response.contains("caller-timeout"));
   1603         assert_eq!(entropy_calls.load(Ordering::SeqCst), 1);
   1604 
   1605         let body = r#"{"contract_version":1,"operation_id":"slow-02","request":{"wait":true}}"#;
   1606         let request = format!(
   1607             "POST /v1/slow HTTP/1.1\r\nHost: local\r\nContent-Type: application/json\r\nContent-Length: {}\r\n\r\n{body}",
   1608             body.len()
   1609         );
   1610         let response = String::from_utf8(exchange(&socket, request.as_bytes()).await)
   1611             .expect("entropy response");
   1612         assert!(response.contains("correlation_unavailable"));
   1613         assert_eq!(entropy_calls.load(Ordering::SeqCst), 2);
   1614 
   1615         cancellation.cancel();
   1616         task.await.expect("server task").expect("server shutdown");
   1617     }
   1618 
   1619     #[tokio::test]
   1620     async fn rejects_http_1_0_before_dispatch() {
   1621         let directory = super::test_support::short_tempdir();
   1622         let (socket, binding) = binding(&directory).await;
   1623         let calls = Arc::new(AtomicUsize::new(0));
   1624         let handler_calls = Arc::clone(&calls);
   1625         let mut router = AdminRouter::new();
   1626         router
   1627             .route(AdminHttpMethod::Get, "/v1/status", move |request| {
   1628                 let calls = Arc::clone(&handler_calls);
   1629                 async move {
   1630                     calls.fetch_add(1, Ordering::SeqCst);
   1631                     request.success(&true).expect("status result")
   1632                 }
   1633             })
   1634             .expect("status route");
   1635         let server = AdminServer::new(router, AdminTransportLimits::DEFAULT, FixedEntropy(0x23))
   1636             .expect("admin server");
   1637         let cancellation = CancellationToken::new();
   1638         let task = tokio::spawn(server.serve(binding, cancellation.clone()));
   1639 
   1640         let response = String::from_utf8(
   1641             exchange(&socket, b"GET /v1/status HTTP/1.0\r\nHost: local\r\n\r\n").await,
   1642         )
   1643         .expect("HTTP/1.0 response");
   1644         assert!(response.contains("505 HTTP Version Not Supported"));
   1645         assert!(response.contains("http_version_unsupported"));
   1646         assert_eq!(calls.load(Ordering::SeqCst), 0);
   1647 
   1648         cancellation.cancel();
   1649         task.await.expect("server task").expect("server shutdown");
   1650     }
   1651 
   1652     #[tokio::test]
   1653     async fn request_deadline_returns_a_safe_timeout_and_cancels_the_handler_future() {
   1654         let directory = super::test_support::short_tempdir();
   1655         let (socket, binding) = binding(&directory).await;
   1656         let mut router = AdminRouter::new();
   1657         router
   1658             .route(AdminHttpMethod::Get, "/v1/slow", |request| async move {
   1659                 tokio::time::sleep(std::time::Duration::from_secs(60)).await;
   1660                 request
   1661                     .success(&serde_json::json!({"late": true}))
   1662                     .expect("late result")
   1663             })
   1664             .expect("slow route");
   1665         let server = AdminServer::new(
   1666             router,
   1667             limits_with(1024, 4, std::time::Duration::from_millis(20)),
   1668             FixedEntropy(9),
   1669         )
   1670         .expect("admin server");
   1671         let cancellation = CancellationToken::new();
   1672         let task = tokio::spawn(server.serve(binding, cancellation.clone()));
   1673 
   1674         let response = exchange(&socket, b"GET /v1/slow HTTP/1.1\r\nHost: local\r\n\r\n").await;
   1675         let text = String::from_utf8(response).expect("response");
   1676         assert!(text.starts_with("HTTP/1.1 504 Gateway Timeout\r\n"));
   1677         assert!(text.contains("request_timeout"));
   1678 
   1679         cancellation.cancel();
   1680         task.await.expect("server task").expect("server shutdown");
   1681     }
   1682 
   1683     #[tokio::test]
   1684     async fn enforces_header_query_response_and_body_correlation_boundaries() {
   1685         let directory = super::test_support::short_tempdir();
   1686         let (socket, binding) = binding(&directory).await;
   1687         let calls = Arc::new(AtomicUsize::new(0));
   1688         let handler_calls = Arc::clone(&calls);
   1689         let mut router = AdminRouter::new();
   1690         router
   1691             .route(AdminHttpMethod::Get, "/v1/large", move |request| {
   1692                 let calls = Arc::clone(&handler_calls);
   1693                 async move {
   1694                     calls.fetch_add(1, Ordering::SeqCst);
   1695                     match request.success(&"x".repeat(1024)) {
   1696                         Ok(outcome) => outcome,
   1697                         Err(AdminRouteOutcomeError::ResponseLimit) => {
   1698                             AdminRouteOutcome::failure(AdminRouteFailure::new(
   1699                                 AdminRouteFailureStatus::Internal,
   1700                                 known_error(
   1701                                     "response_body_too_large",
   1702                                     "admin response body exceeds the limit",
   1703                                 ),
   1704                             ))
   1705                         }
   1706                         Err(_) => panic!("large result should only exceed the cap"),
   1707                     }
   1708                 }
   1709             })
   1710             .expect("large route");
   1711         router
   1712             .route(AdminHttpMethod::Post, "/v1/input", |request| async move {
   1713                 request.success(&true).expect("input result")
   1714             })
   1715             .expect("input route");
   1716         let mut values = AdminTransportLimits::DEFAULT.values();
   1717         values.header_bytes = 64;
   1718         values.query_items = 1;
   1719         values.response_body_utf8_bytes = ADMIN_MIN_RESPONSE_BODY_UTF8_BYTES;
   1720         let limits = AdminTransportLimits::new(values).expect("boundary limits");
   1721         let server = AdminServer::new(router, limits, FixedEntropy(11)).expect("admin server");
   1722         let cancellation = CancellationToken::new();
   1723         let task = tokio::spawn(server.serve(binding, cancellation.clone()));
   1724 
   1725         let headers = exchange(
   1726             &socket,
   1727             b"GET /v1/large HTTP/1.1\r\nHost: local\r\nX-Large: 0123456789012345678901234567890123456789012345678901234567890123456789\r\n\r\n",
   1728         )
   1729         .await;
   1730         assert!(
   1731             String::from_utf8(headers)
   1732                 .expect("header response")
   1733                 .contains("request_headers_too_large")
   1734         );
   1735 
   1736         let query = exchange(
   1737             &socket,
   1738             b"GET /v1/large?a=1&b=2 HTTP/1.1\r\nHost: local\r\n\r\n",
   1739         )
   1740         .await;
   1741         assert!(
   1742             String::from_utf8(query)
   1743                 .expect("query response")
   1744                 .contains("query_limit_exceeded")
   1745         );
   1746 
   1747         let response = exchange(&socket, b"GET /v1/large HTTP/1.1\r\nHost: local\r\n\r\n").await;
   1748         let response = String::from_utf8(response).expect("bounded response");
   1749         assert!(response.contains("response_body_too_large"));
   1750         assert!(response.len() < ADMIN_MIN_RESPONSE_BODY_UTF8_BYTES as usize + 256);
   1751         assert_eq!(calls.load(Ordering::SeqCst), 1);
   1752 
   1753         let body = r#"{"contract_version":1,"operation_id":"input-01","correlation_id":null,"request":{"value":true}}"#;
   1754         let invalid_correlation = format!(
   1755             "POST /v1/input HTTP/1.1\r\nHost: local\r\nContent-Type: application/json\r\nContent-Length: {}\r\n\r\n{body}",
   1756             body.len()
   1757         );
   1758         let invalid_correlation = exchange(&socket, invalid_correlation.as_bytes()).await;
   1759         assert!(
   1760             String::from_utf8(invalid_correlation)
   1761                 .expect("correlation response")
   1762                 .contains("malformed_json")
   1763         );
   1764 
   1765         cancellation.cancel();
   1766         task.await.expect("server task").expect("server shutdown");
   1767     }
   1768 
   1769     #[tokio::test]
   1770     async fn connection_admission_never_exceeds_the_configured_limit() {
   1771         let directory = super::test_support::short_tempdir();
   1772         let (socket, binding) = binding(&directory).await;
   1773         let entered = Arc::new(Notify::new());
   1774         let release = Arc::new(Notify::new());
   1775         let handler_entered = Arc::clone(&entered);
   1776         let handler_release = Arc::clone(&release);
   1777         let mut router = AdminRouter::new();
   1778         router
   1779             .route(AdminHttpMethod::Get, "/v1/block", move |request| {
   1780                 let entered = Arc::clone(&handler_entered);
   1781                 let release = Arc::clone(&handler_release);
   1782                 async move {
   1783                     entered.notify_one();
   1784                     release.notified().await;
   1785                     request
   1786                         .success(&serde_json::json!({"done": true}))
   1787                         .expect("blocking result")
   1788                 }
   1789             })
   1790             .expect("blocking route");
   1791         let server = AdminServer::new(
   1792             router,
   1793             limits_with(1024, 1, std::time::Duration::from_secs(1)),
   1794             FixedEntropy(10),
   1795         )
   1796         .expect("admin server");
   1797         let cancellation = CancellationToken::new();
   1798         let task = tokio::spawn(server.serve(binding, cancellation.clone()));
   1799 
   1800         let first_socket = socket.clone();
   1801         let first = tokio::spawn(async move {
   1802             exchange(
   1803                 &first_socket,
   1804                 b"GET /v1/block HTTP/1.1\r\nHost: local\r\n\r\n",
   1805             )
   1806             .await
   1807         });
   1808         entered.notified().await;
   1809         let second = tokio::time::timeout(
   1810             std::time::Duration::from_millis(200),
   1811             exchange_allowing_reset(&socket, b"GET /v1/block HTTP/1.1\r\nHost: local\r\n\r\n"),
   1812         )
   1813         .await
   1814         .expect("second connection must close without waiting");
   1815         assert!(
   1816             second.is_empty(),
   1817             "excess connection must receive no response"
   1818         );
   1819         release.notify_one();
   1820         assert!(
   1821             String::from_utf8(first.await.expect("first task"))
   1822                 .expect("first response")
   1823                 .starts_with("HTTP/1.1 200 OK")
   1824         );
   1825 
   1826         cancellation.cancel();
   1827         task.await.expect("server task").expect("server shutdown");
   1828     }
   1829 
   1830     #[tokio::test]
   1831     async fn graceful_cancellation_stops_admission_and_drains_an_active_request() {
   1832         let directory = super::test_support::short_tempdir();
   1833         let (socket, binding) = binding(&directory).await;
   1834         let entered = Arc::new(Notify::new());
   1835         let release = Arc::new(Notify::new());
   1836         let handler_entered = Arc::clone(&entered);
   1837         let handler_release = Arc::clone(&release);
   1838         let mut router = AdminRouter::new();
   1839         router
   1840             .route(AdminHttpMethod::Get, "/v1/drain", move |request| {
   1841                 let entered = Arc::clone(&handler_entered);
   1842                 let release = Arc::clone(&handler_release);
   1843                 async move {
   1844                     entered.notify_one();
   1845                     release.notified().await;
   1846                     request.success(&true).expect("drained result")
   1847                 }
   1848             })
   1849             .expect("drain route");
   1850         let server = AdminServer::new(
   1851             router,
   1852             limits_with(1024, 1, std::time::Duration::from_secs(1)),
   1853             FixedEntropy(12),
   1854         )
   1855         .expect("admin server");
   1856         let cancellation = CancellationToken::new();
   1857         let mut task = tokio::spawn(server.serve(binding, cancellation.clone()));
   1858         let client_socket = socket.clone();
   1859         let client = tokio::spawn(async move {
   1860             exchange(
   1861                 &client_socket,
   1862                 b"GET /v1/drain HTTP/1.1\r\nHost: local\r\n\r\n",
   1863             )
   1864             .await
   1865         });
   1866 
   1867         entered.notified().await;
   1868         cancellation.cancel();
   1869         assert!(
   1870             tokio::time::timeout(std::time::Duration::from_millis(20), &mut task)
   1871                 .await
   1872                 .is_err(),
   1873             "graceful cancellation must retain active request work"
   1874         );
   1875         release.notify_one();
   1876         assert!(
   1877             String::from_utf8(client.await.expect("client task"))
   1878                 .expect("drained response")
   1879                 .starts_with("HTTP/1.1 200 OK")
   1880         );
   1881         task.await.expect("server task").expect("server shutdown");
   1882         assert!(!socket.exists());
   1883     }
   1884 
   1885     #[test]
   1886     fn route_and_server_configuration_fail_closed() {
   1887         assert!(matches!(
   1888             AdminServer::new(
   1889                 AdminRouter::new(),
   1890                 AdminTransportLimits::DEFAULT,
   1891                 FixedEntropy(1),
   1892             ),
   1893             Err(AdminServerConfigError::NoRoutes)
   1894         ));
   1895         let mut router = AdminRouter::new();
   1896         assert!(matches!(
   1897             router.route(AdminHttpMethod::Get, "/v2/status", |request| async move {
   1898                 request.success(&true).expect("bool")
   1899             }),
   1900             Err(AdminRouteRegistrationError::InvalidPath(
   1901                 AdminRoutePathError::WrongVersionPrefix
   1902             ))
   1903         ));
   1904         router
   1905             .route(AdminHttpMethod::Get, "/v1/status", |request| async move {
   1906                 request.success(&true).expect("bool")
   1907             })
   1908             .expect("first route");
   1909         assert_eq!(
   1910             router
   1911                 .route(AdminHttpMethod::Get, "/v1/status", |request| async move {
   1912                     request.success(&true).expect("bool")
   1913                 })
   1914                 .expect_err("duplicate route"),
   1915             AdminRouteRegistrationError::Duplicate
   1916         );
   1917 
   1918         let mut values = AdminTransportLimits::DEFAULT.values();
   1919         values.response_body_utf8_bytes = ADMIN_MIN_RESPONSE_BODY_UTF8_BYTES - 1;
   1920         let limits = AdminTransportLimits::new(values).expect("small response limit");
   1921         assert_eq!(
   1922             AdminServer::new(router, limits, FixedEntropy(1)).expect_err("small response cap"),
   1923             AdminServerConfigError::ResponseLimitTooSmall
   1924         );
   1925         assert_eq!(ADMIN_MIN_RESPONSE_BODY_UTF8_BYTES, 512);
   1926         let longest_correlation = AdminCorrelationId::new("x".repeat(128)).expect("correlation");
   1927         let fallback = AdminFailureResponse::new(
   1928             longest_correlation,
   1929             known_error(
   1930                 "response_body_too_large",
   1931                 "admin response body exceeds the limit",
   1932             ),
   1933         );
   1934         assert!(encode_bounded(&fallback, ADMIN_MIN_RESPONSE_BODY_UTF8_BYTES as usize).is_ok());
   1935 
   1936         let mut parameterized = AdminRouter::new();
   1937         parameterized
   1938             .route(
   1939                 AdminHttpMethod::Get,
   1940                 "/v1/items/{item_id}",
   1941                 |request| async move { request.success(&true).expect("parameterized result") },
   1942             )
   1943             .expect("parameterized route");
   1944         parameterized
   1945             .route(
   1946                 AdminHttpMethod::Get,
   1947                 "/v1/items/status",
   1948                 |request| async move { request.success(&true).expect("static result") },
   1949             )
   1950             .expect("more-specific static route");
   1951         assert_eq!(
   1952             parameterized
   1953                 .route(
   1954                     AdminHttpMethod::Get,
   1955                     "/v1/items/{other_id}",
   1956                     |request| async move { request.success(&true).expect("ambiguous result") }
   1957                 )
   1958                 .expect_err("ambiguous route"),
   1959             AdminRouteRegistrationError::Ambiguous
   1960         );
   1961         assert!(matches!(
   1962             AdminRoutePath::new("/v1/items/{Bad}"),
   1963             Err(AdminRoutePathError::InvalidParameter)
   1964         ));
   1965     }
   1966 
   1967     #[test]
   1968     fn capped_encoding_and_result_validation_fail_before_unbounded_response_allocation() {
   1969         let oversized = "x".repeat(ADMIN_MIN_RESPONSE_BODY_UTF8_BYTES as usize + 1);
   1970         assert!(matches!(
   1971             encode_bounded(&oversized, ADMIN_MIN_RESPONSE_BODY_UTF8_BYTES as usize),
   1972             Err(BoundedEncodingError::Limit)
   1973         ));
   1974 
   1975         let mut writer = CappedWriter::new(8);
   1976         assert!(io::Write::write_all(&mut writer, b"123456789").is_err());
   1977         assert!(writer.exceeded);
   1978         assert!(writer.bytes.len() <= 8);
   1979 
   1980         let request = AdminRequest {
   1981             method: AdminHttpMethod::Get,
   1982             path: AdminRoutePath::new("/v1/test").expect("path"),
   1983             query: None,
   1984             correlation_id: AdminCorrelationId::new("safe-id").expect("correlation"),
   1985             parameters: BTreeMap::new(),
   1986             body: Bytes::new(),
   1987             response_body_limit: ADMIN_MIN_RESPONSE_BODY_UTF8_BYTES as usize,
   1988         };
   1989         assert!(matches!(
   1990             request.success(&Option::<bool>::None),
   1991             Err(AdminRouteOutcomeError::InvalidPayload)
   1992         ));
   1993 
   1994         let malformed = AdminRequest {
   1995             body: Bytes::from_static(b"secret malformed JSON"),
   1996             ..request
   1997         }
   1998         .decode_json::<bool>()
   1999         .expect_err("malformed request must fail");
   2000         assert_eq!(malformed, AdminRequestDecodeError::Malformed);
   2001         assert!(std::error::Error::source(&malformed).is_none());
   2002         assert!(!format!("{malformed:?}").contains("secret"));
   2003 
   2004         let request = AdminRequest {
   2005             method: AdminHttpMethod::Get,
   2006             path: AdminRoutePath::new("/v1/test").expect("path"),
   2007             query: None,
   2008             correlation_id: AdminCorrelationId::new("safe-id").expect("correlation"),
   2009             parameters: BTreeMap::new(),
   2010             body: Bytes::new(),
   2011             response_body_limit: ADMIN_MIN_RESPONSE_BODY_UTF8_BYTES as usize,
   2012         };
   2013         let unsupported_json_map_key = BTreeMap::from([((1_u8, 2_u8), true)]);
   2014         let encoding = request
   2015             .success(&unsupported_json_map_key)
   2016             .expect_err("tuple map key must not encode as JSON");
   2017         assert_eq!(encoding, AdminRouteOutcomeError::Encoding);
   2018         assert!(std::error::Error::source(&encoding).is_none());
   2019     }
   2020 
   2021     #[test]
   2022     fn generated_correlation_is_exact_and_entropy_failure_is_safe() {
   2023         let correlation = generated_correlation(&FixedEntropy(0xab)).expect("fixed entropy");
   2024         assert_eq!(correlation.as_str(), "abababababababababababababababab");
   2025 
   2026         let failure = generated_correlation(&FailingEntropy).expect_err("entropy failure");
   2027         assert_eq!(failure.code().as_str(), "correlation_unavailable");
   2028         assert_eq!(fallback_correlation().as_str(), FALLBACK_CORRELATION_ID);
   2029     }
   2030 
   2031     #[test]
   2032     fn package_source_has_no_forbidden_listener_or_web_authority() {
   2033         let source = include_str!("server.rs");
   2034         for forbidden in [
   2035             concat!("Tcp", "Listener"),
   2036             concat!("Access-Control", "-Allow"),
   2037             concat!("co", "rs"),
   2038             concat!("browser", "_auth"),
   2039         ] {
   2040             assert!(
   2041                 !source.contains(forbidden),
   2042                 "forbidden server authority: {forbidden}"
   2043             );
   2044         }
   2045     }
   2046 
   2047     #[test]
   2048     fn request_and_outcome_debug_redact_body_query_and_result() {
   2049         let request = AdminRequest {
   2050             method: AdminHttpMethod::Post,
   2051             path: AdminRoutePath::new("/v1/test").expect("path"),
   2052             query: Some("secret=query".to_owned()),
   2053             correlation_id: AdminCorrelationId::new("safe-id").expect("correlation"),
   2054             parameters: BTreeMap::from([("item_id".to_owned(), "secret-item".to_owned())]),
   2055             body: Bytes::from_static(b"{\"secret\":true}"),
   2056             response_body_limit: 1024,
   2057         };
   2058         let debug = format!("{request:?}");
   2059         assert!(!debug.contains("secret=query"));
   2060         assert!(!debug.contains("secret\":true"));
   2061         assert!(!debug.contains("secret-item"));
   2062         let outcome = request
   2063             .success(&serde_json::json!({"secret": true}))
   2064             .expect("outcome");
   2065         assert!(!format!("{outcome:?}").contains("secret"));
   2066     }
   2067 
   2068     #[test]
   2069     fn strict_json_routes_accessors_and_safe_errors_cover_the_full_value_surface() {
   2070         assert!(valid_parameter_name("item_1"));
   2071         for rejected in [
   2072             "",
   2073             "1item",
   2074             "Item",
   2075             "item-name",
   2076             &"x".repeat(ADMIN_ROUTE_PARAMETER_NAME_MAX_UTF8_BYTES + 1),
   2077         ] {
   2078             assert!(!valid_parameter_name(rejected));
   2079         }
   2080         assert_eq!(decode_route_parameter(""), None);
   2081         assert_eq!(decode_route_parameter("plain"), Some("plain".to_owned()));
   2082 
   2083         for path in ["/", "/v", "/v1", "/version2", "/v2beta"] {
   2084             assert!(!unknown_major_version(path), "{path}");
   2085         }
   2086         for path in ["/v0", "/v2", "/v99/status"] {
   2087             assert!(unknown_major_version(path), "{path}");
   2088         }
   2089         assert_eq!(query_item_count(None), 0);
   2090         assert_eq!(query_item_count(Some("")), 0);
   2091         assert_eq!(query_item_count(Some("one")), 1);
   2092         assert_eq!(query_item_count(Some("one&two")), 2);
   2093 
   2094         let mut headers = HeaderMap::new();
   2095         assert!(!is_json_content_type(&headers));
   2096         headers.insert(CONTENT_TYPE, HeaderValue::from_static(JSON_CONTENT_TYPE));
   2097         assert!(is_json_content_type(&headers));
   2098         headers.insert(
   2099             CONTENT_TYPE,
   2100             HeaderValue::from_static("application/json; charset=utf-8"),
   2101         );
   2102         assert!(is_json_content_type(&headers));
   2103         headers.insert(CONTENT_TYPE, HeaderValue::from_static("text/plain"));
   2104         assert!(!is_json_content_type(&headers));
   2105 
   2106         for document in [
   2107             "true",
   2108             "-7",
   2109             "9",
   2110             "1.5",
   2111             r#""text""#,
   2112             "[true,2]",
   2113             r#"{"value":3}"#,
   2114         ] {
   2115             serde_json::from_str::<StrictJsonPayload>(document).unwrap();
   2116         }
   2117         for rejected in ["null", "[1,null]", r#"{"same":1,"same":2}"#] {
   2118             assert!(serde_json::from_str::<StrictJsonPayload>(rejected).is_err());
   2119         }
   2120 
   2121         let route = AdminRoutePath::new("/v1/items/{item_id}").unwrap();
   2122         assert_eq!(route.as_str(), "/v1/items/{item_id}");
   2123         assert!(route.overlaps(&AdminRoutePath::new("/v1/items/static").unwrap()));
   2124         assert!(!route.overlaps(&AdminRoutePath::new("/v1/other/static").unwrap()));
   2125         assert!(!route.overlaps(&AdminRoutePath::new("/v1/items/static/more").unwrap()));
   2126         assert_eq!(
   2127             route.match_path("/v1/items/value%2D1").unwrap(),
   2128             BTreeMap::from([("item_id".to_owned(), "value-1".to_owned())])
   2129         );
   2130         for rejected in [
   2131             "v1/items/value",
   2132             "/v1/items/value/",
   2133             "/v1//items/value",
   2134             "/v1/items",
   2135             "/v1/other/value",
   2136             "/v1/items/%",
   2137             "/v1/items/%GG",
   2138             "/v1/items/%2F",
   2139             "/v1/items/%5c",
   2140             "/v1/items/%00",
   2141             "/v1/items/%0A",
   2142             "/v1/items/%FF",
   2143         ] {
   2144             assert!(route.match_path(rejected).is_none(), "{rejected}");
   2145         }
   2146         assert!(
   2147             route
   2148                 .match_path(&format!(
   2149                     "/v1/items/{}",
   2150                     "x".repeat(ADMIN_ROUTE_PARAMETER_VALUE_MAX_UTF8_BYTES + 1)
   2151                 ))
   2152                 .is_none()
   2153         );
   2154 
   2155         let invalid_paths = [
   2156             ("", AdminRoutePathError::Empty),
   2157             ("/v2/items", AdminRoutePathError::WrongVersionPrefix),
   2158             ("/v1/items/", AdminRoutePathError::WrongVersionPrefix),
   2159             ("/v1//items", AdminRoutePathError::EmptySegment),
   2160             ("/v1/Items", AdminRoutePathError::InvalidCharacter),
   2161             ("/v1/{Bad}", AdminRoutePathError::InvalidParameter),
   2162             ("/v1/{item}/{item}", AdminRoutePathError::DuplicateParameter),
   2163         ];
   2164         for (path, expected) in invalid_paths {
   2165             assert_eq!(AdminRoutePath::new(path).unwrap_err(), expected);
   2166         }
   2167         let exact_maximum = format!(
   2168             "/v1/{}",
   2169             "x".repeat(ADMIN_ROUTE_PATH_MAX_UTF8_BYTES - "/v1/".len())
   2170         );
   2171         assert_eq!(
   2172             AdminRoutePath::new(&exact_maximum)
   2173                 .expect("exact maximum route")
   2174                 .as_str(),
   2175             exact_maximum
   2176         );
   2177         assert_eq!(
   2178             AdminRoutePath::new(format!(
   2179                 "/v1/{}",
   2180                 "x".repeat(ADMIN_ROUTE_PATH_MAX_UTF8_BYTES)
   2181             ))
   2182             .unwrap_err(),
   2183             AdminRoutePathError::TooLong
   2184         );
   2185         assert_eq!(
   2186             AdminRoutePath::new(format!("/v1/{}", "x".repeat(4 * 1024 * 1024))),
   2187             Err(AdminRoutePathError::TooLong)
   2188         );
   2189 
   2190         assert_eq!(
   2191             AdminHttpMethod::from_http(&Method::GET),
   2192             Some(AdminHttpMethod::Get)
   2193         );
   2194         assert_eq!(
   2195             AdminHttpMethod::from_http(&Method::POST),
   2196             Some(AdminHttpMethod::Post)
   2197         );
   2198         assert_eq!(AdminHttpMethod::from_http(&Method::DELETE), None);
   2199 
   2200         let request = AdminRequest {
   2201             method: AdminHttpMethod::Post,
   2202             path: route,
   2203             query: Some("page=1".to_owned()),
   2204             correlation_id: AdminCorrelationId::new("correlation-1").unwrap(),
   2205             parameters: BTreeMap::from([("item_id".to_owned(), "item-1".to_owned())]),
   2206             body: Bytes::from_static(b"true"),
   2207             response_body_limit: 1024,
   2208         };
   2209         assert_eq!(request.method(), AdminHttpMethod::Post);
   2210         assert_eq!(request.path().as_str(), "/v1/items/{item_id}");
   2211         assert_eq!(request.query(), Some("page=1"));
   2212         assert_eq!(request.correlation_id().as_str(), "correlation-1");
   2213         assert_eq!(request.parameter("item_id"), Some("item-1"));
   2214         assert_eq!(request.parameter("missing"), None);
   2215         assert_eq!(request.body(), b"true");
   2216         assert!(request.decode_json::<bool>().unwrap());
   2217         let empty = AdminRequest {
   2218             body: Bytes::new(),
   2219             ..request
   2220         };
   2221         assert_eq!(
   2222             empty.decode_json::<bool>().unwrap_err(),
   2223             AdminRequestDecodeError::Empty
   2224         );
   2225 
   2226         let error = known_error("stable_error", "stable message");
   2227         for status in [
   2228             AdminRouteFailureStatus::BadRequest,
   2229             AdminRouteFailureStatus::NotFound,
   2230             AdminRouteFailureStatus::Conflict,
   2231             AdminRouteFailureStatus::Unavailable,
   2232             AdminRouteFailureStatus::Internal,
   2233         ] {
   2234             assert!(
   2235                 status.http_status().is_client_error() || status.http_status().is_server_error()
   2236             );
   2237             let failure = AdminRouteFailure::new(status, error.clone());
   2238             assert_eq!(failure.status(), status);
   2239             assert_eq!(failure.error(), &error);
   2240             assert!(format!("{:?}", AdminRouteOutcome::failure(failure)).contains("Failure"));
   2241         }
   2242         for rendered in [
   2243             AdminRoutePathError::Empty.to_string(),
   2244             AdminRouteRegistrationError::Duplicate.to_string(),
   2245             AdminRequestDecodeError::Malformed.to_string(),
   2246             AdminRouteOutcomeError::Encoding.to_string(),
   2247             AdminRouteOutcomeError::InvalidPayload.to_string(),
   2248             AdminRouteOutcomeError::ResponseLimit.to_string(),
   2249         ] {
   2250             assert!(!rendered.is_empty());
   2251         }
   2252 
   2253         use std::io::Write as _;
   2254         let mut writer = CappedWriter::new(4);
   2255         writer.flush().unwrap();
   2256         assert_eq!(writer.write(b"four").unwrap(), 4);
   2257         assert!(writer.write(b"x").is_err());
   2258     }
   2259 }