Skip to content

Commit

Permalink
Merge branch 'release/v1.2.1'
Browse files Browse the repository at this point in the history
  • Loading branch information
rousan committed Jun 3, 2020
2 parents 0d7157a + aea2e87 commit 5dff3c7
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 30 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "multer"
version = "1.2.0"
version = "1.2.1"
description = "An async parser for `multipart/form-data` content-type in Rust."
homepage = "https://github.com/rousan/multer-rs"
repository = "https://github.com/rousan/multer-rs"
Expand Down
15 changes: 8 additions & 7 deletions examples/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,19 @@ use tokio::fs::{File, OpenOptions};
use tokio::io::{AsyncWrite, AsyncWriteExt};

async fn handle(req: Request<Body>) -> Result<Response<Body>, Infallible> {
let mut stream = req.into_body();
let stream = req.into_body();

let multipart_constraints = Constraints::new()
.allowed_fields(vec!["a", "b"])
.size_limit(SizeLimit::new().per_field(30).for_field("a", 10));
// let multipart_constraints = Constraints::new()
// .allowed_fields(vec!["a", "b"])
// .size_limit(SizeLimit::new().per_field(30).for_field("a", 10));

let mut multipart = Multipart::new_with_constraints(stream, "X-INSOMNIA-BOUNDARY", multipart_constraints);
let mut multipart = Multipart::new(stream, "X-INSOMNIA-BOUNDARY");

while let Some(field) = multipart.next_field().await.unwrap() {
println!("{:?}", field.name());
println!("name: {:?}", field.name());
println!("filename: {:?}", field.file_name());
let text = field.text().await.unwrap();
println!("{}", text);
println!("content: {}", text);
}

Ok(Response::new("Hello, World!".into()))
Expand Down
46 changes: 29 additions & 17 deletions src/constants.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use lazy_static::lazy_static;
use regex::Regex;
use regex::bytes::Regex;

pub(crate) const DEFAULT_WHOLE_STREAM_SIZE_LIMIT: u64 = u64::MAX;
pub(crate) const DEFAULT_PER_FIELD_SIZE_LIMIT: u64 = u64::MAX;
Expand All @@ -13,8 +13,8 @@ pub(crate) const CRLF: &'static str = "\r\n";
pub(crate) const CRLF_CRLF: &'static str = "\r\n\r\n";

lazy_static! {
pub(crate) static ref CONTENT_DISPOSITION_FIELD_NAME_RE: Regex = Regex::new(r#"name="([^"]+)""#).unwrap();
pub(crate) static ref CONTENT_DISPOSITION_FILE_NAME_RE: Regex = Regex::new(r#"filename="([^"]+)""#).unwrap();
pub(crate) static ref CONTENT_DISPOSITION_FIELD_NAME_RE: Regex = Regex::new(r#"(?-u)name="([^"]+)""#).unwrap();
pub(crate) static ref CONTENT_DISPOSITION_FILE_NAME_RE: Regex = Regex::new(r#"(?-u)filename="([^"]+)""#).unwrap();
}

#[cfg(test)]
Expand All @@ -23,35 +23,47 @@ mod tests {

#[test]
fn test_content_disposition_field_name_re() {
let val = r#"form-data; name="my_field""#;
let val = br#"form-data; name="my_field""#;
let name = CONTENT_DISPOSITION_FIELD_NAME_RE.captures(val).unwrap();
assert_eq!(name.get(1).unwrap().as_str(), "my_field");
assert_eq!(name.get(1).unwrap().as_bytes(), b"my_field");

let val = r#"form-data; name="my field""#;
let val = br#"form-data; name="my field""#;
let name = CONTENT_DISPOSITION_FIELD_NAME_RE.captures(val).unwrap();
assert_eq!(name.get(1).unwrap().as_str(), "my field");
assert_eq!(name.get(1).unwrap().as_bytes(), b"my field");

let val = r#"form-data; name="my_field"; filename="file abc.txt""#;
let val = br#"form-data; name="my_field"; filename="file abc.txt""#;
let name = CONTENT_DISPOSITION_FIELD_NAME_RE.captures(val).unwrap();
assert_eq!(name.get(1).unwrap().as_str(), "my_field");
assert_eq!(name.get(1).unwrap().as_bytes(), b"my_field");

let val = r#"form-data; name="my field"; filename="file abc.txt""#;
let val = br#"form-data; name="my field"; filename="file abc.txt""#;
let name = CONTENT_DISPOSITION_FIELD_NAME_RE.captures(val).unwrap();
assert_eq!(name.get(1).unwrap().as_str(), "my field");
assert_eq!(name.get(1).unwrap().as_bytes(), b"my field");

let val = "form-data; name=\"你好\"; filename=\"file abc.txt\"".as_bytes();
let name = CONTENT_DISPOSITION_FIELD_NAME_RE.captures(val).unwrap();
assert_eq!(name.get(1).unwrap().as_bytes(), "你好".as_bytes());

let val = "form-data; name=\"কখগ\"; filename=\"你好.txt\"".as_bytes();
let name = CONTENT_DISPOSITION_FIELD_NAME_RE.captures(val).unwrap();
assert_eq!(name.get(1).unwrap().as_bytes(), "কখগ".as_bytes());
}

#[test]
fn test_content_disposition_file_name_re() {
let val = r#"form-data; name="my_field"; filename="file_name.txt""#;
let val = br#"form-data; name="my_field"; filename="file_name.txt""#;
let file_name = CONTENT_DISPOSITION_FILE_NAME_RE.captures(val).unwrap();
assert_eq!(file_name.get(1).unwrap().as_bytes(), b"file_name.txt");

let val = br#"form-data; name="my_field"; filename="file name.txt""#;
let file_name = CONTENT_DISPOSITION_FILE_NAME_RE.captures(val).unwrap();
assert_eq!(file_name.get(1).unwrap().as_str(), "file_name.txt");
assert_eq!(file_name.get(1).unwrap().as_bytes(), b"file name.txt");

let val = r#"form-data; name="my_field"; filename="file name.txt""#;
let val = br#"form-data; filename="file-name.txt""#;
let file_name = CONTENT_DISPOSITION_FILE_NAME_RE.captures(val).unwrap();
assert_eq!(file_name.get(1).unwrap().as_str(), "file name.txt");
assert_eq!(file_name.get(1).unwrap().as_bytes(), b"file-name.txt");

let val = r#"form-data; filename="file-name.txt""#;
let val = "form-data; filename=\"কখগ-你好.txt\"".as_bytes();
let file_name = CONTENT_DISPOSITION_FILE_NAME_RE.captures(val).unwrap();
assert_eq!(file_name.get(1).unwrap().as_str(), "file-name.txt");
assert_eq!(file_name.get(1).unwrap().as_bytes(), "কখগ-你好.txt".as_bytes());
}
}
10 changes: 5 additions & 5 deletions src/content_disposition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@ pub(crate) struct ContentDisposition {

impl ContentDisposition {
pub fn parse(headers: &HeaderMap) -> ContentDisposition {
let content_disposition = headers
.get(header::CONTENT_DISPOSITION)
.and_then(|val| val.to_str().ok());
let content_disposition = headers.get(header::CONTENT_DISPOSITION).map(|val| val.as_bytes());

let field_name = content_disposition
.and_then(|val| constants::CONTENT_DISPOSITION_FIELD_NAME_RE.captures(val))
.and_then(|cap| cap.get(1))
.map(|m| m.as_str().to_owned());
.map(|m| m.as_bytes().to_vec())
.and_then(|bytes| String::from_utf8(bytes).ok());

let file_name = content_disposition
.and_then(|val| constants::CONTENT_DISPOSITION_FILE_NAME_RE.captures(val))
.and_then(|cap| cap.get(1))
.map(|m| m.as_str().to_owned());
.map(|m| m.as_bytes().to_vec())
.and_then(|bytes| String::from_utf8(bytes).ok());

ContentDisposition { field_name, file_name }
}
Expand Down

0 comments on commit 5dff3c7

Please sign in to comment.