1#![cfg_attr(not(any(test, feature = "std")), no_std)]
2#![deny(clippy::missing_safety_doc, clippy::undocumented_unsafe_blocks)]
3#![cfg_attr(test, deny(warnings))]
4
5use core::{fmt, result, str};
25
26use crate::iter::Bytes;
27
28mod iter;
29#[macro_use]
30mod macros;
31mod simd;
32
33#[inline]
44fn is_method_token(b: u8) -> bool {
45 match b {
46 b'A'..=b'Z' => true,
48 _ => TOKEN_MAP[b as usize],
49 }
50}
51
52static URI_MAP: [bool; 256] = byte_map!(
56 b'!'..=0x7e | 0x80..=0xFF
57);
58
59#[inline]
60pub(crate) fn is_uri_token(b: u8) -> bool {
61 URI_MAP[b as usize]
62}
63
64static TOKEN_MAP: [bool; 256] = byte_map!(
65 b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' |
66 b'!' | b'#' | b'$' | b'%' | b'&' | b'\'' | b'*' | b'+' |
67 b'-' | b'.' | b'^' | b'_' | b'`' | b'|' | b'~'
68);
69
70#[inline]
71pub(crate) fn is_header_name_token(b: u8) -> bool {
72 TOKEN_MAP[b as usize]
73}
74
75static HEADER_VALUE_MAP: [bool; 256] = byte_map!(
76 b'\t' | b' '..=0x7e | 0x80..=0xFF
77);
78
79#[inline]
80pub(crate) fn is_header_value_token(b: u8) -> bool {
81 HEADER_VALUE_MAP[b as usize]
82}
83
84#[derive(Copy, Clone, PartialEq, Eq, Debug)]
86pub enum Error {
87 HeaderName,
89 HeaderValue,
91 NewLine,
93 Status,
95 Token,
97 TooManyHeaders,
99 Version,
101}
102
103impl Error {
104 #[inline]
105 fn description_str(&self) -> &'static str {
106 match *self {
107 Error::HeaderName => "invalid header name",
108 Error::HeaderValue => "invalid header value",
109 Error::NewLine => "invalid new line",
110 Error::Status => "invalid response status",
111 Error::Token => "invalid token",
112 Error::TooManyHeaders => "too many headers",
113 Error::Version => "invalid HTTP version",
114 }
115 }
116}
117
118impl fmt::Display for Error {
119 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120 f.write_str(self.description_str())
121 }
122}
123
124#[cfg(feature = "std")]
125impl std::error::Error for Error {
126 fn description(&self) -> &str {
127 self.description_str()
128 }
129}
130
131#[derive(Debug, PartialEq, Eq)]
134pub struct InvalidChunkSize;
135
136impl fmt::Display for InvalidChunkSize {
137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138 f.write_str("invalid chunk size")
139 }
140}
141
142pub type Result<T> = result::Result<Status<T>, Error>;
148
149#[derive(Copy, Clone, Eq, PartialEq, Debug)]
155pub enum Status<T> {
156 Complete(T),
158 Partial,
160}
161
162impl<T> Status<T> {
163 #[inline]
165 pub fn is_complete(&self) -> bool {
166 match *self {
167 Status::Complete(..) => true,
168 Status::Partial => false,
169 }
170 }
171
172 #[inline]
174 pub fn is_partial(&self) -> bool {
175 match *self {
176 Status::Complete(..) => false,
177 Status::Partial => true,
178 }
179 }
180
181 #[inline]
184 pub fn unwrap(self) -> T {
185 match self {
186 Status::Complete(t) => t,
187 Status::Partial => panic!("Tried to unwrap Status::Partial"),
188 }
189 }
190}
191
192#[derive(Clone, Debug, Default)]
194pub struct ParserConfig {
195 allow_spaces_after_header_name_in_responses: bool,
196 allow_obsolete_multiline_headers_in_responses: bool,
197 allow_multiple_spaces_in_request_line_delimiters: bool,
198 allow_multiple_spaces_in_response_status_delimiters: bool,
199 allow_space_before_first_header_name: bool,
200 ignore_invalid_headers_in_responses: bool,
201 ignore_invalid_headers_in_requests: bool,
202}
203
204impl ParserConfig {
205 pub fn allow_spaces_after_header_name_in_responses(&mut self, value: bool) -> &mut Self {
207 self.allow_spaces_after_header_name_in_responses = value;
208 self
209 }
210
211 pub fn allow_multiple_spaces_in_request_line_delimiters(&mut self, value: bool) -> &mut Self {
225 self.allow_multiple_spaces_in_request_line_delimiters = value;
226 self
227 }
228
229 pub fn multiple_spaces_in_request_line_delimiters_are_allowed(&self) -> bool {
231 self.allow_multiple_spaces_in_request_line_delimiters
232 }
233
234 pub fn allow_multiple_spaces_in_response_status_delimiters(
249 &mut self,
250 value: bool,
251 ) -> &mut Self {
252 self.allow_multiple_spaces_in_response_status_delimiters = value;
253 self
254 }
255
256 pub fn multiple_spaces_in_response_status_delimiters_are_allowed(&self) -> bool {
258 self.allow_multiple_spaces_in_response_status_delimiters
259 }
260
261 pub fn allow_obsolete_multiline_headers_in_responses(&mut self, value: bool) -> &mut Self {
285 self.allow_obsolete_multiline_headers_in_responses = value;
286 self
287 }
288
289 pub fn obsolete_multiline_headers_in_responses_are_allowed(&self) -> bool {
291 self.allow_obsolete_multiline_headers_in_responses
292 }
293
294 pub fn allow_space_before_first_header_name(&mut self, value: bool) -> &mut Self {
318 self.allow_space_before_first_header_name = value;
319 self
320 }
321
322 pub fn space_before_first_header_name_are_allowed(&self) -> bool {
324 self.allow_space_before_first_header_name
325 }
326
327 pub fn ignore_invalid_headers_in_responses(&mut self, value: bool) -> &mut Self {
358 self.ignore_invalid_headers_in_responses = value;
359 self
360 }
361
362 pub fn ignore_invalid_headers_in_requests(&mut self, value: bool) -> &mut Self {
364 self.ignore_invalid_headers_in_requests = value;
365 self
366 }
367}
368
369#[inline]
370fn skip_empty_lines(bytes: &mut Bytes<'_>) -> Result<()> {
371 loop {
372 let b = bytes.peek();
373 match b {
374 Some(b'\r') => {
375 unsafe { bytes.bump() };
377 expect!(bytes.next() == b'\n' => Err(Error::NewLine));
378 }
379 Some(b'\n') => {
380 unsafe {
382 bytes.bump();
383 }
384 }
385 Some(..) => {
386 bytes.slice();
387 return Ok(Status::Complete(()));
388 }
389 None => return Ok(Status::Partial),
390 }
391 }
392}
393
394#[inline]
395fn skip_spaces(bytes: &mut Bytes<'_>) -> Result<()> {
396 loop {
397 let b = bytes.peek();
398 match b {
399 Some(b' ') => {
400 unsafe { bytes.bump() };
402 }
403 Some(..) => {
404 bytes.slice();
405 return Ok(Status::Complete(()));
406 }
407 None => return Ok(Status::Partial),
408 }
409 }
410}
411
412#[inline]
413pub fn parse_request<'b>(src: &'b [u8]) -> Result<(usize, &'b str, &'b str, u8)> {
415 let mut bytes = Bytes::new(src);
416
417 let method = complete!(parse_method(&mut bytes));
418 let path = complete!(parse_uri(&mut bytes));
419 let version = complete!(parse_version(&mut bytes));
420 newline!(bytes);
421 Ok(Status::Complete((bytes.slice_pos(), method, path, version)))
422}
423
424#[inline]
425pub fn parse_response<'b>(buf: &'b [u8]) -> Result<(usize, u8, u16, &'b str)> {
427 let mut bytes = Bytes::new(buf);
428
429 complete!(skip_empty_lines(&mut bytes));
430 let version = complete!(parse_version(&mut bytes));
431 complete!(skip_empty_lines(&mut bytes));
432 space!(bytes or Error::Version);
433 complete!(skip_spaces(&mut bytes));
434 let code = complete!(parse_code(&mut bytes));
435
436 let reason = match next!(bytes) {
446 b' ' => {
447 complete!(skip_spaces(&mut bytes));
448 bytes.slice();
449 complete!(parse_reason(&mut bytes))
450 }
451 b'\r' => {
452 expect!(bytes.next() == b'\n' => Err(Error::Status));
453 bytes.slice();
454 ""
455 }
456 b'\n' => {
457 bytes.slice();
458 ""
459 }
460 _ => return Err(Error::Status),
461 };
462
463 Ok(Status::Complete((bytes.slice_pos(), version, code, reason)))
464}
465
466#[derive(Copy, Clone, Eq, PartialEq, Debug, Default)]
468pub struct Header {
469 pub name_start: usize,
473 pub name_end: usize,
474 pub value_start: usize,
479 pub value_end: usize,
480}
481
482#[inline]
483#[allow(missing_docs)]
484pub fn parse_version<'a>(bytes: &mut Bytes<'a>) -> Result<u8> {
486 if let Some(eight) = bytes.peek_n::<[u8; 8]>(8) {
487 const H10: u64 = u64::from_ne_bytes(*b"HTTP/1.0");
488 const H11: u64 = u64::from_ne_bytes(*b"HTTP/1.1");
489 unsafe {
491 bytes.advance(8);
492 }
493 return match u64::from_ne_bytes(eight) {
494 H10 => Ok(Status::Complete(0)),
495 H11 => Ok(Status::Complete(1)),
496 _ => Err(Error::Version),
497 };
498 }
499
500 expect!(bytes.next() == b'H' => Err(Error::Version));
505 expect!(bytes.next() == b'T' => Err(Error::Version));
506 expect!(bytes.next() == b'T' => Err(Error::Version));
507 expect!(bytes.next() == b'P' => Err(Error::Version));
508 expect!(bytes.next() == b'/' => Err(Error::Version));
509 expect!(bytes.next() == b'1' => Err(Error::Version));
510 expect!(bytes.next() == b'.' => Err(Error::Version));
511 Ok(Status::Partial)
512}
513
514#[inline]
515#[doc(hidden)]
516#[allow(missing_docs)]
517fn parse_method<'a>(mut bytes: &mut Bytes<'a>) -> Result<&'a str> {
519 complete!(skip_empty_lines(bytes));
520
521 const GET: [u8; 4] = *b"GET ";
522 const POST: [u8; 4] = *b"POST";
523 match bytes.peek_n::<[u8; 4]>(4) {
524 Some(GET) => {
525 let method = unsafe {
527 bytes.advance(4); str::from_utf8_unchecked(bytes.slice_skip(1)) };
530 complete!(skip_spaces(bytes));
531 Ok(Status::Complete(method))
532 }
533 Some(POST) if unsafe { bytes.peek_ahead(4) } == Some(b' ') => {
539 let method = unsafe {
541 bytes.advance(5); str::from_utf8_unchecked(bytes.slice_skip(1)) };
544 complete!(skip_spaces(bytes));
545 Ok(Status::Complete(method))
546 }
547 _ => parse_token(&mut bytes),
548 }
549}
550
551#[inline]
565fn parse_reason<'a>(bytes: &mut Bytes<'a>) -> Result<&'a str> {
566 let mut seen_obs_text = false;
567 loop {
568 let b = next!(bytes);
569 if b == b'\r' {
570 expect!(bytes.next() == b'\n' => Err(Error::Status));
571 return Ok(Status::Complete(
572 unsafe {
578 let bytes = bytes.slice_skip(2);
579 if !seen_obs_text {
580 str::from_utf8_unchecked(bytes)
582 } else {
583 ""
585 }
586 },
587 ));
588 } else if b == b'\n' {
589 return Ok(Status::Complete(
590 unsafe {
594 let bytes = bytes.slice_skip(1);
595 if !seen_obs_text {
596 str::from_utf8_unchecked(bytes)
598 } else {
599 ""
601 }
602 },
603 ));
604 } else if !(b == 0x09 || b == b' ' || (0x21..=0x7E).contains(&b) || b >= 0x80) {
605 return Err(Error::Status);
606 } else if b >= 0x80 {
607 seen_obs_text = true;
608 }
609 }
610}
611
612#[inline]
613fn parse_token<'a>(bytes: &mut Bytes<'a>) -> Result<&'a str> {
614 let b = next!(bytes);
615 if !is_method_token(b) {
616 return Err(Error::Token);
618 }
619
620 loop {
621 let b = next!(bytes);
622 if b == b' ' {
623 return Ok(Status::Complete(
624 unsafe { str::from_utf8_unchecked(bytes.slice_skip(1)) },
626 ));
627 } else if !is_method_token(b) {
628 return Err(Error::Token);
629 }
630 }
631}
632
633#[inline]
634#[allow(missing_docs)]
635fn parse_uri<'a>(bytes: &mut Bytes<'a>) -> Result<&'a str> {
637 let start = bytes.pos();
638 simd::match_uri_vectored(bytes);
639 let end = bytes.pos();
640
641 if next!(bytes) == b' ' {
642 if end == start {
644 return Err(Error::Token);
645 }
646
647 match str::from_utf8(unsafe { bytes.slice_skip(1) }) {
649 Ok(uri) => {
650 complete!(skip_spaces(bytes));
651 Ok(Status::Complete(uri))
652 }
653 Err(_) => Err(Error::Token),
654 }
655 } else {
656 Err(Error::Token)
657 }
658}
659
660#[inline]
661fn parse_code(bytes: &mut Bytes<'_>) -> Result<u16> {
662 let hundreds = expect!(bytes.next() == b'0'..=b'9' => Err(Error::Status));
663 let tens = expect!(bytes.next() == b'0'..=b'9' => Err(Error::Status));
664 let ones = expect!(bytes.next() == b'0'..=b'9' => Err(Error::Status));
665
666 Ok(Status::Complete(
667 (hundreds - b'0') as u16 * 100 + (tens - b'0') as u16 * 10 + (ones - b'0') as u16,
668 ))
669}
670
671pub fn parse_header(src: &[u8]) -> Result<(usize, Option<Header>)> {
690 let mut bytes = Bytes::new(src);
691 parse_header_iter_uninit(&mut bytes, &HeaderParserConfig::default())
692}
693
694#[derive(Clone, Debug, Default)]
695struct HeaderParserConfig {
696 allow_spaces_after_header_name: bool,
697 allow_obsolete_multiline_headers: bool,
698}
699
700fn parse_header_iter_uninit<'a>(
710 bytes: &mut Bytes<'a>,
711 config: &HeaderParserConfig,
712) -> Result<(usize, Option<Header>)> {
713 let start = bytes.as_ref().as_ptr() as usize;
715 let mut header = Header::default();
716
717 macro_rules! maybe_continue_after_obsolete_line_folding {
718 ($bytes:ident, $label:lifetime) => {
719 if config.allow_obsolete_multiline_headers {
720 match $bytes.peek() {
721 None => {
722 return Ok(Status::Partial);
726 }
727 Some(b' ') | Some(b'\t') => {
728 continue $label;
730 }
731 _ => {
732 },
737 }
738 }
739 }
740 }
741
742 loop {
743 macro_rules! handle_invalid_char {
747 ($bytes:ident, $b:ident, $err:ident) => {
748 return Err(Error::$err);
749 };
750 }
751
752 let b = next!(bytes);
754 if b == b'\r' {
755 expect!(bytes.next() == b'\n' => Err(Error::NewLine));
756 let end = bytes.as_ref().as_ptr() as usize;
757 return Ok(Status::Complete((end - start, None)));
758 }
759 if b == b'\n' {
760 let end = bytes.as_ref().as_ptr() as usize;
761 return Ok(Status::Complete((end - start, None)));
762 }
763 if !is_header_name_token(b) {
764 handle_invalid_char!(bytes, b, HeaderName);
765 }
766
767 header.name_start = bytes.slice_pos() - 1;
768
769 #[allow(clippy::never_loop)]
770 'name: loop {
772 simd::match_header_name_vectored(bytes);
773 let mut b = next!(bytes);
774
775 header.name_end = bytes.slice_pos() - 1;
777 bytes.commit();
778
779 if b == b':' {
780 break 'name;
781 }
782
783 if config.allow_spaces_after_header_name {
784 while b == b' ' || b == b'\t' {
785 b = next!(bytes);
786
787 if b == b':' {
788 bytes.commit();
789 break 'name;
790 }
791 }
792 }
793
794 handle_invalid_char!(bytes, b, HeaderName);
795 }
796
797 let mut b;
798
799 header.value_start = bytes.slice_pos() + 1;
800
801 #[allow(clippy::never_loop)]
802 let value_slice = 'value: loop {
803 'whitespace_after_colon: loop {
805 b = next!(bytes);
806 if b == b' ' || b == b'\t' {
807 bytes.slice();
808 continue 'whitespace_after_colon;
809 }
810 if is_header_value_token(b) {
811 break 'whitespace_after_colon;
812 }
813
814 if b == b'\r' {
815 expect!(bytes.next() == b'\n' => Err(Error::HeaderValue));
816 } else if b != b'\n' {
817 handle_invalid_char!(bytes, b, HeaderValue);
818 }
819
820 maybe_continue_after_obsolete_line_folding!(bytes, 'whitespace_after_colon);
821
822 let whitespace_slice = bytes.slice();
823
824 break 'value &whitespace_slice[0..0];
827 }
828
829 'value_lines: loop {
830 simd::match_header_value_vectored(bytes);
833 let b = next!(bytes);
834
835 let skip = if b == b'\r' {
837 expect!(bytes.next() == b'\n' => Err(Error::HeaderValue));
838 2
839 } else if b == b'\n' {
840 1
841 } else {
842 handle_invalid_char!(bytes, b, HeaderValue);
843 };
844
845 maybe_continue_after_obsolete_line_folding!(bytes, 'value_lines);
846
847 unsafe {
849 break 'value bytes.slice_skip(skip);
850 }
851 }
852 };
853
854 header.value_end = bytes.slice_pos();
855
856 if let Some(last_visible) = value_slice
858 .iter()
859 .rposition(|b| *b != b' ' && *b != b'\t' && *b != b'\r' && *b != b'\n')
860 {
861 header.value_end = header.value_start + last_visible + 1;
862 }
863
864 return Ok(Status::Complete((bytes.slice_pos(), Some(header))));
865 }
866}
867
868pub fn parse_chunk_size(buf: &[u8]) -> result::Result<Status<(usize, u64)>, InvalidChunkSize> {
881 const RADIX: u64 = 16;
882 let mut bytes = Bytes::new(buf);
883 let mut size = 0;
884 let mut in_chunk_size = true;
885 let mut in_ext = false;
886 let mut count = 0;
887 loop {
888 let b = next!(bytes);
889 match b {
890 b'0'..=b'9' if in_chunk_size => {
891 if count > 15 {
892 return Err(InvalidChunkSize);
893 }
894 count += 1;
895 if cfg!(debug_assertions) && size > (u64::MAX / RADIX) {
896 return Err(InvalidChunkSize);
901 }
902 size *= RADIX;
903 size += (b - b'0') as u64;
904 }
905 b'a'..=b'f' | b'A'..=b'F' if in_chunk_size => {
906 if count > 15 {
907 return Err(InvalidChunkSize);
908 }
909 count += 1;
910 if cfg!(debug_assertions) && size > (u64::MAX / RADIX) {
911 return Err(InvalidChunkSize);
912 }
913 size *= RADIX;
914 size += ((b | 0x20) + 10 - b'a') as u64;
915 }
916 b'\r' => match next!(bytes) {
917 b'\n' => break,
918 _ => return Err(InvalidChunkSize),
919 },
920 b';' if !in_ext => {
922 in_ext = true;
923 in_chunk_size = false;
924 }
925 b'\t' | b' ' if !in_ext && !in_chunk_size => {}
928 b'\t' | b' ' if in_chunk_size => in_chunk_size = false,
930 _ if in_ext => {}
936 _ => return Err(InvalidChunkSize),
939 }
940 }
941 Ok(Status::Complete((bytes.slice_pos(), size)))
942}
943
944#[cfg(test)]
945mod tests {
946 use super::{parse_chunk_size, Error, Request, Response, Status, EMPTY_HEADER};
947
948 const NUM_OF_HEADERS: usize = 4;
949
950 macro_rules! req {
951 ($name:ident, $buf:expr, |$arg:ident| $body:expr) => {
952 req! {$name, $buf, Ok(Status::Complete($buf.len())), |$arg| $body }
953 };
954 ($name:ident, $buf:expr, $len:expr, |$arg:ident| $body:expr) => {
955 #[test]
956 fn $name() {
957 let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
958 let mut req = Request::new(&mut headers[..]);
959 let status = req.parse($buf.as_ref());
960 assert_eq!(status, $len);
961 closure(req);
962
963 fn closure($arg: Request) {
964 $body
965 }
966 }
967 };
968 }
969
970 req! {
971 test_request_simple,
972 b"GET / HTTP/1.1\r\n\r\n",
973 |req| {
974 assert_eq!(req.method.unwrap(), "GET");
975 assert_eq!(req.path.unwrap(), "/");
976 assert_eq!(req.version.unwrap(), 1);
977 assert_eq!(req.headers.len(), 0);
978 }
979 }
980
981 req! {
982 test_request_simple_with_query_params,
983 b"GET /thing?data=a HTTP/1.1\r\n\r\n",
984 |req| {
985 assert_eq!(req.method.unwrap(), "GET");
986 assert_eq!(req.path.unwrap(), "/thing?data=a");
987 assert_eq!(req.version.unwrap(), 1);
988 assert_eq!(req.headers.len(), 0);
989 }
990 }
991
992 req! {
993 test_request_simple_with_whatwg_query_params,
994 b"GET /thing?data=a^ HTTP/1.1\r\n\r\n",
995 |req| {
996 assert_eq!(req.method.unwrap(), "GET");
997 assert_eq!(req.path.unwrap(), "/thing?data=a^");
998 assert_eq!(req.version.unwrap(), 1);
999 assert_eq!(req.headers.len(), 0);
1000 }
1001 }
1002
1003 req! {
1004 test_request_headers,
1005 b"GET / HTTP/1.1\r\nHost: foo.com\r\nCookie: \r\n\r\n",
1006 |req| {
1007 assert_eq!(req.method.unwrap(), "GET");
1008 assert_eq!(req.path.unwrap(), "/");
1009 assert_eq!(req.version.unwrap(), 1);
1010 assert_eq!(req.headers.len(), 2);
1011 assert_eq!(req.headers[0].name, "Host");
1012 assert_eq!(req.headers[0].value, b"foo.com");
1013 assert_eq!(req.headers[1].name, "Cookie");
1014 assert_eq!(req.headers[1].value, b"");
1015 }
1016 }
1017
1018 req! {
1019 test_request_headers_optional_whitespace,
1020 b"GET / HTTP/1.1\r\nHost: \tfoo.com\t \r\nCookie: \t \r\n\r\n",
1021 |req| {
1022 assert_eq!(req.method.unwrap(), "GET");
1023 assert_eq!(req.path.unwrap(), "/");
1024 assert_eq!(req.version.unwrap(), 1);
1025 assert_eq!(req.headers.len(), 2);
1026 assert_eq!(req.headers[0].name, "Host");
1027 assert_eq!(req.headers[0].value, b"foo.com");
1028 assert_eq!(req.headers[1].name, "Cookie");
1029 assert_eq!(req.headers[1].value, b"");
1030 }
1031 }
1032
1033 req! {
1034 test_request_header_value_htab_short,
1036 b"GET / HTTP/1.1\r\nUser-Agent: some\tagent\r\n\r\n",
1037 |req| {
1038 assert_eq!(req.method.unwrap(), "GET");
1039 assert_eq!(req.path.unwrap(), "/");
1040 assert_eq!(req.version.unwrap(), 1);
1041 assert_eq!(req.headers.len(), 1);
1042 assert_eq!(req.headers[0].name, "User-Agent");
1043 assert_eq!(req.headers[0].value, b"some\tagent");
1044 }
1045 }
1046
1047 req! {
1048 test_request_header_value_htab_med,
1050 b"GET / HTTP/1.1\r\nUser-Agent: 1234567890some\tagent\r\n\r\n",
1051 |req| {
1052 assert_eq!(req.method.unwrap(), "GET");
1053 assert_eq!(req.path.unwrap(), "/");
1054 assert_eq!(req.version.unwrap(), 1);
1055 assert_eq!(req.headers.len(), 1);
1056 assert_eq!(req.headers[0].name, "User-Agent");
1057 assert_eq!(req.headers[0].value, b"1234567890some\tagent");
1058 }
1059 }
1060
1061 req! {
1062 test_request_header_value_htab_long,
1064 b"GET / HTTP/1.1\r\nUser-Agent: 1234567890some\t1234567890agent1234567890\r\n\r\n",
1065 |req| {
1066 assert_eq!(req.method.unwrap(), "GET");
1067 assert_eq!(req.path.unwrap(), "/");
1068 assert_eq!(req.version.unwrap(), 1);
1069 assert_eq!(req.headers.len(), 1);
1070 assert_eq!(req.headers[0].name, "User-Agent");
1071 assert_eq!(req.headers[0].value, &b"1234567890some\t1234567890agent1234567890"[..]);
1072 }
1073 }
1074
1075 req! {
1076 test_request_header_no_space_after_colon,
1078 b"GET / HTTP/1.1\r\nUser-Agent:omg-no-space1234567890some1234567890agent1234567890\r\n\r\n",
1079 |req| {
1080 assert_eq!(req.method.unwrap(), "GET");
1081 assert_eq!(req.path.unwrap(), "/");
1082 assert_eq!(req.version.unwrap(), 1);
1083 assert_eq!(req.headers.len(), 1);
1084 assert_eq!(req.headers[0].name, "User-Agent");
1085 assert_eq!(req.headers[0].value, &b"omg-no-space1234567890some1234567890agent1234567890"[..]);
1086 }
1087 }
1088
1089 req! {
1090 test_request_headers_max,
1091 b"GET / HTTP/1.1\r\nA: A\r\nB: B\r\nC: C\r\nD: D\r\n\r\n",
1092 |req| {
1093 assert_eq!(req.headers.len(), NUM_OF_HEADERS);
1094 }
1095 }
1096
1097 req! {
1098 test_request_multibyte,
1099 b"GET / HTTP/1.1\r\nHost: foo.com\r\nUser-Agent: \xe3\x81\xb2\xe3/1.0\r\n\r\n",
1100 |req| {
1101 assert_eq!(req.method.unwrap(), "GET");
1102 assert_eq!(req.path.unwrap(), "/");
1103 assert_eq!(req.version.unwrap(), 1);
1104 assert_eq!(req.headers.len(), 2);
1105 assert_eq!(req.headers[0].name, "Host");
1106 assert_eq!(req.headers[0].value, b"foo.com");
1107 assert_eq!(req.headers[1].name, "User-Agent");
1108 assert_eq!(req.headers[1].value, b"\xe3\x81\xb2\xe3/1.0");
1109 }
1110 }
1111
1112 req! {
1114 test_request_one_byte_method,
1115 b"G", Ok(Status::Partial),
1116 |_req| {}
1117 }
1118
1119 req! {
1121 test_request_partial_method,
1122 b"GE", Ok(Status::Partial),
1123 |_req| {}
1124 }
1125
1126 req! {
1128 test_request_method_no_delimiter,
1129 b"GET", Ok(Status::Partial),
1130 |_req| {}
1131 }
1132
1133 req! {
1136 test_request_method_only,
1137 b"GET ", Ok(Status::Partial),
1138 |_req| {}
1139 }
1140
1141 req! {
1142 test_request_partial,
1143 b"GET / HTTP/1.1\r\n\r", Ok(Status::Partial),
1144 |_req| {}
1145 }
1146
1147 req! {
1148 test_request_partial_version,
1149 b"GET / HTTP/1.", Ok(Status::Partial),
1150 |_req| {}
1151 }
1152
1153 req! {
1154 test_request_method_path_no_delimiter,
1155 b"GET /", Ok(Status::Partial),
1156 |_req| {}
1157 }
1158
1159 req! {
1160 test_request_method_path_only,
1161 b"GET / ", Ok(Status::Partial),
1162 |_req| {}
1163 }
1164
1165 req! {
1166 test_request_partial_parses_headers_as_much_as_it_can,
1167 b"GET / HTTP/1.1\r\nHost: yolo\r\n",
1168 Ok(crate::Status::Partial),
1169 |req| {
1170 assert_eq!(req.method.unwrap(), "GET");
1171 assert_eq!(req.path.unwrap(), "/");
1172 assert_eq!(req.version.unwrap(), 1);
1173 assert_eq!(req.headers.len(), NUM_OF_HEADERS); assert_eq!(req.headers[0].name, "Host");
1175 assert_eq!(req.headers[0].value, b"yolo");
1176 }
1177 }
1178
1179 req! {
1180 test_request_newlines,
1181 b"GET / HTTP/1.1\nHost: foo.bar\n\n",
1182 |_r| {}
1183 }
1184
1185 req! {
1186 test_request_empty_lines_prefix,
1187 b"\r\n\r\nGET / HTTP/1.1\r\n\r\n",
1188 |req| {
1189 assert_eq!(req.method.unwrap(), "GET");
1190 assert_eq!(req.path.unwrap(), "/");
1191 assert_eq!(req.version.unwrap(), 1);
1192 assert_eq!(req.headers.len(), 0);
1193 }
1194 }
1195
1196 req! {
1197 test_request_empty_lines_prefix_lf_only,
1198 b"\n\nGET / HTTP/1.1\n\n",
1199 |req| {
1200 assert_eq!(req.method.unwrap(), "GET");
1201 assert_eq!(req.path.unwrap(), "/");
1202 assert_eq!(req.version.unwrap(), 1);
1203 assert_eq!(req.headers.len(), 0);
1204 }
1205 }
1206
1207 req! {
1208 test_request_path_backslash,
1209 b"\n\nGET /\\?wayne\\=5 HTTP/1.1\n\n",
1210 |req| {
1211 assert_eq!(req.method.unwrap(), "GET");
1212 assert_eq!(req.path.unwrap(), "/\\?wayne\\=5");
1213 assert_eq!(req.version.unwrap(), 1);
1214 assert_eq!(req.headers.len(), 0);
1215 }
1216 }
1217
1218 req! {
1219 test_request_with_invalid_token_delimiter,
1220 b"GET\n/ HTTP/1.1\r\nHost: foo.bar\r\n\r\n",
1221 Err(crate::Error::Token),
1222 |_r| {}
1223 }
1224
1225 req! {
1226 test_request_with_invalid_but_short_version,
1227 b"GET / HTTP/1!",
1228 Err(crate::Error::Version),
1229 |_r| {}
1230 }
1231
1232 req! {
1233 test_request_with_empty_method,
1234 b" / HTTP/1.1\r\n\r\n",
1235 Err(crate::Error::Token),
1236 |_r| {}
1237 }
1238
1239 req! {
1240 test_request_with_empty_path,
1241 b"GET HTTP/1.1\r\n\r\n",
1242 Err(crate::Error::Token),
1243 |_r| {}
1244 }
1245
1246 req! {
1247 test_request_with_empty_method_and_path,
1248 b" HTTP/1.1\r\n\r\n",
1249 Err(crate::Error::Token),
1250 |_r| {}
1251 }
1252
1253 macro_rules! res {
1254 ($name:ident, $buf:expr, |$arg:ident| $body:expr) => {
1255 res! {$name, $buf, Ok(Status::Complete($buf.len())), |$arg| $body }
1256 };
1257 ($name:ident, $buf:expr, $len:expr, |$arg:ident| $body:expr) => {
1258 #[test]
1259 fn $name() {
1260 let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
1261 let mut res = Response::new(&mut headers[..]);
1262 let status = res.parse($buf.as_ref());
1263 assert_eq!(status, $len);
1264 closure(res);
1265
1266 fn closure($arg: Response) {
1267 $body
1268 }
1269 }
1270 };
1271 }
1272
1273 res! {
1274 test_response_simple,
1275 b"HTTP/1.1 200 OK\r\n\r\n",
1276 |res| {
1277 assert_eq!(res.version.unwrap(), 1);
1278 assert_eq!(res.code.unwrap(), 200);
1279 assert_eq!(res.reason.unwrap(), "OK");
1280 }
1281 }
1282
1283 res! {
1284 test_response_newlines,
1285 b"HTTP/1.0 403 Forbidden\nServer: foo.bar\n\n",
1286 |_r| {}
1287 }
1288
1289 res! {
1290 test_response_reason_missing,
1291 b"HTTP/1.1 200 \r\n\r\n",
1292 |res| {
1293 assert_eq!(res.version.unwrap(), 1);
1294 assert_eq!(res.code.unwrap(), 200);
1295 assert_eq!(res.reason.unwrap(), "");
1296 }
1297 }
1298
1299 res! {
1300 test_response_reason_missing_no_space,
1301 b"HTTP/1.1 200\r\n\r\n",
1302 |res| {
1303 assert_eq!(res.version.unwrap(), 1);
1304 assert_eq!(res.code.unwrap(), 200);
1305 assert_eq!(res.reason.unwrap(), "");
1306 }
1307 }
1308
1309 res! {
1310 test_response_reason_missing_no_space_with_headers,
1311 b"HTTP/1.1 200\r\nFoo: bar\r\n\r\n",
1312 |res| {
1313 assert_eq!(res.version.unwrap(), 1);
1314 assert_eq!(res.code.unwrap(), 200);
1315 assert_eq!(res.reason.unwrap(), "");
1316 assert_eq!(res.headers.len(), 1);
1317 assert_eq!(res.headers[0].name, "Foo");
1318 assert_eq!(res.headers[0].value, b"bar");
1319 }
1320 }
1321
1322 res! {
1323 test_response_reason_with_space_and_tab,
1324 b"HTTP/1.1 101 Switching Protocols\t\r\n\r\n",
1325 |res| {
1326 assert_eq!(res.version.unwrap(), 1);
1327 assert_eq!(res.code.unwrap(), 101);
1328 assert_eq!(res.reason.unwrap(), "Switching Protocols\t");
1329 }
1330 }
1331
1332 static RESPONSE_REASON_WITH_OBS_TEXT_BYTE: &[u8] = b"HTTP/1.1 200 X\xFFZ\r\n\r\n";
1333 res! {
1334 test_response_reason_with_obsolete_text_byte,
1335 RESPONSE_REASON_WITH_OBS_TEXT_BYTE,
1336 |res| {
1337 assert_eq!(res.version.unwrap(), 1);
1338 assert_eq!(res.code.unwrap(), 200);
1339 assert_eq!(res.reason.unwrap(), "");
1341 }
1342 }
1343
1344 res! {
1345 test_response_reason_with_nul_byte,
1346 b"HTTP/1.1 200 \x00\r\n\r\n",
1347 Err(crate::Error::Status),
1348 |_res| {}
1349 }
1350
1351 res! {
1352 test_response_version_missing_space,
1353 b"HTTP/1.1",
1354 Ok(Status::Partial),
1355 |_res| {}
1356 }
1357
1358 res! {
1359 test_response_code_missing_space,
1360 b"HTTP/1.1 200",
1361 Ok(Status::Partial),
1362 |_res| {}
1363 }
1364
1365 res! {
1366 test_response_partial_parses_headers_as_much_as_it_can,
1367 b"HTTP/1.1 200 OK\r\nServer: yolo\r\n",
1368 Ok(crate::Status::Partial),
1369 |res| {
1370 assert_eq!(res.version.unwrap(), 1);
1371 assert_eq!(res.code.unwrap(), 200);
1372 assert_eq!(res.reason.unwrap(), "OK");
1373 assert_eq!(res.headers.len(), NUM_OF_HEADERS); assert_eq!(res.headers[0].name, "Server");
1375 assert_eq!(res.headers[0].value, b"yolo");
1376 }
1377 }
1378
1379 res! {
1380 test_response_empty_lines_prefix_lf_only,
1381 b"\n\nHTTP/1.1 200 OK\n\n",
1382 |_res| {}
1383 }
1384
1385 res! {
1386 test_response_no_cr,
1387 b"HTTP/1.0 200\nContent-type: text/html\n\n",
1388 |res| {
1389 assert_eq!(res.version.unwrap(), 0);
1390 assert_eq!(res.code.unwrap(), 200);
1391 assert_eq!(res.reason.unwrap(), "");
1392 assert_eq!(res.headers.len(), 1);
1393 assert_eq!(res.headers[0].name, "Content-type");
1394 assert_eq!(res.headers[0].value, b"text/html");
1395 }
1396 }
1397
1398 #[test]
1400 fn partial_permutations() {
1401 let req_str = "GET / HTTP/1.1\r\n\r\n";
1402 let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
1403 let mut req = Request::new(&mut headers[..]);
1404 for i in 0..req_str.len() {
1405 let status = req.parse(&req_str.as_bytes()[..i]);
1406 assert_eq!(
1407 status,
1408 Ok(Status::Partial),
1409 "partial request line should return partial. \
1410 Portion which failed: '{seg}' (below {i})",
1411 seg = &req_str[..i]
1412 );
1413 }
1414 }
1415
1416 static RESPONSE_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON: &[u8] =
1417 b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Credentials : true\r\nBread: baguette\r\n\r\n";
1418
1419 #[test]
1420 fn test_forbid_response_with_whitespace_between_header_name_and_colon() {
1421 let mut headers = [EMPTY_HEADER; 2];
1422 let mut response = Response::new(&mut headers[..]);
1423 let result = response.parse(RESPONSE_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON);
1424
1425 assert_eq!(result, Err(crate::Error::HeaderName));
1426 }
1427
1428 #[test]
1429 fn test_allow_response_with_whitespace_between_header_name_and_colon() {
1430 let mut headers = [EMPTY_HEADER; 2];
1431 let mut response = Response::new(&mut headers[..]);
1432 let result = crate::ParserConfig::default()
1433 .allow_spaces_after_header_name_in_responses(true)
1434 .parse_response(
1435 &mut response,
1436 RESPONSE_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON,
1437 );
1438
1439 assert_eq!(result, Ok(Status::Complete(77)));
1440 assert_eq!(response.version.unwrap(), 1);
1441 assert_eq!(response.code.unwrap(), 200);
1442 assert_eq!(response.reason.unwrap(), "OK");
1443 assert_eq!(response.headers.len(), 2);
1444 assert_eq!(response.headers[0].name, "Access-Control-Allow-Credentials");
1445 assert_eq!(response.headers[0].value, &b"true"[..]);
1446 assert_eq!(response.headers[1].name, "Bread");
1447 assert_eq!(response.headers[1].value, &b"baguette"[..]);
1448 }
1449
1450 #[test]
1451 fn test_ignore_header_line_with_whitespaces_after_header_name_in_response() {
1452 let mut headers = [EMPTY_HEADER; 2];
1453 let mut response = Response::new(&mut headers[..]);
1454 let result = crate::ParserConfig::default()
1455 .ignore_invalid_headers_in_responses(true)
1456 .parse_response(
1457 &mut response,
1458 RESPONSE_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON,
1459 );
1460
1461 assert_eq!(result, Ok(Status::Complete(77)));
1462 assert_eq!(response.version.unwrap(), 1);
1463 assert_eq!(response.code.unwrap(), 200);
1464 assert_eq!(response.reason.unwrap(), "OK");
1465 assert_eq!(response.headers.len(), 1);
1466 assert_eq!(response.headers[0].name, "Bread");
1467 assert_eq!(response.headers[0].value, &b"baguette"[..]);
1468 }
1469
1470 static REQUEST_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON: &[u8] =
1471 b"GET / HTTP/1.1\r\nHost : localhost\r\n\r\n";
1472
1473 #[test]
1474 fn test_forbid_request_with_whitespace_between_header_name_and_colon() {
1475 let mut headers = [EMPTY_HEADER; 1];
1476 let mut request = Request::new(&mut headers[..]);
1477 let result = request.parse(REQUEST_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON);
1478
1479 assert_eq!(result, Err(crate::Error::HeaderName));
1480 }
1481
1482 #[test]
1483 fn test_ignore_header_line_with_whitespaces_after_header_name_in_request() {
1484 let mut headers = [EMPTY_HEADER; 2];
1485 let mut request = Request::new(&mut headers[..]);
1486 let result = crate::ParserConfig::default()
1487 .ignore_invalid_headers_in_requests(true)
1488 .parse_request(
1489 &mut request,
1490 REQUEST_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON,
1491 );
1492
1493 assert_eq!(result, Ok(Status::Complete(36)));
1494 }
1495
1496 static RESPONSE_WITH_OBSOLETE_LINE_FOLDING_AT_START: &[u8] =
1497 b"HTTP/1.1 200 OK\r\nLine-Folded-Header: \r\n \r\n hello there\r\n\r\n";
1498
1499 #[test]
1500 fn test_forbid_response_with_obsolete_line_folding_at_start() {
1501 let mut headers = [EMPTY_HEADER; 1];
1502 let mut response = Response::new(&mut headers[..]);
1503 let result = response.parse(RESPONSE_WITH_OBSOLETE_LINE_FOLDING_AT_START);
1504
1505 assert_eq!(result, Err(crate::Error::HeaderName));
1506 }
1507
1508 #[test]
1509 fn test_allow_response_with_obsolete_line_folding_at_start() {
1510 let mut headers = [EMPTY_HEADER; 1];
1511 let mut response = Response::new(&mut headers[..]);
1512 let result = crate::ParserConfig::default()
1513 .allow_obsolete_multiline_headers_in_responses(true)
1514 .parse_response(&mut response, RESPONSE_WITH_OBSOLETE_LINE_FOLDING_AT_START);
1515
1516 assert_eq!(
1517 result,
1518 Ok(Status::Complete(
1519 RESPONSE_WITH_OBSOLETE_LINE_FOLDING_AT_START.len()
1520 ))
1521 );
1522 assert_eq!(response.version.unwrap(), 1);
1523 assert_eq!(response.code.unwrap(), 200);
1524 assert_eq!(response.reason.unwrap(), "OK");
1525 assert_eq!(response.headers.len(), 1);
1526 assert_eq!(response.headers[0].name, "Line-Folded-Header");
1527 assert_eq!(response.headers[0].value, &b"hello there"[..]);
1528 }
1529
1530 static RESPONSE_WITH_OBSOLETE_LINE_FOLDING_AT_END: &[u8] =
1531 b"HTTP/1.1 200 OK\r\nLine-Folded-Header: hello there\r\n \r\n \r\n\r\n";
1532
1533 #[test]
1534 fn test_forbid_response_with_obsolete_line_folding_at_end() {
1535 let mut headers = [EMPTY_HEADER; 1];
1536 let mut response = Response::new(&mut headers[..]);
1537 let result = response.parse(RESPONSE_WITH_OBSOLETE_LINE_FOLDING_AT_END);
1538
1539 assert_eq!(result, Err(crate::Error::HeaderName));
1540 }
1541
1542 #[test]
1543 fn test_allow_response_with_obsolete_line_folding_at_end() {
1544 let mut headers = [EMPTY_HEADER; 1];
1545 let mut response = Response::new(&mut headers[..]);
1546 let result = crate::ParserConfig::default()
1547 .allow_obsolete_multiline_headers_in_responses(true)
1548 .parse_response(&mut response, RESPONSE_WITH_OBSOLETE_LINE_FOLDING_AT_END);
1549
1550 assert_eq!(
1551 result,
1552 Ok(Status::Complete(
1553 RESPONSE_WITH_OBSOLETE_LINE_FOLDING_AT_END.len()
1554 ))
1555 );
1556 assert_eq!(response.version.unwrap(), 1);
1557 assert_eq!(response.code.unwrap(), 200);
1558 assert_eq!(response.reason.unwrap(), "OK");
1559 assert_eq!(response.headers.len(), 1);
1560 assert_eq!(response.headers[0].name, "Line-Folded-Header");
1561 assert_eq!(response.headers[0].value, &b"hello there"[..]);
1562 }
1563
1564 static RESPONSE_WITH_OBSOLETE_LINE_FOLDING_IN_MIDDLE: &[u8] =
1565 b"HTTP/1.1 200 OK\r\nLine-Folded-Header: hello \r\n \r\n there\r\n\r\n";
1566
1567 #[test]
1568 fn test_forbid_response_with_obsolete_line_folding_in_middle() {
1569 let mut headers = [EMPTY_HEADER; 1];
1570 let mut response = Response::new(&mut headers[..]);
1571 let result = response.parse(RESPONSE_WITH_OBSOLETE_LINE_FOLDING_IN_MIDDLE);
1572
1573 assert_eq!(result, Err(crate::Error::HeaderName));
1574 }
1575
1576 #[test]
1577 fn test_allow_response_with_obsolete_line_folding_in_middle() {
1578 let mut headers = [EMPTY_HEADER; 1];
1579 let mut response = Response::new(&mut headers[..]);
1580 let result = crate::ParserConfig::default()
1581 .allow_obsolete_multiline_headers_in_responses(true)
1582 .parse_response(&mut response, RESPONSE_WITH_OBSOLETE_LINE_FOLDING_IN_MIDDLE);
1583
1584 assert_eq!(
1585 result,
1586 Ok(Status::Complete(
1587 RESPONSE_WITH_OBSOLETE_LINE_FOLDING_IN_MIDDLE.len()
1588 ))
1589 );
1590 assert_eq!(response.version.unwrap(), 1);
1591 assert_eq!(response.code.unwrap(), 200);
1592 assert_eq!(response.reason.unwrap(), "OK");
1593 assert_eq!(response.headers.len(), 1);
1594 assert_eq!(response.headers[0].name, "Line-Folded-Header");
1595 assert_eq!(response.headers[0].value, &b"hello \r\n \r\n there"[..]);
1596 }
1597
1598 static RESPONSE_WITH_OBSOLETE_LINE_FOLDING_IN_EMPTY_HEADER: &[u8] =
1599 b"HTTP/1.1 200 OK\r\nLine-Folded-Header: \r\n \r\n \r\n\r\n";
1600
1601 #[test]
1602 fn test_forbid_response_with_obsolete_line_folding_in_empty_header() {
1603 let mut headers = [EMPTY_HEADER; 1];
1604 let mut response = Response::new(&mut headers[..]);
1605 let result = response.parse(RESPONSE_WITH_OBSOLETE_LINE_FOLDING_IN_EMPTY_HEADER);
1606
1607 assert_eq!(result, Err(crate::Error::HeaderName));
1608 }
1609
1610 #[test]
1611 fn test_allow_response_with_obsolete_line_folding_in_empty_header() {
1612 let mut headers = [EMPTY_HEADER; 1];
1613 let mut response = Response::new(&mut headers[..]);
1614 let result = crate::ParserConfig::default()
1615 .allow_obsolete_multiline_headers_in_responses(true)
1616 .parse_response(
1617 &mut response,
1618 RESPONSE_WITH_OBSOLETE_LINE_FOLDING_IN_EMPTY_HEADER,
1619 );
1620
1621 assert_eq!(
1622 result,
1623 Ok(Status::Complete(
1624 RESPONSE_WITH_OBSOLETE_LINE_FOLDING_IN_EMPTY_HEADER.len()
1625 ))
1626 );
1627 assert_eq!(response.version.unwrap(), 1);
1628 assert_eq!(response.code.unwrap(), 200);
1629 assert_eq!(response.reason.unwrap(), "OK");
1630 assert_eq!(response.headers.len(), 1);
1631 assert_eq!(response.headers[0].name, "Line-Folded-Header");
1632 assert_eq!(response.headers[0].value, &b""[..]);
1633 }
1634
1635 #[test]
1636 fn test_chunk_size() {
1637 assert_eq!(parse_chunk_size(b"0\r\n"), Ok(Status::Complete((3, 0))));
1638 assert_eq!(
1639 parse_chunk_size(b"12\r\nchunk"),
1640 Ok(Status::Complete((4, 18)))
1641 );
1642 assert_eq!(
1643 parse_chunk_size(b"3086d\r\n"),
1644 Ok(Status::Complete((7, 198765)))
1645 );
1646 assert_eq!(
1647 parse_chunk_size(b"3735AB1;foo bar*\r\n"),
1648 Ok(Status::Complete((18, 57891505)))
1649 );
1650 assert_eq!(
1651 parse_chunk_size(b"3735ab1 ; baz \r\n"),
1652 Ok(Status::Complete((16, 57891505)))
1653 );
1654 assert_eq!(parse_chunk_size(b"77a65\r"), Ok(Status::Partial));
1655 assert_eq!(parse_chunk_size(b"ab"), Ok(Status::Partial));
1656 assert_eq!(
1657 parse_chunk_size(b"567f8a\rfoo"),
1658 Err(crate::InvalidChunkSize)
1659 );
1660 assert_eq!(
1661 parse_chunk_size(b"567f8a\rfoo"),
1662 Err(crate::InvalidChunkSize)
1663 );
1664 assert_eq!(
1665 parse_chunk_size(b"567xf8a\r\n"),
1666 Err(crate::InvalidChunkSize)
1667 );
1668 assert_eq!(
1669 parse_chunk_size(b"ffffffffffffffff\r\n"),
1670 Ok(Status::Complete((18, u64::MAX)))
1671 );
1672 assert_eq!(
1673 parse_chunk_size(b"1ffffffffffffffff\r\n"),
1674 Err(crate::InvalidChunkSize)
1675 );
1676 assert_eq!(
1677 parse_chunk_size(b"Affffffffffffffff\r\n"),
1678 Err(crate::InvalidChunkSize)
1679 );
1680 assert_eq!(
1681 parse_chunk_size(b"fffffffffffffffff\r\n"),
1682 Err(crate::InvalidChunkSize)
1683 );
1684 }
1685
1686 static RESPONSE_WITH_MULTIPLE_SPACE_DELIMITERS: &[u8] = b"HTTP/1.1 200 OK\r\n\r\n";
1687
1688 #[test]
1689 fn test_forbid_response_with_multiple_space_delimiters() {
1690 let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
1691 let mut response = Response::new(&mut headers[..]);
1692 let result = response.parse(RESPONSE_WITH_MULTIPLE_SPACE_DELIMITERS);
1693
1694 assert_eq!(result, Err(crate::Error::Status));
1695 }
1696
1697 #[test]
1698 fn test_allow_response_with_multiple_space_delimiters() {
1699 let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
1700 let mut response = Response::new(&mut headers[..]);
1701 let result = crate::ParserConfig::default()
1702 .allow_multiple_spaces_in_response_status_delimiters(true)
1703 .parse_response(&mut response, RESPONSE_WITH_MULTIPLE_SPACE_DELIMITERS);
1704
1705 assert_eq!(
1706 result,
1707 Ok(Status::Complete(
1708 RESPONSE_WITH_MULTIPLE_SPACE_DELIMITERS.len()
1709 ))
1710 );
1711 assert_eq!(response.version.unwrap(), 1);
1712 assert_eq!(response.code.unwrap(), 200);
1713 assert_eq!(response.reason.unwrap(), "OK");
1714 assert_eq!(response.headers.len(), 0);
1715 }
1716
1717 static RESPONSE_WITH_WEIRD_WHITESPACE_DELIMITERS: &[u8] = b"HTTP/1.1 200\rOK\r\n\r\n";
1720
1721 #[test]
1722 fn test_forbid_response_with_weird_whitespace_delimiters() {
1723 let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
1724 let mut response = Response::new(&mut headers[..]);
1725 let result = response.parse(RESPONSE_WITH_WEIRD_WHITESPACE_DELIMITERS);
1726
1727 assert_eq!(result, Err(crate::Error::Status));
1728 }
1729
1730 #[test]
1731 fn test_still_forbid_response_with_weird_whitespace_delimiters() {
1732 let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
1733 let mut response = Response::new(&mut headers[..]);
1734 let result = crate::ParserConfig::default()
1735 .allow_multiple_spaces_in_response_status_delimiters(true)
1736 .parse_response(&mut response, RESPONSE_WITH_WEIRD_WHITESPACE_DELIMITERS);
1737 assert_eq!(result, Err(crate::Error::Status));
1738 }
1739
1740 static REQUEST_WITH_MULTIPLE_SPACE_DELIMITERS: &[u8] = b"GET / HTTP/1.1\r\n\r\n";
1741
1742 #[test]
1743 fn test_forbid_request_with_multiple_space_delimiters() {
1744 let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
1745 let mut request = Request::new(&mut headers[..]);
1746 let result = request.parse(REQUEST_WITH_MULTIPLE_SPACE_DELIMITERS);
1747
1748 assert_eq!(result, Err(crate::Error::Token));
1749 }
1750
1751 #[test]
1752 fn test_allow_request_with_multiple_space_delimiters() {
1753 let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
1754 let mut request = Request::new(&mut headers[..]);
1755 let result = crate::ParserConfig::default()
1756 .allow_multiple_spaces_in_request_line_delimiters(true)
1757 .parse_request(&mut request, REQUEST_WITH_MULTIPLE_SPACE_DELIMITERS);
1758
1759 assert_eq!(
1760 result,
1761 Ok(Status::Complete(
1762 REQUEST_WITH_MULTIPLE_SPACE_DELIMITERS.len()
1763 ))
1764 );
1765 assert_eq!(request.method.unwrap(), "GET");
1766 assert_eq!(request.path.unwrap(), "/");
1767 assert_eq!(request.version.unwrap(), 1);
1768 assert_eq!(request.headers.len(), 0);
1769 }
1770
1771 static REQUEST_WITH_WEIRD_WHITESPACE_DELIMITERS: &[u8] = b"GET\r/\rHTTP/1.1\r\n\r\n";
1774
1775 #[test]
1776 fn test_forbid_request_with_weird_whitespace_delimiters() {
1777 let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
1778 let mut request = Request::new(&mut headers[..]);
1779 let result = request.parse(REQUEST_WITH_WEIRD_WHITESPACE_DELIMITERS);
1780
1781 assert_eq!(result, Err(crate::Error::Token));
1782 }
1783
1784 #[test]
1785 fn test_still_forbid_request_with_weird_whitespace_delimiters() {
1786 let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
1787 let mut request = Request::new(&mut headers[..]);
1788 let result = crate::ParserConfig::default()
1789 .allow_multiple_spaces_in_request_line_delimiters(true)
1790 .parse_request(&mut request, REQUEST_WITH_WEIRD_WHITESPACE_DELIMITERS);
1791 assert_eq!(result, Err(crate::Error::Token));
1792 }
1793
1794 static REQUEST_WITH_MULTIPLE_SPACES_AND_BAD_PATH: &[u8] = b"GET /foo ohno HTTP/1.1\r\n\r\n";
1795
1796 #[test]
1797 fn test_request_with_multiple_spaces_and_bad_path() {
1798 let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
1799 let mut request = Request::new(&mut headers[..]);
1800 let result = crate::ParserConfig::default()
1801 .allow_multiple_spaces_in_request_line_delimiters(true)
1802 .parse_request(&mut request, REQUEST_WITH_MULTIPLE_SPACES_AND_BAD_PATH);
1803 assert_eq!(result, Err(crate::Error::Version));
1804 }
1805
1806 static REQUEST_WITH_DEL_IN_PATH: &[u8] = b"GET /foo\x7Fohno HTTP/1.1\r\n\r\n";
1810
1811 #[test]
1812 fn test_request_with_del_in_path() {
1813 let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
1814 let mut request = Request::new(&mut headers[..]);
1815 let result = crate::ParserConfig::default()
1816 .allow_multiple_spaces_in_request_line_delimiters(true)
1817 .parse_request(&mut request, crate::tests::REQUEST_WITH_DEL_IN_PATH);
1818 assert_eq!(result, Err(crate::Error::Token));
1819 }
1820
1821 #[test]
1822 #[cfg_attr(miri, ignore)] fn test_all_utf8_char_in_paths() {
1824 for i in 128..256 {
1826 for j in 128..256 {
1827 let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
1828 let mut request = Request::new(&mut headers[..]);
1829 let bytes = [i as u8, j as u8];
1830
1831 match core::str::from_utf8(&bytes) {
1832 Ok(s) => {
1833 let first_line = format!("GET /{} HTTP/1.1\r\n\r\n", s);
1834 let result = crate::ParserConfig::default()
1835 .allow_multiple_spaces_in_request_line_delimiters(true)
1836 .parse_request(&mut request, first_line.as_bytes());
1837
1838 assert_eq!(
1839 result,
1840 Ok(Status::Complete(20)),
1841 "failed for utf8 char i: {}, j: {}",
1842 i,
1843 j
1844 );
1845 }
1846 Err(_) => {
1847 let mut first_line = b"GET /".to_vec();
1848 first_line.extend(&bytes);
1849 first_line.extend(b" HTTP/1.1\r\n\r\n");
1850
1851 let result = crate::ParserConfig::default()
1852 .allow_multiple_spaces_in_request_line_delimiters(true)
1853 .parse_request(&mut request, first_line.as_slice());
1854
1855 assert_eq!(
1856 result,
1857 Err(crate::Error::Token),
1858 "failed for utf8 char i: {}, j: {}",
1859 i,
1860 j
1861 );
1862 }
1863 };
1864
1865 if i < 0xe0 {
1867 continue;
1868 }
1869
1870 for k in 128..256 {
1871 let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
1872 let mut request = Request::new(&mut headers[..]);
1873 let bytes = [i as u8, j as u8, k as u8];
1874
1875 match core::str::from_utf8(&bytes) {
1876 Ok(s) => {
1877 let first_line = format!("GET /{} HTTP/1.1\r\n\r\n", s);
1878 let result = crate::ParserConfig::default()
1879 .allow_multiple_spaces_in_request_line_delimiters(true)
1880 .parse_request(&mut request, first_line.as_bytes());
1881
1882 assert_eq!(
1883 result,
1884 Ok(Status::Complete(21)),
1885 "failed for utf8 char i: {}, j: {}, k: {}",
1886 i,
1887 j,
1888 k
1889 );
1890 }
1891 Err(_) => {
1892 let mut first_line = b"GET /".to_vec();
1893 first_line.extend(&bytes);
1894 first_line.extend(b" HTTP/1.1\r\n\r\n");
1895
1896 let result = crate::ParserConfig::default()
1897 .allow_multiple_spaces_in_request_line_delimiters(true)
1898 .parse_request(&mut request, first_line.as_slice());
1899
1900 assert_eq!(
1901 result,
1902 Err(crate::Error::Token),
1903 "failed for utf8 char i: {}, j: {}, k: {}",
1904 i,
1905 j,
1906 k
1907 );
1908 }
1909 };
1910
1911 if i < 0xf0 {
1913 continue;
1914 }
1915
1916 for l in 128..256 {
1917 let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
1918 let mut request = Request::new(&mut headers[..]);
1919 let bytes = [i as u8, j as u8, k as u8, l as u8];
1920
1921 match core::str::from_utf8(&bytes) {
1922 Ok(s) => {
1923 let first_line = format!("GET /{} HTTP/1.1\r\n\r\n", s);
1924 let result = crate::ParserConfig::default()
1925 .allow_multiple_spaces_in_request_line_delimiters(true)
1926 .parse_request(&mut request, first_line.as_bytes());
1927
1928 assert_eq!(
1929 result,
1930 Ok(Status::Complete(22)),
1931 "failed for utf8 char i: {}, j: {}, k: {}, l: {}",
1932 i,
1933 j,
1934 k,
1935 l
1936 );
1937 }
1938 Err(_) => {
1939 let mut first_line = b"GET /".to_vec();
1940 first_line.extend(&bytes);
1941 first_line.extend(b" HTTP/1.1\r\n\r\n");
1942
1943 let result = crate::ParserConfig::default()
1944 .allow_multiple_spaces_in_request_line_delimiters(true)
1945 .parse_request(&mut request, first_line.as_slice());
1946
1947 assert_eq!(
1948 result,
1949 Err(crate::Error::Token),
1950 "failed for utf8 char i: {}, j: {}, k: {}, l: {}",
1951 i,
1952 j,
1953 k,
1954 l
1955 );
1956 }
1957 };
1958 }
1959 }
1960 }
1961 }
1962 }
1963
1964 static RESPONSE_WITH_SPACES_IN_CODE: &[u8] = b"HTTP/1.1 99 200 OK\r\n\r\n";
1965
1966 #[test]
1967 fn test_response_with_spaces_in_code() {
1968 let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
1969 let mut response = Response::new(&mut headers[..]);
1970 let result = crate::ParserConfig::default()
1971 .allow_multiple_spaces_in_response_status_delimiters(true)
1972 .parse_response(&mut response, RESPONSE_WITH_SPACES_IN_CODE);
1973 assert_eq!(result, Err(crate::Error::Status));
1974 }
1975
1976 #[test]
1977 fn test_response_with_empty_header_name() {
1978 const RESPONSE: &[u8] = b"HTTP/1.1 200 OK\r\n: hello\r\nBread: baguette\r\n\r\n";
1979
1980 let mut headers = [EMPTY_HEADER; 2];
1981 let mut response = Response::new(&mut headers[..]);
1982
1983 let result = crate::ParserConfig::default()
1984 .allow_spaces_after_header_name_in_responses(true)
1985 .parse_response(&mut response, RESPONSE);
1986 assert_eq!(result, Err(crate::Error::HeaderName));
1987
1988 let result = crate::ParserConfig::default()
1989 .ignore_invalid_headers_in_responses(true)
1990 .parse_response(&mut response, RESPONSE);
1991 assert_eq!(result, Ok(Status::Complete(45)));
1992
1993 assert_eq!(response.version.unwrap(), 1);
1994 assert_eq!(response.code.unwrap(), 200);
1995 assert_eq!(response.reason.unwrap(), "OK");
1996 assert_eq!(response.headers.len(), 1);
1997 assert_eq!(response.headers[0].name, "Bread");
1998 assert_eq!(response.headers[0].value, &b"baguette"[..]);
1999 }
2000
2001 #[test]
2002 fn test_request_with_empty_header_name() {
2003 const RESPONSE: &[u8] = b"GET / HTTP/1.1\r\n: hello\r\nBread: baguette\r\n\r\n";
2004
2005 let mut headers = [EMPTY_HEADER; 2];
2006 let mut request = Request::new(&mut headers[..]);
2007
2008 let result = crate::ParserConfig::default().parse_request(&mut request, RESPONSE);
2009 assert_eq!(result, Err(crate::Error::HeaderName));
2010
2011 let result = crate::ParserConfig::default()
2012 .ignore_invalid_headers_in_requests(true)
2013 .parse_request(&mut request, RESPONSE);
2014 assert_eq!(result, Ok(Status::Complete(44)));
2015 }
2016
2017 #[test]
2018 fn test_request_with_whitespace_between_header_name_and_colon() {
2019 const REQUEST: &[u8] =
2020 b"GET / HTTP/1.1\r\nAccess-Control-Allow-Credentials : true\r\nBread: baguette\r\n\r\n";
2021
2022 let mut headers = [EMPTY_HEADER; 2];
2023 let mut request = Request::new(&mut headers[..]);
2024
2025 let result = crate::ParserConfig::default()
2026 .allow_spaces_after_header_name_in_responses(true)
2027 .parse_request(&mut request, REQUEST);
2028 assert_eq!(result, Err(crate::Error::HeaderName));
2029
2030 let result = crate::ParserConfig::default()
2031 .ignore_invalid_headers_in_responses(true)
2032 .parse_request(&mut request, REQUEST);
2033 assert_eq!(result, Err(crate::Error::HeaderName));
2034 }
2035
2036 #[test]
2037 fn test_response_with_invalid_char_between_header_name_and_colon() {
2038 const RESPONSE: &[u8] =
2039 b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Credentials\xFF : true\r\nBread: baguette\r\n\r\n";
2040
2041 let mut headers = [EMPTY_HEADER; 2];
2042 let mut response = Response::new(&mut headers[..]);
2043
2044 let result = crate::ParserConfig::default()
2045 .allow_spaces_after_header_name_in_responses(true)
2046 .parse_response(&mut response, RESPONSE);
2047 assert_eq!(result, Err(crate::Error::HeaderName));
2048
2049 let result = crate::ParserConfig::default()
2050 .ignore_invalid_headers_in_responses(true)
2051 .parse_response(&mut response, RESPONSE);
2052
2053 assert_eq!(result, Ok(Status::Complete(79)));
2054 assert_eq!(response.version.unwrap(), 1);
2055 assert_eq!(response.code.unwrap(), 200);
2056 assert_eq!(response.reason.unwrap(), "OK");
2057 assert_eq!(response.headers.len(), 1);
2058 assert_eq!(response.headers[0].name, "Bread");
2059 assert_eq!(response.headers[0].value, &b"baguette"[..]);
2060 }
2061
2062 #[test]
2063 fn test_request_with_invalid_char_between_header_name_and_colon() {
2064 const REQUEST: &[u8] =
2065 b"GET / HTTP/1.1\r\nAccess-Control-Allow-Credentials\xFF : true\r\nBread: baguette\r\n\r\n";
2066
2067 let mut headers = [EMPTY_HEADER; 2];
2068 let mut request = Request::new(&mut headers[..]);
2069
2070 let result = crate::ParserConfig::default().parse_request(&mut request, REQUEST);
2071 assert_eq!(result, Err(crate::Error::HeaderName));
2072
2073 let result = crate::ParserConfig::default()
2074 .ignore_invalid_headers_in_requests(true)
2075 .parse_request(&mut request, REQUEST);
2076 assert_eq!(result, Ok(Status::Complete(78)));
2077 }
2078
2079 #[test]
2080 fn test_ignore_header_line_with_missing_colon_in_response() {
2081 const RESPONSE: &[u8] =
2082 b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Credentials\r\nBread: baguette\r\n\r\n";
2083
2084 let mut headers = [EMPTY_HEADER; 2];
2085 let mut response = Response::new(&mut headers[..]);
2086
2087 let result = crate::ParserConfig::default().parse_response(&mut response, RESPONSE);
2088 assert_eq!(result, Err(crate::Error::HeaderName));
2089
2090 let result = crate::ParserConfig::default()
2091 .ignore_invalid_headers_in_responses(true)
2092 .parse_response(&mut response, RESPONSE);
2093 assert_eq!(result, Ok(Status::Complete(70)));
2094
2095 assert_eq!(response.version.unwrap(), 1);
2096 assert_eq!(response.code.unwrap(), 200);
2097 assert_eq!(response.reason.unwrap(), "OK");
2098 assert_eq!(response.headers.len(), 1);
2099 assert_eq!(response.headers[0].name, "Bread");
2100 assert_eq!(response.headers[0].value, &b"baguette"[..]);
2101 }
2102
2103 #[test]
2104 fn test_ignore_header_line_with_missing_colon_in_request() {
2105 const REQUEST: &[u8] =
2106 b"GET / HTTP/1.1\r\nAccess-Control-Allow-Credentials\r\nBread: baguette\r\n\r\n";
2107
2108 let mut headers = [EMPTY_HEADER; 2];
2109 let mut request = Request::new(&mut headers[..]);
2110
2111 let result = crate::ParserConfig::default().parse_request(&mut request, REQUEST);
2112 assert_eq!(result, Err(crate::Error::HeaderName));
2113
2114 let result = crate::ParserConfig::default()
2115 .ignore_invalid_headers_in_requests(true)
2116 .parse_request(&mut request, REQUEST);
2117 assert_eq!(result, Ok(Status::Complete(69)));
2118 }
2119
2120 #[test]
2121 fn test_response_header_with_missing_colon_with_folding() {
2122 const RESPONSE: &[u8] =
2123 b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Credentials \r\n hello\r\nBread: baguette\r\n\r\n";
2124
2125 let mut headers = [EMPTY_HEADER; 2];
2126 let mut response = Response::new(&mut headers[..]);
2127
2128 let result = crate::ParserConfig::default()
2129 .allow_obsolete_multiline_headers_in_responses(true)
2130 .allow_spaces_after_header_name_in_responses(true)
2131 .parse_response(&mut response, RESPONSE);
2132 assert_eq!(result, Err(crate::Error::HeaderName));
2133
2134 let result = crate::ParserConfig::default()
2135 .ignore_invalid_headers_in_responses(true)
2136 .parse_response(&mut response, RESPONSE);
2137 assert_eq!(result, Ok(Status::Complete(81)));
2138
2139 assert_eq!(response.version.unwrap(), 1);
2140 assert_eq!(response.code.unwrap(), 200);
2141 assert_eq!(response.reason.unwrap(), "OK");
2142 assert_eq!(response.headers.len(), 1);
2143 assert_eq!(response.headers[0].name, "Bread");
2144 assert_eq!(response.headers[0].value, &b"baguette"[..]);
2145 }
2146
2147 #[test]
2148 fn test_request_header_with_missing_colon_with_folding() {
2149 const REQUEST: &[u8] =
2150 b"GET / HTTP/1.1\r\nAccess-Control-Allow-Credentials \r\n hello\r\nBread: baguette\r\n\r\n";
2151
2152 let mut headers = [EMPTY_HEADER; 2];
2153 let mut request = Request::new(&mut headers[..]);
2154
2155 let result = crate::ParserConfig::default().parse_request(&mut request, REQUEST);
2156 assert_eq!(result, Err(crate::Error::HeaderName));
2157
2158 let result = crate::ParserConfig::default()
2159 .ignore_invalid_headers_in_requests(true)
2160 .parse_request(&mut request, REQUEST);
2161 assert_eq!(result, Ok(Status::Complete(80)));
2162 }
2163
2164 #[test]
2165 fn test_response_header_with_nul_in_header_name() {
2166 const RESPONSE: &[u8] =
2167 b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Cred\0entials: hello\r\nBread: baguette\r\n\r\n";
2168
2169 let mut headers = [EMPTY_HEADER; 2];
2170 let mut response = Response::new(&mut headers[..]);
2171
2172 let result = crate::ParserConfig::default().parse_response(&mut response, RESPONSE);
2173 assert_eq!(result, Err(crate::Error::HeaderName));
2174
2175 let result = crate::ParserConfig::default()
2176 .ignore_invalid_headers_in_responses(true)
2177 .parse_response(&mut response, RESPONSE);
2178 assert_eq!(result, Err(crate::Error::HeaderName));
2179 }
2180
2181 #[test]
2182 fn test_request_header_with_nul_in_header_name() {
2183 const REQUEST: &[u8] =
2184 b"GET / HTTP/1.1\r\nAccess-Control-Allow-Cred\0entials: hello\r\nBread: baguette\r\n\r\n";
2185
2186 let mut headers = [EMPTY_HEADER; 2];
2187 let mut request = Request::new(&mut headers[..]);
2188
2189 let result = crate::ParserConfig::default().parse_request(&mut request, REQUEST);
2190 assert_eq!(result, Err(crate::Error::HeaderName));
2191
2192 let result = crate::ParserConfig::default()
2193 .ignore_invalid_headers_in_requests(true)
2194 .parse_request(&mut request, REQUEST);
2195 assert_eq!(result, Err(crate::Error::HeaderName));
2196 }
2197
2198 #[test]
2199 fn test_header_with_cr_in_header_name() {
2200 const RESPONSE: &[u8] =
2201 b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Cred\rentials: hello\r\nBread: baguette\r\n\r\n";
2202
2203 let mut headers = [EMPTY_HEADER; 2];
2204 let mut response = Response::new(&mut headers[..]);
2205
2206 let result = crate::ParserConfig::default().parse_response(&mut response, RESPONSE);
2207 assert_eq!(result, Err(crate::Error::HeaderName));
2208
2209 let result = crate::ParserConfig::default()
2210 .ignore_invalid_headers_in_responses(true)
2211 .parse_response(&mut response, RESPONSE);
2212 assert_eq!(result, Err(crate::Error::HeaderName));
2213
2214 const REQUEST: &[u8] =
2215 b"GET / HTTP/1.1\r\nAccess-Control-Allow-Cred\rentials: hello\r\nBread: baguette\r\n\r\n";
2216
2217 let mut headers = [EMPTY_HEADER; 2];
2218 let mut request = Request::new(&mut headers[..]);
2219
2220 let result = crate::ParserConfig::default().parse_request(&mut request, REQUEST);
2221 assert_eq!(result, Err(crate::Error::HeaderName));
2222
2223 let result = crate::ParserConfig::default()
2224 .ignore_invalid_headers_in_requests(true)
2225 .parse_request(&mut request, REQUEST);
2226 assert_eq!(result, Err(crate::Error::HeaderName));
2227 }
2228
2229 #[test]
2230 fn test_header_with_nul_in_whitespace_before_colon() {
2231 const RESPONSE: &[u8] =
2232 b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Credentials \0: hello\r\nBread: baguette\r\n\r\n";
2233
2234 let mut headers = [EMPTY_HEADER; 2];
2235 let mut response = Response::new(&mut headers[..]);
2236
2237 let result = crate::ParserConfig::default()
2238 .allow_spaces_after_header_name_in_responses(true)
2239 .parse_response(&mut response, RESPONSE);
2240 assert_eq!(result, Err(crate::Error::HeaderName));
2241
2242 let result = crate::ParserConfig::default()
2243 .allow_spaces_after_header_name_in_responses(true)
2244 .ignore_invalid_headers_in_responses(true)
2245 .parse_response(&mut response, RESPONSE);
2246 assert_eq!(result, Err(crate::Error::HeaderName));
2247
2248 const REQUEST: &[u8] =
2249 b"GET / HTTP/1.1\r\nAccess-Control-Allow-Credentials \0: hello\r\nBread: baguette\r\n\r\n";
2250
2251 let mut headers = [EMPTY_HEADER; 2];
2252 let mut request = Request::new(&mut headers[..]);
2253
2254 let result = crate::ParserConfig::default()
2255 .ignore_invalid_headers_in_requests(true)
2256 .parse_request(&mut request, REQUEST);
2257 assert_eq!(result, Err(crate::Error::HeaderName));
2258 }
2259
2260 #[test]
2261 fn test_header_with_nul_in_value() {
2262 const RESPONSE: &[u8] =
2263 b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Credentials: hell\0o\r\nBread: baguette\r\n\r\n";
2264
2265 let mut headers = [EMPTY_HEADER; 2];
2266 let mut response = Response::new(&mut headers[..]);
2267
2268 let result = crate::ParserConfig::default().parse_response(&mut response, RESPONSE);
2269 assert_eq!(result, Err(crate::Error::HeaderValue));
2270
2271 let result = crate::ParserConfig::default()
2272 .ignore_invalid_headers_in_responses(true)
2273 .parse_response(&mut response, RESPONSE);
2274 assert_eq!(result, Err(crate::Error::HeaderValue));
2275
2276 const REQUEST: &[u8] =
2277 b"GET / HTTP/1.1\r\nAccess-Control-Allow-Credentials: hell\0o\r\nBread: baguette\r\n\r\n";
2278
2279 let mut headers = [EMPTY_HEADER; 2];
2280 let mut request = Request::new(&mut headers[..]);
2281
2282 let result = crate::ParserConfig::default().parse_request(&mut request, REQUEST);
2283 assert_eq!(result, Err(crate::Error::HeaderValue));
2284
2285 let result = crate::ParserConfig::default()
2286 .ignore_invalid_headers_in_requests(true)
2287 .parse_request(&mut request, REQUEST);
2288 assert_eq!(result, Err(crate::Error::HeaderValue));
2289 }
2290
2291 #[test]
2292 fn test_header_with_invalid_char_in_value() {
2293 const RESPONSE: &[u8] =
2294 b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Credentials: hell\x01o\r\nBread: baguette\r\n\r\n";
2295
2296 let mut headers = [EMPTY_HEADER; 2];
2297 let mut response = Response::new(&mut headers[..]);
2298
2299 let result = crate::ParserConfig::default().parse_response(&mut response, RESPONSE);
2300 assert_eq!(result, Err(crate::Error::HeaderValue));
2301
2302 let result = crate::ParserConfig::default()
2303 .ignore_invalid_headers_in_responses(true)
2304 .parse_response(&mut response, RESPONSE);
2305 assert_eq!(result, Ok(Status::Complete(78)));
2306
2307 assert_eq!(response.version.unwrap(), 1);
2308 assert_eq!(response.code.unwrap(), 200);
2309 assert_eq!(response.reason.unwrap(), "OK");
2310 assert_eq!(response.headers.len(), 1);
2311 assert_eq!(response.headers[0].name, "Bread");
2312 assert_eq!(response.headers[0].value, &b"baguette"[..]);
2313
2314 const REQUEST: &[u8] =
2315 b"GET / HTTP/1.1\r\nAccess-Control-Allow-Credentials: hell\x01o\r\nBread: baguette\r\n\r\n";
2316
2317 let mut headers = [EMPTY_HEADER; 2];
2318 let mut request = Request::new(&mut headers[..]);
2319
2320 let result = crate::ParserConfig::default().parse_request(&mut request, REQUEST);
2321 assert_eq!(result, Err(crate::Error::HeaderValue));
2322
2323 let result = crate::ParserConfig::default()
2324 .ignore_invalid_headers_in_requests(true)
2325 .parse_request(&mut request, REQUEST);
2326 assert_eq!(result, Ok(Status::Complete(77)));
2327
2328 assert_eq!(request.version.unwrap(), 1);
2329 assert_eq!(request.method.unwrap(), "GET");
2330 assert_eq!(request.path.unwrap(), "/");
2331 assert_eq!(request.headers.len(), 1);
2332 assert_eq!(request.headers[0].name, "Bread");
2333 assert_eq!(request.headers[0].value, &b"baguette"[..]);
2334 }
2335
2336 #[test]
2337 fn test_header_with_invalid_char_in_value_with_folding() {
2338 const RESPONSE: &[u8] =
2339 b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Credentials: hell\x01o \n world!\r\nBread: baguette\r\n\r\n";
2340
2341 let mut headers = [EMPTY_HEADER; 2];
2342 let mut response = Response::new(&mut headers[..]);
2343
2344 let result = crate::ParserConfig::default().parse_response(&mut response, RESPONSE);
2345 assert_eq!(result, Err(crate::Error::HeaderValue));
2346
2347 let result = crate::ParserConfig::default()
2348 .ignore_invalid_headers_in_responses(true)
2349 .parse_response(&mut response, RESPONSE);
2350 assert_eq!(result, Ok(Status::Complete(88)));
2351
2352 assert_eq!(response.version.unwrap(), 1);
2353 assert_eq!(response.code.unwrap(), 200);
2354 assert_eq!(response.reason.unwrap(), "OK");
2355 assert_eq!(response.headers.len(), 1);
2356 assert_eq!(response.headers[0].name, "Bread");
2357 assert_eq!(response.headers[0].value, &b"baguette"[..]);
2358
2359 const REQUEST: &[u8] =
2360 b"GET / HTTP/1.1\r\nAccess-Control-Allow-Credentials: hell\x01o \n world!\r\nBread: baguette\r\n\r\n";
2361
2362 let mut headers = [EMPTY_HEADER; 2];
2363 let mut request = Request::new(&mut headers[..]);
2364
2365 let result = crate::ParserConfig::default().parse_request(&mut request, REQUEST);
2366 assert_eq!(result, Err(crate::Error::HeaderValue));
2367
2368 let result = crate::ParserConfig::default()
2369 .ignore_invalid_headers_in_requests(true)
2370 .parse_request(&mut request, REQUEST);
2371 assert_eq!(result, Ok(Status::Complete(87)));
2372
2373 assert_eq!(request.version.unwrap(), 1);
2374 assert_eq!(request.method.unwrap(), "GET");
2375 assert_eq!(request.path.unwrap(), "/");
2376 assert_eq!(request.headers.len(), 1);
2377 assert_eq!(request.headers[0].name, "Bread");
2378 assert_eq!(request.headers[0].value, &b"baguette"[..]);
2379 }
2380
2381 #[test]
2382 fn test_method_within_buffer() {
2383 const REQUEST: &[u8] = b"GET / HTTP/1.1\r\n\r\n";
2384
2385 let mut headers = [EMPTY_HEADER; 0];
2386 let mut request = Request::new(&mut headers[..]);
2387
2388 crate::ParserConfig::default()
2389 .parse_request(&mut request, REQUEST)
2390 .unwrap();
2391
2392 let buf_end = unsafe { REQUEST.as_ptr().add(REQUEST.len()) };
2394 let method = request.method.unwrap();
2396 assert!(REQUEST.as_ptr() <= method.as_ptr());
2397 assert!(method.as_ptr() <= buf_end);
2398 }
2399
2400 static RESPONSE_WITH_SPACE_BEFORE_FIRST_HEADER: &[u8] =
2401 b"HTTP/1.1 200 OK\r\n Space-Before-Header: hello there\r\n\r\n";
2402
2403 #[test]
2404 fn test_forbid_response_with_space_before_first_header() {
2405 let mut headers = [EMPTY_HEADER; 1];
2406 let mut response = Response::new(&mut headers[..]);
2407 let result = response.parse(RESPONSE_WITH_SPACE_BEFORE_FIRST_HEADER);
2408
2409 assert_eq!(result, Err(crate::Error::HeaderName));
2410 }
2411
2412 #[test]
2413 fn test_allow_response_response_with_space_before_first_header() {
2414 let mut headers = [EMPTY_HEADER; 1];
2415 let mut response = Response::new(&mut headers[..]);
2416 let result = crate::ParserConfig::default()
2417 .allow_space_before_first_header_name(true)
2418 .parse_response(&mut response, RESPONSE_WITH_SPACE_BEFORE_FIRST_HEADER);
2419
2420 assert_eq!(
2421 result,
2422 Ok(Status::Complete(
2423 RESPONSE_WITH_SPACE_BEFORE_FIRST_HEADER.len()
2424 ))
2425 );
2426 assert_eq!(response.version.unwrap(), 1);
2427 assert_eq!(response.code.unwrap(), 200);
2428 assert_eq!(response.reason.unwrap(), "OK");
2429 assert_eq!(response.headers.len(), 1);
2430 assert_eq!(response.headers[0].name, "Space-Before-Header");
2431 assert_eq!(response.headers[0].value, &b"hello there"[..]);
2432 }
2433
2434 #[test]
2435 fn test_no_space_after_colon() {
2436 let mut headers = [EMPTY_HEADER; 1];
2437 let mut response = Response::new(&mut headers[..]);
2438 let result = crate::ParserConfig::default()
2439 .parse_response(&mut response, b"HTTP/1.1 200 OK\r\nfoo:bar\r\n\r\n");
2440
2441 assert_eq!(result, Ok(Status::Complete(28)));
2442 assert_eq!(response.version.unwrap(), 1);
2443 assert_eq!(response.code.unwrap(), 200);
2444 assert_eq!(response.reason.unwrap(), "OK");
2445 assert_eq!(response.headers.len(), 1);
2446 assert_eq!(response.headers[0].name, "foo");
2447 assert_eq!(response.headers[0].value, &b"bar"[..]);
2448 }
2449
2450 #[test]
2451 fn test_request_with_leading_space() {
2452 let mut headers = [EMPTY_HEADER; 1];
2453 let mut request = Request::new(&mut headers[..]);
2454 let result = crate::ParserConfig::default()
2455 .parse_request(&mut request, b" GET / HTTP/1.1\r\nfoo:bar\r\n\r\n");
2456
2457 assert_eq!(result, Err(Error::Token));
2458 }
2459
2460 #[test]
2461 fn test_request_with_invalid_method() {
2462 let mut headers = [EMPTY_HEADER; 1];
2463 let mut request = Request::new(&mut headers[..]);
2464 let result = crate::ParserConfig::default()
2465 .parse_request(&mut request, b"P()ST / HTTP/1.1\r\nfoo:bar\r\n\r\n");
2466
2467 assert_eq!(result, Err(Error::Token));
2468 }
2469
2470 #[test]
2471 fn test_utf8_in_path_ok() {
2472 let mut headers = [EMPTY_HEADER; 1];
2473 let mut request = Request::new(&mut headers[..]);
2474
2475 let result = crate::ParserConfig::default().parse_request(
2476 &mut request,
2477 b"GET /test?post=I\xE2\x80\x99msorryIforkedyou HTTP/1.1\r\nHost: example.org\r\n\r\n",
2478 );
2479
2480 assert_eq!(result, Ok(Status::Complete(67)));
2481 assert_eq!(request.version.unwrap(), 1);
2482 assert_eq!(request.method.unwrap(), "GET");
2483 assert_eq!(request.path.unwrap(), "/test?post=I’msorryIforkedyou");
2484 assert_eq!(request.headers.len(), 1);
2485 assert_eq!(request.headers[0].name, "Host");
2486 assert_eq!(request.headers[0].value, &b"example.org"[..]);
2487 }
2488
2489 #[test]
2490 fn test_bad_utf8_in_path() {
2491 let mut headers = [EMPTY_HEADER; 1];
2492 let mut request = Request::new(&mut headers[..]);
2493
2494 let result = crate::ParserConfig::default().parse_request(
2495 &mut request,
2496 b"GET /test?post=I\xE2msorryIforkedyou HTTP/1.1\r\nHost: example.org\r\n\r\n",
2497 );
2498
2499 assert_eq!(result, Err(crate::Error::Token));
2500 }
2501}