This is an automated email from the ASF dual-hosted git repository. xuanwo pushed a commit to branch multipart-parser in repository https://gitbox.apache.org/repos/asf/incubator-opendal.git
commit 305f1c814c53d40ac1af9f6d6b963dfb3b613ff5 Author: Xuanwo <[email protected]> AuthorDate: Thu May 18 16:27:26 2023 +0800 Save work Signed-off-by: Xuanwo <[email protected]> --- core/src/raw/http_util/multipart.rs | 66 +++++++++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 6 deletions(-) diff --git a/core/src/raw/http_util/multipart.rs b/core/src/raw/http_util/multipart.rs index 6be885bb6..d77eac726 100644 --- a/core/src/raw/http_util/multipart.rs +++ b/core/src/raw/http_util/multipart.rs @@ -15,8 +15,11 @@ // specific language governing permissions and limitations // under the License. +use std::io::BufRead; +use std::mem; use std::str::FromStr; +use bytes::Buf; use bytes::Bytes; use bytes::BytesMut; use http::header::CONTENT_DISPOSITION; @@ -79,7 +82,7 @@ impl<T: Part> Multipart<T> { bs.extend_from_slice(self.boundary.as_bytes()); bs.extend_from_slice(b"\r\n"); - bs.extend_from_slice(v.build().as_ref()); + bs.extend_from_slice(v.format().as_ref()); } // Write the last boundary @@ -112,14 +115,17 @@ impl<T: Part> Multipart<T> { } /// Part is a trait for multipart part. -pub trait Part { +pub trait Part: Sized { /// TYPE is the type of multipart. /// /// Current available types are: `form-data` and `mixed` const TYPE: &'static str; - /// Build will consume this part and generates the bytes. - fn build(&self) -> Bytes; + /// format will generates the bytes. + fn format(&self) -> Bytes; + + /// parse will parse the bytes into a part. + fn parse(bs: Bytes) -> Result<Self>; } /// FormDataPart is a builder for multipart/form-data part. @@ -165,7 +171,7 @@ impl FormDataPart { impl Part for FormDataPart { const TYPE: &'static str = "form-data"; - fn build(&self) -> Bytes { + fn format(&self) -> Bytes { let mut bs = BytesMut::new(); // Write headers. @@ -183,6 +189,13 @@ impl Part for FormDataPart { bs.freeze() } + + fn parse(_: Bytes) -> Result<Self> { + Err(Error::new( + ErrorKind::Unsupported, + "parse of form-data is not supported", + )) + } } /// MixedPart is a builder for multipart/mixed part. @@ -279,7 +292,7 @@ impl MixedPart { impl Part for MixedPart { const TYPE: &'static str = "mixed"; - fn build(&self) -> Bytes { + fn format(&self) -> Bytes { let mut bs = BytesMut::new(); // Write parts headers. @@ -316,6 +329,47 @@ impl Part for MixedPart { bs.freeze() } + + fn parse(bs: Bytes) -> Result<Self> { + let mut r = bs.reader(); + let mut buf = String::new(); + + let mut part_headers = HeaderMap::new(); + loop { + let n = r.read_line(&mut buf)?; + // Read an unexpected EOF + if n == 0 { + return Err( + Error::new(ErrorKind::Unexpected, "unexpected end of multipart") + .with_operation("Multipart::parse"), + ); + } + // Read a `\r\n`, which means the end of headers. + if n == 1 && buf == "\r" { + break; + } + // Read a `\n`, keep going. + if n == 1 { + continue; + } + + let (header_name, header_value) = buf.split_once(": ").ok_or({ + Error::new(ErrorKind::Unexpected, "invalid header format") + .with_operation("Multipart::parse") + })?; + part_headers.insert( + HeaderName::from_str(header_name).map_err(|err| { + Error::new(ErrorKind::Unexpected, "invalid header name").set_source(err) + })?, + HeaderValue::from_str(header_value).map_err(|err| { + Error::new(ErrorKind::Unexpected, "invalid header value").set_source(err) + })?, + ); + + buf.clear(); + } + todo!() + } } #[cfg(test)]
