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 // TODO: reuse mime later.
15 
16 use std::future::Future;
17 use std::io::Cursor;
18 use std::pin::Pin;
19 use std::task::{Context, Poll};
20 use std::vec::IntoIter;
21 
22 use crate::body::async_impl::{Body, ReusableReader};
23 use crate::{AsyncRead, ReadBuf};
24 
25 /// A structure that helps you build a `multipart/form-data` message.
26 ///
27 /// # Examples
28 ///
29 /// ```
30 /// # use ylong_http::body::{MultiPart, Part};
31 ///
32 /// let multipart = MultiPart::new()
33 ///     .part(Part::new().name("name").body("xiaoming"))
34 ///     .part(Part::new().name("password").body("123456789"));
35 /// ```
36 pub struct MultiPart {
37     parts: Vec<Part>,
38     boundary: String,
39     status: ReadStatus,
40 }
41 
42 impl MultiPart {
43     /// Creates an empty `Multipart` with boundary created automatically.
44     ///
45     /// # Examples
46     ///
47     /// ```
48     /// # use ylong_http::body::MultiPart;
49     ///
50     /// let multipart = MultiPart::new();
51     /// ```
new() -> Self52     pub fn new() -> Self {
53         Self {
54             parts: Vec::new(),
55             boundary: gen_boundary(),
56             status: ReadStatus::Never,
57         }
58     }
59 
60     /// Sets a part to the `Multipart`.
61     ///
62     /// # Examples
63     ///
64     /// ```
65     /// # use ylong_http::body::{MultiPart, Part};
66     ///
67     /// let multipart = MultiPart::new().part(Part::new().name("name").body("xiaoming"));
68     /// ```
part(mut self, part: Part) -> Self69     pub fn part(mut self, part: Part) -> Self {
70         self.parts.push(part);
71         self
72     }
73 
74     /// Gets the boundary of this `Multipart`.
75     ///
76     /// # Examples
77     ///
78     /// ```
79     /// # use ylong_http::body::MultiPart;
80     ///
81     /// let multipart = MultiPart::new();
82     /// let boundary = multipart.boundary();
83     /// ```
boundary(&self) -> &str84     pub fn boundary(&self) -> &str {
85         self.boundary.as_str()
86     }
87 
88     /// Get the total bytes of the `multpart/form-data` message, including
89     /// length of every parts, such as boundaries, headers, bodies, etc.
90     ///
91     /// # Examples
92     ///
93     /// ```
94     /// # use ylong_http::body::{MultiPart, Part};
95     ///
96     /// let multipart = MultiPart::new().part(Part::new().name("name").body("xiaoming"));
97     ///
98     /// let bytes = multipart.total_bytes();
99     /// ```
total_bytes(&self) -> Option<u64>100     pub fn total_bytes(&self) -> Option<u64> {
101         let mut size = 0u64;
102         for part in self.parts.iter() {
103             size += part.length?;
104 
105             // start boundary + \r\n
106             size += 2 + self.boundary.len() as u64 + 2;
107 
108             // Content-Disposition: form-data
109             size += 30;
110 
111             // ; name="xxx"
112             if let Some(name) = part.name.as_ref() {
113                 size += 9 + name.len() as u64;
114             }
115 
116             // ; filename="xxx"
117             if let Some(name) = part.file_name.as_ref() {
118                 size += 13 + name.len() as u64;
119             }
120 
121             // \r\n
122             size += 2;
123 
124             // Content-Type: xxx
125             if let Some(mime) = part.mime.as_ref() {
126                 size += 16 + mime.len() as u64;
127             }
128 
129             // \r\n\r\n
130             size += 2 + 2;
131         }
132         // last boundary
133         size += 2 + self.boundary.len() as u64 + 4;
134         Some(size)
135     }
136 
build_status(&mut self)137     pub(crate) fn build_status(&mut self) {
138         let mut states = Vec::new();
139         for part in self.parts.iter_mut() {
140             states.push(MultiPartState::bytes(
141                 format!("--{}\r\n", self.boundary).into_bytes(),
142             ));
143             states.push(MultiPartState::bytes(
144                 b"Content-Disposition: form-data".to_vec(),
145             ));
146 
147             if let Some(ref name) = part.name {
148                 states.push(MultiPartState::bytes(
149                     format!("; name=\"{name}\"").into_bytes(),
150                 ));
151             }
152 
153             if let Some(ref file_name) = part.file_name {
154                 states.push(MultiPartState::bytes(
155                     format!("; filename=\"{file_name}\"").into_bytes(),
156                 ));
157             }
158 
159             states.push(MultiPartState::bytes(b"\r\n".to_vec()));
160 
161             if let Some(ref mime) = part.mime {
162                 states.push(MultiPartState::bytes(
163                     format!("Content-Type: {mime}\r\n").into_bytes(),
164                 ));
165             }
166 
167             states.push(MultiPartState::bytes(b"\r\n".to_vec()));
168 
169             if let Some(body) = part.body.take() {
170                 states.push(body);
171             }
172 
173             states.push(MultiPartState::bytes(b"\r\n".to_vec()));
174         }
175         states.push(MultiPartState::bytes(
176             format!("--{}--\r\n", self.boundary).into_bytes(),
177         ));
178         self.status = ReadStatus::Reading(MultiPartStates { states, index: 0 })
179     }
180 
reuse_inner(&mut self) -> std::io::Result<()>181     pub(crate) async fn reuse_inner(&mut self) -> std::io::Result<()> {
182         match std::mem::replace(&mut self.status, ReadStatus::Never) {
183             ReadStatus::Never => Ok(()),
184             ReadStatus::Reading(mut states) => {
185                 let res = states.reuse().await;
186                 self.status = ReadStatus::Reading(states);
187                 res
188             }
189             ReadStatus::Finish(mut states) => {
190                 states.reuse().await?;
191                 self.status = ReadStatus::Reading(states);
192                 Ok(())
193             }
194         }
195     }
196 }
197 
198 impl Default for MultiPart {
default() -> Self199     fn default() -> Self {
200         Self::new()
201     }
202 }
203 
204 impl AsyncRead for MultiPart {
poll_read( mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut ReadBuf<'_>, ) -> Poll<std::io::Result<()>>205     fn poll_read(
206         mut self: Pin<&mut Self>,
207         cx: &mut Context<'_>,
208         buf: &mut ReadBuf<'_>,
209     ) -> Poll<std::io::Result<()>> {
210         match self.status {
211             ReadStatus::Never => self.build_status(),
212             ReadStatus::Reading(_) => {}
213             ReadStatus::Finish(_) => return Poll::Ready(Ok(())),
214         }
215 
216         let status = if let ReadStatus::Reading(ref mut status) = self.status {
217             status
218         } else {
219             return Poll::Ready(Ok(()));
220         };
221 
222         if buf.initialize_unfilled().is_empty() {
223             return Poll::Ready(Ok(()));
224         }
225         let filled = buf.filled().len();
226         match Pin::new(status).poll_read(cx, buf) {
227             Poll::Ready(Ok(())) => {
228                 let new_filled = buf.filled().len();
229                 if filled == new_filled {
230                     match std::mem::replace(&mut self.status, ReadStatus::Never) {
231                         ReadStatus::Reading(states) => self.status = ReadStatus::Finish(states),
232                         _ => unreachable!(),
233                     };
234                 }
235                 Poll::Ready(Ok(()))
236             }
237             Poll::Pending => {
238                 let new_filled = buf.filled().len();
239                 if new_filled != filled {
240                     Poll::Ready(Ok(()))
241                 } else {
242                     Poll::Pending
243                 }
244             }
245             x => x,
246         }
247     }
248 }
249 
250 impl ReusableReader for MultiPart {
reuse<'a>( &'a mut self, ) -> Pin<Box<dyn Future<Output = std::io::Result<()>> + Send + Sync + 'a>> where Self: 'a,251     fn reuse<'a>(
252         &'a mut self,
253     ) -> Pin<Box<dyn Future<Output = std::io::Result<()>> + Send + Sync + 'a>>
254     where
255         Self: 'a,
256     {
257         Box::pin(async {
258             match self.status {
259                 ReadStatus::Never => Ok(()),
260                 ReadStatus::Reading(_) => self.reuse_inner().await,
261                 ReadStatus::Finish(_) => self.reuse_inner().await,
262             }
263         })
264     }
265 }
266 
267 /// A structure that represents a part of `multipart/form-data` message.
268 ///
269 /// # Examples
270 ///
271 /// ```
272 /// # use ylong_http::body::Part;
273 ///
274 /// let part = Part::new().name("name").body("xiaoming");
275 /// ```
276 pub struct Part {
277     name: Option<String>,
278     file_name: Option<String>,
279     mime: Option<String>,
280     length: Option<u64>,
281     body: Option<MultiPartState>,
282 }
283 
284 impl Part {
285     /// Creates an empty `Part`.
286     ///
287     /// # Examples
288     ///
289     /// ```
290     /// use ylong_http::body::Part;
291     ///
292     /// let part = Part::new();
293     /// ```
new() -> Self294     pub fn new() -> Self {
295         Self {
296             name: None,
297             file_name: None,
298             mime: None,
299             length: None,
300             body: None,
301         }
302     }
303 
304     /// Sets the name of this `Part`.
305     ///
306     /// The name message will be set to `Content-Disposition` header.
307     ///
308     /// # Examples
309     ///
310     /// ```
311     /// use ylong_http::body::Part;
312     ///
313     /// let part = Part::new().name("name");
314     /// ```
name(mut self, name: &str) -> Self315     pub fn name(mut self, name: &str) -> Self {
316         self.name = Some(String::from(name));
317         self
318     }
319 
320     /// Sets the file name of this `Part`.
321     ///
322     /// The file name message will be set to `Content-Disposition` header.
323     ///
324     /// # Examples
325     ///
326     /// ```
327     /// use ylong_http::body::Part;
328     ///
329     /// let part = Part::new().file_name("example.txt");
330     /// ```
file_name(mut self, file_name: &str) -> Self331     pub fn file_name(mut self, file_name: &str) -> Self {
332         self.file_name = Some(String::from(file_name));
333         self
334     }
335 
336     /// Sets the mime type of this `Part`.
337     ///
338     /// The mime type message will be set to `Content-Type` header.
339     ///
340     /// # Examples
341     ///
342     /// ```
343     /// use ylong_http::body::Part;
344     ///
345     /// let part = Part::new().mime("application/octet-stream");
346     /// ```
mime(mut self, mime: &str) -> Self347     pub fn mime(mut self, mime: &str) -> Self {
348         self.mime = Some(String::from(mime));
349         self
350     }
351 
352     /// Sets the length of body of this `Part`.
353     ///
354     /// The length message will be set to `Content-Length` header.
355     ///
356     /// # Examples
357     ///
358     /// ```
359     /// use ylong_http::body::Part;
360     ///
361     /// let part = Part::new().length(Some(8)).body("xiaoming");
362     /// ```
length(mut self, length: Option<u64>) -> Self363     pub fn length(mut self, length: Option<u64>) -> Self {
364         self.length = length;
365         self
366     }
367 
368     /// Sets a slice body of this `Part`.
369     ///
370     /// The body message will be set to the body part.
371     ///
372     /// # Examples
373     ///
374     /// ```
375     /// use ylong_http::body::Part;
376     ///
377     /// let part = Part::new().mime("application/octet-stream");
378     /// ```
body<T: AsRef<[u8]>>(mut self, body: T) -> Self379     pub fn body<T: AsRef<[u8]>>(mut self, body: T) -> Self {
380         let body = body.as_ref().to_vec();
381         self.length = Some(body.len() as u64);
382         self.body = Some(MultiPartState::bytes(body));
383         self
384     }
385 
386     /// Sets a stream body of this `Part`.
387     ///
388     /// The body message will be set to the body part.
stream<T: ReusableReader + Send + Sync + 'static + Unpin>(mut self, body: T) -> Self389     pub fn stream<T: ReusableReader + Send + Sync + 'static + Unpin>(mut self, body: T) -> Self {
390         self.body = Some(MultiPartState::stream(Box::new(body)));
391         self
392     }
393 }
394 
395 impl Default for Part {
default() -> Self396     fn default() -> Self {
397         Self::new()
398     }
399 }
400 
401 /// A basic trait for MultiPart.
402 pub trait MultiPartBase: ReusableReader {
403     /// Get reference of MultiPart.
multipart(&self) -> &MultiPart404     fn multipart(&self) -> &MultiPart;
405 }
406 
407 impl MultiPartBase for MultiPart {
multipart(&self) -> &MultiPart408     fn multipart(&self) -> &MultiPart {
409         self
410     }
411 }
412 
413 enum ReadStatus {
414     Never,
415     Reading(MultiPartStates),
416     Finish(MultiPartStates),
417 }
418 
419 struct MultiPartStates {
420     states: Vec<MultiPartState>,
421     index: usize,
422 }
423 
424 impl MultiPartStates {
reuse(&mut self) -> std::io::Result<()>425     async fn reuse(&mut self) -> std::io::Result<()> {
426         self.index = 0;
427         for state in self.states.iter_mut() {
428             match state {
429                 MultiPartState::Bytes(bytes) => bytes.set_position(0),
430                 MultiPartState::Stream(stream) => {
431                     stream.reuse().await?;
432                 }
433             }
434         }
435         Ok(())
436     }
437 }
438 
439 impl MultiPartStates {
poll_read_curr( &mut self, cx: &mut Context<'_>, buf: &mut ReadBuf<'_>, ) -> Poll<std::io::Result<()>>440     fn poll_read_curr(
441         &mut self,
442         cx: &mut Context<'_>,
443         buf: &mut ReadBuf<'_>,
444     ) -> Poll<std::io::Result<()>> {
445         let state = match self.states.get_mut(self.index) {
446             Some(state) => state,
447             None => return Poll::Ready(Ok(())),
448         };
449 
450         match state {
451             MultiPartState::Bytes(ref mut bytes) => {
452                 let filled_len = buf.filled().len();
453                 let unfilled = buf.initialize_unfilled();
454                 let unfilled_len = unfilled.len();
455                 let new = std::io::Read::read(bytes, unfilled).unwrap();
456                 buf.set_filled(filled_len + new);
457 
458                 if new < unfilled_len {
459                     self.index += 1;
460                 }
461                 Poll::Ready(Ok(()))
462             }
463             MultiPartState::Stream(stream) => {
464                 let old_len = buf.filled().len();
465                 let result = unsafe { Pin::new_unchecked(stream).poll_read(cx, buf) };
466                 let new_len = buf.filled().len();
467                 match result {
468                     Poll::Ready(Ok(())) => {
469                         if old_len == new_len {
470                             self.index += 1;
471                         }
472                         Poll::Ready(Ok(()))
473                     }
474                     Poll::Pending => Poll::Pending,
475                     x => x,
476                 }
477             }
478         }
479     }
480 }
481 
482 impl AsyncRead for MultiPartStates {
poll_read( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut ReadBuf<'_>, ) -> Poll<std::io::Result<()>>483     fn poll_read(
484         self: Pin<&mut Self>,
485         cx: &mut Context<'_>,
486         buf: &mut ReadBuf<'_>,
487     ) -> Poll<std::io::Result<()>> {
488         let this = self.get_mut();
489         while !buf.initialize_unfilled().is_empty() {
490             if this.states.get(this.index).is_none() {
491                 break;
492             }
493             match this.poll_read_curr(cx, buf) {
494                 Poll::Ready(Ok(())) => {}
495                 x => return x,
496             }
497         }
498         Poll::Ready(Ok(()))
499     }
500 }
501 
502 enum MultiPartState {
503     Bytes(Cursor<Vec<u8>>),
504     Stream(Box<dyn ReusableReader + Send + Sync + Unpin>),
505 }
506 
507 impl MultiPartState {
bytes(bytes: Vec<u8>) -> Self508     fn bytes(bytes: Vec<u8>) -> Self {
509         Self::Bytes(Cursor::new(bytes))
510     }
511 
stream(reader: Box<dyn ReusableReader + Send + Sync + Unpin>) -> Self512     fn stream(reader: Box<dyn ReusableReader + Send + Sync + Unpin>) -> Self {
513         Self::Stream(reader)
514     }
515 }
516 
517 #[cfg(test)]
518 impl PartialEq for MultiPartState {
eq(&self, other: &Self) -> bool519     fn eq(&self, other: &Self) -> bool {
520         match (self, other) {
521             (Self::Bytes(l0), Self::Bytes(r0)) => l0 == r0,
522             // Cant not compare Stream, Should not do this.
523             (Self::Stream(l0), Self::Stream(r0)) => core::ptr::eq(l0, r0),
524             _ => false,
525         }
526     }
527 }
528 
529 #[cfg(test)]
530 impl core::fmt::Debug for MultiPartState {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result531     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
532         match self {
533             Self::Bytes(arg0) => f.debug_tuple("Bytes").field(arg0).finish(),
534             Self::Stream(arg0) => f.debug_tuple("Stream").field(&(arg0 as *const _)).finish(),
535         }
536     }
537 }
538 
gen_boundary() -> String539 fn gen_boundary() -> String {
540     format!(
541         "{:016x}-{:016x}-{:016x}-{:016x}",
542         xor_shift(),
543         xor_shift(),
544         xor_shift(),
545         xor_shift()
546     )
547 }
548 
549 // XORShift* fast-random realization.
xor_shift() -> u64550 fn xor_shift() -> u64 {
551     use std::cell::Cell;
552     use std::collections::hash_map::RandomState;
553     use std::hash::{BuildHasher, Hasher};
554     use std::num::Wrapping;
555 
556     thread_local! {
557         static RNG: Cell<Wrapping<u64>> = Cell::new(Wrapping(seed()));
558     }
559 
560     // The returned value of `seed()` must be nonzero.
561     fn seed() -> u64 {
562         let seed = RandomState::new();
563 
564         let mut out;
565         let mut cnt = 1;
566         let mut hasher = seed.build_hasher();
567 
568         loop {
569             hasher.write_usize(cnt);
570             out = hasher.finish();
571             if out != 0 {
572                 break;
573             }
574             cnt += 1;
575             hasher = seed.build_hasher();
576         }
577         out
578     }
579 
580     RNG.with(|rng| {
581         let mut n = rng.get();
582         n ^= n >> 12;
583         n ^= n << 25;
584         n ^= n >> 27;
585         rng.set(n);
586         n.0.wrapping_mul(0x2545_f491_4f6c_dd1d)
587     })
588 }
589 
590 #[cfg(test)]
591 mod ut_mime {
592     use crate::body::mime::simple::{gen_boundary, MultiPartState, ReadStatus};
593     use crate::body::{MultiPart, Part};
594 
595     /// UT test cases for `gen_boundar`.
596     ///
597     /// # Brief
598     /// 1. Creates two boundarys and compares.
599     /// 3. Checks whether the result is correct.
600     #[test]
ut_gen_boundary()601     fn ut_gen_boundary() {
602         let s1 = gen_boundary();
603         let s2 = gen_boundary();
604         assert_ne!(s1, s2);
605     }
606 
607     /// UT test cases for `Part::new`.
608     ///
609     /// # Brief
610     /// 1. Creates a `Part` by `Part::new`.
611     /// 2. Checks members of `Part`.
612     /// 3. Checks whether the result is correct.
613     #[test]
ut_part_new()614     fn ut_part_new() {
615         let part = Part::new();
616         assert!(part.name.is_none());
617         assert!(part.file_name.is_none());
618         assert!(part.mime.is_none());
619         assert!(part.length.is_none());
620         assert!(part.body.is_none());
621     }
622 
623     /// UT test cases for `Part::default`.
624     ///
625     /// # Brief
626     /// 1. Creates a `Part` by `Part::default`.
627     /// 2. Checks members of `Part`.
628     /// 3. Checks whether the result is correct.
629     #[test]
ut_part_default()630     fn ut_part_default() {
631         let part = Part::default();
632         assert!(part.name.is_none());
633         assert!(part.file_name.is_none());
634         assert!(part.mime.is_none());
635         assert!(part.length.is_none());
636         assert!(part.body.is_none());
637     }
638 
639     /// UT test cases for `Part::name`, `Part::name`, `Part::file_name` and
640     /// `Part::body`.
641     ///
642     /// # Brief
643     /// 1. Creates a `Part` and sets values.
644     /// 2. Checks members of `Part`.
645     /// 3. Checks whether the result is correct.
646     #[test]
ut_part_set()647     fn ut_part_set() {
648         let part = Part::new()
649             .name("name")
650             .file_name("example.txt")
651             .mime("application/octet-stream")
652             .body("1234");
653         assert_eq!(part.name, Some("name".to_string()));
654         assert_eq!(part.file_name, Some("example.txt".to_string()));
655         assert_eq!(part.mime, Some("application/octet-stream".to_string()));
656         assert_eq!(part.body, Some(MultiPartState::bytes("1234".into())));
657         assert_eq!(part.length, Some(4));
658 
659         let part = part.stream("11223344".as_bytes()).length(Some(8));
660         assert_eq!(part.length, Some(8));
661     }
662 
663     /// UT test cases for `MultiPart::new`.
664     ///
665     /// # Brief
666     /// 1. Creates a `MultiPart` by `MultiPart::new`.
667     /// 2. Checks members of `MultiPart`.
668     /// 3. Checks whether the result is correct.
669     #[test]
ut_multipart_new()670     fn ut_multipart_new() {
671         let mp = MultiPart::new();
672         assert!(mp.parts.is_empty());
673         assert!(!mp.boundary().is_empty());
674     }
675 
676     /// UT test cases for `MultiPart::part` and `MultiPart::total_bytes`.
677     ///
678     /// # Brief
679     /// 1. Creates a `MultiPart` and sets values.
680     /// 2. Checks total bytes of `MultiPart`.
681     /// 3. Checks whether the result is correct.
682     #[test]
ut_multipart_set()683     fn ut_multipart_set() {
684         let mp = MultiPart::default();
685         // --boundary--/r/n
686         assert_eq!(mp.total_bytes(), Some(2 + mp.boundary().len() as u64 + 4));
687 
688         let mp = mp.part(
689             Part::new()
690                 .name("name")
691                 .file_name("example.txt")
692                 .mime("application/octet-stream")
693                 .body("1234"),
694         );
695         assert_eq!(
696             mp.total_bytes(),
697             Some(
698                 (2 + mp.boundary().len() as u64 + 2)
699                     + (30 + 9 + 4 + 13 + 11 + 2)       // name, filename, \r\n
700                     + (16 + 24 + 2 + 2)                // mime, \r\n
701                     + 4                                // body
702                     + (2 + mp.boundary().len() as u64 + 4)
703             )
704         );
705     }
706 
707     /// UT test cases for `MultiPart::poll_data`.
708     ///
709     /// # Brief
710     /// 1. Creates a `MultiPart` and sets values.
711     /// 2. Encodes `MultiPart` by `async_impl::Body::data`.
712     /// 3. Checks whether the result is correct.
713     #[cfg(feature = "ylong_base")]
714     #[test]
ut_multipart_poll_data()715     fn ut_multipart_poll_data() {
716         let handle = ylong_runtime::spawn(async move {
717             multipart_poll_data().await;
718         });
719         ylong_runtime::block_on(handle).unwrap();
720     }
721 
722     #[cfg(feature = "ylong_base")]
multipart_poll_data()723     async fn multipart_poll_data() {
724         use std::pin::Pin;
725 
726         use ylong_runtime::futures::poll_fn;
727         use ylong_runtime::io::{AsyncRead, ReadBuf};
728 
729         let mut mp = MultiPart::new().part(
730             Part::new()
731                 .name("name")
732                 .file_name("example.txt")
733                 .mime("application/octet-stream")
734                 .body("1234"),
735         );
736 
737         let mut buf = vec![0u8; 50];
738         let mut v_size = vec![];
739         let mut v_str = vec![];
740 
741         loop {
742             let mut read_buf = ReadBuf::new(&mut buf);
743             poll_fn(|cx| Pin::new(&mut mp).poll_read(cx, &mut read_buf))
744                 .await
745                 .unwrap();
746 
747             let len = read_buf.filled_len();
748             if len == 0 {
749                 break;
750             }
751             v_size.push(len);
752             v_str.extend_from_slice(&buf[..len]);
753         }
754         assert_eq!(v_size, vec![50, 50, 50, 50, 50, 11]);
755     }
756 
757     /// UT test cases for `MultiPart::poll_data`.
758     ///
759     /// # Brief
760     /// 1. Creates a `MultiPart` and sets values.
761     /// 2. Encodes `MultiPart` by `async_impl::Body::data`.
762     /// 3. Checks whether the result is correct.
763     #[cfg(feature = "ylong_base")]
764     #[test]
ut_multipart_poll_data_stream()765     fn ut_multipart_poll_data_stream() {
766         let handle = ylong_runtime::spawn(async move {
767             multipart_poll_data_stream().await;
768         });
769         ylong_runtime::block_on(handle).unwrap();
770     }
771 
772     #[cfg(feature = "ylong_base")]
multipart_poll_data_stream()773     async fn multipart_poll_data_stream() {
774         use std::pin::Pin;
775 
776         use ylong_runtime::futures::poll_fn;
777         use ylong_runtime::io::{AsyncRead, ReadBuf};
778 
779         let mut mp = MultiPart::new().part(
780             Part::new()
781                 .name("name")
782                 .file_name("example.txt")
783                 .mime("application/octet-stream")
784                 .stream("1234".as_bytes())
785                 .length(Some(4)),
786         );
787 
788         let mut buf = vec![0u8; 50];
789         let mut v_size = vec![];
790         let mut v_str = vec![];
791 
792         loop {
793             let mut read_buf = ReadBuf::new(&mut buf);
794             poll_fn(|cx| Pin::new(&mut mp).poll_read(cx, &mut read_buf))
795                 .await
796                 .unwrap();
797 
798             let len = read_buf.filled().len();
799             if len == 0 {
800                 break;
801             }
802             v_size.push(len);
803             v_str.extend_from_slice(&buf[..len]);
804         }
805         assert_eq!(v_size, vec![50, 50, 50, 50, 50, 11]);
806     }
807 }
808