1use std::str::FromStr;
4
5use http::{
6 header::{self, HeaderMap, HeaderName},
7 request::Parts,
8 uri::{Scheme, Uri},
9};
10use url::Url;
11
12use crate::body::Body;
13
14pub type Request<B = Body> = http::request::Request<B>;
18
19pub const X_FORWARDED_FOR: HeaderName = HeaderName::from_static("x-forwarded-for");
23
24pub const X_REAL_IP: HeaderName = HeaderName::from_static("x-real-ip");
26
27pub trait RequestPartsExt: sealed::SealedRequestPartsExt {
29 fn host(&self) -> Option<&str>;
31 fn url(&self) -> Option<url::Url>;
33}
34
35mod sealed {
36 pub trait SealedRequestPartsExt {
37 fn headers(&self) -> &http::header::HeaderMap;
38 fn uri(&self) -> &http::uri::Uri;
39 fn extensions(&self) -> &http::Extensions;
40 }
41}
42
43impl sealed::SealedRequestPartsExt for Parts {
44 fn headers(&self) -> &HeaderMap {
45 &self.headers
46 }
47 fn uri(&self) -> &Uri {
48 &self.uri
49 }
50 fn extensions(&self) -> &http::Extensions {
51 &self.extensions
52 }
53}
54
55impl<B> sealed::SealedRequestPartsExt for Request<B> {
56 fn headers(&self) -> &HeaderMap {
57 self.headers()
58 }
59 fn uri(&self) -> &Uri {
60 self.uri()
61 }
62 fn extensions(&self) -> &http::Extensions {
63 self.extensions()
64 }
65}
66
67impl<T> RequestPartsExt for T
68where
69 T: sealed::SealedRequestPartsExt,
70{
71 fn host(&self) -> Option<&str> {
72 simdutf8::basic::from_utf8(self.headers().get(header::HOST)?.as_bytes()).ok()
73 }
74
75 fn url(&self) -> Option<Url> {
76 let host = self.host()?;
77 let uri = self.uri();
78 let path = uri.path();
79 let scheme = if let Some(scheme) = uri.scheme() {
80 scheme
81 } else if let Some(scheme) = self.extensions().get::<Scheme>() {
82 scheme
83 } else {
84 &Scheme::HTTP
85 };
86
87 Url::from_str(&format!("{scheme}://{host}{path}")).ok()
88 }
89}