Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more try_* fns to Request #929

Merged
merged 1 commit into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions crates/core/src/http/errors/parse_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ pub enum ParseError {
#[error("The request's body is empty.")]
EmptyBody,

/// The Hyper request's body is empty.
#[error("Data is not exist.")]
NotExist,

/// Parse error when parse from str.
#[error("Parse error when parse from str.")]
ParseFromStr,
Expand Down
2 changes: 1 addition & 1 deletion crates/core/src/http/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ cfg_feature! {
#![feature = "cookie"]
pub use cookie;
}
pub use errors::{ParseError, StatusError};
pub use errors::{ParseError, ParseResult, StatusError, StatusResult};
pub use headers;
pub use http::method::Method;
pub use http::{header, method, uri, HeaderMap, HeaderName, HeaderValue, StatusCode};
Expand Down
156 changes: 112 additions & 44 deletions crates/core/src/http/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::extract::{Extractible, Metadata};
use crate::fuse::TransProto;
use crate::http::body::ReqBody;
use crate::http::form::{FilePart, FormData};
use crate::http::{Mime, ParseError, Response, Version};
use crate::http::{Mime, ParseError, ParseResult, Response, Version};
use crate::routing::PathParams;
use crate::serde::{
from_request, from_str_map, from_str_multi_map, from_str_multi_val, from_str_val,
Expand Down Expand Up @@ -416,9 +416,20 @@ impl Request {
&mut self.headers
}

/// Get header with supplied name and try to parse to a 'T', returns None if failed or not found.
/// Get header with supplied name and try to parse to a 'T'.
///
/// Returns `None` if failed or not found.
#[inline]
pub fn header<'de, T>(&'de self, key: impl AsHeaderName) -> Option<T>
where
T: Deserialize<'de>,
{
self.try_header(key).ok()
}

/// Try to get header with supplied name and try to parse to a 'T'.
#[inline]
pub fn try_header<'de, T>(&'de self, key: impl AsHeaderName) -> ParseResult<T>
where
T: Deserialize<'de>,
{
Expand All @@ -428,7 +439,7 @@ impl Request {
.iter()
.filter_map(|v| v.to_str().ok())
.collect::<Vec<_>>();
from_str_multi_val(values).ok()
from_str_multi_val(values).map_err(Into::into)
}

/// Modify a header for this request.
Expand Down Expand Up @@ -641,7 +652,19 @@ impl Request {
where
T: Deserialize<'de>,
{
self.params.get(key).and_then(|v| from_str_val(v).ok())
self.try_param(key).ok()
}

/// Try to get param value from params.
#[inline]
pub fn try_param<'de, T>(&'de self, key: &str) -> ParseResult<T>
where
T: Deserialize<'de>,
{
self.params
.get(key)
.ok_or(ParseError::NotExist)
.and_then(|v| from_str_val(v).map_err(Into::into))
}

/// Get queries reference.
Expand All @@ -663,95 +686,146 @@ impl Request {
/// Get query value from queries.
#[inline]
pub fn query<'de, T>(&'de self, key: &str) -> Option<T>
where
T: Deserialize<'de>,
{
self.try_query(key).ok()
}

/// Try to get query value from queries.
#[inline]
pub fn try_query<'de, T>(&'de self, key: &str) -> ParseResult<T>
where
T: Deserialize<'de>,
{
self.queries()
.get_vec(key)
.and_then(|vs| from_str_multi_val(vs).ok())
.ok_or(ParseError::NotExist)
.and_then(|vs| from_str_multi_val(vs).map_err(Into::into))
}

/// Get field data from form.
#[inline]
pub async fn form<'de, T>(&'de mut self, key: &str) -> Option<T>
where
T: Deserialize<'de>,
{
self.try_form(key).await.ok()
}

/// Try to get field data from form.
#[inline]
pub async fn try_form<'de, T>(&'de mut self, key: &str) -> ParseResult<T>
where
T: Deserialize<'de>,
{
self.form_data()
.await
.ok()
.and_then(|ps| ps.fields.get_vec(key))
.and_then(|vs| from_str_multi_val(vs).ok())
.and_then(|ps| ps.fields.get_vec(key).ok_or(ParseError::NotExist))
.and_then(|vs| from_str_multi_val(vs).map_err(Into::into))
}

