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 //! HTTP/1.1 request encoder implementation. 15 //! 16 //! The encoder is used to serialize the request into the specified buf in 17 //! a certain format. 18 //! 19 //! # Examples 20 //! 21 //! ``` 22 //! use ylong_http::h1::RequestEncoder; 23 //! use ylong_http::request::Request; 24 //! 25 //! let request = Request::builder() 26 //! .method("GET") 27 //! .url("www.example.com") 28 //! .version("HTTP/1.1") 29 //! .header("ACCEPT", "text/html") 30 //! .body(()) 31 //! .unwrap(); 32 //! 33 //! // Gets `RequestPart`. 34 //! let (part, _) = request.into_parts(); 35 //! let mut encoder = RequestEncoder::new(part); 36 //! 37 //! // We use `message` to store all the body data. 38 //! let mut message = Vec::new(); 39 //! // We use `buf` to store save temporary data. 40 //! let mut buf = [0u8; 20]; 41 //! 42 //! // First encoding, buf is filled. 43 //! let size = encoder.encode(&mut buf).unwrap(); 44 //! assert_eq!(&buf[..size], "GET www.example.com ".as_bytes()); 45 //! message.extend_from_slice(&buf[..size]); 46 //! 47 //! // Second encoding, buf is filled. 48 //! let size = encoder.encode(&mut buf).unwrap(); 49 //! assert_eq!(&buf[..size], "HTTP/1.1\r\naccept:tex".as_bytes()); 50 //! message.extend_from_slice(&buf[..size]); 51 //! 52 //! // Third encoding, part of buf is filled, this indicates that encoding has ended. 53 //! let size = encoder.encode(&mut buf).unwrap(); 54 //! assert_eq!(&buf[..size], "t/html\r\n\r\n".as_bytes()); 55 //! message.extend_from_slice(&buf[..size]); 56 //! 57 //! // We can assemble temporary data into a complete data. 58 //! let result = "GET www.example.com HTTP/1.1\r\naccept:text/html\r\n\r\n"; 59 //! assert_eq!(message.as_slice(), result.as_bytes()); 60 //! ``` 61 62 use std::io::Read; 63 64 use crate::error::{ErrorKind, HttpError}; 65 use crate::headers::{HeaderName, Headers, HeadersIntoIter}; 66 use crate::request::method::Method; 67 use crate::request::uri::Uri; 68 use crate::request::RequestPart; 69 use crate::version::Version; 70 71 /// A encoder that is used to encode request message in `HTTP/1.1` format. 72 /// 73 /// This encoder supports you to use the encode method multiple times to output 74 /// the result in multiple bytes slices. 75 /// 76 /// # Examples 77 /// 78 /// ``` 79 /// use ylong_http::h1::RequestEncoder; 80 /// use ylong_http::request::Request; 81 /// 82 /// let request = Request::builder() 83 /// .method("GET") 84 /// .url("www.example.com") 85 /// .version("HTTP/1.1") 86 /// .header("ACCEPT", "text/html") 87 /// .body(()) 88 /// .unwrap(); 89 /// 90 /// // Gets `RequestPart`. 91 /// let (part, _) = request.into_parts(); 92 /// let mut encoder = RequestEncoder::new(part); 93 /// 94 /// // We use `message` to store all the body data. 95 /// let mut message = Vec::new(); 96 /// // We use `buf` to store save temporary data. 97 /// let mut buf = [0u8; 20]; 98 /// 99 /// // First encoding, buf is filled. 100 /// let size = encoder.encode(&mut buf).unwrap(); 101 /// assert_eq!(&buf[..size], "GET www.example.com ".as_bytes()); 102 /// message.extend_from_slice(&buf[..size]); 103 /// 104 /// // Second encoding, buf is filled. 105 /// let size = encoder.encode(&mut buf).unwrap(); 106 /// assert_eq!(&buf[..size], "HTTP/1.1\r\naccept:tex".as_bytes()); 107 /// message.extend_from_slice(&buf[..size]); 108 /// 109 /// // Third encoding, part of buf is filled, this indicates that encoding has ended. 110 /// let size = encoder.encode(&mut buf).unwrap(); 111 /// assert_eq!(&buf[..size], "t/html\r\n\r\n".as_bytes()); 112 /// message.extend_from_slice(&buf[..size]); 113 /// 114 /// // We can assemble temporary data into a complete data. 115 /// let result = "GET www.example.com HTTP/1.1\r\naccept:text/html\r\n\r\n"; 116 /// assert_eq!(message.as_slice(), result.as_bytes()); 117 /// ``` 118 pub struct RequestEncoder { 119 encode_status: EncodeState, 120 method_part: EncodeMethod, 121 method_sp_part: EncodeSp, 122 uri_part: EncodeUri, 123 uri_sp_part: EncodeSp, 124 version_part: EncodeVersion, 125 version_crlf_part: EncodeCrlf, 126 headers_part: EncodeHeader, 127 headers_crlf_part: EncodeCrlf, 128 is_proxy: bool, 129 } 130 131 enum EncodeState { 132 // "Method" phase of encoding request-message. 133 Method, 134 // "MethodSp" phase of encoding whitespace after method. 135 MethodSp, 136 // "Uri" phase of encoding request-message. 137 Uri, 138 // "UriSp" phase of encoding whitespace after uri. 139 UriSp, 140 // "Version" phase of encoding request-message. 141 Version, 142 // "VersionCrlf" phase of encoding whitespace after version. 143 VersionCrlf, 144 // "Header" phase of encoding request-message. 145 Header, 146 // "HeaderCrlf" phase of encoding /r/n after header. 147 HeaderCrlf, 148 // "EncodeFinished" phase of finishing the encoding. 149 EncodeFinished, 150 } 151 152 // Component encoding status. 153 enum TokenStatus<T, E> { 154 // The current component is completely encoded. 155 Complete(T), 156 // The current component is partially encoded. 157 Partial(E), 158 } 159 160 type TokenResult<T> = Result<TokenStatus<usize, T>, HttpError>; 161 162 impl RequestEncoder { 163 /// Creates a new `RequestEncoder` from a `RequestPart`. 164 /// 165 /// # Examples 166 /// 167 /// ``` 168 /// use ylong_http::h1::RequestEncoder; 169 /// use ylong_http::request::Request; 170 /// 171 /// let request = Request::builder() 172 /// .method("GET") 173 /// .url("www.example.com") 174 /// .version("HTTP/1.1") 175 /// .header("ACCEPT", "text/html") 176 /// .body(()) 177 /// .unwrap(); 178 /// 179 /// let (part, _) = request.into_parts(); 180 /// let encoder = RequestEncoder::new(part); 181 /// ``` new(part: RequestPart) -> Self182 pub fn new(part: RequestPart) -> Self { 183 Self { 184 encode_status: EncodeState::Method, 185 method_part: EncodeMethod::new(part.method), 186 method_sp_part: EncodeSp::new(), 187 uri_part: EncodeUri::new(part.uri, false), 188 uri_sp_part: EncodeSp::new(), 189 version_part: EncodeVersion::new(part.version), 190 version_crlf_part: EncodeCrlf::new(), 191 headers_part: EncodeHeader::new(part.headers), 192 headers_crlf_part: EncodeCrlf::new(), 193 is_proxy: false, 194 } 195 } 196 197 /// Encodes `RequestPart` into target buf and returns the number of 198 /// bytes written. 199 /// 200 /// If the length of buf is not enough to write all the output results, 201 /// the state will be saved until the next call to this method. 202 /// 203 /// # Return Value 204 /// 205 /// This method may return the following results: 206 /// 207 /// - `Ok(size) && size == buf.len()`: it means that buf has been completely 208 /// filled, but the result may not be fully output. You **must** call this 209 /// method again to obtain the rest part of the result. Otherwise you may 210 /// lose some parts of the result. 211 /// 212 /// - `Ok(size) && size < buf.len()`: it indicates that the result has been 213 /// fully output. 214 /// 215 /// - `Err(e)`: it indicates that an error has occurred during encoding. 216 /// 217 /// # Examples 218 /// 219 /// ``` 220 /// use ylong_http::h1::RequestEncoder; 221 /// use ylong_http::request::Request; 222 /// 223 /// let request = Request::builder() 224 /// .method("GET") 225 /// .url("www.example.com") 226 /// .version("HTTP/1.1") 227 /// .header("ACCEPT", "text/html") 228 /// .body(()) 229 /// .unwrap(); 230 /// 231 /// let (part, _) = request.into_parts(); 232 /// let mut encoder = RequestEncoder::new(part); 233 /// 234 /// let mut buf = [0_u8; 10]; 235 /// let mut message = Vec::new(); 236 /// let mut idx = 0; 237 /// loop { 238 /// let size = encoder.encode(&mut buf).unwrap(); 239 /// message.extend_from_slice(&buf[..size]); 240 /// if size < buf.len() { 241 /// break; 242 /// } 243 /// } 244 /// 245 /// let result = "GET www.example.com HTTP/1.1\r\naccept:text/html\r\n\r\n"; 246 /// assert_eq!(message.as_slice(), result.as_bytes()); 247 /// ``` encode(&mut self, dst: &mut [u8]) -> Result<usize, HttpError>248 pub fn encode(&mut self, dst: &mut [u8]) -> Result<usize, HttpError> { 249 if dst.is_empty() { 250 return Err(ErrorKind::InvalidInput.into()); 251 } 252 let mut count = 0; 253 while count != dst.len() { 254 count += match self.encode_status { 255 EncodeState::Method => self.method_encode(&mut dst[count..]), 256 EncodeState::MethodSp => self.method_sp_encode(&mut dst[count..]), 257 EncodeState::Uri => self.uri_encode(&mut dst[count..]), 258 EncodeState::UriSp => self.uri_sp_encode(&mut dst[count..]), 259 EncodeState::Version => self.version_encode(&mut dst[count..]), 260 EncodeState::VersionCrlf => self.version_crlf_encode(&mut dst[count..]), 261 EncodeState::Header => self.header_encode(&mut dst[count..]), 262 EncodeState::HeaderCrlf => self.header_crlf_encode(&mut dst[count..]), 263 EncodeState::EncodeFinished => return Ok(count), 264 }?; 265 } 266 Ok(dst.len()) 267 } 268 269 /// Sets the `is_proxy` flag. 270 /// 271 /// If you enable the flag, the uri part will be encoded as a relative path 272 /// in the headline. Otherwise the uri part will be fully encoded in the 273 /// headline. 274 /// 275 /// You should use this method before the uri part being encoded. 276 /// 277 /// # Examples 278 /// 279 /// ``` 280 /// use ylong_http::h1::RequestEncoder; 281 /// use ylong_http::request::Request; 282 /// 283 /// let request = Request::builder() 284 /// .method("GET") 285 /// .url("www.example.com") 286 /// .version("HTTP/1.1") 287 /// .header("ACCEPT", "text/html") 288 /// .body(()) 289 /// .unwrap(); 290 /// 291 /// let (part, _) = request.into_parts(); 292 /// let mut encoder = RequestEncoder::new(part); 293 /// // After you create the request encoder, users can choose to set the proxy. 294 /// encoder.set_proxy(true); 295 /// 296 /// let mut buf = [0u8; 1024]; 297 /// let size = encoder.encode(&mut buf).unwrap(); 298 /// // If you set the `is_proxy` flag, the uri will be encoded as a relative path. 299 /// assert_eq!( 300 /// &buf[..size], 301 /// b"GET / HTTP/1.1\r\naccept:text/html\r\n\r\n".as_slice() 302 /// ); 303 /// ``` set_proxy(&mut self, is_proxy: bool)304 pub fn set_proxy(&mut self, is_proxy: bool) { 305 self.is_proxy = is_proxy; 306 } 307 method_encode(&mut self, dst: &mut [u8]) -> Result<usize, HttpError>308 fn method_encode(&mut self, dst: &mut [u8]) -> Result<usize, HttpError> { 309 match self.method_part.encode(dst)? { 310 TokenStatus::Complete(output_size) => { 311 self.encode_status = EncodeState::MethodSp; 312 Ok(output_size) 313 } 314 TokenStatus::Partial(output_size) => { 315 self.encode_status = EncodeState::Method; 316 Ok(output_size) 317 } 318 } 319 } 320 method_sp_encode(&mut self, dst: &mut [u8]) -> Result<usize, HttpError>321 fn method_sp_encode(&mut self, dst: &mut [u8]) -> Result<usize, HttpError> { 322 match self.method_sp_part.encode(dst)? { 323 TokenStatus::Complete(output_size) => { 324 self.uri_part.is_proxy = self.is_proxy; 325 self.encode_status = EncodeState::Uri; 326 Ok(output_size) 327 } 328 TokenStatus::Partial(output_size) => { 329 self.encode_status = EncodeState::MethodSp; 330 Ok(output_size) 331 } 332 } 333 } 334 uri_encode(&mut self, dst: &mut [u8]) -> Result<usize, HttpError>335 fn uri_encode(&mut self, dst: &mut [u8]) -> Result<usize, HttpError> { 336 match self.uri_part.encode(dst)? { 337 TokenStatus::Complete(output_size) => { 338 self.encode_status = EncodeState::UriSp; 339 Ok(output_size) 340 } 341 TokenStatus::Partial(output_size) => { 342 self.encode_status = EncodeState::Uri; 343 Ok(output_size) 344 } 345 } 346 } 347 uri_sp_encode(&mut self, dst: &mut [u8]) -> Result<usize, HttpError>348 fn uri_sp_encode(&mut self, dst: &mut [u8]) -> Result<usize, HttpError> { 349 match self.uri_sp_part.encode(dst)? { 350 TokenStatus::Complete(output_size) => { 351 self.encode_status = EncodeState::Version; 352 Ok(output_size) 353 } 354 TokenStatus::Partial(output_size) => { 355 self.encode_status = EncodeState::UriSp; 356 Ok(output_size) 357 } 358 } 359 } 360 version_encode(&mut self, dst: &mut [u8]) -> Result<usize, HttpError>361 fn version_encode(&mut self, dst: &mut [u8]) -> Result<usize, HttpError> { 362 match self.version_part.encode(dst)? { 363 TokenStatus::Complete(output_size) => { 364 self.encode_status = EncodeState::VersionCrlf; 365 Ok(output_size) 366 } 367 TokenStatus::Partial(output_size) => { 368 self.encode_status = EncodeState::Version; 369 Ok(output_size) 370 } 371 } 372 } 373 version_crlf_encode(&mut self, dst: &mut [u8]) -> Result<usize, HttpError>374 fn version_crlf_encode(&mut self, dst: &mut [u8]) -> Result<usize, HttpError> { 375 match self.version_crlf_part.encode(dst)? { 376 TokenStatus::Complete(output_size) => { 377 self.encode_status = EncodeState::Header; 378 Ok(output_size) 379 } 380 TokenStatus::Partial(output_size) => { 381 self.encode_status = EncodeState::VersionCrlf; 382 Ok(output_size) 383 } 384 } 385 } 386 header_encode(&mut self, dst: &mut [u8]) -> Result<usize, HttpError>387 fn header_encode(&mut self, dst: &mut [u8]) -> Result<usize, HttpError> { 388 match self.headers_part.encode(dst)? { 389 TokenStatus::Complete(output_size) => { 390 self.encode_status = EncodeState::HeaderCrlf; 391 Ok(output_size) 392 } 393 TokenStatus::Partial(output_size) => { 394 self.encode_status = EncodeState::Header; 395 Ok(output_size) 396 } 397 } 398 } 399 header_crlf_encode(&mut self, dst: &mut [u8]) -> Result<usize, HttpError>400 fn header_crlf_encode(&mut self, dst: &mut [u8]) -> Result<usize, HttpError> { 401 match self.headers_crlf_part.encode(dst)? { 402 TokenStatus::Complete(output_size) => { 403 self.encode_status = EncodeState::EncodeFinished; 404 Ok(output_size) 405 } 406 TokenStatus::Partial(output_size) => { 407 self.encode_status = EncodeState::HeaderCrlf; 408 Ok(output_size) 409 } 410 } 411 } 412 } 413 414 struct EncodeMethod { 415 inner: Method, 416 src_idx: usize, 417 } 418 419 impl EncodeMethod { new(method: Method) -> Self420 fn new(method: Method) -> Self { 421 Self { 422 inner: method, 423 src_idx: 0, 424 } 425 } 426 encode(&mut self, buf: &mut [u8]) -> TokenResult<usize>427 fn encode(&mut self, buf: &mut [u8]) -> TokenResult<usize> { 428 let method = self.inner.as_str().as_bytes(); 429 WriteData::new(method, &mut self.src_idx, buf).write() 430 } 431 } 432 433 struct EncodeUri { 434 inner: Vec<u8>, 435 inner_proxy: Vec<u8>, 436 src_idx: usize, 437 is_proxy: bool, 438 } 439 440 impl EncodeUri { new(uri: Uri, is_proxy: bool) -> Self441 fn new(uri: Uri, is_proxy: bool) -> Self { 442 let mut init_proxy_uri = vec![]; 443 let path = uri.path_and_query(); 444 if let Some(p) = path { 445 init_proxy_uri = p.as_bytes().to_vec(); 446 } else { 447 init_proxy_uri.extend_from_slice(b"/"); 448 } 449 let init_uri = uri.to_string().into_bytes(); 450 Self { 451 inner: init_uri, 452 inner_proxy: init_proxy_uri, 453 src_idx: 0, 454 is_proxy, 455 } 456 } 457 encode(&mut self, buf: &mut [u8]) -> TokenResult<usize>458 fn encode(&mut self, buf: &mut [u8]) -> TokenResult<usize> { 459 let mut uri = self.inner.as_slice(); 460 if self.is_proxy { 461 uri = self.inner_proxy.as_slice(); 462 } 463 WriteData::new(uri, &mut self.src_idx, buf).write() 464 } 465 } 466 467 struct EncodeVersion { 468 inner: Version, 469 src_idx: usize, 470 } 471 472 impl EncodeVersion { new(version: Version) -> Self473 fn new(version: Version) -> Self { 474 Self { 475 inner: version, 476 src_idx: 0, 477 } 478 } 479 encode(&mut self, buf: &mut [u8]) -> TokenResult<usize>480 fn encode(&mut self, buf: &mut [u8]) -> TokenResult<usize> { 481 let version = self.inner.as_str().as_bytes(); 482 let mut task = WriteData::new(version, &mut self.src_idx, buf); 483 task.write() 484 } 485 } 486 487 struct EncodeHeader { 488 inner: HeadersIntoIter, 489 status: Option<HeaderStatus>, 490 name: HeaderName, 491 value: Vec<u8>, 492 name_idx: usize, 493 colon_idx: usize, 494 value_idx: usize, 495 } 496 497 enum HeaderStatus { 498 Name, 499 Colon, 500 Value, 501 Crlf(EncodeCrlf), 502 EmptyHeader, 503 } 504 505 impl EncodeHeader { new(header: Headers) -> Self506 fn new(header: Headers) -> Self { 507 let mut header_iter = header.into_iter(); 508 if let Some((header_name, header_value)) = header_iter.next() { 509 Self { 510 inner: header_iter, 511 status: Some(HeaderStatus::Name), 512 name: header_name, 513 value: header_value.to_str().unwrap().into_bytes(), 514 name_idx: 0, 515 colon_idx: 0, 516 value_idx: 0, 517 } 518 } else { 519 Self { 520 inner: header_iter, 521 status: Some(HeaderStatus::EmptyHeader), 522 name: HeaderName::from_bytes(" ".as_bytes()).unwrap(), 523 value: vec![], 524 name_idx: 0, 525 colon_idx: 0, 526 value_idx: 0, 527 } 528 } 529 } 530 encode(&mut self, buf: &mut [u8]) -> TokenResult<usize>531 fn encode(&mut self, buf: &mut [u8]) -> TokenResult<usize> { 532 match self.status.take().unwrap() { 533 HeaderStatus::Name => { 534 let name = self.name.as_bytes(); 535 let mut task = WriteData::new(name, &mut self.name_idx, buf); 536 match task.write()? { 537 TokenStatus::Complete(size) => { 538 self.status = Some(HeaderStatus::Colon); 539 Ok(TokenStatus::Partial(size)) 540 } 541 TokenStatus::Partial(size) => { 542 self.status = Some(HeaderStatus::Name); 543 Ok(TokenStatus::Partial(size)) 544 } 545 } 546 } 547 HeaderStatus::Colon => { 548 let colon = ":".as_bytes(); 549 let mut task = WriteData::new(colon, &mut self.colon_idx, buf); 550 match task.write()? { 551 TokenStatus::Complete(size) => { 552 self.status = Some(HeaderStatus::Value); 553 Ok(TokenStatus::Partial(size)) 554 } 555 TokenStatus::Partial(size) => { 556 self.status = Some(HeaderStatus::Colon); 557 Ok(TokenStatus::Partial(size)) 558 } 559 } 560 } 561 HeaderStatus::Value => { 562 let value = self.value.as_slice(); 563 let mut task = WriteData::new(value, &mut self.value_idx, buf); 564 match task.write()? { 565 TokenStatus::Complete(size) => { 566 let crlf = EncodeCrlf::new(); 567 self.status = Some(HeaderStatus::Crlf(crlf)); 568 Ok(TokenStatus::Partial(size)) 569 } 570 TokenStatus::Partial(size) => { 571 self.status = Some(HeaderStatus::Value); 572 Ok(TokenStatus::Partial(size)) 573 } 574 } 575 } 576 HeaderStatus::Crlf(mut crlf) => match crlf.encode(buf)? { 577 TokenStatus::Complete(size) => { 578 if let Some(iter) = self.inner.next() { 579 let (header_name, header_value) = iter; 580 self.status = Some(HeaderStatus::Name); 581 self.name = header_name; 582 self.value = header_value.to_str().unwrap().into_bytes(); 583 self.name_idx = 0; 584 self.colon_idx = 0; 585 self.value_idx = 0; 586 Ok(TokenStatus::Partial(size)) 587 } else { 588 Ok(TokenStatus::Complete(size)) 589 } 590 } 591 TokenStatus::Partial(size) => { 592 self.status = Some(HeaderStatus::Crlf(crlf)); 593 Ok(TokenStatus::Partial(size)) 594 } 595 }, 596 HeaderStatus::EmptyHeader => Ok(TokenStatus::Complete(0)), 597 } 598 } 599 } 600 601 struct EncodeSp { 602 src_idx: usize, 603 } 604 605 impl EncodeSp { new() -> Self606 fn new() -> Self { 607 Self { src_idx: 0 } 608 } 609 encode(&mut self, buf: &mut [u8]) -> TokenResult<usize>610 fn encode(&mut self, buf: &mut [u8]) -> TokenResult<usize> { 611 let sp = " ".as_bytes(); 612 let mut task = WriteData::new(sp, &mut self.src_idx, buf); 613 task.write() 614 } 615 } 616 617 struct EncodeCrlf { 618 src_idx: usize, 619 } 620 621 impl EncodeCrlf { new() -> Self622 fn new() -> Self { 623 Self { src_idx: 0 } 624 } 625 encode(&mut self, buf: &mut [u8]) -> TokenResult<usize>626 fn encode(&mut self, buf: &mut [u8]) -> TokenResult<usize> { 627 let crlf = "\r\n".as_bytes(); 628 let mut task = WriteData::new(crlf, &mut self.src_idx, buf); 629 task.write() 630 } 631 } 632 633 struct WriteData<'a> { 634 src: &'a [u8], 635 src_idx: &'a mut usize, 636 dst: &'a mut [u8], 637 } 638 639 impl<'a> WriteData<'a> { new(src: &'a [u8], src_idx: &'a mut usize, dst: &'a mut [u8]) -> Self640 fn new(src: &'a [u8], src_idx: &'a mut usize, dst: &'a mut [u8]) -> Self { 641 WriteData { src, src_idx, dst } 642 } 643 write(&mut self) -> TokenResult<usize>644 fn write(&mut self) -> TokenResult<usize> { 645 let src_idx = *self.src_idx; 646 let input_len = self.src.len() - src_idx; 647 let output_len = self.dst.len(); 648 let num = (&self.src[src_idx..]).read(self.dst).unwrap(); 649 if output_len >= input_len { 650 return Ok(TokenStatus::Complete(num)); 651 } 652 *self.src_idx += num; 653 Ok(TokenStatus::Partial(num)) 654 } 655 } 656 impl Default for RequestEncoder { default() -> Self657 fn default() -> Self { 658 RequestEncoder::new(RequestPart::default()) 659 } 660 } 661 662 #[cfg(test)] 663 mod ut_request_encoder { 664 use super::RequestEncoder; 665 use crate::request::{Request, RequestBuilder}; 666 667 /// UT test cases for `RequestEncoder::new`. 668 /// 669 /// # Brief 670 /// 1. Calls `RequestEncoder::new` to create a `RequestEncoder`. 671 #[test] ut_request_encoder_new()672 fn ut_request_encoder_new() { 673 let request = Request::new(()); 674 let (part, _) = request.into_parts(); 675 let _encoder = RequestEncoder::new(part); 676 // Success if no panic. 677 } 678 679 /// UT test cases for `RequestEncoder::encode`. 680 /// 681 /// # Brief 682 /// 1. Creates a `Request` by calling methods of `Request::builder`. 683 /// 2. Gets a request part by calling `Request::into_parts`. 684 /// 3. Creates a `RequestEncoder` by calling `RequestBuilder::new`. 685 /// 4. Calls `RequestEncoder::encode` method in a loop and collects the 686 /// results. 687 /// 5. Checks if the test result is correct. 688 #[test] ut_request_encoder_encode_1()689 fn ut_request_encoder_encode_1() { 690 macro_rules! encoder_test_case { 691 ( 692 Method: $method:expr, 693 Uri: $uri:expr, 694 Version: $version:expr, 695 $(Header: $name:expr, $value:expr,)* 696 RequestLine: $request_line:expr, 697 ) => {{ 698 let request = Request::builder() 699 .method($method) 700 .url($uri) 701 .version($version) 702 $(.header($name, $value))* 703 .body(()) 704 .unwrap(); 705 706 let (part, _) = request.into_parts(); 707 let mut encoder = RequestEncoder::new(part); 708 let mut buf = [0u8; 5]; 709 let mut res = Vec::new(); 710 loop { 711 let size = encoder.encode(&mut buf).unwrap(); 712 res.extend_from_slice(&buf[..size]); 713 if size < buf.len() { 714 break; 715 } 716 } 717 718 let str = std::str::from_utf8(res.as_slice()) 719 .expect("Cannot convert res to &str"); 720 721 assert!(str.find($request_line).is_some()); 722 723 $( 724 let target_header = format!( 725 "{}:{}\r\n", 726 ($name).to_lowercase(), 727 ($value).to_lowercase(), 728 ); 729 assert!(str.find(target_header.as_str()).is_some()); 730 )* 731 }}; 732 } 733 734 // No header-lines. 735 encoder_test_case! { 736 Method: "GET", 737 Uri: "www.example.com", 738 Version: "HTTP/1.1", 739 RequestLine: "GET www.example.com HTTP/1.1\r\n", 740 } 741 742 // 1 header-line. 743 encoder_test_case! { 744 Method: "GET", 745 Uri: "www.example.com", 746 Version: "HTTP/1.1", 747 Header: "ACCEPT", "text/html", 748 RequestLine: "GET www.example.com HTTP/1.1\r\n", 749 } 750 751 // More than 1 header-lines. 752 encoder_test_case! { 753 Method: "GET", 754 Uri: "www.example.com", 755 Version: "HTTP/1.1", 756 Header: "ACCEPT", "text/html", 757 Header: "HOST", "127.0.0.1", 758 RequestLine: "GET www.example.com HTTP/1.1\r\n", 759 } 760 } 761 762 /// UT test cases for `RequestEncoder::set_proxy`. 763 /// 764 /// # Brief 765 /// 1. Creates a `Request` by calling `RequestBuilder::build`. 766 /// 2. Calls set_proxy. 767 /// 3. Checks if the test result is correct. 768 #[test] ut_request_encoder_set_proxy()769 fn ut_request_encoder_set_proxy() { 770 let request = RequestBuilder::new() 771 .method("GET") 772 .url("www.example.com") 773 .version("HTTP/1.1") 774 .body(()) 775 .unwrap(); 776 let (part, _) = request.into_parts(); 777 let mut encoder = RequestEncoder::new(part); 778 assert!(!encoder.is_proxy); 779 780 encoder.set_proxy(true); 781 assert!(encoder.is_proxy); 782 783 let mut buf = [0u8; 100]; 784 let size = encoder.encode(&mut buf).unwrap(); 785 let res = std::str::from_utf8(&buf[..size]).unwrap(); 786 assert_eq!(res, "GET / HTTP/1.1\r\n\r\n"); 787 } 788 } 789