1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 use core::convert::TryFrom;
15 use core::mem::take;
16 
17 use crate::body::mime::{DecodeHeaders, MimePart};
18 use crate::error::{ErrorKind, HttpError};
19 use crate::headers::{Header, HeaderName, HeaderValue, Headers};
20 
21 /// `MimeMulti` is a Composite MIME body which is defined in [`RFC2046`]: \
22 /// In the case of multipart entities, in which one or more different
23 /// sets of data are combined in a single body, a "multipart" media type
24 /// field must appear in the entity's header.  The body must then contain
25 /// one or more body parts, each preceded by a boundary delimiter line,
26 /// and the last one followed by a closing boundary delimiter line. \
27 ///
28 /// `MimeMulti` can be built by [`MimeMultiBuilder`], then can set headers and
29 /// boundary, and add part([`MimePart`] or `MimeMulti`).
30 ///
31 /// [`RFC2046`]: https://www.rfc-editor.org/rfc/rfc2046#section-5.1
32 /// [`MimeMultiBuilder`]: MimeMultiBuilder
33 /// [`MimePart`]: MimePart
34 ///
35 /// # Examples
36 ///
37 /// ```
38 /// use ylong_http::body::{MimeMulti, MimePart};
39 ///
40 /// let multi1 = MimeMulti::builder()
41 ///     .set_content_type(b"multipart/mixed", b"abc".to_vec())
42 ///     .set_boundary(b"abc".to_vec())
43 ///     .add_part(
44 ///         MimePart::builder()
45 ///             .header("key1", "value1")
46 ///             .body_from_reader("111111".as_bytes())
47 ///             .build()
48 ///             .unwrap(),
49 ///     )
50 ///     .add_part(
51 ///         MimePart::builder()
52 ///             .header("key2", "value2")
53 ///             .body_from_reader("22222".as_bytes())
54 ///             .build()
55 ///             .unwrap(),
56 ///     )
57 ///     .build()
58 ///     .unwrap();
59 ///
60 /// let multi = MimeMulti::builder()
61 ///     .set_boundary(b"abcde".to_vec())
62 ///     .add_part(
63 ///         MimePart::builder()
64 ///             .header("key3", "value3")
65 ///             .body_from_reader("33333".as_bytes())
66 ///             .build()
67 ///             .unwrap(),
68 ///     )
69 ///     .add_multi(multi1)
70 ///     .add_part(
71 ///         MimePart::builder()
72 ///             .header("key4", "value4")
73 ///             .body_from_async_reader("444444".as_bytes()) // nothing in sync
74 ///             .build()
75 ///             .unwrap(),
76 ///     )
77 ///     .build()
78 ///     .unwrap();
79 /// ```
80 #[derive(Debug, Default, PartialEq)]
81 pub struct MimeMulti<'a> {
82     // [`RFC2046`]: https://www.rfc-editor.org/rfc/rfc2046#section-5.1
83     //
84     // |========================================================================
85     // |   dash-boundary := "--" boundary                                      |
86     // |                    ; boundary taken from the value of                 |
87     // |                    ; boundary parameter of the                        |
88     // |                    ; Content-Type field.                              |
89     // |                                                                       |
90     // |   multipart-body := [preamble CRLF]                                   |
91     // |                     dash-boundary transport-padding CRLF              |
92     // |                     body-part *encapsulation                          |
93     // |                     close-delimiter transport-padding                 |
94     // |                     [CRLF epilogue]                                   |
95     // |                                                                       |
96     // |  transport-padding := *LWSP-char                                      |
97     // |                        ; Composers MUST NOT generate                  |
98     // |                        ; non-zero length transport                    |
99     // |                        ; padding, but receivers MUST                  |
100     // |                        ; be able to handle padding                    |
101     // |                        ; added by message transports.                 |
102     // |                                                                       |
103     // |   encapsulation := delimiter transport-padding                        |
104     // |                    CRLF body-part                                     |
105     // |                                                                       |
106     // |   delimiter := CRLF dash-boundary                                     |
107     // |                                                                       |
108     // |   close-delimiter := delimiter "--"                                   |
109     // |                                                                       |
110     // |   preamble := discard-text                                            |
111     // |                                                                       |
112     // |   epilogue := discard-text                                            |
113     // |                                                                       |
114     // |   discard-text := *(*text CRLF) *text                                 |
115     // |                   ; May be ignored or discarded.                      |
116     // |                                                                       |
117     // |   body-part := MIME-part-headers [CRLF *OCTET]                        |
118     // |                ; Lines in a body-part must not start                  |
119     // |                ; with the specified dash-boundary and                 |
120     // |                ; the delimiter must not appear anywhere               |
121     // |                ; in the body part.  Note that the                     |
122     // |                ; semantics of a body-part differ from                 |
123     // |                ; the semantics of a message, as                       |
124     // |                ; described in the text.                               |
125     // |                                                                       |
126     // |   OCTET := <any 0-255 octet value>                                    |
127     // |========================================================================
128     pub(crate) headers: Headers,
129     pub(crate) boundary: Vec<u8>,
130     pub(crate) list: Vec<XPart<'a>>,
131 }
132 
133 impl<'a> MimeMulti<'a> {
new() -> Self134     pub(crate) fn new() -> Self {
135         MimeMulti {
136             headers: Headers::new(),
137 
138             // In [`RFC 2046`]
139             // The simplest boundary delimiter line possible is something like "---",
140             // with a closing boundary delimiter line of "-----".
141             // [`RFC2046`]: https://www.rfc-editor.org/rfc/rfc2046#section-5.1.1
142             boundary: b"-".to_vec(),
143             list: vec![],
144         }
145     }
146 
set_headers(&mut self, headers: Headers)147     pub(crate) fn set_headers(&mut self, headers: Headers) {
148         self.headers = headers;
149     }
150 
insert_header<N, V>( &mut self, name: N, value: V, ) -> Result<&mut Headers, HttpError> where HeaderName: TryFrom<N>, <HeaderName as TryFrom<N>>::Error: Into<HttpError>, HeaderValue: TryFrom<V>, <HeaderValue as TryFrom<V>>::Error: Into<HttpError>,151     pub(crate) fn insert_header<N, V>(
152         &mut self,
153         name: N,
154         value: V,
155     ) -> Result<&mut Headers, HttpError>
156     where
157         HeaderName: TryFrom<N>,
158         <HeaderName as TryFrom<N>>::Error: Into<HttpError>,
159         HeaderValue: TryFrom<V>,
160         <HeaderValue as TryFrom<V>>::Error: Into<HttpError>,
161     {
162         self.headers.insert(name, value)?;
163         Ok(self.headers_mut())
164     }
165 
append_header<N, V>( &mut self, name: N, value: V, ) -> Result<&mut Headers, HttpError> where HeaderName: TryFrom<N>, <HeaderName as TryFrom<N>>::Error: Into<HttpError>, HeaderValue: TryFrom<V>, <HeaderValue as TryFrom<V>>::Error: Into<HttpError>,166     pub(crate) fn append_header<N, V>(
167         &mut self,
168         name: N,
169         value: V,
170     ) -> Result<&mut Headers, HttpError>
171     where
172         HeaderName: TryFrom<N>,
173         <HeaderName as TryFrom<N>>::Error: Into<HttpError>,
174         HeaderValue: TryFrom<V>,
175         <HeaderValue as TryFrom<V>>::Error: Into<HttpError>,
176     {
177         self.headers.append(name, value)?;
178         Ok(self.headers_mut())
179     }
180 
set_boundary(&mut self, boundary: Vec<u8>)181     pub(crate) fn set_boundary(&mut self, boundary: Vec<u8>) {
182         self.boundary = boundary;
183     }
184 
set_content_type( &mut self, content_type: &[u8], boundary: Vec<u8>, ) -> Result<&mut Headers, HttpError>185     pub(crate) fn set_content_type(
186         &mut self,
187         content_type: &[u8],
188         boundary: Vec<u8>,
189     ) -> Result<&mut Headers, HttpError> {
190         let mut v = vec![];
191         v.extend_from_slice(content_type);
192         v.extend_from_slice(b"; boundary=");
193         v.extend_from_slice(&boundary);
194 
195         self.boundary = boundary;
196         self.headers.insert("Content-Type", &v[..])?;
197         Ok(self.headers_mut())
198     }
199 
add_part(&mut self, part: MimePart<'a>)200     pub(crate) fn add_part(&mut self, part: MimePart<'a>) {
201         self.list.push(XPart::Part(part));
202     }
203 
add_multi(&mut self, multi: MimeMulti<'a>)204     pub(crate) fn add_multi(&mut self, multi: MimeMulti<'a>) {
205         self.list.push(XPart::Multi(multi));
206     }
207 
add_xpart(&mut self, xpart: XPart<'a>)208     pub(crate) fn add_xpart(&mut self, xpart: XPart<'a>) {
209         self.list.push(xpart);
210     }
211 
212     /// Creates a [`MimeMultiBuilder`].
213     ///
214     /// [`MimeMultiBuilder`]: MimeMultiBuilder
215     ///
216     /// # Examples
217     ///
218     /// ```
219     /// use ylong_http::body::MimeMulti;
220     ///
221     /// let multi = MimeMulti::builder().build().unwrap();
222     /// ```
builder() -> MimeMultiBuilder<'a>223     pub fn builder() -> MimeMultiBuilder<'a> {
224         MimeMultiBuilder::new()
225     }
226 
227     /// Gets the reference of headers.
headers(&self) -> &Headers228     pub fn headers(&self) -> &Headers {
229         &self.headers
230     }
231 
232     /// Gets the mutable reference of headers.
headers_mut(&mut self) -> &mut Headers233     pub fn headers_mut(&mut self) -> &mut Headers {
234         &mut self.headers
235     }
236 
237     /// Gets the ownership of headers by replacing it with an default value.
headers_once(&mut self) -> Headers238     pub fn headers_once(&mut self) -> Headers {
239         take(&mut self.headers)
240     }
241 
242     /// Gets the reference of boundary.
boundary(&self) -> &[u8]243     pub fn boundary(&self) -> &[u8] {
244         &self.boundary
245     }
246 
247     /// Gets the mutable reference of boundary.
boundary_mut(&mut self) -> &mut [u8]248     pub fn boundary_mut(&mut self) -> &mut [u8] {
249         &mut self.boundary
250     }
251 
252     /// Gets the ownership of boundary by replacing it with an default value.
boundary_once(&mut self) -> Vec<u8>253     pub fn boundary_once(&mut self) -> Vec<u8> {
254         take(&mut self.boundary)
255     }
256 
257     /// Gets the reference of part list.
list(&self) -> &Vec<XPart>258     pub fn list(&self) -> &Vec<XPart> {
259         &self.list
260     }
261 
262     /// Gets the mutable reference of part list.
list_mut(&mut self) -> &mut Vec<XPart<'a>>263     pub fn list_mut(&mut self) -> &mut Vec<XPart<'a>> {
264         &mut self.list
265     }
266 
267     /// Gets the ownership of part list by replacing it with an default value.
list_once(&mut self) -> Vec<XPart>268     pub fn list_once(&mut self) -> Vec<XPart> {
269         take(&mut self.list)
270     }
271 }
272 
273 /// `MimeMultiBuilder` can set set a Composite MIME body [`MimeMulti`]. \
274 /// `MimeMultiBuilder` can set headers and boundary, and add part([`MimePart`]
275 /// or [`MimeMulti`]).
276 ///
277 /// [`MimePart`]: MimePart
278 /// [`MimeMulti`]: MimeMulti
279 ///
280 /// # Examples
281 ///
282 /// ```
283 /// use ylong_http::body::{MimeMulti, MimePart};
284 ///
285 /// let multi1 = MimeMulti::builder()
286 ///     .set_content_type(b"multipart/mixed", b"abc".to_vec())
287 ///     .set_boundary(b"abc".to_vec())
288 ///     .add_part(
289 ///         MimePart::builder()
290 ///             .header("key1", "value1")
291 ///             .body_from_reader("111111".as_bytes())
292 ///             .build()
293 ///             .unwrap(),
294 ///     )
295 ///     .add_part(
296 ///         MimePart::builder()
297 ///             .header("key2", "value2")
298 ///             .body_from_reader("22222".as_bytes())
299 ///             .build()
300 ///             .unwrap(),
301 ///     )
302 ///     .build()
303 ///     .unwrap();
304 ///
305 /// let multi = MimeMulti::builder()
306 ///     .set_boundary(b"abcde".to_vec())
307 ///     .add_part(
308 ///         MimePart::builder()
309 ///             .header("key3", "value3")
310 ///             .body_from_reader("33333".as_bytes())
311 ///             .build()
312 ///             .unwrap(),
313 ///     )
314 ///     .add_multi(multi1)
315 ///     .add_part(
316 ///         MimePart::builder()
317 ///             .header("key4", "value4")
318 ///             .body_from_async_reader("444444".as_bytes()) // nothing in sync
319 ///             .build()
320 ///             .unwrap(),
321 ///     )
322 ///     .build()
323 ///     .unwrap();
324 /// ```
325 pub struct MimeMultiBuilder<'a> {
326     inner: Result<MimeMulti<'a>, HttpError>,
327 }
328 
329 impl<'a> MimeMultiBuilder<'a> {
330     /// Creates a new [`MimeMultiBuilder`].
331     ///
332     /// [`MimeMultiBuilder`]: MimeMultiBuilder
333     ///
334     /// # Examples
335     ///
336     /// ```
337     /// use ylong_http::body::MimeMultiBuilder;
338     ///
339     /// let mut multi = MimeMultiBuilder::new().build().unwrap();
340     /// ```
new() -> Self341     pub fn new() -> Self {
342         MimeMultiBuilder {
343             inner: Ok(MimeMulti::new()),
344         }
345     }
346 
347     /// Sets headers to the Composite MIME body. \
348     /// It is recommended to use [`set_content_type`] to set header
349     /// 'Content-Type' and set boundary simultaneously.
350     ///
351     /// [`set_content_type`]: MimeMultiBuilder::set_content_type
352     ///
353     /// # Examples
354     ///
355     /// ```
356     /// use ylong_http::body::MimeMultiBuilder;
357     /// use ylong_http::headers::Headers;
358     ///
359     /// let multi = MimeMultiBuilder::new()
360     ///     .set_headers({
361     ///         let mut headers = Headers::new();
362     ///         headers
363     ///             .append("Content-Type", "multipart/mixed; boundary=ab")
364     ///             .unwrap();
365     ///         headers
366     ///     })
367     ///     .set_boundary(b"ab".to_vec());
368     /// ```
set_headers(mut self, headers: Headers) -> Self369     pub fn set_headers(mut self, headers: Headers) -> Self {
370         self.inner = self.inner.map(move |mut inner| {
371             inner.set_headers(headers);
372             inner
373         });
374         self
375     }
376 
377     /// Inserts header to the Composite MIME body.
378     ///
379     /// # Examples
380     ///
381     /// ```
382     /// use ylong_http::body::MimeMultiBuilder;
383     ///
384     /// let multi = MimeMultiBuilder::new()
385     ///     .insert_header("accept", "text/html")
386     ///     .insert_header("accept", "text/plain");
387     /// ```
insert_header<N, V>(mut self, name: N, value: V) -> Self where HeaderName: TryFrom<N>, <HeaderName as TryFrom<N>>::Error: Into<HttpError>, HeaderValue: TryFrom<V>, <HeaderValue as TryFrom<V>>::Error: Into<HttpError>,388     pub fn insert_header<N, V>(mut self, name: N, value: V) -> Self
389     where
390         HeaderName: TryFrom<N>,
391         <HeaderName as TryFrom<N>>::Error: Into<HttpError>,
392         HeaderValue: TryFrom<V>,
393         <HeaderValue as TryFrom<V>>::Error: Into<HttpError>,
394     {
395         self.inner = self.inner.and_then(move |mut inner| {
396             inner.insert_header(name, value)?;
397             Ok(inner)
398         });
399         self
400     }
401 
402     /// Appends header to the Composite MIME body.
403     ///
404     /// # Examples
405     ///
406     /// ```
407     /// use ylong_http::body::MimeMultiBuilder;
408     ///
409     /// let multi = MimeMultiBuilder::new()
410     ///     .append_header("accept", "text/html")
411     ///     .append_header("accept", "text/plain");
412     /// ```
append_header<N, V>(mut self, name: N, value: V) -> Self where HeaderName: TryFrom<N>, <HeaderName as TryFrom<N>>::Error: Into<HttpError>, HeaderValue: TryFrom<V>, <HeaderValue as TryFrom<V>>::Error: Into<HttpError>,413     pub fn append_header<N, V>(mut self, name: N, value: V) -> Self
414     where
415         HeaderName: TryFrom<N>,
416         <HeaderName as TryFrom<N>>::Error: Into<HttpError>,
417         HeaderValue: TryFrom<V>,
418         <HeaderValue as TryFrom<V>>::Error: Into<HttpError>,
419     {
420         self.inner = self.inner.and_then(move |mut inner| {
421             inner.append_header(name, value)?;
422             Ok(inner)
423         });
424         self
425     }
426 
427     // TODO: boundary check
428     /// The boundary is defined in [`RFC2046`].
429     /// The only mandatory global parameter for the "multipart" media type is
430     /// the boundary parameter, which consists of 1 to 70 characters from a
431     /// set of characters known to be very robust through mail gateways, and
432     /// NOT ending with white space. \
433     /// It is recommended to use [`set_content_type`] to set header
434     /// 'Content-Type' and set boundary simultaneously.
435     ///
436     /// [`RFC2046`]: https://www.rfc-editor.org/rfc/rfc2046#section-5.1.1
437     /// [`set_content_type`]: MimeMultiBuilder::set_content_type
set_boundary(mut self, boundary: Vec<u8>) -> Self438     pub fn set_boundary(mut self, boundary: Vec<u8>) -> Self {
439         self.inner = self.inner.map(move |mut inner| {
440             inner.set_boundary(boundary);
441             inner
442         });
443         self
444     }
445 
446     /// It is recommended to use `set_content_type` to set header 'Content-Type'
447     /// and set boundary simultaneously. \
448     /// The Content-Type field for multipart entities requires one parameter,
449     /// "boundary". A typical "multipart" Content-Type header field might look
450     /// like this In [`RFC2046`]: \
451     /// *Content-Type: multipart/mixed; boundary=gc0p4Jq0M2Yt08j34c0p*
452     ///
453     /// [`RFC2046`]: https://www.rfc-editor.org/rfc/rfc2046#section-5.1.1
454     ///
455     /// # Examples
456     ///
457     /// ```
458     /// use ylong_http::body::MimeMultiBuilder;
459     ///
460     /// let mut multi = MimeMultiBuilder::new().set_content_type(b"multipart/mixed", b"ab".to_vec());
461     /// ```
set_content_type(mut self, content_type: &'a [u8], boundary: Vec<u8>) -> Self462     pub fn set_content_type(mut self, content_type: &'a [u8], boundary: Vec<u8>) -> Self {
463         self.inner = self.inner.and_then(move |mut inner| {
464             inner.set_content_type(content_type, boundary)?;
465             Ok(inner)
466         });
467         self
468     }
469 
470     /// Adds a single body part When it is a `MimePart`.
471     ///
472     /// # Examples
473     ///
474     /// ```
475     /// use ylong_http::body::{MimeMultiBuilder, MimePart};
476     ///
477     /// let part = MimePart::builder()
478     ///     .header("key1", "value1")
479     ///     .body_from_reader("9876543210\r\n".as_bytes())
480     ///     .build()
481     ///     .unwrap();
482     /// let multi = MimeMultiBuilder::new().add_part(part);
483     /// ```
add_part(mut self, part: MimePart<'a>) -> Self484     pub fn add_part(mut self, part: MimePart<'a>) -> Self {
485         self.inner = self.inner.map(move |mut inner| {
486             inner.add_part(part);
487             inner
488         });
489         self
490     }
491 
492     /// Adds a multi body part When it is a `MimeMulti`.
493     /// # Examples
494     ///
495     /// ```
496     /// use ylong_http::body::{MimeMulti, MimeMultiBuilder};
497     ///
498     /// let multi1 = MimeMulti::builder().build().unwrap();
499     /// let multi = MimeMultiBuilder::new().add_multi(multi1);
500     /// ```
add_multi(mut self, multi: MimeMulti<'a>) -> Self501     pub fn add_multi(mut self, multi: MimeMulti<'a>) -> Self {
502         self.inner = self.inner.map(move |mut inner| {
503             inner.add_multi(multi);
504             inner
505         });
506         self
507     }
508 
509     /// Adds a multi body part When it is a `XPart`.
510     /// # Examples
511     ///
512     /// ```
513     /// use ylong_http::body::{MimeMulti, MimeMultiBuilder, XPart};
514     ///
515     /// let multi1 = MimeMulti::builder().build().unwrap();
516     /// let multi = MimeMultiBuilder::new().add_xpart(XPart::Multi(multi1));
517     /// ```
add_xpart(mut self, xpart: XPart<'a>) -> Self518     pub fn add_xpart(mut self, xpart: XPart<'a>) -> Self {
519         self.inner = self.inner.map(move |mut inner| {
520             inner.add_xpart(xpart);
521             inner
522         });
523         self
524     }
525 
526     /// Builds a [`MimeMulti`].
527     ///
528     /// [`MimeMulti`]: MimeMulti
529     ///
530     /// # Examples
531     ///
532     /// ```
533     /// use ylong_http::body::MimeMultiBuilder;
534     ///
535     /// let multi = MimeMultiBuilder::new().build().unwrap();
536     /// ```
build(self) -> Result<MimeMulti<'a>, HttpError>537     pub fn build(self) -> Result<MimeMulti<'a>, HttpError> {
538         self.inner
539     }
540 }
541 
542 impl<'a> Default for MimeMultiBuilder<'a> {
default() -> Self543     fn default() -> Self {
544         Self::new()
545     }
546 }
547 
548 /// `MimePart` or `MimeMulti` as a part.
549 #[derive(Debug, PartialEq)]
550 pub enum XPart<'a> {
551     /// `MimePart`
552     Part(MimePart<'a>),
553     /// `MimeMulti`
554     Multi(MimeMulti<'a>),
555 }
556