Skip to main content

apimock_server/
http_util.rs

1//! HTTP utilities used only by the server crate.
2//!
3//! `normalize_url_path` previously lived alongside these but moved to
4//! `apimock-routing::util::http` in 5.0 — the matcher needs it; these
5//! two helpers are HTTP-layer only.
6
7use hyper::{
8    HeaderMap,
9    header::{CONTENT_TYPE, HeaderValue},
10};
11use tokio::time;
12
13use std::time::Duration;
14
15/// Inspect `Content-Type` to decide whether a request body should be
16/// parsed as JSON.
17///
18/// Returns:
19/// - `Some(true)`  — header is present and starts with `application/json`
20///   (supports `application/json; charset=utf-8` and similar).
21/// - `Some(false)` — header is present but is something else.
22/// - `None`        — header is absent, so we can't tell.
23///
24/// The three-valued return is deliberate: callers treat "absent" and
25/// "present-but-wrong" differently (the first is a common shortcut, the
26/// second is a likely client bug).
27pub fn content_type_is_application_json(headers: &HeaderMap<HeaderValue>) -> Option<bool> {
28    let content_type = headers.get(CONTENT_TYPE)?;
29
30    let Ok(content_type) = content_type.to_str() else {
31        return Some(false);
32    };
33
34    Some(
35        content_type
36            .trim_start()
37            .to_ascii_lowercase()
38            .starts_with("application/json"),
39    )
40}
41
42/// Sleep `milliseconds` ms on the async runtime.
43///
44/// Used by `respond.delay_response_milliseconds` to simulate slow
45/// backends when a mock needs to exercise client timeout behaviour.
46pub async fn delay_response(milliseconds: u32) {
47    time::sleep(Duration::from_millis(milliseconds.into())).await
48}