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