/// Get field data from form, if key is not found in form data, then get from query.
#[inline]
pub async fn form_or_query<'de, T>(&'de mut self, key: &str) -> Option<T>
where
T: Deserialize<'de>,
{
self.try_form_or_query(key).await.ok()
}

/// Try to get field data from form, if key is not found in form data, then get from query.
#[inline]
pub async fn try_form_or_query<'de, T>(&'de mut self, key: &str) -> ParseResult<T>
where
T: Deserialize<'de>,
{
if let Ok(form_data) = self.form_data().await {
if form_data.fields.contains_key(key) {
return self.form(key).await;
return self.try_form(key).await;
}
}
self.query(key)
self.try_query(key)
}

/// Get value from query, if key is not found in queries, then get from form.
#[inline]
pub async fn query_or_form<'de, T>(&'de mut self, key: &str) -> Option<T>
where
T: Deserialize<'de>,
{
self.try_query_or_form(key).await.ok()
}

/// Try to get value from query, if key is not found in queries, then get from form.
#[inline]
pub async fn try_query_or_form<'de, T>(&'de mut self, key: &str) -> ParseResult<T>
where
T: Deserialize<'de>,
{
if self.queries().contains_key(key) {
self.query(key)
self.try_query(key)
} else {
self.form(key).await
self.try_form(key).await
}
}

