From 100285a13a389da1dd41bb8bbdb9992912e7ce74 Mon Sep 17 00:00:00 2001 From: asonix Date: Sat, 15 Jul 2023 21:37:31 -0500 Subject: [PATCH] Add test from ferristseng repo --- src/internal.rs | 13 ++++++++++-- src/lib.rs | 53 +++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/src/internal.rs b/src/internal.rs index 4e5e12a..437e80d 100644 --- a/src/internal.rs +++ b/src/internal.rs @@ -227,11 +227,20 @@ where Poll::Ready(Ok(())) } } else if buf.remaining() > final_boundary_len(&self.boundary) { - write_final_boundary(&self.boundary, buf); self.closed = true; - Poll::Ready(Ok(())) + + write_final_boundary(&self.boundary, buf); + + if buf.remaining() > crlf_len() { + write_crlf(buf); + Poll::Ready(Ok(())) + } else { + self.write_clrf_to_pending(); + self.poll_read(cx, buf) + } } else { self.write_final_boundary_to_pending(); + self.write_clrf_to_pending(); self.closed = true; self.poll_read(cx, buf) } diff --git a/src/lib.rs b/src/lib.rs index 2686fd8..dff7969 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -230,7 +230,7 @@ impl<'a> From>> for Part> { #[cfg(test)] mod tests { - use std::{future::poll_fn, pin::Pin}; + use std::{future::poll_fn, io::Cursor, pin::Pin}; struct Streamer(S); @@ -269,7 +269,56 @@ mod tests { let out = String::from_utf8(out).expect("Valid string"); - assert_eq!(out, "--hello\r\ncontent-type: text/plain\r\ncontent-disposition: form-data; name=\"first_name\"\r\n\r\nJohn\r\n--hello\r\ncontent-type: text/plain\r\ncontent-disposition: form-data; name=\"last_name\"\r\n\r\nDoe\r\n--hello--") + assert_eq!(out, "--hello\r\ncontent-type: text/plain\r\ncontent-disposition: form-data; name=\"first_name\"\r\n\r\nJohn\r\n--hello\r\ncontent-type: text/plain\r\ncontent-disposition: form-data; name=\"last_name\"\r\n\r\nDoe\r\n--hello--\r\n") + } + + #[tokio::test] + async fn test_form_body_stream() { + let body = super::Body::builder() + .boundary(String::from("hello")) + .append(super::Part::new_str(String::from("name1"), "value1")) + .append(super::Part::new_str(String::from("name2"), "value2")) + .append(super::Part::new( + String::from("input"), + Cursor::new("Hello World!"), + )) + .build(); + + let mut out = Vec::new(); + + let mut streamer = Streamer(body); + + while let Some(res) = streamer.next().await { + out.extend(res.expect("read success")); + } + + let out = String::from_utf8(out).expect("Valid string"); + + assert_eq!( + out, + [ + "--hello\r\n", + "content-type: text/plain\r\n", + "content-disposition: form-data; name=\"name1\"\r\n", + "\r\n", + "value1\r\n", + "--hello\r\n", + "content-type: text/plain\r\n", + "content-disposition: form-data; name=\"name2\"\r\n", + "\r\n", + "value2\r\n", + "--hello\r\n", + "content-type: application/octet-stream\r\n", + "content-disposition: form-data; name=\"input\"\r\n", + "\r\n", + "Hello World!\r\n", + "--hello--\r\n", + ] + .into_iter() + .map(|s| s.chars()) + .flatten() + .collect::() + ); } #[test]