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::cmp::min; 15 use core::pin::Pin; 16 use core::task::{Context, Poll}; 17 use std::io::{Error, Read}; 18 19 use super::origin::{FromAsyncReader, FromBytes, FromReader}; 20 use super::{async_impl, sync_impl}; 21 use crate::body::origin::FromAsyncBody; 22 use crate::{AsyncRead, ReadBuf}; 23 24 /// `TextBody` is used to represent the body of plain text type. 25 /// 26 /// You can create a `TextBody` in a variety of ways, such as reading from 27 /// memory or reading from a file. 28 /// 29 /// # Read From Memory 30 /// 31 /// You can create a `TextBody` by reading memory slice. 32 /// 33 /// For example, you can use a memory slice to create a `TextBody`: 34 /// 35 /// ``` 36 /// use ylong_http::body::TextBody; 37 /// 38 /// let text = "Hello World"; 39 /// let body = TextBody::from_bytes(text.as_bytes()); 40 /// ``` 41 /// 42 /// This type of `TextBody` implements both [`sync_impl::Body`] and 43 /// [`async_impl::Body`]. 44 /// 45 /// # Read From Reader 46 /// 47 /// You can create a `TextBody` by reading from a synchronous reader. 48 /// 49 /// For example, you can use a `&[u8]` to create a `TextBody`: 50 /// 51 /// ```no_run 52 /// use ylong_http::body::TextBody; 53 /// 54 /// // In this usage `&[u8]` is treated as a synchronous reader. 55 /// let reader = "Hello World"; 56 /// let body = TextBody::from_reader(reader.as_bytes()); 57 /// ``` 58 /// 59 /// This type of `TextBody` **only** implements [`sync_impl::Body`]. 60 /// 61 /// # Read From Async Reader 62 /// 63 /// You can create a `TextBody` by reading from an asynchronous reader. 64 /// 65 /// For example, you can use a `&[u8]` to create a `TextBody`: 66 /// 67 /// ```no_run 68 /// use ylong_http::body::TextBody; 69 /// 70 /// async fn text_body_from_async_reader() { 71 /// // In this usage `&[u8]` is treated as an asynchronous reader. 72 /// let reader = "Hello World"; 73 /// let body = TextBody::from_async_reader(reader.as_bytes()); 74 /// } 75 /// ``` 76 /// 77 /// This type of `TextBody` **only** implements [`async_impl::Body`]. 78 /// 79 /// # Read Body Content 80 /// 81 /// After you have created a `TextBody`, you can use the methods of 82 /// [`sync_impl::Body`] or [`async_impl::Body`] to read data, like the examples 83 /// below: 84 /// 85 /// sync: 86 /// 87 /// ```no_run 88 /// use ylong_http::body::sync_impl::Body; 89 /// use ylong_http::body::TextBody; 90 /// 91 /// let text = "Hello World"; 92 /// let mut body = TextBody::from_bytes(text.as_bytes()); 93 /// 94 /// let mut buf = [0u8; 1024]; 95 /// loop { 96 /// let size = body.data(&mut buf).unwrap(); 97 /// if size == 0 { 98 /// break; 99 /// } 100 /// // Operates on the data you read.. 101 /// } 102 /// ``` 103 /// 104 /// async: 105 /// 106 /// ```no_run 107 /// use ylong_http::body::async_impl::Body; 108 /// use ylong_http::body::TextBody; 109 /// 110 /// async fn read_from_body() { 111 /// let text = "Hello World"; 112 /// let mut body = TextBody::from_bytes(text.as_bytes()); 113 /// 114 /// let mut buf = [0u8; 1024]; 115 /// loop { 116 /// let size = body.data(&mut buf).await.unwrap(); 117 /// if size == 0 { 118 /// break; 119 /// } 120 /// // Operates on the data you read.. 121 /// } 122 /// } 123 /// ``` 124 /// 125 /// [`sync_impl::Body`]: sync_impl::Body 126 /// [`async_impl::Body`]: async_impl::Body 127 pub struct TextBody<T> { 128 from: T, 129 } 130 131 impl<'a> TextBody<FromBytes<'a>> { 132 /// Creates a `TextBody` by a memory slice. 133 /// 134 /// # Examples 135 /// 136 /// ``` 137 /// use ylong_http::body::TextBody; 138 /// 139 /// let text = "Hello World"; 140 /// let body = TextBody::from_bytes(text.as_bytes()); 141 /// ``` from_bytes(bytes: &'a [u8]) -> Self142 pub fn from_bytes(bytes: &'a [u8]) -> Self { 143 TextBody { 144 from: FromBytes::new(bytes), 145 } 146 } 147 } 148 149 impl<T: Read> TextBody<FromReader<T>> { 150 /// Creates a `TextBody` from a synchronous reader. 151 /// 152 /// ```no_run 153 /// use ylong_http::body::TextBody; 154 /// 155 /// // In this usage `&[u8]` is treated as a synchronous reader. 156 /// let reader = "Hello World"; 157 /// let body = TextBody::from_reader(reader.as_bytes()); 158 /// ``` from_reader(reader: T) -> Self159 pub fn from_reader(reader: T) -> Self { 160 TextBody { 161 from: FromReader::new(reader), 162 } 163 } 164 } 165 166 impl<T: AsyncRead + Unpin + Send + Sync> TextBody<FromAsyncReader<T>> { 167 /// Creates a `TextBody` from an asynchronous reader. 168 /// 169 /// ```no_run 170 /// use ylong_http::body::TextBody; 171 /// 172 /// async fn text_body_from_async_reader() { 173 /// let reader = "Hello World"; 174 /// let body = TextBody::from_async_reader(reader.as_bytes()); 175 /// } 176 /// ``` from_async_reader(reader: T) -> Self177 pub fn from_async_reader(reader: T) -> Self { 178 Self { 179 from: FromAsyncReader::new(reader), 180 } 181 } 182 } 183 184 impl<'a> sync_impl::Body for TextBody<FromBytes<'a>> { 185 type Error = Error; 186 data(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error>187 fn data(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { 188 Read::read(&mut *self.from, buf) 189 } 190 } 191 192 impl<'c> async_impl::Body for TextBody<FromBytes<'c>> { 193 type Error = Error; 194 poll_data( mut self: Pin<&mut Self>, _cx: &mut Context<'_>, buf: &mut [u8], ) -> Poll<Result<usize, Self::Error>>195 fn poll_data( 196 mut self: Pin<&mut Self>, 197 _cx: &mut Context<'_>, 198 buf: &mut [u8], 199 ) -> Poll<Result<usize, Self::Error>> { 200 Poll::Ready(Read::read(&mut *self.from, buf)) 201 } 202 } 203 204 impl<T: Read> sync_impl::Body for TextBody<FromReader<T>> { 205 type Error = Error; 206 data(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error>207 fn data(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { 208 self.from.read(buf) 209 } 210 } 211 212 impl<T: AsyncRead + Unpin + Send + Sync> async_impl::Body for TextBody<FromAsyncReader<T>> { 213 type Error = Error; 214 poll_data( mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8], ) -> Poll<Result<usize, Self::Error>>215 fn poll_data( 216 mut self: Pin<&mut Self>, 217 cx: &mut Context<'_>, 218 buf: &mut [u8], 219 ) -> Poll<Result<usize, Self::Error>> { 220 let mut buf = ReadBuf::new(buf); 221 match Pin::new(&mut *self.from).poll_read(cx, &mut buf) { 222 Poll::Ready(Ok(())) => Poll::Ready(Ok(buf.filled().len())), 223 Poll::Ready(Err(e)) => Poll::Ready(Err(e)), 224 Poll::Pending => Poll::Pending, 225 } 226 } 227 } 228 229 /// A decoder for decoding plaintext body. 230 /// 231 /// You need to provide the decoder with a body length and some byte slices 232 /// containing a legal body. The decoder will divide the correct body and 233 /// redundant parts according to the `HTTP` syntax. 234 /// 235 /// This decoder supports decoding segmented byte slices. 236 /// 237 /// # Examples 238 /// 239 /// ``` 240 /// use ylong_http::body::TextBodyDecoder; 241 /// 242 /// // Creates a decoder and set the body length to 20. 243 /// let mut decoder = TextBodyDecoder::new(20); 244 /// 245 /// // Provides the decoder with the first slice that may contain the body data. 246 /// // The length of this slice is 10, which is less than 20, so it is considered 247 /// // legal body data. 248 /// // The remaining body length is 10 after decoding. 249 /// let slice1 = b"This is a "; 250 /// let (text, left) = decoder.decode(slice1); 251 /// // Since the slice provided before is not enough for the decoder to 252 /// // complete the decoding, the status of the returned `Text` is `Partial` 253 /// // and no left data is returned. 254 /// assert!(text.is_partial()); 255 /// assert_eq!(text.data(), b"This is a "); 256 /// assert!(left.is_empty()); 257 /// 258 /// // Provides the decoder with the second slice that may contain the body data. 259 /// // The data length is 26, which is more than 10, so the first 10 bytes of 260 /// // the data will be considered legal body, and the rest will be considered 261 /// // redundant data. 262 /// let slice2 = b"text body.[REDUNDANT DATA]"; 263 /// let (text, left) = decoder.decode(slice2); 264 /// // Since the body data is fully decoded, the status of the returned `Text` 265 /// // is `Complete`. The left data is also returned. 266 /// assert!(text.is_complete()); 267 /// assert_eq!(text.data(), b"text body."); 268 /// assert_eq!(left, b"[REDUNDANT DATA]"); 269 /// 270 /// // Provides the decoder with the third slice. Since the body data has been 271 /// // fully decoded, the given slice is regard as redundant data. 272 /// let slice3 = b"[REDUNDANT DATA]"; 273 /// let (text, left) = decoder.decode(slice3); 274 /// assert!(text.is_complete()); 275 /// assert!(text.data().is_empty()); 276 /// assert_eq!(left, b"[REDUNDANT DATA]"); 277 /// ``` 278 pub struct TextBodyDecoder { 279 left: u64, 280 } 281 282 impl TextBodyDecoder { 283 /// Creates a new `TextBodyDecoder` from a body length. 284 /// 285 /// This body length generally comes from the `Content-Length` field. 286 /// 287 /// # Examples 288 /// 289 /// ``` 290 /// use ylong_http::body::TextBodyDecoder; 291 /// 292 /// let decoder = TextBodyDecoder::new(10); 293 /// ``` new(length: u64) -> TextBodyDecoder294 pub fn new(length: u64) -> TextBodyDecoder { 295 TextBodyDecoder { left: length } 296 } 297 298 /// Decodes a byte slice that may contain a plaintext body. This method 299 /// supports decoding segmented byte slices. 300 /// 301 /// After each call to this method, a `Text` and a `&[u8]` are returned. 302 /// `Text` contains a piece of legal body data inside. The returned `&[u8]` 303 /// contains redundant data. 304 /// 305 /// # Examples 306 /// 307 /// ``` 308 /// use ylong_http::body::TextBodyDecoder; 309 /// 310 /// // Creates a decoder and set the body length to 20. 311 /// let mut decoder = TextBodyDecoder::new(20); 312 /// 313 /// // Provides the decoder with the first slice that may contain the body data. 314 /// // The length of this slice is 10, which is less than 20, so it is considered 315 /// // legal body data. 316 /// // The remaining body length is 10 after decoding. 317 /// let slice1 = b"This is a "; 318 /// let (text, left) = decoder.decode(slice1); 319 /// // Since the slice provided before is not enough for the decoder to 320 /// // complete the decoding, the status of the returned `Text` is `Partial` 321 /// // and no left data is returned. 322 /// assert!(text.is_partial()); 323 /// assert_eq!(text.data(), b"This is a "); 324 /// assert!(left.is_empty()); 325 /// 326 /// // Provides the decoder with the second slice that may contain the body data. 327 /// // The data length is 26, which is more than 10, so the first 10 bytes of 328 /// // the data will be considered legal body, and the rest will be considered 329 /// // redundant data. 330 /// let slice2 = b"text body.[REDUNDANT DATA]"; 331 /// let (text, left) = decoder.decode(slice2); 332 /// // Since the body data is fully decoded, the status of the returned `Text` 333 /// // is `Complete`. The left data is also returned. 334 /// assert!(text.is_complete()); 335 /// assert_eq!(text.data(), b"text body."); 336 /// assert_eq!(left, b"[REDUNDANT DATA]"); 337 /// 338 /// // Provides the decoder with the third slice. Since the body data has been 339 /// // fully decoded, the given slice is regard as redundant data. 340 /// let slice3 = b"[REDUNDANT DATA]"; 341 /// let (text, left) = decoder.decode(slice3); 342 /// assert!(text.is_complete()); 343 /// assert!(text.data().is_empty()); 344 /// assert_eq!(left, b"[REDUNDANT DATA]"); 345 /// ``` decode<'a>(&mut self, buf: &'a [u8]) -> (Text<'a>, &'a [u8])346 pub fn decode<'a>(&mut self, buf: &'a [u8]) -> (Text<'a>, &'a [u8]) { 347 if self.left == 0 { 348 return (Text::complete(&buf[..0]), buf); 349 } 350 351 let size = min(self.left, buf.len() as u64); 352 self.left -= size; 353 let end = size as usize; 354 if self.left == 0 { 355 (Text::complete(&buf[..end]), &buf[end..]) 356 } else { 357 (Text::partial(&buf[..end]), &buf[end..]) 358 } 359 } 360 } 361 362 /// Decode result of a text buffer. 363 /// The `state` records the decode status, and the data records the decoded 364 /// data. 365 #[derive(Debug)] 366 pub struct Text<'a> { 367 state: TextState, 368 data: &'a [u8], 369 } 370 371 impl<'a> Text<'a> { 372 /// Checks whether this `Text` contains the last valid part of the body 373 /// data. 374 /// 375 /// # Examples 376 /// 377 /// ``` 378 /// use ylong_http::body::TextBodyDecoder; 379 /// 380 /// let bytes = b"This is a "; 381 /// let mut decoder = TextBodyDecoder::new(20); 382 /// let (text, _) = decoder.decode(bytes); 383 /// assert!(!text.is_complete()); 384 /// 385 /// let bytes = b"text body."; 386 /// let (text, _) = decoder.decode(bytes); 387 /// assert!(text.is_complete()); 388 /// ``` is_complete(&self) -> bool389 pub fn is_complete(&self) -> bool { 390 matches!(self.state, TextState::Complete) 391 } 392 393 /// Checks whether this `Text` contains a non-last part of the body data. 394 /// 395 /// # Examples 396 /// 397 /// ``` 398 /// use ylong_http::body::TextBodyDecoder; 399 /// 400 /// let bytes = b"This is a "; 401 /// let mut decoder = TextBodyDecoder::new(20); 402 /// let (text, _) = decoder.decode(bytes); 403 /// assert!(text.is_partial()); 404 /// 405 /// let bytes = b"text body."; 406 /// let (text, _) = decoder.decode(bytes); 407 /// assert!(!text.is_partial()); 408 /// ``` is_partial(&self) -> bool409 pub fn is_partial(&self) -> bool { 410 !self.is_complete() 411 } 412 413 /// Gets the underlying data of this `Text`. The returned data is a part 414 /// of the body data. 415 /// 416 /// # Examples 417 /// 418 /// ``` 419 /// use ylong_http::body::TextBodyDecoder; 420 /// 421 /// let bytes = b"This is a text body."; 422 /// let mut decoder = TextBodyDecoder::new(20); 423 /// let (text, _) = decoder.decode(bytes); 424 /// assert_eq!(text.data(), b"This is a text body."); 425 /// ``` data(&self) -> &[u8]426 pub fn data(&self) -> &[u8] { 427 self.data 428 } 429 complete(data: &'a [u8]) -> Self430 pub(crate) fn complete(data: &'a [u8]) -> Self { 431 Self { 432 state: TextState::Complete, 433 data, 434 } 435 } 436 partial(data: &'a [u8]) -> Self437 pub(crate) fn partial(data: &'a [u8]) -> Self { 438 Self { 439 state: TextState::Partial, 440 data, 441 } 442 } 443 } 444 445 #[derive(Debug)] 446 enum TextState { 447 Partial, 448 Complete, 449 } 450 451 #[cfg(test)] 452 mod ut_text { 453 use crate::body::text::{TextBody, TextBodyDecoder}; 454 455 /// UT test cases for `TextBody::from_bytes`. 456 /// 457 /// # Brief 458 /// 1. Calls `TextBody::from_bytes()` to create a `TextBody`. 459 #[test] ut_text_body_from_bytes()460 fn ut_text_body_from_bytes() { 461 let bytes = b"Hello World!"; 462 let _body = TextBody::from_bytes(bytes); 463 // Success if no panic. 464 } 465 466 /// UT test cases for `TextBody::from_reader`. 467 /// 468 /// # Brief 469 /// 1. Calls `TextBody::from_reader()` to create a `TextBody`. 470 #[test] ut_text_body_from_reader()471 fn ut_text_body_from_reader() { 472 let reader = "Hello World!".as_bytes(); 473 let _body = TextBody::from_reader(reader); 474 // Success if no panic. 475 } 476 477 /// UT test cases for `TextBody::from_async_reader`. 478 /// 479 /// # Brief 480 /// 1. Calls `TextBody::from_async_reader()` to create a `TextBody`. 481 #[test] ut_text_body_from_async_reader()482 fn ut_text_body_from_async_reader() { 483 let reader = "Hello World!".as_bytes(); 484 let _body = TextBody::from_async_reader(reader); 485 // Success if no panic. 486 } 487 488 /// UT test cases for `sync_impl::Body::data` of `TextBody<FromBytes<'_>>`. 489 /// 490 /// # Brief 491 /// 1. Creates a `TextBody<FromBytes<'_>>`. 492 /// 2. Calls its `sync_impl::Body::data` method and then checks the results. 493 #[test] ut_text_body_from_bytes_syn_data()494 fn ut_text_body_from_bytes_syn_data() { 495 use crate::body::sync_impl::Body; 496 497 let bytes = b"Hello World!"; 498 let mut body = TextBody::from_bytes(bytes); 499 let mut buf = [0u8; 5]; 500 501 let size = body.data(&mut buf).expect("First read failed."); 502 assert_eq!(size, 5); 503 assert_eq!(&buf[..size], b"Hello"); 504 505 let size = body.data(&mut buf).expect("Second read failed."); 506 assert_eq!(size, 5); 507 assert_eq!(&buf[..size], b" Worl"); 508 509 let size = body.data(&mut buf).expect("Third read failed."); 510 assert_eq!(size, 2); 511 assert_eq!(&buf[..size], b"d!"); 512 } 513 514 /// UT test cases for `async_impl::Body::data` of `TextBody<FromBytes<'_>>`. 515 /// 516 /// # Brief 517 /// 1. Creates a `TextBody<FromBytes<'_>>`. 518 /// 2. Calls its `async_impl::Body::data` method and then checks the 519 /// results. 520 #[cfg(feature = "ylong_base")] 521 #[test] ut_text_body_from_bytes_asyn_data()522 fn ut_text_body_from_bytes_asyn_data() { 523 let handle = ylong_runtime::spawn(async move { 524 text_body_from_bytes_asyn_data().await; 525 }); 526 ylong_runtime::block_on(handle).unwrap(); 527 } 528 529 #[cfg(feature = "ylong_base")] text_body_from_bytes_asyn_data()530 async fn text_body_from_bytes_asyn_data() { 531 use crate::body::async_impl::Body; 532 533 let bytes = b"Hello World!"; 534 let mut body = TextBody::from_bytes(bytes); 535 let mut buf = [0u8; 5]; 536 537 let size = body.data(&mut buf).await.expect("First read failed."); 538 assert_eq!(size, 5); 539 assert_eq!(&buf[..size], b"Hello"); 540 541 let size = body.data(&mut buf).await.expect("Second read failed."); 542 assert_eq!(size, 5); 543 assert_eq!(&buf[..size], b" Worl"); 544 545 let size = body.data(&mut buf).await.expect("Third read failed."); 546 assert_eq!(size, 2); 547 assert_eq!(&buf[..size], b"d!"); 548 } 549 550 /// UT test cases for `sync_impl::Body::data` of `TextBody<FromReader<T>>`. 551 /// 552 /// # Brief 553 /// 1. Creates a `TextBody<FromReader<T>>`. 554 /// 2. Calls its `sync_impl::Body::data` method and then checks the results. 555 #[test] ut_text_body_from_reader_syn_data()556 fn ut_text_body_from_reader_syn_data() { 557 use crate::body::sync_impl::Body; 558 559 let reader = "Hello World!".as_bytes(); 560 let mut body = TextBody::from_reader(reader); 561 let mut buf = [0u8; 5]; 562 563 let size = body.data(&mut buf).expect("First read failed."); 564 assert_eq!(size, 5); 565 assert_eq!(&buf[..size], b"Hello"); 566 567 let size = body.data(&mut buf).expect("Second read failed."); 568 assert_eq!(size, 5); 569 assert_eq!(&buf[..size], b" Worl"); 570 571 let size = body.data(&mut buf).expect("Third read failed."); 572 assert_eq!(size, 2); 573 assert_eq!(&buf[..size], b"d!"); 574 } 575 576 /// UT test cases for `async_impl::Body::data` of 577 /// `TextBody<FromAsyncReader<T>>`. 578 /// 579 /// # Brief 580 /// 1. Creates a `TextBody<FromAsyncReader<T>>`. 581 /// 2. Calls its `async_impl::Body::data` method and then checks the 582 /// results. 583 #[cfg(feature = "ylong_base")] 584 #[test] ut_text_body_from_async_reader_asyn_data()585 fn ut_text_body_from_async_reader_asyn_data() { 586 let handle = ylong_runtime::spawn(async move { 587 text_body_from_async_reader_asyn_data().await; 588 }); 589 ylong_runtime::block_on(handle).unwrap(); 590 } 591 592 #[cfg(feature = "ylong_base")] text_body_from_async_reader_asyn_data()593 async fn text_body_from_async_reader_asyn_data() { 594 use crate::body::async_impl::Body; 595 596 let reader = "Hello World!".as_bytes(); 597 let mut body = TextBody::from_async_reader(reader); 598 let mut buf = [0u8; 5]; 599 600 let size = body.data(&mut buf).await.expect("First read failed."); 601 assert_eq!(size, 5); 602 assert_eq!(&buf[..size], b"Hello"); 603 604 let size = body.data(&mut buf).await.expect("Second read failed."); 605 assert_eq!(size, 5); 606 assert_eq!(&buf[..size], b" Worl"); 607 608 let size = body.data(&mut buf).await.expect("Third read failed."); 609 assert_eq!(size, 2); 610 assert_eq!(&buf[..size], b"d!"); 611 } 612 613 /// UT test cases for `TextBodyDecoder::decode`. 614 /// 615 /// # Brief 616 /// 1. Creates a `TextBodyDecoder` by calling `TextBodyDecoder::new`. 617 /// 2. Decodes text body by calling `TextBodyDecoder::decode` 618 /// 3. Checks if the test result is correct. 619 #[test] ut_text_body_decoder_decode()620 fn ut_text_body_decoder_decode() { 621 // Test 1: 622 let bytes = b"this is the text body! and this is remaining data"; 623 let mut decoder = TextBodyDecoder::new(22); 624 let (text, left) = decoder.decode(&bytes[..4]); 625 assert!(text.is_partial()); 626 assert_eq!(text.data(), b"this"); 627 assert!(left.is_empty()); 628 629 let (text, left) = decoder.decode(&bytes[4..11]); 630 assert!(text.is_partial()); 631 assert_eq!(text.data(), b" is the"); 632 assert!(left.is_empty()); 633 634 let (text, left) = decoder.decode(&bytes[11..26]); 635 assert!(text.is_complete()); 636 assert_eq!(text.data(), b" text body!"); 637 assert_eq!(left, b" and"); 638 639 let (text, left) = decoder.decode(&bytes[26..]); 640 assert!(text.is_complete()); 641 assert!(text.data().is_empty()); 642 assert_eq!(left, b" this is remaining data"); 643 644 // Test 2: 645 let bytes = b"this is the text body! And this is remaining data"; 646 let mut decoder = TextBodyDecoder::new(22); 647 let (text, left) = decoder.decode(bytes); 648 assert!(text.is_complete()); 649 assert_eq!(text.data(), b"this is the text body!"); 650 assert_eq!(left, b" And this is remaining data"); 651 } 652 } 653