aboutsummaryrefslogtreecommitdiff
path: root/src/request.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/request.rs')
-rw-r--r--src/request.rs82
1 files changed, 70 insertions, 12 deletions
diff --git a/src/request.rs b/src/request.rs
index 7846367..79ca2ae 100644
--- a/src/request.rs
+++ b/src/request.rs
@@ -8,7 +8,9 @@ use hyper::{body::Bytes, header};
use hyper::http::request::Parts as ReqParts;
use std::collections::HashMap;
-use crate::{Error, security};
+use crate::security;
+
+use error::*;
type HyperRequest = hyper::Request<hyper::Body>;
@@ -72,14 +74,14 @@ impl Parts {
}
/// Parses the query string of the request into a given struct.
- pub fn query<T: DeserializeOwned>(&self) -> Result<T,Error> {
- serde_urlencoded::from_str::<T>(self.parts.uri.query().unwrap_or("")).map_err(|e|Error::bad_request(e.to_string()))
+ pub fn query<T: DeserializeOwned>(&self) -> Result<T,QueryError> {
+ serde_urlencoded::from_str::<T>(self.parts.uri.query().unwrap_or("")).map_err(QueryError)
}
}
impl Body {
- pub async fn into_bytes(self) -> Result<Bytes,Error> {
- hyper::body::to_bytes(self.body).await.map_err(|_|Error::internal("failed to read body".to_string()))
+ pub async fn into_bytes(self) -> Result<Bytes, BodyError> {
+ hyper::body::to_bytes(self.body).await.map_err(BodyError)
}
/// Parses a `application/x-www-form-urlencoded` request body into a given struct.
@@ -102,10 +104,10 @@ impl Body {
/// Ok(Response::new(format!("hello {}", msg.text).into()))
/// }
/// ```
- pub async fn into_form<T: DeserializeOwned>(self) -> Result<T,Error> {
+ pub async fn into_form<T: DeserializeOwned>(self) -> Result<T, FormError> {
self.enforce_content_type(APPLICATION_WWW_FORM_URLENCODED)?;
let full_body = self.into_bytes().await?;
- serde_urlencoded::from_bytes::<T>(&full_body).map_err(|e|Error::bad_request(e.to_string()))
+ serde_urlencoded::from_bytes::<T>(&full_body).map_err(FormError::Deserialize)
}
/// Parses a `application/x-www-form-urlencoded` request body into a given struct.
@@ -140,20 +142,76 @@ impl Body {
/// Ok(response)
/// }
/// ```
- pub async fn into_form_csrf<T: DeserializeOwned>(self, csrf_token: &security::CsrfToken) -> Result<T,Error> {
+ pub async fn into_form_csrf<T: DeserializeOwned>(self, csrf_token: &security::CsrfToken) -> Result<T, CsrfProtectedFormError> {
self.enforce_content_type(APPLICATION_WWW_FORM_URLENCODED)?;
let full_body = self.into_bytes().await?;
- let csrf_data = serde_urlencoded::from_bytes::<CsrfData>(&full_body).map_err(|_|Error::bad_request("no csrf token".to_string()))?;
+ let csrf_data = serde_urlencoded::from_bytes::<CsrfData>(&full_body).map_err(|_| CsrfProtectedFormError::NoCsrf)?;
csrf_token.matches(csrf_data.csrf)?;
- serde_urlencoded::from_bytes::<T>(&full_body).map_err(|e|Error::bad_request(e.to_string()))
+ serde_urlencoded::from_bytes::<T>(&full_body).map_err(CsrfProtectedFormError::Deserialize)
}
- fn enforce_content_type(&self, mime: Mime) -> Result<(),Error> {
+ fn enforce_content_type(&self, mime: Mime) -> Result<(), WrongContentTypeError> {
if let Some(content_type) = &self.content_type {
if *content_type == mime.to_string() {
return Ok(())
}
}
- Err(Error::bad_request(format!("expected content-type: {}", mime)))
+ Err(WrongContentTypeError{expected: mime, received: self.content_type.as_ref().and_then(|h| h.to_str().ok().map(|s| s.to_owned()))})
+ }
+}
+
+pub mod error {
+ use mime::Mime;
+ use thiserror::Error;
+ use hyper::StatusCode;
+
+ use crate::security::CsrfError;
+ #[derive(Error, Debug)]
+ #[error("query deserialize error: {0}")]
+ pub struct QueryError(pub serde_urlencoded::de::Error);
+ impl_into_http_error!(QueryError, StatusCode::BAD_REQUEST);
+
+ #[derive(Error, Debug)]
+ #[error("failed to read body")]
+ pub struct BodyError(pub hyper::Error);
+ impl_into_http_error!(BodyError, StatusCode::BAD_REQUEST);
+
+ #[derive(Error, Debug)]
+ #[error("expected Content-Type {expected} but received {}", received.as_ref().unwrap_or(&"nothing".to_owned()))]
+ pub struct WrongContentTypeError {
+ pub expected: Mime,
+ pub received: Option<String>,
+ }
+
+ #[derive(Error, Debug)]
+ pub enum FormError {
+ #[error("{0}")]
+ ContentType(#[from] WrongContentTypeError),
+
+ #[error("{0}")]
+ Body(#[from] BodyError),
+
+ #[error("form deserialize error: {0}")]
+ Deserialize(#[from] serde_urlencoded::de::Error),
+ }
+ impl_into_http_error!(FormError, StatusCode::BAD_REQUEST);
+
+ #[derive(Error, Debug)]
+ pub enum CsrfProtectedFormError {
+ #[error("{0}")]
+ ContentType(#[from] WrongContentTypeError),
+
+ #[error("{0}")]
+ Body(#[from] BodyError),
+
+ #[error("form deserialize error: {0}")]
+ Deserialize(#[from] serde_urlencoded::de::Error),
+
+ #[error("no csrf token in form data")]
+ NoCsrf,
+
+ #[error("{0}")]
+ Csrf(#[from] CsrfError),
}
+ impl_into_http_error!(CsrfProtectedFormError, StatusCode::BAD_REQUEST);
} \ No newline at end of file