Skip to main content

roas_http_validator/adapters/
http.rs

1//! `http::Request` — and so axum, warp, tonic, hyper and reqwest.
2//!
3//! This is the adapter that covers most of the ecosystem at once.
4//! `axum::extract::Request` *is* `http::Request<axum::body::Body>`, a
5//! `tower::Service` is `Service<http::Request<B>>`, and warp, tonic and
6//! hyper all speak the same type — so one impl serves them all.
7//!
8//! Both halves are covered: [`http::Request`] itself, and
9//! [`http::request::Parts`] for the middleware that has already split
10//! the request to get at its body.
11
12use std::borrow::Cow;
13
14use http::header::HeaderMap;
15use http::{Method, Uri};
16
17use crate::request::{RequestView, ToRequestView};
18
19impl ToRequestView for http::request::Parts {
20    fn request_view(&self) -> RequestView<'_> {
21        view(&self.method, &self.uri, &self.headers)
22    }
23}
24
25impl<B> ToRequestView for http::Request<B> {
26    fn request_view(&self) -> RequestView<'_> {
27        view(self.method(), self.uri(), self.headers())
28    }
29}
30
31fn view<'r>(method: &'r Method, uri: &'r Uri, headers: &'r HeaderMap) -> RequestView<'r> {
32    let view = RequestView::new(method.as_str(), uri.path()).with_headers(headers.iter().map(
33        |(name, value)| {
34            let value = match value.to_str() {
35                Ok(text) => Cow::Borrowed(text),
36                // A header that is not UTF-8 is still a header. Dropping
37                // it would make a required one look absent, so it is
38                // carried through lossily and judged as what arrived.
39                Err(_) => Cow::Owned(String::from_utf8_lossy(value.as_bytes()).into_owned()),
40            };
41            (Cow::Borrowed(name.as_str()), value)
42        },
43    ));
44    match uri.query() {
45        Some(query) => view.with_query(query),
46        None => view,
47    }
48}