use crate::{
HttpBody, HttpRequest,
error::Error,
headers::{FromHeaders, Header, HeaderMap, HeaderName, HeaderValue},
http::{Extensions, FromRequestRef, Method, Parts, Uri, Version},
};
pub struct HttpRequestMut {
inner: HttpRequest,
}
impl std::fmt::Debug for HttpRequestMut {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("HttpRequestMut(..)")
}
}
impl HttpRequestMut {
#[inline]
pub(crate) fn new(inner: HttpRequest) -> Self {
Self { inner }
}
#[inline]
pub fn uri(&self) -> &Uri {
self.inner.uri()
}
#[inline]
pub fn headers(&self) -> &HeaderMap {
self.inner.headers()
}
#[inline]
#[allow(unused)]
pub(crate) fn headers_mut(&mut self) -> &mut HeaderMap {
self.inner.headers_mut()
}
#[inline]
pub fn method(&self) -> &Method {
self.inner.method()
}
#[inline]
pub fn version(&self) -> Version {
self.inner.version()
}
#[inline]
#[allow(unused)]
pub(crate) fn extensions(&self) -> &Extensions {
self.inner.extensions()
}
#[inline]
#[allow(unused)]
pub(crate) fn extensions_mut(&mut self) -> &mut Extensions {
self.inner.extensions_mut()
}
#[inline]
pub fn get_header<T: FromHeaders>(&self) -> Option<Header<T>> {
self.inner.get_header()
}
#[inline]
pub fn get_all_headers<T: FromHeaders>(&self) -> impl Iterator<Item = Header<T>> {
self.inner.get_all_headers()
}
#[inline]
pub fn insert_header<T: FromHeaders>(&mut self, header: Header<T>) -> &mut Self {
self.inner
.headers_mut()
.insert(header.name(), header.value().clone());
self
}
#[inline]
pub fn try_insert_header<T>(
&mut self,
header: impl TryInto<Header<T>, Error = Error>,
) -> Result<&mut Self, Error>
where
T: FromHeaders,
{
let header = header.try_into()?;
Ok(self.insert_header(header))
}
#[inline]
pub fn insert_raw_header(&mut self, name: HeaderName, value: HeaderValue) -> &mut Self {
self.inner.headers_mut().insert(name, value);
self
}
#[inline]
pub fn try_insert_raw_header(&mut self, name: &str, value: &str) -> Result<&mut Self, Error> {
let name = HeaderName::from_bytes(name.as_bytes()).map_err(Error::from)?;
let value = HeaderValue::from_str(value).map_err(Error::from)?;
Ok(self.insert_raw_header(name, value))
}
#[inline]
pub fn append_header<T>(&mut self, header: Header<T>) -> &mut Self
where
T: FromHeaders,
{
self.inner
.headers_mut()
.append(header.name(), header.value().clone());
self
}
#[inline]
pub fn try_append_header<T>(
&mut self,
header: impl TryInto<Header<T>, Error = Error>,
) -> Result<&mut Self, Error>
where
T: FromHeaders,
{
let header = header.try_into()?;
Ok(self.append_header(header))
}
#[inline]
pub fn append_raw_header(&mut self, name: HeaderName, value: HeaderValue) -> &mut Self {
self.inner.headers_mut().append(name, value);
self
}
#[inline]
pub fn try_append_raw_header(&mut self, name: &str, value: &str) -> Result<&mut Self, Error> {
let name = HeaderName::from_bytes(name.as_bytes()).map_err(Error::from)?;
let value = HeaderValue::from_str(value).map_err(Error::from)?;
Ok(self.append_raw_header(name, value))
}
#[inline]
pub fn remove_header<T>(&mut self) -> bool
where
T: FromHeaders,
{
self.inner.headers_mut().remove(&T::NAME).is_some()
}
#[inline]
pub fn try_remove_header(&mut self, name: &str) -> Result<bool, Error> {
let name = HeaderName::from_bytes(name.as_bytes()).map_err(Error::from)?;
Ok(self.inner.headers_mut().remove(name).is_some())
}
pub fn body_limit(&self) -> Option<usize> {
self.inner.body_limit()
}
#[inline]
pub fn extract<T: FromRequestRef>(&self) -> Result<T, Error> {
self.inner.extract()
}
#[inline]
pub fn path_args(&self) -> impl Iterator<Item = (&str, &str)> {
self.inner.path_args()
}
#[inline]
pub fn query_args(&self) -> impl Iterator<Item = (&str, &str)> {
self.inner.query_args()
}
pub fn as_read_only(&self) -> &HttpRequest {
&self.inner
}
#[inline]
pub(crate) fn freeze(self) -> HttpRequest {
self.inner
}
#[inline]
pub fn into_parts(self) -> (Parts, HttpBody) {
self.inner.into_parts()
}
#[inline]
pub fn from_parts(parts: Parts, body: HttpBody) -> Self {
let inner = HttpRequest::from_parts(parts, body);
Self { inner }
}
}
pub trait IntoTapResult: sealed::Sealed {
fn into_result(self) -> Result<HttpRequestMut, Error>;
}
impl IntoTapResult for HttpRequestMut {
#[inline]
fn into_result(self) -> Result<HttpRequestMut, Error> {
Ok(self)
}
}
impl IntoTapResult for Result<HttpRequestMut, Error> {
#[inline]
fn into_result(self) -> Result<HttpRequestMut, Error> {
self
}
}
mod sealed {
use crate::{HttpRequestMut, error::Error};
pub trait Sealed {}
impl Sealed for HttpRequestMut {}
impl Sealed for Result<HttpRequestMut, Error> {}
}
#[cfg(test)]
#[allow(unreachable_pub)]
#[allow(unused)]
mod tests {
use super::*;
use crate::HttpBody;
use crate::headers::headers;
use crate::http::Request;
use crate::http::endpoints::route::{PathArg, PathArgs};
headers! {
(Foo, "x-foo")
}
fn create_req() -> HttpRequestMut {
let (parts, body) = Request::get("/")
.body(HttpBody::empty())
.unwrap()
.into_parts();
HttpRequestMut::new(HttpRequest::from_parts(parts, body))
}
#[test]
fn it_debugs() {
let req = create_req();
assert_eq!(format!("{req:?}"), "HttpRequestMut(..)");
}
#[test]
fn it_returns_url_path() {
use crate::http::request_scope::HttpRequestScope;
let args: PathArgs = smallvec::smallvec![
PathArg {
name: "id".into(),
value: "123".into()
},
PathArg {
name: "name".into(),
value: "John".into()
}
]
.into();
let req = Request::get("/")
.extension(HttpRequestScope {
params: args,
..HttpRequestScope::default()
})
.body(HttpBody::empty())
.unwrap();
let (parts, body) = req.into_parts();
let req = HttpRequestMut::new(HttpRequest::from_parts(parts, body));
let mut args = req.path_args();
assert_eq!(args.next().unwrap(), ("id", "123"));
assert_eq!(args.next().unwrap(), ("name", "John"));
}
#[test]
fn it_returns_url_query() {
let req = Request::get("/test?id=123&name=John")
.body(HttpBody::empty())
.unwrap();
let (parts, body) = req.into_parts();
let req = HttpRequestMut::new(HttpRequest::from_parts(parts, body));
let mut args = req.query_args();
assert_eq!(args.next().unwrap(), ("id", "123"));
assert_eq!(args.next().unwrap(), ("name", "John"));
}
#[test]
fn it_returns_empty_iter_if_no_path_params() {
let req = create_req();
let mut args = req.path_args();
assert!(args.next().is_none());
}
#[test]
fn it_returns_empty_iter_if_no_query_params() {
let req = create_req();
let mut args = req.query_args();
assert!(args.next().is_none());
}
#[test]
fn it_inserts_header() {
let mut req = create_req();
let header: Header<Foo> = Header::from_static("some key");
let _ = req.insert_header(header);
assert_eq!(req.headers().get("x-foo").unwrap(), "some key");
}
#[test]
fn it_tries_insert_header() {
let mut req = create_req();
req.try_insert_header::<Foo>("some key").unwrap();
assert_eq!(req.get_header::<Foo>().unwrap().value(), "some key");
}
#[test]
fn it_inserts_raw_header() {
let mut req = create_req();
req.insert_raw_header(
HeaderName::from_static("x-api-key"),
HeaderValue::from_static("some key"),
);
assert_eq!(req.headers().get("x-api-key").unwrap(), "some key");
}
#[test]
fn it_tries_insert_raw_header() {
let mut ctx = create_req();
ctx.try_insert_raw_header("x-foo", "some key").unwrap();
assert_eq!(ctx.get_header::<Foo>().unwrap().value(), "some key");
}
#[test]
fn it_appends_header() {
let mut req = create_req();
let api_key_header: Header<Foo> = Header::from_static("1");
let _ = req.append_header(api_key_header);
let api_key_header: Header<Foo> = Header::from_static("2");
let _ = req.append_header(api_key_header);
assert_eq!(
req.headers()
.get_all("x-foo")
.into_iter()
.collect::<Vec<_>>(),
["1", "2"]
);
}
#[test]
fn it_tries_append_header() {
let mut req = create_req();
req.try_append_header::<Foo>("1").unwrap();
req.try_append_header::<Foo>("2").unwrap();
assert_eq!(
req.get_all_headers::<Foo>()
.map(|h| h.into_inner())
.collect::<Vec<_>>(),
["1", "2"]
);
}
#[test]
fn it_appends_raw_header() {
let mut req = create_req();
req.append_raw_header(
HeaderName::from_static("x-foo"),
HeaderValue::from_static("1"),
);
req.append_raw_header(
HeaderName::from_static("x-foo"),
HeaderValue::from_static("2"),
);
assert_eq!(
req.get_all_headers::<Foo>()
.map(|h| h.into_inner())
.collect::<Vec<_>>(),
["1", "2"]
);
}
#[test]
fn it_tries_appends_raw_header() {
let mut req = create_req();
req.try_append_raw_header("x-foo", "1").unwrap();
req.try_append_raw_header("x-foo", "2").unwrap();
assert_eq!(
req.get_all_headers::<Foo>()
.map(|h| h.into_inner())
.collect::<Vec<_>>(),
["1", "2"]
);
}
#[test]
fn it_removes_header() {
let mut req = create_req();
let header: Header<Foo> = Header::from_static("some key");
let _ = req.insert_header(header);
req.remove_header::<Foo>();
assert!(req.headers().get("x-foo").is_none());
}
#[test]
fn it_tries_remove_header() {
let mut req = create_req();
let api_key_header: Header<Foo> = Header::from_static("some key");
let _ = req.insert_header(api_key_header);
let result = req.try_remove_header("x-foo").unwrap();
assert!(result);
assert!(req.headers().get("x-api-key").is_none());
}
}