Skip to content

Commit

Permalink
Add a way to add headers to parts of multipart form data
Browse files Browse the repository at this point in the history
  • Loading branch information
jcaesar committed Aug 26, 2018
1 parent 993658c commit e5a3189
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 4 deletions.
2 changes: 1 addition & 1 deletion src/multipart.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
//! # multipart/form-data
pub use ::multipart_::{Form, Part};
pub use ::multipart_::{Form, Part, HeaderMap};
57 changes: 54 additions & 3 deletions src/multipart_.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ use std::path::Path;
use mime_guess::{self, Mime};
use url::percent_encoding;
use uuid::Uuid;
use http;

/// An alias to http::HeaderMap so http is unneded as an explicit dependency
pub type HeaderMap = http::HeaderMap<String>;

use {Body};

Expand Down Expand Up @@ -129,6 +133,7 @@ pub struct Part {
value: Body,
mime: Option<Mime>,
file_name: Option<Cow<'static, str>>,
hdr: HeaderMap,
}

impl Part {
Expand Down Expand Up @@ -183,6 +188,7 @@ impl Part {
value: value,
mime: None,
file_name: None,
hdr: HeaderMap::default()
}
}

Expand All @@ -197,6 +203,21 @@ impl Part {
self.file_name = Some(filename.into());
self
}

/// Returns a reference to the map of additional header fields
pub fn header_fields(&self) -> &HeaderMap {
&self.hdr
}

/// Returns a mutable reference to the map of additional header fields
pub fn header_fields_mut(&mut self) -> &mut HeaderMap {
&mut self.hdr
}

/// Replaces the additional header fields
pub fn replace_header_fields(&mut self, hdr: HeaderMap) -> () {
self.hdr = hdr
}
}

impl fmt::Debug for Part {
Expand All @@ -205,6 +226,7 @@ impl fmt::Debug for Part {
.field("value", &self.value)
.field("mime", &self.mime)
.field("file_name", &self.file_name)
.field("hdr", &self.hdr)
.finish()
}
}
Expand Down Expand Up @@ -305,7 +327,7 @@ impl Read for Reader {

fn header(name: &str, field: &Part) -> String {
format!(
"Content-Disposition: form-data; {}{}{}",
"Content-Disposition: form-data; {}{}{}{}",
format_parameter("name", name),
match field.file_name {
Some(ref file_name) => format!("; {}", format_parameter("filename", file_name)),
Expand All @@ -314,7 +336,12 @@ fn header(name: &str, field: &Part) -> String {
match field.mime {
Some(ref mime) => format!("\r\nContent-Type: {}", mime),
None => "".to_string(),
}
},
field.hdr.iter().fold(
"".to_string(),
|hdrs, (k,v)|
format!("{}\r\n{}: {}", hdrs, k.as_str(), v)
)
)
}

Expand Down Expand Up @@ -403,7 +430,6 @@ mod tests {
Part::text("value3").file_name("filename"),
);
form.boundary = "boundary".to_string();
let length = form.compute_length();
let expected = "--boundary\r\n\
Content-Disposition: form-data; name=\"key1\"\r\n\r\n\
value1\r\n\
Expand All @@ -422,6 +448,31 @@ mod tests {
);
println!("START EXPECTED\n{}\nEND EXPECTED", expected);
assert_eq!(::std::str::from_utf8(&output).unwrap(), expected);
}

#[test]
fn read_to_end_with_header() {
let mut output = Vec::new();
let mut part = Part::text("value2").mime(::mime::IMAGE_BMP);
part.header_fields_mut().insert("Hdr3", "/a/b/c".to_string());
let mut form = Form::new().part("key2", part);
form.boundary = "boundary".to_string();
let length = form.compute_length();
let expected = "--boundary\r\n\
Content-Disposition: form-data; name=\"key2\"\r\n\
Content-Type: image/bmp\r\n\
hdr3: /a/b/c\r\n\
\r\n\
value2\r\n\
--boundary--\r\n";
form.reader().read_to_end(&mut output).unwrap();
// These prints are for debug purposes in case the test fails
println!(
"START REAL\n{}\nEND REAL",
::std::str::from_utf8(&output).unwrap()
);
println!("START EXPECTED\n{}\nEND EXPECTED", expected);
assert_eq!(::std::str::from_utf8(&output).unwrap(), expected);
assert_eq!(length.unwrap(), expected.len() as u64);
}

Expand Down

0 comments on commit e5a3189

Please sign in to comment.