Support raw byte slices '&[u8]' in form fields.

Resolves #2148.
This commit is contained in:
badoken 2022-10-08 19:38:37 +01:00 committed by Sergio Benitez
parent 2f74380d69
commit 569bc09a1d
2 changed files with 83 additions and 0 deletions

View File

@ -322,6 +322,27 @@ impl<'v> FromFormField<'v> for bool {
}
}
#[crate::async_trait]
impl<'v> FromFormField<'v> for Capped<&'v [u8]> {
fn from_value(field: ValueField<'v>) -> Result<'v, Self> {
Ok(Capped::from(field.value.as_bytes()))
}
async fn from_data(f: DataField<'v, '_>) -> Result<'v, Self> {
use crate::data::{Capped, Outcome, FromData};
match <Capped<&'v [u8]> as FromData>::from_data(f.request, f.data).await {
Outcome::Success(p) => Ok(p),
Outcome::Failure((_, e)) => Err(e)?,
Outcome::Forward(..) => {
Err(Error::from(ErrorKind::Unexpected).with_entity(Entity::DataField))?
}
}
}
}
impl_strict_from_form_field_from_capped!(&'v [u8]);
#[crate::async_trait]
impl<'v> FromFormField<'v> for Capped<Cow<'v, str>> {
fn from_value(field: ValueField<'v>) -> Result<'v, Self> {

View File

@ -0,0 +1,62 @@
#[macro_use] extern crate rocket;
use std::str::from_utf8;
use rocket::form::Form;
use rocket::http::{ContentType, Status};
use rocket::local::blocking::Client;
#[derive(FromForm)]
struct DataForm<'r> {
foo: &'r [u8],
bar: &'r [u8],
}
#[post("/", data = "<form>")]
fn form(form: Form<DataForm<'_>>) -> String {
from_utf8(form.foo).unwrap().to_string() + from_utf8(form.bar).unwrap()
}
#[test]
fn test_from_form_fields_of_multipart_files_into_byte_slices() {
let body = &[
"--X-BOUNDARY",
r#"Content-Disposition: form-data; name="foo"; filename="foo.txt""#,
"Content-Type: text/plain",
"",
"start>",
"--X-BOUNDARY",
r#"Content-Disposition: form-data; name="foo"; filename="foo2.txt""#,
"Content-Type: text/plain",
"",
"second-start...",
"--X-BOUNDARY",
r#"Content-Disposition: form-data; name="bar"; filename="bar.txt""#,
"Content-Type: text/plain",
"",
"<finish",
"--X-BOUNDARY--",
"",
].join("\r\n");
let client = Client::debug_with(routes![form]).unwrap();
let response = client.post("/")
.header("multipart/form-data; boundary=X-BOUNDARY".parse::<ContentType>().unwrap())
.body(body)
.dispatch();
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.into_string().unwrap(), "start><finish");
}
#[test]
fn test_from_form_fields_of_values_into_byte_slices() {
let client = Client::debug_with(routes![form]).unwrap();
let response = client.post("/")
.header(ContentType::Form)
.body(format!("bar={}&foo={}", "...finish", "start..."))
.dispatch();
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.into_string().unwrap(), "start......finish");
}