Forward whole-form errors in 'FromForm' derive.

Resolves #2672.
This commit is contained in:
Sergio Benitez 2024-01-17 12:15:01 -08:00
parent 9d56249d86
commit e493be8d3c
3 changed files with 68 additions and 1 deletions

View File

@ -211,6 +211,12 @@ pub fn derive_from_form(input: proc_macro::TokenStream) -> TokenStream {
__fut.await;
})))
)
.inner_mapper(MapperBuild::new()
.with_output(|_, _| quote! {
fn push_error(__c: &mut Self::Context, __e: #_form::Error<'r>) {
__c.__errors.push(__e);
}
}))
.inner_mapper(MapperBuild::new()
.with_output(|_, output| quote! {
fn finalize(mut __c: Self::Context) -> #_Result<Self, #_form::Errors<'r>> {

View File

@ -67,10 +67,17 @@ impl<'r, 'i> Parser<'r, 'i> {
.get("data-form")
.unwrap_or(Limits::DATA_FORM);
// Increase internal limit by 1 so multer can limit to `form_limit`.
let stream = data.open(form_limit + 1);
let constraints = multer::Constraints::new()
.size_limit(multer::SizeLimit::new()
.whole_stream(form_limit.into())
.per_field(form_limit.into()));
Ok(Parser::Multipart(MultipartParser {
request: req,
buffer: local_cache_once!(req, SharedStack::new()),
source: Multipart::with_reader(data.open(form_limit), boundary),
source: Multipart::with_reader_with_constraints(stream, boundary, constraints),
done: false,
}))
}

View File

@ -0,0 +1,54 @@
#[macro_use] extern crate rocket;
use rocket::{Config, Build, Rocket};
use rocket::{data::Limits, form::Form};
use rocket::http::{ContentType, Status};
use ubyte::{ToByteUnit, ByteUnit};
#[derive(FromForm)]
struct Data<'r> {
foo: Option<&'r str>,
}
#[rocket::post("/", data = "<form>")]
fn form<'r>(form: Form<Data<'r>>) -> &'r str {
form.foo.unwrap_or("missing")
}
fn rocket_with_form_data_limit(limit: ByteUnit) -> Rocket<Build> {
rocket::custom(Config {
limits: Limits::default().limit("data-form", limit),
..Config::debug_default()
}).mount("/", routes![form])
}
#[test]
fn test_multipart_limit() {
use rocket::local::blocking::Client;
let body = &[
"--X-BOUNDARY",
r#"Content-Disposition: form-data; name="foo"; filename="foo.txt""#,
"Content-Type: text/plain",
"",
"hi",
"--X-BOUNDARY--",
"",
].join("\r\n");
let client = Client::debug(rocket_with_form_data_limit(body.len().bytes())).unwrap();
let response = client.post("/")
.header("multipart/form-data; boundary=X-BOUNDARY".parse::<ContentType>().unwrap())
.body(body)
.dispatch();
assert_eq!(response.into_string().unwrap(), "hi");
let client = Client::debug(rocket_with_form_data_limit(body.len().bytes() - 1)).unwrap();
let response = client.post("/")
.header("multipart/form-data; boundary=X-BOUNDARY".parse::<ContentType>().unwrap())
.body(body)
.dispatch();
assert_eq!(response.status(), Status::PayloadTooLarge);
}