Don't include generic in error type
This commit is contained in:
parent
1e635ce27c
commit
d83b0ad464
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "actix-form-data"
|
name = "actix-form-data"
|
||||||
description = "Multipart Form Data for Actix Web"
|
description = "Multipart Form Data for Actix Web"
|
||||||
version = "0.6.0-beta.8"
|
version = "0.6.0-beta.9"
|
||||||
license = "GPL-3.0"
|
license = "GPL-3.0"
|
||||||
authors = ["asonix <asonix@asonix.dog>"]
|
authors = ["asonix <asonix@asonix.dog>"]
|
||||||
repository = "https://git.asonix.dog/Aardwolf/actix-form-data.git"
|
repository = "https://git.asonix.dog/Aardwolf/actix-form-data.git"
|
||||||
|
|
|
@ -1,24 +1,10 @@
|
||||||
use actix_form_data::{Field, Form, Value};
|
use actix_form_data::{Error, Field, Form, Value};
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
web::{post, resource},
|
web::{post, resource},
|
||||||
App, HttpResponse, HttpServer, ResponseError,
|
App, HttpResponse, HttpServer,
|
||||||
};
|
};
|
||||||
use futures_util::stream::StreamExt;
|
use futures_util::stream::StreamExt;
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
|
||||||
#[error("{inner}")]
|
|
||||||
struct MyError {
|
|
||||||
inner: Box<dyn std::error::Error + 'static>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MyError {
|
|
||||||
fn new(e: impl std::error::Error + 'static) -> Self {
|
|
||||||
Self { inner: Box::new(e) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ResponseError for MyError {}
|
|
||||||
|
|
||||||
async fn upload(uploaded_content: Value<()>) -> HttpResponse {
|
async fn upload(uploaded_content: Value<()>) -> HttpResponse {
|
||||||
println!("Uploaded Content: {:#?}", uploaded_content);
|
println!("Uploaded Content: {:#?}", uploaded_content);
|
||||||
HttpResponse::Created().finish()
|
HttpResponse::Created().finish()
|
||||||
|
@ -39,9 +25,9 @@ async fn main() -> Result<(), anyhow::Error> {
|
||||||
"files",
|
"files",
|
||||||
Field::array(Field::file(|_, _, mut stream| async move {
|
Field::array(Field::file(|_, _, mut stream| async move {
|
||||||
while let Some(res) = stream.next().await {
|
while let Some(res) = stream.next().await {
|
||||||
res.map_err(MyError::new)?;
|
res?;
|
||||||
}
|
}
|
||||||
Ok(()) as Result<(), MyError>
|
Ok(()) as Result<(), Error>
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@ async fn upload(uploaded_content: Value<PathBuf>) -> HttpResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn save_file(
|
async fn save_file(
|
||||||
stream: Pin<Box<dyn Stream<Item = Result<Bytes, Error<Errors>>>>>,
|
stream: Pin<Box<dyn Stream<Item = Result<Bytes, Error>>>>,
|
||||||
count: usize,
|
count: usize,
|
||||||
) -> Result<String, JsonError> {
|
) -> Result<String, JsonError> {
|
||||||
use futures_lite::io::AsyncWriteExt;
|
use futures_lite::io::AsyncWriteExt;
|
||||||
|
|
13
src/error.rs
13
src/error.rs
|
@ -30,9 +30,7 @@ use actix_web::{
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum Error<E> {
|
pub enum Error {
|
||||||
#[error("{0}")]
|
|
||||||
FileFn(E),
|
|
||||||
#[error("Error parsing payload, {0}")]
|
#[error("Error parsing payload, {0}")]
|
||||||
Payload(#[from] PayloadError),
|
Payload(#[from] PayloadError),
|
||||||
#[error("Error in multipart creation, {0}")]
|
#[error("Error in multipart creation, {0}")]
|
||||||
|
@ -63,19 +61,15 @@ pub enum Error<E> {
|
||||||
FileSize,
|
FileSize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E> From<MultipartError> for Error<E> {
|
impl From<MultipartError> for Error {
|
||||||
fn from(m: MultipartError) -> Self {
|
fn from(m: MultipartError) -> Self {
|
||||||
Error::Multipart(m)
|
Error::Multipart(m)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E> ResponseError for Error<E>
|
impl ResponseError for Error {
|
||||||
where
|
|
||||||
E: ResponseError,
|
|
||||||
{
|
|
||||||
fn status_code(&self) -> StatusCode {
|
fn status_code(&self) -> StatusCode {
|
||||||
match *self {
|
match *self {
|
||||||
Error::FileFn(ref e) => e.status_code(),
|
|
||||||
Error::Payload(ref e) => e.status_code(),
|
Error::Payload(ref e) => e.status_code(),
|
||||||
_ => StatusCode::BAD_REQUEST,
|
_ => StatusCode::BAD_REQUEST,
|
||||||
}
|
}
|
||||||
|
@ -83,7 +77,6 @@ where
|
||||||
|
|
||||||
fn error_response(&self) -> HttpResponse {
|
fn error_response(&self) -> HttpResponse {
|
||||||
match *self {
|
match *self {
|
||||||
Error::FileFn(ref e) => e.error_response(),
|
|
||||||
Error::Payload(ref e) => e.error_response(),
|
Error::Payload(ref e) => e.error_response(),
|
||||||
Error::Multipart(_)
|
Error::Multipart(_)
|
||||||
| Error::ParseField(_)
|
| Error::ParseField(_)
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
//! while let Some(_) = stream.next().await {
|
//! while let Some(_) = stream.next().await {
|
||||||
//! // do something
|
//! // do something
|
||||||
//! }
|
//! }
|
||||||
//! Ok(()) as Result<(), std::io::Error>
|
//! Ok(()) as Result<(), Error>
|
||||||
//! })),
|
//! })),
|
||||||
//! );
|
//! );
|
||||||
//!
|
//!
|
||||||
|
|
|
@ -130,7 +130,8 @@ where
|
||||||
|
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let uploaded = match handle_multipart(multipart, form.clone()).await {
|
let uploaded = match handle_multipart(multipart, form.clone()).await {
|
||||||
Ok(uploaded) => uploaded,
|
Ok(Ok(uploaded)) => uploaded,
|
||||||
|
Ok(Err(e)) => return Err(e.into()),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
if let Some(f) = form.transform_error.clone() {
|
if let Some(f) = form.transform_error.clone() {
|
||||||
return Err((f)(e));
|
return Err((f)(e));
|
||||||
|
|
52
src/types.rs
52
src/types.rs
|
@ -157,8 +157,8 @@ pub type FileFn<T, E> = Arc<
|
||||||
dyn Fn(
|
dyn Fn(
|
||||||
String,
|
String,
|
||||||
Mime,
|
Mime,
|
||||||
Pin<Box<dyn Stream<Item = Result<Bytes, Error<E>>>>>,
|
Pin<Box<dyn Stream<Item = Result<Bytes, Error>>>>,
|
||||||
) -> Pin<Box<dyn Future<Output = Result<T, Error<E>>>>>
|
) -> Pin<Box<dyn Future<Output = Result<T, E>>>>
|
||||||
+ Send
|
+ Send
|
||||||
+ Sync,
|
+ Sync,
|
||||||
>;
|
>;
|
||||||
|
@ -211,7 +211,7 @@ impl<T, E> Field<T, E> {
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use actix_form_data::{Form, Field};
|
/// # use actix_form_data::{Error, Form, Field};
|
||||||
/// # use tokio::sync::mpsc::channel;
|
/// # use tokio::sync::mpsc::channel;
|
||||||
/// # use futures_util::stream::StreamExt;
|
/// # use futures_util::stream::StreamExt;
|
||||||
/// #
|
/// #
|
||||||
|
@ -226,13 +226,13 @@ impl<T, E> Field<T, E> {
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
/// Ok(()) as Result<_, std::io::Error>
|
/// Ok(()) as Result<_, Error>
|
||||||
/// }
|
/// }
|
||||||
/// }));
|
/// }));
|
||||||
/// ```
|
/// ```
|
||||||
pub fn file<F, Fut>(f: F) -> Self
|
pub fn file<F, Fut>(f: F) -> Self
|
||||||
where
|
where
|
||||||
F: Fn(String, Mime, Pin<Box<dyn Stream<Item = Result<Bytes, Error<E>>>>>) -> Fut
|
F: Fn(String, Mime, Pin<Box<dyn Stream<Item = Result<Bytes, Error>>>>) -> Fut
|
||||||
+ Send
|
+ Send
|
||||||
+ Sync
|
+ Sync
|
||||||
+ Clone
|
+ Clone
|
||||||
|
@ -242,7 +242,7 @@ impl<T, E> Field<T, E> {
|
||||||
{
|
{
|
||||||
Field::File(Arc::new(move |filename, mime, stream| {
|
Field::File(Arc::new(move |filename, mime, stream| {
|
||||||
let f = f.clone();
|
let f = f.clone();
|
||||||
Box::pin(async move { (f)(filename, mime, stream).await.map_err(Error::FileFn) })
|
Box::pin(async move { (f)(filename, mime, stream).await })
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,8 +250,8 @@ impl<T, E> Field<T, E> {
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use actix_form_data::{Form, Field};
|
/// # use actix_form_data::{Error, Form, Field};
|
||||||
/// let form = Form::<(), std::io::Error>::new().field("text-field", Field::bytes());
|
/// let form = Form::<(), Error>::new().field("text-field", Field::bytes());
|
||||||
pub fn bytes() -> Self {
|
pub fn bytes() -> Self {
|
||||||
Field::Bytes
|
Field::Bytes
|
||||||
}
|
}
|
||||||
|
@ -260,8 +260,8 @@ impl<T, E> Field<T, E> {
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use actix_form_data::{Form, Field};
|
/// # use actix_form_data::{Error, Form, Field};
|
||||||
/// let form = Form::<(), std::io::Error>::new().field("text-field", Field::text());
|
/// let form = Form::<(), Error>::new().field("text-field", Field::text());
|
||||||
pub fn text() -> Self {
|
pub fn text() -> Self {
|
||||||
Field::Text
|
Field::Text
|
||||||
}
|
}
|
||||||
|
@ -270,8 +270,8 @@ impl<T, E> Field<T, E> {
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use actix_form_data::{Form, Field};
|
/// # use actix_form_data::{Error, Form, Field};
|
||||||
/// let form = Form::<(), std::io::Error>::new().field("int-field", Field::int());
|
/// let form = Form::<(), Error>::new().field("int-field", Field::int());
|
||||||
/// ```
|
/// ```
|
||||||
pub fn int() -> Self {
|
pub fn int() -> Self {
|
||||||
Field::Int
|
Field::Int
|
||||||
|
@ -281,8 +281,8 @@ impl<T, E> Field<T, E> {
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use actix_form_data::{Form, Field};
|
/// # use actix_form_data::{Error, Form, Field};
|
||||||
/// let form = Form::<(), std::io::Error>::new().field("float-field", Field::float());
|
/// let form = Form::<(), Error>::new().field("float-field", Field::float());
|
||||||
/// ```
|
/// ```
|
||||||
pub fn float() -> Self {
|
pub fn float() -> Self {
|
||||||
Field::Float
|
Field::Float
|
||||||
|
@ -292,9 +292,9 @@ impl<T, E> Field<T, E> {
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use actix_form_data::{Form, Field};
|
/// # use actix_form_data::{Error, Form, Field};
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// let form = Form::<(), std::io::Error>::new()
|
/// let form = Form::<(), Error>::new()
|
||||||
/// .field(
|
/// .field(
|
||||||
/// "array-field",
|
/// "array-field",
|
||||||
/// Field::array(Field::text())
|
/// Field::array(Field::text())
|
||||||
|
@ -309,9 +309,9 @@ impl<T, E> Field<T, E> {
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use actix_form_data::{Form, Field};
|
/// # use actix_form_data::{Error, Form, Field};
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// let form = Form::<(), std::io::Error>::new()
|
/// let form = Form::<(), Error>::new()
|
||||||
/// .field(
|
/// .field(
|
||||||
/// "map-field",
|
/// "map-field",
|
||||||
/// Field::map()
|
/// Field::map()
|
||||||
|
@ -434,9 +434,9 @@ impl<T, E> Map<T, E> {
|
||||||
/// Add a `Field` to a map
|
/// Add a `Field` to a map
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use actix_form_data::Field;
|
/// # use actix_form_data::{Error, Field};
|
||||||
/// #
|
/// #
|
||||||
/// Field::<(), std::io::Error>::map()
|
/// Field::<(), Error>::map()
|
||||||
/// .field("sub-field", Field::text())
|
/// .field("sub-field", Field::text())
|
||||||
/// .field("sub-field-two", Field::text())
|
/// .field("sub-field-two", Field::text())
|
||||||
/// .finalize();
|
/// .finalize();
|
||||||
|
@ -449,9 +449,9 @@ impl<T, E> Map<T, E> {
|
||||||
|
|
||||||
/// Finalize the map into a `Field`, so it can be added to a Form
|
/// Finalize the map into a `Field`, so it can be added to a Form
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use actix_form_data::Field;
|
/// # use actix_form_data::{Error, Field};
|
||||||
/// #
|
/// #
|
||||||
/// Field::<(), std::io::Error>::map()
|
/// Field::<(), Error>::map()
|
||||||
/// .field("sub-field", Field::text())
|
/// .field("sub-field", Field::text())
|
||||||
/// .field("sub-field-two", Field::text())
|
/// .field("sub-field-two", Field::text())
|
||||||
/// .finalize();
|
/// .finalize();
|
||||||
|
@ -477,8 +477,8 @@ impl<T, E> Map<T, E> {
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use actix_form_data::{Form, Field};
|
/// # use actix_form_data::{Error, Form, Field};
|
||||||
/// let form = Form::<(), std::io::Error>::new()
|
/// let form = Form::<(), Error>::new()
|
||||||
/// .field("field-name", Field::text())
|
/// .field("field-name", Field::text())
|
||||||
/// .field("second-field", Field::int())
|
/// .field("second-field", Field::int())
|
||||||
/// .field("third-field", Field::float())
|
/// .field("third-field", Field::float())
|
||||||
|
@ -502,7 +502,7 @@ pub struct Form<T, E> {
|
||||||
pub(crate) max_field_size: usize,
|
pub(crate) max_field_size: usize,
|
||||||
pub(crate) max_files: u32,
|
pub(crate) max_files: u32,
|
||||||
pub(crate) max_file_size: usize,
|
pub(crate) max_file_size: usize,
|
||||||
pub(crate) transform_error: Option<Arc<dyn Fn(Error<E>) -> actix_web::Error + Send + Sync>>,
|
pub(crate) transform_error: Option<Arc<dyn Fn(Error) -> actix_web::Error + Send + Sync>>,
|
||||||
inner: Map<T, E>,
|
inner: Map<T, E>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -549,7 +549,7 @@ impl<T, E> Form<T, E> {
|
||||||
/// Set the Transform Error method to convert Error types into actix_web::Error by hand
|
/// Set the Transform Error method to convert Error types into actix_web::Error by hand
|
||||||
pub fn transform_error(
|
pub fn transform_error(
|
||||||
mut self,
|
mut self,
|
||||||
f: impl Fn(Error<E>) -> actix_web::Error + Send + Sync + 'static,
|
f: impl Fn(Error) -> actix_web::Error + Send + Sync + 'static,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
self.transform_error = Some(Arc::new(f));
|
self.transform_error = Some(Arc::new(f));
|
||||||
self
|
self
|
||||||
|
|
|
@ -65,7 +65,7 @@ fn consolidate<T>(mf: MultipartForm<T>) -> Value<T> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_multipart_name<E>(name: String) -> Result<Vec<NamePart>, Error<E>> {
|
fn parse_multipart_name(name: String) -> Result<Vec<NamePart>, Error> {
|
||||||
name.split('[')
|
name.split('[')
|
||||||
.map(|part| {
|
.map(|part| {
|
||||||
if part.len() == 1 && part.ends_with(']') {
|
if part.len() == 1 && part.ends_with(']') {
|
||||||
|
@ -104,7 +104,7 @@ async fn handle_file_upload<T, E>(
|
||||||
filename: Option<String>,
|
filename: Option<String>,
|
||||||
form: Form<T, E>,
|
form: Form<T, E>,
|
||||||
file_fn: FileFn<T, E>,
|
file_fn: FileFn<T, E>,
|
||||||
) -> Result<MultipartContent<T>, Error<E>>
|
) -> Result<Result<MultipartContent<T>, E>, Error>
|
||||||
where
|
where
|
||||||
T: 'static,
|
T: 'static,
|
||||||
E: 'static,
|
E: 'static,
|
||||||
|
@ -142,20 +142,23 @@ where
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
.await?;
|
.await;
|
||||||
|
|
||||||
Ok(MultipartContent::File(FileMeta {
|
match result {
|
||||||
filename,
|
Ok(result) => Ok(Ok(MultipartContent::File(FileMeta {
|
||||||
content_type,
|
filename,
|
||||||
result,
|
content_type,
|
||||||
}))
|
result,
|
||||||
|
}))),
|
||||||
|
Err(e) => Ok(Err(e)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_form_data<T, E>(
|
async fn handle_form_data<T, E>(
|
||||||
mut field: actix_multipart::Field,
|
mut field: actix_multipart::Field,
|
||||||
term: FieldTerminator<T, E>,
|
term: FieldTerminator<T, E>,
|
||||||
form: Form<T, E>,
|
form: Form<T, E>,
|
||||||
) -> Result<MultipartContent<T>, Error<E>>
|
) -> Result<MultipartContent<T>, Error>
|
||||||
where
|
where
|
||||||
T: 'static,
|
T: 'static,
|
||||||
E: 'static,
|
E: 'static,
|
||||||
|
@ -195,7 +198,7 @@ where
|
||||||
async fn handle_stream_field<T, E>(
|
async fn handle_stream_field<T, E>(
|
||||||
field: actix_multipart::Field,
|
field: actix_multipart::Field,
|
||||||
form: Form<T, E>,
|
form: Form<T, E>,
|
||||||
) -> Result<MultipartHash<T>, Error<E>>
|
) -> Result<Result<MultipartHash<T>, E>, Error>
|
||||||
where
|
where
|
||||||
T: 'static,
|
T: 'static,
|
||||||
E: 'static,
|
E: 'static,
|
||||||
|
@ -211,19 +214,22 @@ where
|
||||||
|
|
||||||
let content = match term {
|
let content = match term {
|
||||||
FieldTerminator::File(file_fn) => {
|
FieldTerminator::File(file_fn) => {
|
||||||
handle_file_upload(field, content_disposition.filename, form, file_fn).await?
|
match handle_file_upload(field, content_disposition.filename, form, file_fn).await? {
|
||||||
|
Ok(content) => content,
|
||||||
|
Err(e) => return Ok(Err(e)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
term => handle_form_data(field, term, form.clone()).await?,
|
term => handle_form_data(field, term, form.clone()).await?,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok((name, content))
|
Ok(Ok((name, content)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle multipart streams from Actix Web
|
/// Handle multipart streams from Actix Web
|
||||||
pub async fn handle_multipart<T, E>(
|
pub async fn handle_multipart<T, E>(
|
||||||
m: actix_multipart::Multipart,
|
m: actix_multipart::Multipart,
|
||||||
form: Form<T, E>,
|
form: Form<T, E>,
|
||||||
) -> Result<Value<T>, Error<E>>
|
) -> Result<Result<Value<T>, E>, Error>
|
||||||
where
|
where
|
||||||
T: 'static,
|
T: 'static,
|
||||||
E: 'static,
|
E: 'static,
|
||||||
|
@ -245,7 +251,10 @@ where
|
||||||
}
|
}
|
||||||
opt = unordered.next() => {
|
opt = unordered.next() => {
|
||||||
if let Some(res) = opt {
|
if let Some(res) = opt {
|
||||||
let (name_parts, content) = res?;
|
let (name_parts, content) = match res? {
|
||||||
|
Ok(tup) => tup,
|
||||||
|
Err(e) => return Ok(Err(e)),
|
||||||
|
};
|
||||||
|
|
||||||
let (l, r) = count(&content, file_count, field_count, &form)?;
|
let (l, r) = count(&content, file_count, field_count, &form)?;
|
||||||
file_count = l;
|
file_count = l;
|
||||||
|
@ -258,7 +267,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(consolidate(multipart_form))
|
Ok(Ok(consolidate(multipart_form)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn count<T, E>(
|
fn count<T, E>(
|
||||||
|
@ -266,7 +275,7 @@ fn count<T, E>(
|
||||||
mut file_count: u32,
|
mut file_count: u32,
|
||||||
mut field_count: u32,
|
mut field_count: u32,
|
||||||
form: &Form<T, E>,
|
form: &Form<T, E>,
|
||||||
) -> Result<(u32, u32), Error<E>> {
|
) -> Result<(u32, u32), Error> {
|
||||||
match content {
|
match content {
|
||||||
MultipartContent::File(_) => {
|
MultipartContent::File(_) => {
|
||||||
file_count += 1;
|
file_count += 1;
|
||||||
|
|
Loading…
Reference in a new issue