• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::pin::Pin;
16 use core::task::{Context, Poll};
17 use std::io::Read;
18 
19 use crate::body::mime::common::{data_copy, SizeResult, TokenStatus};
20 use crate::body::mime::{EncodeHeaders, MixFrom, PartStatus};
21 use crate::body::{async_impl, sync_impl, MimePart};
22 use crate::error::{ErrorKind, HttpError};
23 use crate::{AsyncRead, ReadBuf};
24 
25 /// `MimePartEncoder` can get a [`MimePart`] to encode into data that can be
26 /// transmitted.
27 ///
28 /// [`MimePart`]: MimePart
29 ///
30 /// # Examples
31 ///
32 /// ```
33 /// use ylong_http::body::{sync_impl, MimePart, MimePartEncoder};
34 ///
35 /// let part = MimePart::builder()
36 ///     .header("accept", "text/html")
37 ///     .body_from_reader("01234567890123456789".as_bytes())
38 ///     .body_from_bytes(b"9876543210\r\n")
39 ///     .build()
40 ///     .unwrap();
41 /// let mut part_encoder = MimePartEncoder::from_part(part);
42 /// let mut buf = vec![0u8; 10];
43 /// let mut v_size = vec![];
44 /// let mut v_str = vec![];
45 ///
46 /// loop {
47 ///     let len = sync_impl::Body::data(&mut part_encoder, &mut buf).unwrap();
48 ///     if len == 0 {
49 ///         break;
50 ///     }
51 ///     v_size.push(len);
52 ///     v_str.extend_from_slice(&buf[..len]);
53 /// }
54 /// assert_eq!(v_size, vec![10, 10, 10, 2]);
55 /// assert_eq!(v_str, b"accept:text/html\r\n\r\n9876543210\r\n");
56 /// ```
57 #[derive(Debug)]
58 pub struct MimePartEncoder<'a> {
59     // Encode stage now
60     stage: PartStatus,
61     headers_encode: EncodeHeaders,
62     body: Option<MixFrom<'a>>,
63     // src which is need to encode
64     src: Vec<u8>,
65     // index of src
66     src_idx: usize,
67 }
68 
69 impl<'a> MimePartEncoder<'a> {
70     /// Creates a `MimePartEncoder` by a [`MimePart`].
71     ///
72     /// [`MimePart`]: MimePart
73     ///
74     /// # Examples
75     ///
76     /// ```
77     /// use ylong_http::body::{MimePart, MimePartEncoder};
78     ///
79     /// let part = MimePart::builder().build().unwrap();
80     /// let part_encoder = MimePartEncoder::from_part(part);
81     /// ```
from_part(part: MimePart<'a>) -> Self82     pub fn from_part(part: MimePart<'a>) -> Self {
83         let body = (!part.body.is_empty()).then_some(part.body);
84 
85         MimePartEncoder {
86             stage: PartStatus::Start,
87             headers_encode: EncodeHeaders::new(part.headers),
88             src: vec![],
89             src_idx: 0,
90             body,
91         }
92     }
93 
check_next(&mut self)94     fn check_next(&mut self) {
95         match self.stage {
96             PartStatus::Start => {
97                 self.stage = PartStatus::Headers;
98                 // init
99                 self.src_idx = 0;
100                 self.src = vec![];
101             }
102             PartStatus::Headers => {
103                 self.stage = PartStatus::Crlf;
104                 if self.body.is_some() {
105                     // has body, so has Crlf
106                     self.src = b"\r\n".to_vec();
107                 } else {
108                     self.src = vec![];
109                 }
110                 self.src_idx = 0;
111             }
112             PartStatus::Crlf => {
113                 self.stage = PartStatus::Body;
114                 // Just record index
115                 self.src_idx = 0;
116             }
117             PartStatus::Body => {
118                 self.stage = PartStatus::End;
119                 self.src_idx = 0;
120             }
121             PartStatus::End => {
122                 // init
123                 self.src_idx = 0;
124                 self.src = vec![];
125             }
126         }
127     }
128 
start_encode(&mut self) -> SizeResult129     fn start_encode(&mut self) -> SizeResult {
130         self.check_next();
131         Ok(0)
132     }
133 
134     // use EncodeHeaders.encode
headers_encode(&mut self, dst: &mut [u8]) -> SizeResult135     fn headers_encode(&mut self, dst: &mut [u8]) -> SizeResult {
136         match self.headers_encode.encode(dst)? {
137             TokenStatus::Partial(size) => Ok(size),
138             TokenStatus::Complete(size) => {
139                 self.check_next();
140                 Ok(size)
141             }
142         }
143     }
144 
crlf_encode(&mut self, dst: &mut [u8]) -> SizeResult145     fn crlf_encode(&mut self, dst: &mut [u8]) -> SizeResult {
146         match data_copy(&self.src, &mut self.src_idx, dst)? {
147             TokenStatus::Partial(size) => Ok(size),
148             TokenStatus::Complete(size) => {
149                 self.check_next();
150                 Ok(size)
151             }
152         }
153     }
154 
155     // Uses `syn::Body::data` of `MixFrom`.
body_sync_encode(&mut self, dst: &mut [u8]) -> SizeResult156     fn body_sync_encode(&mut self, dst: &mut [u8]) -> SizeResult {
157         if let Some(body) = &mut self.body {
158             let size = sync_impl::Body::data(body, dst)?;
159             if size == 0 {
160                 self.check_next();
161             }
162             return Ok(size);
163         }
164         self.check_next();
165         Ok(0)
166     }
167 }
168 
169 impl sync_impl::Body for MimePartEncoder<'_> {
170     type Error = std::io::Error;
171 
data(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error>172     fn data(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
173         let mut count = 0;
174         while count != buf.len() {
175             let encode_size = match self.stage {
176                 PartStatus::Start => self.start_encode(),
177                 PartStatus::Headers => self.headers_encode(&mut buf[count..]),
178                 PartStatus::Crlf => self.crlf_encode(&mut buf[count..]),
179                 PartStatus::Body => self.body_sync_encode(&mut buf[count..]),
180                 PartStatus::End => return Ok(count),
181             };
182             count += encode_size?;
183         }
184         Ok(count)
185     }
186 }
187 
188 impl async_impl::Body for MimePartEncoder<'_> {
189     type Error = std::io::Error;
190 
poll_data( mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8], ) -> Poll<Result<usize, Self::Error>>191     fn poll_data(
192         mut self: Pin<&mut Self>,
193         cx: &mut Context<'_>,
194         buf: &mut [u8],
195     ) -> Poll<Result<usize, Self::Error>> {
196         let mut count = 0;
197         while count != buf.len() {
198             let encode_size: Poll<SizeResult> = match self.stage {
199                 PartStatus::Start => Poll::Ready(self.start_encode()),
200                 PartStatus::Headers => Poll::Ready(self.headers_encode(&mut buf[count..])),
201                 PartStatus::Crlf => Poll::Ready(self.crlf_encode(&mut buf[count..])),
202                 PartStatus::Body => match &mut self.body {
203                     Some(body) => {
204                         let poll_result = Pin::new(body).poll_data(cx, &mut buf[count..]);
205                         if let Poll::Ready(Ok(0)) = poll_result {
206                             // complete async read body
207                             self.check_next();
208                         };
209                         poll_result
210                     }
211                     _ => {
212                         self.check_next();
213                         Poll::Ready(Ok(0))
214                     }
215                 },
216                 PartStatus::End => return Poll::Ready(Ok(count)),
217             };
218 
219             match encode_size {
220                 Poll::Ready(Ok(size)) => count += size,
221                 Poll::Ready(Err(err)) => return Poll::Ready(Err(err)),
222                 Poll::Pending => return Poll::Pending,
223             }
224         }
225         Poll::Ready(Ok(count))
226     }
227 }
228 
229 #[cfg(test)]
230 mod ut_mime_part_encoder {
231     use crate::body::{async_impl, sync_impl, MimePart, MimePartEncoder};
232     use crate::headers::Headers;
233 
234     /// UT test cases for `syn::Body::data` of `MimePartEncoder`.
235     ///
236     /// # Brief
237     /// 1. Creates a `MimePart`.
238     /// 2. Sets body by `body_from_owned`.
239     /// 3. Builds a `MimePartEncoder` by `from_part` and encodes.
240     /// 4. Checks whether the result is correct.
241     #[test]
ut_mime_part_encoder_body_from_owned()242     fn ut_mime_part_encoder_body_from_owned() {
243         part_encode_compare! (
244             MimePart: {
245                 BodyOwned: b"123456".to_vec(),
246             },
247             ResultData: b"\r\n123456",
248             Sync,
249         );
250     }
251 
252     /// UT test cases for `syn::Body::data` of `MimePartEncoder`.
253     ///
254     /// # Brief
255     /// 1. Creates a `MimePart`.
256     /// 2. Sets body by `body_from_bytes`.
257     /// 3. Builds a `MimePartEncoder` by `from_part` and encodes.
258     /// 4. Checks whether the result is correct.
259     #[test]
ut_mime_part_encoder_body_from_bytes()260     fn ut_mime_part_encoder_body_from_bytes() {
261         part_encode_compare! (
262             MimePart: {
263                 BodySlice: "123456".as_bytes(),
264             },
265             BufSize: 5,
266             ResultData: b"\r\n123456",
267             Sync,
268         );
269     }
270 
271     /// UT test cases for `syn::Body::data` of `MimePartEncoder`.
272     ///
273     /// # Brief
274     /// 1. Creates a `MimePart`.
275     /// 2. Sets body by `body_from_reader`.
276     /// 3. Builds a `MimePartEncoder` by `from_part` and encodes.
277     /// 4. Checks whether the result is correct.
278     #[test]
ut_mime_part_encoder_body_from_reader()279     fn ut_mime_part_encoder_body_from_reader() {
280         part_encode_compare! (
281             MimePart: {
282                 BodyReader: "123456".as_bytes(),
283             },
284             BufSize: 5,
285             ResultData: b"\r\n123456",
286             Sync,
287         );
288     }
289 
290     /// UT test cases for `syn::Body::data` of `MimePartEncoder`.
291     ///
292     /// # Brief
293     /// 1. Creates a `MimePart`.
294     /// 2. Sets headers and sets body.
295     /// 3. Builds a `MimePartEncoder` by `from_part` and encodes.
296     /// 4. Checks whether the result is correct.
297     #[test]
ut_mime_part_encoder_data_common()298     fn ut_mime_part_encoder_data_common() {
299         part_encode_compare! (
300             MimePart: {
301                 Header: "accept", "text/html",
302                 BodyReader: "9876543210\r\n".as_bytes(),
303             },
304             BufSize: 10,
305             ResultSize: vec![10, 10, 10, 2],
306             ResultData: b"accept:text/html\r\n\r\n9876543210\r\n",
307             Sync,
308         );
309     }
310 
311     /// UT test cases for `syn::Body::data` of `MimePartEncoder`.
312     ///
313     /// # Brief
314     /// 1. Creates a `MimePart`.
315     /// 2. Doesn't set headers and only sets body.
316     /// 3. Builds a `MimePartEncoder` by `from_part` and encodes.
317     /// 4. Checks whether the result is correct.
318     #[test]
ut_mime_part_encoder_data_noheaders()319     fn ut_mime_part_encoder_data_noheaders() {
320         part_encode_compare! (
321             MimePart: {
322                 BodySlice: b"0123456789--0123",
323             },
324             BufSize: 10,
325             ResultSize: vec![10, 8],
326             ResultData: b"\r\n0123456789--0123",
327             Sync,
328         );
329     }
330 
331     /// UT test cases for `syn::Body::data` of `MimePartEncoder`.
332     ///
333     /// # Brief
334     /// 1. Creates a `MimePart`.
335     /// 2. Doesn't set body and only sets headers.
336     /// 3. Builds a `MimePartEncoder` by `from_part` and encodes.
337     /// 4. Checks whether the result is correct.
338     #[test]
ut_mime_part_encoder_data_nobody()339     fn ut_mime_part_encoder_data_nobody() {
340         // no body no CRLF
341         part_encode_compare! (
342             MimePart: {
343                 Header: "key", "\"value\"",
344             },
345             ResultData: b"key:\"value\"\r\n",
346             Sync,
347         );
348 
349         part_encode_compare! (
350             MimePart: {
351                 Header: "key1", "value1",
352                 Header: "key2", "value2",
353             },
354             BufSize: 10,
355             ResultSize: vec![10, 10, 6],
356             Sync,
357         );
358     }
359 
360     /// UT test cases for `syn::Body::data` of `MimePartEncoder`.
361     ///
362     /// # Brief
363     /// 1. Creates a `MimePart`.
364     /// 2. Doesn't set headers and doesn't set headers.
365     /// 3. Builds a `MimePartEncoder` by `from_part` and encodes.
366     /// 4. Checks whether the result is correct.
367     #[test]
ut_mime_part_encoder_data_noheaders_nobody()368     fn ut_mime_part_encoder_data_noheaders_nobody() {
369         part_encode_compare! (
370             MimePart: {
371             },
372             ResultData: b"",
373             Sync,
374         );
375     }
376 
377     /// UT test cases for `asyn::Body::data` of `MimePartEncoder`.
378     ///
379     /// # Brief
380     /// 1. Creates a `MimePart`.
381     /// 2. Sets body by `body_from_owned`.
382     /// 3. Builds a `MimePartEncoder` by `from_part` and encodes asynchronously.
383     /// 4. Checks whether the result is correct.
384     #[test]
ut_mime_part_encoder_body_from_owned_then_async_data()385     fn ut_mime_part_encoder_body_from_owned_then_async_data() {
386         let handle = ylong_runtime::spawn(async move {
387             mime_part_encoder_body_from_owned_then_async_data().await;
388         });
389         ylong_runtime::block_on(handle).unwrap();
390     }
391 
mime_part_encoder_body_from_owned_then_async_data()392     async fn mime_part_encoder_body_from_owned_then_async_data() {
393         part_encode_compare! (
394             MimePart: {
395                 BodyOwned: b"123456".to_vec(),
396             },
397             BufSize: 5,
398             ResultSize: vec![5, 3],
399             ResultData: b"\r\n123456",
400             Async,
401         );
402     }
403 
404     /// UT test cases for `asyn::Body::data` of `MimePartEncoder`.
405     ///
406     /// # Brief
407     /// 1. Creates a `MimePart`.
408     /// 2. Sets body by `body_from_bytes`.
409     /// 3. Builds a `MimePartEncoder` by `from_part` and encodes asynchronously.
410     /// 4. Checks whether the result is correct.
411     #[test]
ut_mime_part_encoder_body_from_bytes_then_async_data()412     fn ut_mime_part_encoder_body_from_bytes_then_async_data() {
413         let handle = ylong_runtime::spawn(async move {
414             mime_part_encoder_body_from_bytes_then_async_data().await;
415         });
416         ylong_runtime::block_on(handle).unwrap();
417     }
418 
mime_part_encoder_body_from_bytes_then_async_data()419     async fn mime_part_encoder_body_from_bytes_then_async_data() {
420         part_encode_compare! (
421             MimePart: {
422                 BodySlice: b"123456",
423             },
424             BufSize: 5,
425             ResultSize: vec![5, 3],
426             ResultData: b"\r\n123456",
427             Async,
428         );
429     }
430 
431     /// UT test cases for `asyn::Body::data` of `MimePartEncoder`.
432     ///
433     /// # Brief
434     /// 1. Creates a `MimePart`.
435     /// 2. Sets headers and sets body.
436     /// 3. Builds a `MimePartEncoder` by `from_part` and encodes asynchronously.
437     /// 4. Checks whether the result is correct.
438     #[test]
ut_mime_part_encoder_common_then_async_data()439     fn ut_mime_part_encoder_common_then_async_data() {
440         let handle = ylong_runtime::spawn(async move {
441             mime_part_encoder_common_then_async_data().await;
442         });
443         ylong_runtime::block_on(handle).unwrap();
444     }
445 
mime_part_encoder_common_then_async_data()446     async fn mime_part_encoder_common_then_async_data() {
447         part_encode_compare! (
448             MimePart: {
449                 Header: "accept", "text/html",
450                 BodySlice: b"9876543210\r\n",
451             },
452             BufSize: 10,
453             ResultSize: vec![10, 10, 10, 2],
454             ResultData: b"accept:text/html\r\n\r\n9876543210\r\n",
455             Async,
456         );
457     }
458 }
459