/// Get [`FilePart`] reference from request.
#[inline]
pub async fn file<'a>(&'a mut self, key: &'a str) -> Option<&'a FilePart> {
self.form_data().await.ok().and_then(|ps| ps.files.get(key))
pub async fn file(&mut self, key: &str) -> Option<&FilePart> {
self.try_file(key).await.ok().flatten()
}
/// Try to get [`FilePart`] reference from request.
#[inline]
pub async fn try_file(&mut self, key: &str) -> ParseResult<Option<&FilePart>> {
self.form_data().await.map(|ps| ps.files.get(key))
}

/// Get [`FilePart`] reference from request.
#[inline]
pub async fn first_file(&mut self) -> Option<&FilePart> {
self.try_first_file().await.ok().flatten()
}

/// Try to get [`FilePart`] reference from request.
#[inline]
pub async fn try_first_file(&mut self) -> ParseResult<Option<&FilePart>> {
self.form_data()
.await
.ok()
.and_then(|ps| ps.files.iter().next())
.map(|(_, f)| f)
.map(|ps| ps.files.iter().next().map(|(_, f)| f))
}

/// Get [`FilePart`] list reference from request.
#[inline]
pub async fn files<'a>(&'a mut self, key: &'a str) -> Option<&'a Vec<FilePart>> {
self.form_data()
.await
.ok()
.and_then(|ps| ps.files.get_vec(key))
pub async fn files(&mut self, key: &str) -> Option<&Vec<FilePart>> {
self.try_files(key).await.ok().flatten()
}
/// Try to get [`FilePart`] list reference from request.
#[inline]
pub async fn try_files(&mut self, key: &str) -> ParseResult<Option<&Vec<FilePart>>> {
self.form_data().await.map(|ps| ps.files.get_vec(key))
}

/// Get [`FilePart`] list reference from request.
#[inline]
pub async fn all_files(&mut self) -> Vec<&FilePart> {
self.try_all_files().await.unwrap_or_default()
}

/// Try to get [`FilePart`] list reference from request.
#[inline]
pub async fn try_all_files(&mut self) -> ParseResult<Vec<&FilePart>> {
self.form_data()
.await
.ok()
.map(|ps| ps.files.iter().map(|(_, f)| f).collect())
.unwrap_or_default()
}

/// Get request payload with default max size limit(64KB).
///
/// <https://github.com/hyperium/hyper/issues/3111>
/// *Notice: This method takes body.
#[inline]
pub async fn payload(&mut self) -> Result<&Bytes, ParseError> {
pub async fn payload(&mut self) -> ParseResult<&Bytes> {
self.payload_with_max_size(self.secure_max_size()).await
}

Expand All @@ -760,7 +834,7 @@ impl Request {
/// <https://github.com/hyperium/hyper/issues/3111>
/// *Notice: This method takes body.
#[inline]
pub async fn payload_with_max_size(&mut self, max_size: usize) -> Result<&Bytes, ParseError> {
pub async fn payload_with_max_size(&mut self, max_size: usize) -> ParseResult<&Bytes> {
let body = self.take_body();
self.payload
.get_or_try_init(|| async {
Expand All @@ -777,7 +851,7 @@ impl Request {
///
/// *Notice: This method takes body and body's size is not limited.
#[inline]
pub async fn form_data(&mut self) -> Result<&FormData, ParseError> {
pub async fn form_data(&mut self) -> ParseResult<&FormData> {
if let Some(ctype) = self.content_type() {
if ctype.subtype() == mime::WWW_FORM_URLENCODED || ctype.type_() == mime::MULTIPART {
let body = self.take_body();
Expand All @@ -795,7 +869,7 @@ impl Request {

/// Extract request as type `T` from request's different parts.
#[inline]
pub async fn extract<'de, T>(&'de mut self) -> Result<T, ParseError>
pub async fn extract<'de, T>(&'de mut self) -> ParseResult<T>
where
T: Extractible<'de> + Deserialize<'de> + Send,
{
Expand All @@ -807,7 +881,7 @@ impl Request {
pub async fn extract_with_metadata<'de, T>(
&'de mut self,
metadata: &'de Metadata,
) -> Result<T, ParseError>
) -> ParseResult<T>
where
T: Deserialize<'de> + Send,
{
Expand All @@ -816,7 +890,7 @@ impl Request {

/// Parse url params as type `T` from request.
#[inline]
pub fn parse_params<'de, T>(&'de mut self) -> Result<T, ParseError>
pub fn parse_params<'de, T>(&'de mut self) -> ParseResult<T>
where
T: Deserialize<'de>,
{
Expand All @@ -826,7 +900,7 @@ impl Request {

/// Parse queries as type `T` from request.
#[inline]
pub fn parse_queries<'de, T>(&'de mut self) -> Result<T, ParseError>
pub fn parse_queries<'de, T>(&'de mut self) -> ParseResult<T>
where
T: Deserialize<'de>,
{
Expand All @@ -836,7 +910,7 @@ impl Request {

/// Parse headers as type `T` from request.
#[inline]
pub fn parse_headers<'de, T>(&'de mut self) -> Result<T, ParseError>
pub fn parse_headers<'de, T>(&'de mut self) -> ParseResult<T>
where
T: Deserialize<'de>,
{
Expand All @@ -851,7 +925,7 @@ impl Request {
#![feature = "cookie"]
/// Parse cookies as type `T` from request.
#[inline]
pub fn parse_cookies<'de, T>(&'de mut self) -> Result<T, ParseError>
pub fn parse_cookies<'de, T>(&'de mut self) -> ParseResult<T>
where
T: Deserialize<'de>,
{
Expand All @@ -865,18 +939,15 @@ impl Request {

/// Parse json body as type `T` from request with default max size limit.
#[inline]
pub async fn parse_json<'de, T>(&'de mut self) -> Result<T, ParseError>
pub async fn parse_json<'de, T>(&'de mut self) -> ParseResult<T>
where
T: Deserialize<'de>,
{
self.parse_json_with_max_size(self.secure_max_size()).await
}
/// Parse json body as type `T` from request with max size limit.
#[inline]
pub async fn parse_json_with_max_size<'de, T>(
&'de mut self,
max_size: usize,
) -> Result<T, ParseError>
pub async fn parse_json_with_max_size<'de, T>(&'de mut self, max_size: usize) -> ParseResult<T>
where
T: Deserialize<'de>,
{
Expand All @@ -902,7 +973,7 @@ impl Request {

/// Parse form body as type `T` from request.
#[inline]
pub async fn parse_form<'de, T>(&'de mut self) -> Result<T, ParseError>
pub async fn parse_form<'de, T>(&'de mut self) -> ParseResult<T>
where
T: Deserialize<'de>,
{
Expand All @@ -917,18 +988,15 @@ impl Request {

/// Parse json body or form body as type `T` from request with default max size.
#[inline]
pub async fn parse_body<'de, T>(&'de mut self) -> Result<T, ParseError>
pub async fn parse_body<'de, T>(&'de mut self) -> ParseResult<T>
where
T: Deserialize<'de>,
{
self.parse_body_with_max_size(self.secure_max_size()).await
}

/// Parse json body or form body as type `T` from request with max size.
pub async fn parse_body_with_max_size<'de, T>(
&'de mut self,
max_size: usize,
) -> Result<T, ParseError>
pub async fn parse_body_with_max_size<'de, T>(&'de mut self, max_size: usize) -> ParseResult<T>
where
T: Deserialize<'de>,
{
Expand Down