mirror of https://github.com/fafhrd91/actix-web
fix(multipart): count ignored fields towards `MultipartFormConfig` li… (#4026)
fix(multipart): count ignored fields towards `MultipartFormConfig` limits
This commit is contained in:
parent
be62050f9d
commit
4434a494ee
|
|
@ -227,7 +227,7 @@ pub fn impl_multipart_form(input: proc_macro::TokenStream) -> proc_macro::TokenS
|
||||||
::actix_multipart::MultipartError::UnknownField(field.name().unwrap().to_string())
|
::actix_multipart::MultipartError::UnknownField(field.name().unwrap().to_string())
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
quote!(::std::result::Result::Ok(()))
|
quote!(::actix_multipart::form::discard_field(field, limits).await)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Value for duplicate action
|
// Value for duplicate action
|
||||||
|
|
@ -289,7 +289,7 @@ pub fn impl_multipart_form(input: proc_macro::TokenStream) -> proc_macro::TokenS
|
||||||
) -> ::std::pin::Pin<::std::boxed::Box<dyn ::std::future::Future<Output = ::std::result::Result<(), ::actix_multipart::MultipartError>> + 't>> {
|
) -> ::std::pin::Pin<::std::boxed::Box<dyn ::std::future::Future<Output = ::std::result::Result<(), ::actix_multipart::MultipartError>> + 't>> {
|
||||||
match field.name().unwrap() {
|
match field.name().unwrap() {
|
||||||
#handle_field_impl
|
#handle_field_impl
|
||||||
_ => return ::std::boxed::Box::pin(::std::future::ready(#unknown_field_result)),
|
_ => return ::std::boxed::Box::pin(async move { #unknown_field_result }),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,9 @@ where
|
||||||
) -> Self::Future {
|
) -> Self::Future {
|
||||||
if state.contains_key(&field.form_field_name) {
|
if state.contains_key(&field.form_field_name) {
|
||||||
match duplicate_field {
|
match duplicate_field {
|
||||||
DuplicateField::Ignore => return Box::pin(ready(Ok(()))),
|
DuplicateField::Ignore => {
|
||||||
|
return Box::pin(async move { discard_field(field, limits).await });
|
||||||
|
}
|
||||||
|
|
||||||
DuplicateField::Deny => {
|
DuplicateField::Deny => {
|
||||||
return Box::pin(ready(Err(MultipartError::DuplicateField(
|
return Box::pin(ready(Err(MultipartError::DuplicateField(
|
||||||
|
|
@ -159,7 +161,9 @@ where
|
||||||
) -> Self::Future {
|
) -> Self::Future {
|
||||||
if state.contains_key(&field.form_field_name) {
|
if state.contains_key(&field.form_field_name) {
|
||||||
match duplicate_field {
|
match duplicate_field {
|
||||||
DuplicateField::Ignore => return Box::pin(ready(Ok(()))),
|
DuplicateField::Ignore => {
|
||||||
|
return Box::pin(async move { discard_field(field, limits).await });
|
||||||
|
}
|
||||||
|
|
||||||
DuplicateField::Deny => {
|
DuplicateField::Deny => {
|
||||||
return Box::pin(ready(Err(MultipartError::DuplicateField(
|
return Box::pin(ready(Err(MultipartError::DuplicateField(
|
||||||
|
|
@ -312,6 +316,16 @@ impl Limits {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Drain a field that will not be retained while still accounting for form limits.
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub async fn discard_field(mut field: Field, limits: &mut Limits) -> Result<(), MultipartError> {
|
||||||
|
while let Some(chunk) = field.try_next().await? {
|
||||||
|
limits.try_consume_limits(chunk.len(), false)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Typed `multipart/form-data` extractor.
|
/// Typed `multipart/form-data` extractor.
|
||||||
///
|
///
|
||||||
/// To extract typed data from a multipart stream, the inner type `T` must implement the
|
/// To extract typed data from a multipart stream, the inner type `T` must implement the
|
||||||
|
|
@ -710,6 +724,32 @@ mod tests {
|
||||||
assert_eq!(response.status(), StatusCode::OK);
|
assert_eq!(response.status(), StatusCode::OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn test_discarded_fields_count_towards_total_limit() {
|
||||||
|
let srv = actix_test::start(|| {
|
||||||
|
App::new()
|
||||||
|
.route("/unknown", web::post().to(test_upload_limits_memory))
|
||||||
|
.route("/duplicate", web::post().to(test_duplicate_ignore_route))
|
||||||
|
.app_data(
|
||||||
|
MultipartFormConfig::default()
|
||||||
|
.memory_limit(usize::MAX)
|
||||||
|
.total_limit(20),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut form = multipart::Form::default();
|
||||||
|
form.add_text("field", "7 bytes");
|
||||||
|
form.add_text("unknown", "this string is 28 bytes long");
|
||||||
|
let response = send_form(&srv, form, "/unknown").await;
|
||||||
|
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
|
||||||
|
|
||||||
|
let mut form = multipart::Form::default();
|
||||||
|
form.add_text("field", "first_value");
|
||||||
|
form.add_text("field", "this string is 28 bytes long");
|
||||||
|
let response = send_form(&srv, form, "/duplicate").await;
|
||||||
|
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
/// Test the Limits.
|
/// Test the Limits.
|
||||||
#[derive(MultipartForm)]
|
#[derive(MultipartForm)]
|
||||||
struct TestMemoryUploadLimits {
|
struct TestMemoryUploadLimits {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue