use crate::Config as QsConfig;
use crate::error::Error as QsError;
#[cfg(feature = "actix3")]
use actix_web3 as actix_web;
#[cfg(feature = "actix4")]
use actix_web4 as actix_web;
#[cfg(feature = "actix3")]
use actix_web::HttpResponse;
use actix_web::dev::Payload;
use actix_web::{Error as ActixError, FromRequest, HttpRequest, ResponseError, web};
use futures_util::StreamExt;
use futures_util::future::{FutureExt, LocalBoxFuture, Ready, ready};
use serde::de;
use serde::de::DeserializeOwned;
use std::fmt::Debug;
use std::sync::Arc;
#[cfg(feature = "actix3")]
impl ResponseError for QsError {
fn error_response(&self) -> HttpResponse {
HttpResponse::BadRequest().finish()
}
}
#[cfg(feature = "actix4")]
impl ResponseError for QsError {
fn status_code(&self) -> actix_web::http::StatusCode {
actix_web::http::StatusCode::BAD_REQUEST
}
}
pub use crate::web::QsQuery;
impl<T> FromRequest for QsQuery<T>
where
T: de::DeserializeOwned,
{
type Error = ActixError;
type Future = Ready<Result<Self, ActixError>>;
#[cfg(feature = "actix3")]
type Config = QsQueryConfig;
#[inline]
fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
let query_config = req
.app_data::<QsQueryConfig>()
.unwrap_or(&DEFAULT_QUERY_CONFIG);
let res = query_config
.qs_config
.deserialize_str::<T>(req.query_string())
.map(|val| Ok(QsQuery(val)))
.unwrap_or_else(move |e| {
let e = if let Some(error_handler) = &query_config.ehandler {
(error_handler)(e, req)
} else {
e.into()
};
Err(e)
});
ready(res)
}
}
pub use crate::web::QsForm;
impl<T> FromRequest for QsForm<T>
where
T: DeserializeOwned + Debug,
{
type Error = ActixError;
type Future = LocalBoxFuture<'static, Result<Self, ActixError>>;
#[cfg(feature = "actix3")]
type Config = QsQueryConfig;
fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future {
let mut stream = payload.take();
let req_clone = req.clone();
let query_config: QsQueryConfig = req
.app_data::<QsQueryConfig>()
.unwrap_or(&DEFAULT_FORM_CONFIG)
.clone();
async move {
let mut bytes = web::BytesMut::new();
while let Some(item) = stream.next().await {
bytes.extend_from_slice(&item.unwrap());
}
query_config
.qs_config
.deserialize_bytes::<T>(&bytes)
.map(|val| Ok(QsForm(val)))
.unwrap_or_else(|e| {
let e = if let Some(error_handler) = &query_config.ehandler {
(error_handler)(e, &req_clone)
} else {
e.into()
};
Err(e)
})
}
.boxed_local()
}
}
type ActixErrorHandler = Option<Arc<dyn Fn(QsError, &HttpRequest) -> ActixError + Send + Sync>>;
#[derive(Clone, Default)]
pub struct QsQueryConfig {
ehandler: ActixErrorHandler,
qs_config: QsConfig,
}
static DEFAULT_QUERY_CONFIG: QsQueryConfig = QsQueryConfig {
ehandler: None,
qs_config: QsConfig::new(),
};
static DEFAULT_FORM_CONFIG: QsQueryConfig = QsQueryConfig {
ehandler: None,
qs_config: QsConfig::new().use_form_encoding(true),
};
impl QsQueryConfig {
pub fn error_handler<F>(mut self, f: F) -> Self
where
F: Fn(QsError, &HttpRequest) -> ActixError + Send + Sync + 'static,
{
self.ehandler = Some(Arc::new(f));
self
}
pub fn qs_config(mut self, config: QsConfig) -> Self {
self.qs_config = config;
self
}
}