Skip to content

Commit

Permalink
removed write-multipart-chunked
Browse files Browse the repository at this point in the history
  • Loading branch information
Neelay Sant committed Jan 13, 2023
1 parent 090b980 commit a1b418b
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 110 deletions.
86 changes: 0 additions & 86 deletions src/multipart/mime_multipart/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -496,89 +496,3 @@ pub fn write_chunk<S: Write>(stream: &mut S, chunk: &[u8]) -> Result<(), ::std::
stream.write_all(b"\r\n")?;
Ok(())
}

/// Stream a multipart body to the output `stream` given, made up of the `parts`
/// given, using Tranfer-Encoding: Chunked. Top-level headers are NOT included in this
/// stream; the caller must send those prior to calling write_multipart_chunked().
pub fn write_multipart_chunked<S: Write>(
stream: &mut S,
boundary: &Vec<u8>,
nodes: &Vec<Node>,
) -> Result<(), Error> {
for node in nodes {
// write a boundary
write_chunk(stream, b"--")?;
write_chunk(stream, &boundary)?;
write_chunk(stream, b"\r\n")?;

match node {
&Node::Part(ref part) => {
// write the part's headers
for header in part.headers.iter() {
write_chunk(stream, header.name().as_bytes())?;
write_chunk(stream, b": ")?;
write_chunk(stream, header.value_string().as_bytes())?;
write_chunk(stream, b"\r\n")?;
}

// write the blank line
write_chunk(stream, b"\r\n")?;

// Write the part's content
write_chunk(stream, &part.body)?;
}
&Node::File(ref filepart) => {
// write the part's headers
for header in filepart.headers.iter() {
write_chunk(stream, header.name().as_bytes())?;
write_chunk(stream, b": ")?;
write_chunk(stream, header.value_string().as_bytes())?;
write_chunk(stream, b"\r\n")?;
}

// write the blank line
write_chunk(stream, b"\r\n")?;

// Write out the files's length
let metadata = std::fs::metadata(&filepart.path)?;
write!(stream, "{:x}\r\n", metadata.len())?;

// Write out the file's content
let mut file = File::open(&filepart.path)?;
std::io::copy(&mut file, stream)? as usize;
stream.write(b"\r\n")?;
}
&Node::Multipart((ref headers, ref subnodes)) => {
// Get boundary
let boundary = get_multipart_boundary(headers)?;

// write the multipart headers
for header in headers.iter() {
write_chunk(stream, header.name().as_bytes())?;
write_chunk(stream, b": ")?;
write_chunk(stream, header.value_string().as_bytes())?;
write_chunk(stream, b"\r\n")?;
}

// write the blank line
write_chunk(stream, b"\r\n")?;

// Recurse
write_multipart_chunked(stream, &boundary, &subnodes)?;
}
}

// write a line terminator
write_chunk(stream, b"\r\n")?;
}

// write a final boundary
write_chunk(stream, b"--")?;
write_chunk(stream, &boundary)?;
write_chunk(stream, b"--")?;

// Write an empty chunk to signal the end of the body
write_chunk(stream, b"")?;

Ok(())
}
54 changes: 30 additions & 24 deletions src/multipart/mime_multipart/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ use hyper::server::Request as HyperRequest;

use mock::MockStream;

use hyper::header::{Headers, ContentDisposition, DispositionParam, ContentType,
DispositionType};
use hyper::header::{ContentDisposition, ContentType, DispositionParam, DispositionType, Headers};
// This is required to import the old style macros
use mime::*;

Expand Down Expand Up @@ -55,21 +54,23 @@ fn parser() {

match read_multipart_body(&mut reader, &headers, false) {
Ok(nodes) => {

assert_eq!(nodes.len(), 3);

if let Node::Part(ref part) = nodes[0] {
assert_eq!(part.body, b"{\r\n\
assert_eq!(
part.body,
b"{\r\n\
\"id\": 15\r\n\
}");
}"
);
} else {
panic!("1st node of wrong type");
}

if let Node::File(ref filepart) = nodes[1] {
assert_eq!(filepart.size, Some(30));
assert_eq!(filepart.filename().unwrap().unwrap(), "image.gif");
assert_eq!(filepart.content_type().unwrap(), mime!(Image/Gif));
assert_eq!(filepart.content_type().unwrap(), mime!(Image / Gif));

assert!(filepart.path.exists());
assert!(filepart.path.is_file());
Expand All @@ -87,14 +88,13 @@ fn parser() {
} else {
panic!("3rd node of wrong type");
}
},
}
Err(err) => panic!("{}", err),
}
}

