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