diff --git a/actix-multipart-derive/Cargo.toml b/actix-multipart-derive/Cargo.toml index ee758b184..a2ab56951 100644 --- a/actix-multipart-derive/Cargo.toml +++ b/actix-multipart-derive/Cargo.toml @@ -10,6 +10,7 @@ proc-macro = true [dependencies] quote = "1" syn = { version = "1", features = ["extra-traits"] } +proc-macro2 = "1" # [dev-dependencies] actix-multipart = "0.3.0-beta.1" diff --git a/actix-multipart-derive/src/lib.rs b/actix-multipart-derive/src/lib.rs index e199ead67..04db36825 100644 --- a/actix-multipart-derive/src/lib.rs +++ b/actix-multipart-derive/src/lib.rs @@ -2,6 +2,7 @@ use proc_macro::TokenStream; use quote::quote; use syn::{ parse_macro_input, Data, DataStruct, DeriveInput, Field, Fields, FieldsNamed, Ident, + Meta, MetaList, MetaNameValue, NestedMeta, Path, }; #[proc_macro_derive(MultipartForm, attributes(multipart))] @@ -29,12 +30,45 @@ pub fn derive(input: TokenStream) -> TokenStream { }); let field_max_sizes = fields.iter().map(|f| { - let Field { ident, .. } = f; + let Field { ident, attrs, .. } = f; - // TODO: parse field attributes find - // #[multipart(max_size = n)] + for attr in attrs { + // TODO: use something like https://github.com/TedDriggs/darling ?? - quote! { stringify!(#ident) => Some(8096) } + if let Ok(m) = attr.parse_meta() { + if let Meta::List(MetaList { path, nested, .. }) = m { + if path.get_ident().unwrap() + != &Ident::new("multipart", proc_macro2::Span::call_site()) + { + continue; + } + + // it's our meta list, marked by multipart + + if let Some(NestedMeta::Meta(Meta::NameValue(MetaNameValue { + path: Path { segments, .. }, + lit, + .. + }))) = nested.first() + { + for seg in segments { + // if there's a max_size attr in the list, extract the lit + if &seg.ident + == &Ident::new( + "max_size", + proc_macro2::Span::call_site(), + ) + { + // TODO: ensure literal is numeric + return quote! { stringify!(#ident) => Some(#lit) }; + } + } + } + } + } + } + + quote! { stringify!(#ident) => None } }); let build_fields = fields.iter().map(|f| { diff --git a/actix-multipart-derive/src/main.rs b/actix-multipart-derive/src/main.rs index 548f00c39..5a93ce0d1 100644 --- a/actix-multipart-derive/src/main.rs +++ b/actix-multipart-derive/src/main.rs @@ -6,7 +6,7 @@ use bytes::BytesMut; struct Form { name: String, - #[multipart(max_size = 8096)] + #[multipart(max_size = 1024)] file: BytesMut, } diff --git a/actix-multipart/src/byte_builder.rs b/actix-multipart/src/byte_builder.rs new file mode 100644 index 000000000..3377cf927 --- /dev/null +++ b/actix-multipart/src/byte_builder.rs @@ -0,0 +1,18 @@ +use bytes::{BufMut, Bytes, BytesMut}; + +pub trait BuildFromBytes { + fn append(&mut self, next: Bytes); +} + +impl BuildFromBytes for String { + fn append(&mut self, chunk: Bytes) { + let chunk_str = std::str::from_utf8(&chunk).expect("string field is not utf-8"); + self.push_str(chunk_str); + } +} + +impl BuildFromBytes for BytesMut { + fn append(&mut self, chunk: Bytes) { + self.put(&chunk[..]); + } +} diff --git a/actix-multipart/src/lib.rs b/actix-multipart/src/lib.rs index ddd0b4a8a..f67e57cb6 100644 --- a/actix-multipart/src/lib.rs +++ b/actix-multipart/src/lib.rs @@ -1,27 +1,10 @@ #![allow(clippy::borrow_interior_mutable_const)] +mod byte_builder; mod error; mod extractor; mod server; +pub use self::byte_builder::BuildFromBytes; pub use self::error::MultipartError; pub use self::server::{Field, Multipart}; - -use bytes::{BufMut, Bytes, BytesMut}; - -pub trait BuildFromBytes { - fn append(&mut self, next: Bytes); -} - -impl BuildFromBytes for String { - fn append(&mut self, chunk: Bytes) { - let chunk_str = std::str::from_utf8(&chunk).expect("string field is not utf-8"); - self.push_str(chunk_str); - } -} - -impl BuildFromBytes for BytesMut { - fn append(&mut self, chunk: Bytes) { - self.put(&chunk[..]); - } -}