build values from complete byte objects

This commit is contained in:
Rob Ede 2020-08-24 10:13:02 +01:00
parent 90b122c999
commit daf148a3d7
No known key found for this signature in database
GPG Key ID: C2A3B36E841A91E6
3 changed files with 50 additions and 31 deletions

View File

@ -76,21 +76,21 @@ pub fn derive(input: TokenStream) -> TokenStream {
quote! { #ident: self.#ident.unwrap() } quote! { #ident: self.#ident.unwrap() }
}); });
let field_appending = fields.iter().map(|f| { let bytes_appending = fields.iter().map(|f| {
let Field { ident, .. } = f;
quote! {
stringify!(#ident) => field_bytes.put(chunk),
}
});
let fields_from_bytes = fields.iter().map(|f| {
let Field { ident, ty, .. } = f; let Field { ident, ty, .. } = f;
quote! { quote! {
stringify!(#ident) => match builder.#ident { stringify!(#ident) => {
Some(ref mut field) => { builder.#ident.replace(#ty::from_bytes(field_bytes));
field.append(chunk);
} }
None => {
let mut field = #ty::default();
field.append(chunk);
builder.#ident.replace(field);
}
},
} }
}); });
@ -121,9 +121,11 @@ pub fn derive(input: TokenStream) -> TokenStream {
type Config = (); type Config = ();
fn from_request(req: &::actix_web::HttpRequest, payload: &mut ::actix_web::dev::Payload) -> Self::Future { fn from_request(req: &::actix_web::HttpRequest, payload: &mut ::actix_web::dev::Payload) -> Self::Future {
use futures_util::future::FutureExt; use ::futures_util::future::FutureExt;
use futures_util::stream::StreamExt; use ::futures_util::stream::StreamExt;
use actix_multipart::BuildFromBytes; use ::actix_web::error;
use ::actix_multipart::{FromBytes, Multipart};
use ::bytes::{BufMut, BytesMut};
let pl = payload.take(); let pl = payload.take();
let req2 = req.clone(); let req2 = req.clone();
@ -140,26 +142,36 @@ pub fn derive(input: TokenStream) -> TokenStream {
let cd = field.content_disposition().unwrap(); let cd = field.content_disposition().unwrap();
let name = cd.get_name().unwrap(); let name = cd.get_name().unwrap();
println!("FIELD: {}", name);
let mut size = 0; let mut size = 0;
let mut field_bytes = BytesMut::new();
while let Some(chunk) = field.next().await { while let Some(chunk) = field.next().await {
let chunk = chunk?; let chunk = chunk?;
size += chunk.len(); size += chunk.len();
if (size > #b_ident::max_size(&name).unwrap_or(std::usize::MAX)) { if (size > #b_ident::max_size(&name).unwrap_or(std::usize::MAX)) {
return Err(::actix_web::error::ErrorPayloadTooLarge("field is too large")); return Err(error::ErrorPayloadTooLarge("field is too large"));
} }
match name { match name {
#(#field_appending)* #(#bytes_appending)*
_ => todo!("unknown field"), _ => {
// unknown field
},
} }
} }
println!(); let field_bytes = field_bytes.freeze();
match name {
#(#fields_from_bytes)*
_ => {
// unknown field
},
}
} }
builder.build() builder.build()

View File

@ -1,18 +1,25 @@
use bytes::{BufMut, Bytes, BytesMut}; use bytes::{Bytes, BytesMut};
pub trait BuildFromBytes { pub trait FromBytes {
fn append(&mut self, next: Bytes); fn from_bytes(next: Bytes) -> Self;
} }
impl BuildFromBytes for String { impl FromBytes for String {
fn append(&mut self, chunk: Bytes) { fn from_bytes(bytes: Bytes) -> Self {
let chunk_str = std::str::from_utf8(&chunk).expect("string field is not utf-8"); std::str::from_utf8(&bytes)
self.push_str(chunk_str); .expect("string field is not utf-8")
.to_owned()
} }
} }
impl BuildFromBytes for BytesMut { impl FromBytes for Bytes {
fn append(&mut self, chunk: Bytes) { fn from_bytes(bytes: Bytes) -> Self {
self.put(&chunk[..]); bytes
}
}
impl FromBytes for BytesMut {
fn from_bytes(bytes: Bytes) -> Self {
BytesMut::from(bytes.as_ref())
} }
} }

View File

@ -5,6 +5,6 @@ mod error;
mod extractor; mod extractor;
mod server; mod server;
pub use self::byte_builder::BuildFromBytes; pub use self::byte_builder::FromBytes;
pub use self::error::MultipartError; pub use self::error::MultipartError;
pub use self::server::{Field, Multipart}; pub use self::server::{Field, Multipart};