#[test]
fn mixed_parser() {

let input = b"POST / HTTP/1.1\r\n\
Host: example.domain\r\n\
Content-Type: multipart/form-data; boundary=AaB03x\r\n\
Expand Down Expand Up @@ -131,7 +131,6 @@ fn mixed_parser() {

match read_multipart_body(&mut reader, &headers, false) {
Ok(nodes) => {

assert_eq!(nodes.len(), 2);

if let Node::Part(ref part) = nodes[0] {
Expand Down Expand Up @@ -164,18 +163,17 @@ fn mixed_parser() {
if let Node::File(ref filepart) = subnodes[1] {
assert_eq!(filepart.size, Some(37));
assert_eq!(filepart.filename().unwrap().unwrap(), "awesome_image.gif");
assert_eq!(filepart.content_type().unwrap(), mime!(Image/Gif));
assert_eq!(filepart.content_type().unwrap(), mime!(Image / Gif));

assert!(filepart.path.exists());
assert!(filepart.path.is_file());
} else {
panic!("2st subnode of wrong type");
}

} else {
panic!("2st node of wrong type");
}
},
}
Err(err) => panic!("{}", err),
}
}
Expand Down Expand Up @@ -219,12 +217,10 @@ fn test_line_feed() {

#[inline]
fn get_content_disposition_name(cd: &ContentDisposition) -> Option<String> {
if let Some(&DispositionParam::Ext(_, ref value)) = cd.parameters.iter()
.find(|&x| match *x {
DispositionParam::Ext(ref token,_) => &*token == "name",
_ => false,
})
{
if let Some(&DispositionParam::Ext(_, ref value)) = cd.parameters.iter().find(|&x| match *x {
DispositionParam::Ext(ref token, _) => &*token == "name",
_ => false,
}) {
Some(value.clone())
} else {
None
Expand All @@ -242,7 +238,10 @@ fn test_output() {
h.set(ContentType(Mime(TopLevel::Text, SubLevel::Plain, vec![])));
h.set(ContentDisposition {
disposition: DispositionType::Ext("form-data".to_owned()),
parameters: vec![DispositionParam::Ext("name".to_owned(), "first_name".to_owned())],
parameters: vec![DispositionParam::Ext(
"name".to_owned(),
"first_name".to_owned(),
)],
});
h
},
Expand All @@ -255,7 +254,10 @@ fn test_output() {
h.set(ContentType(Mime(TopLevel::Text, SubLevel::Plain, vec![])));
h.set(ContentDisposition {
disposition: DispositionType::Ext("form-data".to_owned()),
parameters: vec![DispositionParam::Ext("name".to_owned(), "last_name".to_owned())],
parameters: vec![DispositionParam::Ext(
"name".to_owned(),
"last_name".to_owned(),
)],
});
h
},
Expand Down Expand Up @@ -291,7 +293,10 @@ fn test_chunked() {
h.set(ContentType(Mime(TopLevel::Text, SubLevel::Plain, vec![])));
h.set(ContentDisposition {
disposition: DispositionType::Ext("form-data".to_owned()),
parameters: vec![DispositionParam::Ext("name".to_owned(), "first_name".to_owned())],
parameters: vec![DispositionParam::Ext(
"name".to_owned(),
"first_name".to_owned(),
)],
});
h
},
Expand All @@ -304,7 +309,10 @@ fn test_chunked() {
h.set(ContentType(Mime(TopLevel::Text, SubLevel::Plain, vec![])));
h.set(ContentDisposition {
disposition: DispositionType::Ext("form-data".to_owned()),
parameters: vec![DispositionParam::Ext("name".to_owned(), "last_name".to_owned())],
parameters: vec![DispositionParam::Ext(
"name".to_owned(),
"last_name".to_owned(),
)],
});
h
},
Expand All @@ -315,8 +323,6 @@ fn test_chunked() {
nodes.push(Node::Part(first_name));
nodes.push(Node::Part(last_name));

assert!(write_multipart_chunked(&mut output, &boundary, &nodes).is_ok());

let string = String::from_utf8_lossy(&output);

// Hard to compare programmatically since the headers could come in any order.
Expand Down

0 comments on commit a1b418b

Please sign in to comment.