diff --git a/actix-multipart-derive/Cargo.toml b/actix-multipart-derive/Cargo.toml index a6fb1a2ca..4a30898b4 100644 --- a/actix-multipart-derive/Cargo.toml +++ b/actix-multipart-derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-multipart-derive" -version = "0.4.0" +version = "0.5.0" authors = ["Jacob Halsey "] description = "Multipart form derive macro for Actix Web" keywords = ["http", "web", "framework", "async", "futures"] @@ -20,5 +20,7 @@ quote = "1" syn = "1" [dev-dependencies] -actix-multipart = "0.4" +actix-multipart = "0.5" actix-web = "4" +rustversion = "1" +trybuild = "1" diff --git a/actix-multipart-derive/README.md b/actix-multipart-derive/README.md index 8cad498fa..95f80bc79 100644 --- a/actix-multipart-derive/README.md +++ b/actix-multipart-derive/README.md @@ -1,3 +1,3 @@ # actix-multipart-derive -> The derive macro implementation for actix-multipart +> The derive macro implementation for actix-multipart. diff --git a/actix-multipart-derive/src/lib.rs b/actix-multipart-derive/src/lib.rs index 86241e4b2..9b6ecbae6 100644 --- a/actix-multipart-derive/src/lib.rs +++ b/actix-multipart-derive/src/lib.rs @@ -1,4 +1,6 @@ //! Multipart form derive macro for Actix Web. +//! +//! See [`macro@MultipartForm`] for usage examples. #![deny(rust_2018_idioms, nonstandard_style)] #![warn(future_incompatible)] @@ -57,13 +59,13 @@ struct ParsedField<'t> { /// Each field type should implement the `FieldReader` trait: /// /// ``` -/// use actix_multipart::form::{tempfile::Tempfile, text::Text, MultipartForm}; +/// use actix_multipart::form::{tempfile::TempFile, text::Text, MultipartForm}; /// /// #[derive(MultipartForm)] /// struct ImageUpload { /// description: Text, /// timestamp: Text, -/// image: Tempfile, +/// image: TempFile, /// } /// ``` /// @@ -75,12 +77,12 @@ struct ParsedField<'t> { /// name](https://www.rfc-editor.org/rfc/rfc7578#section-4.3). /// /// ``` -/// use actix_multipart::form::{tempfile::Tempfile, text::Text, MultipartForm}; +/// use actix_multipart::form::{tempfile::TempFile, text::Text, MultipartForm}; /// /// #[derive(MultipartForm)] /// struct Form { /// category: Option>, -/// files: Vec, +/// files: Vec, /// } /// ``` /// @@ -89,12 +91,12 @@ struct ParsedField<'t> { /// You can use the `#[multipart(rename = "foo")]` attribute to receive a field by a different name. /// /// ``` -/// use actix_multipart::form::{tempfile::Tempfile, MultipartForm}; +/// use actix_multipart::form::{tempfile::TempFile, MultipartForm}; /// /// #[derive(MultipartForm)] /// struct Form { /// #[multipart(rename = "files[]")] -/// files: Vec, +/// files: Vec, /// } /// ``` /// @@ -106,7 +108,7 @@ struct ParsedField<'t> { /// Note: the form is also subject to the global limits configured using `MultipartFormConfig`. /// /// ``` -/// use actix_multipart::form::{tempfile::Tempfile, text::Text, MultipartForm}; +/// use actix_multipart::form::{tempfile::TempFile, text::Text, MultipartForm}; /// /// #[derive(MultipartForm)] /// struct Form { @@ -114,7 +116,7 @@ struct ParsedField<'t> { /// description: Text, /// /// #[multipart(limit = "512 MiB")] -/// files: Vec, +/// files: Vec, /// } /// ``` /// @@ -124,8 +126,7 @@ struct ParsedField<'t> { /// `#[multipart(deny_unknown_fields)]` attribute: /// /// ``` -/// use actix_multipart::form::MultipartForm; -/// +/// # use actix_multipart::form::MultipartForm; /// #[derive(MultipartForm)] /// #[multipart(deny_unknown_fields)] /// struct Form { } diff --git a/actix-multipart-derive/tests/trybuild.rs b/actix-multipart-derive/tests/trybuild.rs new file mode 100644 index 000000000..7b9f14ed7 --- /dev/null +++ b/actix-multipart-derive/tests/trybuild.rs @@ -0,0 +1,16 @@ +#[rustversion::stable(1.59)] // MSRV +#[test] +fn compile_macros() { + let t = trybuild::TestCases::new(); + + t.pass("tests/trybuild/all-required.rs"); + t.pass("tests/trybuild/optional-and-list.rs"); + t.pass("tests/trybuild/rename.rs"); + t.pass("tests/trybuild/deny-unknown.rs"); + + t.pass("tests/trybuild/deny-duplicates.rs"); + t.compile_fail("tests/trybuild/deny-parse-fail.rs"); + + t.pass("tests/trybuild/size-limits.rs"); + t.compile_fail("tests/trybuild/size-limit-parse-fail.rs"); +} diff --git a/actix-multipart-derive/tests/trybuild/all-required.rs b/actix-multipart-derive/tests/trybuild/all-required.rs new file mode 100644 index 000000000..1b4a824d9 --- /dev/null +++ b/actix-multipart-derive/tests/trybuild/all-required.rs @@ -0,0 +1,19 @@ +use actix_web::{web, App, Responder}; + +use actix_multipart::form::{tempfile::TempFile, text::Text, MultipartForm}; + +#[derive(Debug, MultipartForm)] +struct ImageUpload { + description: Text, + timestamp: Text, + image: TempFile, +} + +async fn handler(_form: MultipartForm) -> impl Responder { + "Hello World!" +} + +#[actix_web::main] +async fn main() { + App::new().default_service(web::to(handler)); +} diff --git a/actix-multipart-derive/tests/trybuild/deny-duplicates.rs b/actix-multipart-derive/tests/trybuild/deny-duplicates.rs new file mode 100644 index 000000000..9fcc1506c --- /dev/null +++ b/actix-multipart-derive/tests/trybuild/deny-duplicates.rs @@ -0,0 +1,16 @@ +use actix_web::{web, App, Responder}; + +use actix_multipart::form::MultipartForm; + +#[derive(MultipartForm)] +#[multipart(duplicate_field = "deny")] +struct Form {} + +async fn handler(_form: MultipartForm
) -> impl Responder { + "Hello World!" +} + +#[actix_web::main] +async fn main() { + App::new().default_service(web::to(handler)); +} diff --git a/actix-multipart-derive/tests/trybuild/deny-parse-fail.rs b/actix-multipart-derive/tests/trybuild/deny-parse-fail.rs new file mode 100644 index 000000000..5ea566fb0 --- /dev/null +++ b/actix-multipart-derive/tests/trybuild/deny-parse-fail.rs @@ -0,0 +1,7 @@ +use actix_multipart::form::MultipartForm; + +#[derive(MultipartForm)] +#[multipart(duplicate_field = "no")] +struct Form {} + +fn main() {} diff --git a/actix-multipart-derive/tests/trybuild/deny-parse-fail.stderr b/actix-multipart-derive/tests/trybuild/deny-parse-fail.stderr new file mode 100644 index 000000000..d25e43525 --- /dev/null +++ b/actix-multipart-derive/tests/trybuild/deny-parse-fail.stderr @@ -0,0 +1,5 @@ +error: Unknown literal value `no` + --> tests/trybuild/deny-parse-fail.rs:4:31 + | +4 | #[multipart(duplicate_field = "no")] + | ^^^^ diff --git a/actix-multipart-derive/tests/trybuild/deny-unknown.rs b/actix-multipart-derive/tests/trybuild/deny-unknown.rs new file mode 100644 index 000000000..e03460624 --- /dev/null +++ b/actix-multipart-derive/tests/trybuild/deny-unknown.rs @@ -0,0 +1,16 @@ +use actix_web::{web, App, Responder}; + +use actix_multipart::form::MultipartForm; + +#[derive(MultipartForm)] +#[multipart(deny_unknown_fields)] +struct Form {} + +async fn handler(_form: MultipartForm) -> impl Responder { + "Hello World!" +} + +#[actix_web::main] +async fn main() { + App::new().default_service(web::to(handler)); +} diff --git a/actix-multipart-derive/tests/trybuild/optional-and-list.rs b/actix-multipart-derive/tests/trybuild/optional-and-list.rs new file mode 100644 index 000000000..deef3de59 --- /dev/null +++ b/actix-multipart-derive/tests/trybuild/optional-and-list.rs @@ -0,0 +1,18 @@ +use actix_web::{web, App, Responder}; + +use actix_multipart::form::{tempfile::TempFile, text::Text, MultipartForm}; + +#[derive(MultipartForm)] +struct Form { + category: Option>, + files: Vec, +} + +async fn handler(_form: MultipartForm) -> impl Responder { + "Hello World!" +} + +#[actix_web::main] +async fn main() { + App::new().default_service(web::to(handler)); +} diff --git a/actix-multipart-derive/tests/trybuild/rename.rs b/actix-multipart-derive/tests/trybuild/rename.rs new file mode 100644 index 000000000..1f66bbb43 --- /dev/null +++ b/actix-multipart-derive/tests/trybuild/rename.rs @@ -0,0 +1,18 @@ +use actix_web::{web, App, Responder}; + +use actix_multipart::form::{tempfile::TempFile, MultipartForm}; + +#[derive(MultipartForm)] +struct Form { + #[multipart(rename = "files[]")] + files: Vec, +} + +async fn handler(_form: MultipartForm) -> impl Responder { + "Hello World!" +} + +#[actix_web::main] +async fn main() { + App::new().default_service(web::to(handler)); +} diff --git a/actix-multipart-derive/tests/trybuild/size-limit-parse-fail.rs b/actix-multipart-derive/tests/trybuild/size-limit-parse-fail.rs new file mode 100644 index 000000000..c3d495317 --- /dev/null +++ b/actix-multipart-derive/tests/trybuild/size-limit-parse-fail.rs @@ -0,0 +1,21 @@ +use actix_multipart::form::{text::Text, MultipartForm}; + +#[derive(MultipartForm)] +struct Form { + #[multipart(limit = "2 bytes")] + description: Text, +} + +#[derive(MultipartForm)] +struct Form2 { + #[multipart(limit = "2 megabytes")] + description: Text, +} + +#[derive(MultipartForm)] +struct Form3 { + #[multipart(limit = "four meters")] + description: Text, +} + +fn main() {} diff --git a/actix-multipart-derive/tests/trybuild/size-limit-parse-fail.stderr b/actix-multipart-derive/tests/trybuild/size-limit-parse-fail.stderr new file mode 100644 index 000000000..fc02a78c4 --- /dev/null +++ b/actix-multipart-derive/tests/trybuild/size-limit-parse-fail.stderr @@ -0,0 +1,17 @@ +error: Could not parse size limit `2 bytes`: invalid digit found in string + --> tests/trybuild/size-limit-parse-fail.rs:6:5 + | +6 | description: Text, + | ^^^^^^^^^^^ + +error: Could not parse size limit `2 megabytes`: invalid digit found in string + --> tests/trybuild/size-limit-parse-fail.rs:12:5 + | +12 | description: Text, + | ^^^^^^^^^^^ + +error: Could not parse size limit `four meters`: invalid digit found in string + --> tests/trybuild/size-limit-parse-fail.rs:18:5 + | +18 | description: Text, + | ^^^^^^^^^^^ diff --git a/actix-multipart-derive/tests/trybuild/size-limits.rs b/actix-multipart-derive/tests/trybuild/size-limits.rs new file mode 100644 index 000000000..92c3d0db5 --- /dev/null +++ b/actix-multipart-derive/tests/trybuild/size-limits.rs @@ -0,0 +1,21 @@ +use actix_web::{web, App, Responder}; + +use actix_multipart::form::{tempfile::TempFile, text::Text, MultipartForm}; + +#[derive(MultipartForm)] +struct Form { + #[multipart(limit = "2 KiB")] + description: Text, + + #[multipart(limit = "512 MiB")] + files: Vec, +} + +async fn handler(_form: MultipartForm) -> impl Responder { + "Hello World!" +} + +#[actix_web::main] +async fn main() { + App::new().default_service(web::to(handler)); +} diff --git a/actix-multipart/Cargo.toml b/actix-multipart/Cargo.toml index fc84559a8..2a14be007 100644 --- a/actix-multipart/Cargo.toml +++ b/actix-multipart/Cargo.toml @@ -26,7 +26,7 @@ name = "actix_multipart" path = "src/lib.rs" [dependencies] -actix-multipart-derive = { version = "=0.4.0", optional = true } +actix-multipart-derive = { version = "=0.5.0", optional = true } actix-utils = "3" actix-web = { version = "4", default-features = false } diff --git a/actix-web/Cargo.toml b/actix-web/Cargo.toml index 44755035c..6cb86bbdd 100644 --- a/actix-web/Cargo.toml +++ b/actix-web/Cargo.toml @@ -103,7 +103,7 @@ actix-test = { version = "0.1", features = ["openssl", "rustls"] } awc = { version = "3", features = ["openssl"] } brotli = "3.3.3" -const-str = "0.4" +const-str = "0.3" criterion = { version = "0.4", features = ["html_reports"] } env_logger = "0.9" flate2 = "1.0.13" diff --git a/awc/Cargo.toml b/awc/Cargo.toml index a69a07d67..00c3c87c5 100644 --- a/awc/Cargo.toml +++ b/awc/Cargo.toml @@ -99,7 +99,7 @@ actix-utils = "3" actix-web = { version = "4", features = ["openssl"] } brotli = "3.3.3" -const-str = "0.4" +const-str = "0.3" env_logger = "0.9" flate2 = "1.0.13" futures-util = { version = "0.3.17", default-features = false }