1use crate::{
3 error::{Error, ParseErr},
4 uri::Uri,
5};
6use std::{
7 collections::{hash_map, HashMap},
8 fmt,
9 io::Write,
10 str,
11};
12use unicase::Ascii;
13
14pub(crate) const CR_LF_2: [u8; 4] = [13, 10, 13, 10];
15
16#[derive(Debug, PartialEq, Clone)]
20pub struct Response {
21 status: Status,
22 headers: Headers,
23}
24
25impl Response {
26 pub fn from_head(head: &[u8]) -> Result<Response, Error> {
40 let mut head = str::from_utf8(head)?.splitn(2, '\n');
41
42 let status = head.next().ok_or(ParseErr::StatusErr)?.parse()?;
43 let headers = head.next().ok_or(ParseErr::HeadersErr)?.parse()?;
44
45 Ok(Response { status, headers })
46 }
47
48 pub fn try_from<T: Write>(res: &[u8], writer: &mut T) -> Result<Response, Error> {
64 if res.is_empty() {
65 Err(Error::Parse(ParseErr::Empty))
66 } else {
67 let pos = match find_slice(res, &CR_LF_2) {
68 Some(v) => v,
69 None => res.len(),
70 };
71
72 let response = Self::from_head(&res[..pos])?;
73 writer.write_all(&res[pos..])?;
74
75 Ok(response)
76 }
77 }
78
79 pub const fn status_code(&self) -> StatusCode {
96 self.status.code
97 }
98
99 pub fn version(&self) -> &str {
116 &self.status.version
117 }
118
119 pub fn reason(&self) -> &str {
136 &self.status.reason
137 }
138
139 pub fn headers(&self) -> &Headers {
156 &self.headers
157 }
158
159 pub fn content_len(&self) -> Option<usize> {
177 self.headers()
178 .get("Content-Length")
179 .and_then(|len| len.parse().ok())
180 .or_else(|| {
181 if self.status.code.0 == 204 {
182 Some(0)
183 } else {
184 None
185 }
186 })
187 }
188}
189
190#[derive(PartialEq, Debug, Clone)]
192pub struct Status {
193 version: String,
194 code: StatusCode,
195 reason: String,
196}
197
198impl Status {
199 pub fn new(version: &str, code: StatusCode, reason: &str) -> Status {
200 Status::from((version, code, reason))
201 }
202}
203
204impl<T, U, V> From<(T, U, V)> for Status
205where
206 T: ToString,
207 V: ToString,
208 StatusCode: From<U>,
209{
210 fn from(status: (T, U, V)) -> Status {
211 Status {
212 version: status.0.to_string(),
213 code: StatusCode::from(status.1),
214 reason: status.2.to_string(),
215 }
216 }
217}
218
219impl str::FromStr for Status {
220 type Err = ParseErr;
221
222 fn from_str(status_line: &str) -> Result<Status, Self::Err> {
223 let mut status_line = status_line.trim().splitn(3, ' ');
224
225 let version = status_line.next().ok_or(ParseErr::StatusErr)?;
226 let code: StatusCode = status_line.next().ok_or(ParseErr::StatusErr)?.parse()?;
227 let reason = match status_line.next() {
228 Some(reason) => reason,
229 None => code.reason().unwrap_or("Unknown"),
230 };
231
232 Ok(Status::from((version, code, reason)))
233 }
234}
235
236#[derive(Debug, PartialEq, Clone, Default)]
248pub struct Headers(HashMap<Ascii<String>, String>);
249
250impl Headers {
251 pub fn new() -> Headers {
263 Headers(HashMap::new())
264 }
265
266 pub fn with_capacity(capacity: usize) -> Headers {
278 Headers(HashMap::with_capacity(capacity))
279 }
280
281 pub fn iter(&self) -> hash_map::Iter<Ascii<String>, String> {
296 self.0.iter()
297 }
298
299 pub fn get<T: ToString + ?Sized>(&self, k: &T) -> Option<&std::string::String> {
311 self.0.get(&Ascii::new(k.to_string()))
312 }
313
314 pub fn insert<T, U>(&mut self, key: &T, val: &U) -> Option<String>
329 where
330 T: ToString + ?Sized,
331 U: ToString + ?Sized,
332 {
333 self.0.insert(Ascii::new(key.to_string()), val.to_string())
334 }
335
336 pub fn default_http(uri: &Uri) -> Headers {
347 let mut headers = Headers::with_capacity(4);
348
349 headers.insert("Host", &uri.host_header().unwrap_or_default());
350 headers.insert("Referer", &uri);
351
352 headers
353 }
354}
355
356impl str::FromStr for Headers {
357 type Err = ParseErr;
358
359 fn from_str(s: &str) -> Result<Headers, ParseErr> {
360 let headers = s.trim();
361
362 if headers.lines().all(|e| e.contains(':')) {
363 let headers = headers
364 .lines()
365 .map(|elem| {
366 let idx = elem.find(':').unwrap();
367 let (key, value) = elem.split_at(idx);
368 (Ascii::new(key.to_string()), value[1..].trim().to_string())
369 })
370 .collect();
371
372 Ok(Headers(headers))
373 } else {
374 Err(ParseErr::HeadersErr)
375 }
376 }
377}
378
379impl From<HashMap<Ascii<String>, String>> for Headers {
380 fn from(map: HashMap<Ascii<String>, String>) -> Headers {
381 Headers(map)
382 }
383}
384
385impl From<Headers> for HashMap<Ascii<String>, String> {
386 fn from(map: Headers) -> HashMap<Ascii<String>, String> {
387 map.0
388 }
389}
390
391impl fmt::Display for Headers {
392 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
393 let headers: String = self
394 .iter()
395 .map(|(key, val)| format!(" {}: {}\r\n", key, val))
396 .collect();
397
398 write!(f, "{{\r\n{}}}", headers)
399 }
400}
401
402#[derive(Debug, PartialEq, Clone, Copy)]
412pub struct StatusCode(u16);
413
414impl StatusCode {
415 pub const fn new(code: u16) -> StatusCode {
424 StatusCode(code)
425 }
426
427 pub const fn is_info(self) -> bool {
437 self.0 >= 100 && self.0 < 200
438 }
439
440 pub const fn is_success(self) -> bool {
450 self.0 >= 200 && self.0 < 300
451 }
452
453 pub const fn is_redirect(self) -> bool {
463 self.0 >= 300 && self.0 < 400
464 }
465
466 pub const fn is_client_err(self) -> bool {
476 self.0 >= 400 && self.0 < 500
477 }
478
479 pub const fn is_server_err(self) -> bool {
489 self.0 >= 500 && self.0 < 600
490 }
491
492 pub fn is<F: FnOnce(u16) -> bool>(self, f: F) -> bool {
502 f(self.0)
503 }
504
505 pub const fn reason(self) -> Option<&'static str> {
515 let reason = match self.0 {
516 100 => "Continue",
517 101 => "Switching Protocols",
518 102 => "Processing",
519 200 => "OK",
520 201 => "Created",
521 202 => "Accepted",
522 203 => "Non Authoritative Information",
523 204 => "No Content",
524 205 => "Reset Content",
525 206 => "Partial Content",
526 207 => "Multi-Status",
527 208 => "Already Reported",
528 226 => "IM Used",
529 300 => "Multiple Choices",
530 301 => "Moved Permanently",
531 302 => "Found",
532 303 => "See Other",
533 304 => "Not Modified",
534 305 => "Use Proxy",
535 307 => "Temporary Redirect",
536 308 => "Permanent Redirect",
537 400 => "Bad Request",
538 401 => "Unauthorized",
539 402 => "Payment Required",
540 403 => "Forbidden",
541 404 => "Not Found",
542 405 => "Method Not Allowed",
543 406 => "Not Acceptable",
544 407 => "Proxy Authentication Required",
545 408 => "Request Timeout",
546 409 => "Conflict",
547 410 => "Gone",
548 411 => "Length Required",
549 412 => "Precondition Failed",
550 413 => "Payload Too Large",
551 414 => "URI Too Long",
552 415 => "Unsupported Media Type",
553 416 => "Range Not Satisfiable",
554 417 => "Expectation Failed",
555 418 => "I'm a teapot",
556 421 => "Misdirected Request",
557 422 => "Unprocessable Entity",
558 423 => "Locked",
559 424 => "Failed Dependency",
560 426 => "Upgrade Required",
561 428 => "Precondition Required",
562 429 => "Too Many Requests",
563 431 => "Request Header Fields Too Large",
564 451 => "Unavailable For Legal Reasons",
565 500 => "Internal Server Error",
566 501 => "Not Implemented",
567 502 => "Bad Gateway",
568 503 => "Service Unavailable",
569 504 => "Gateway Timeout",
570 505 => "HTTP Version Not Supported",
571 506 => "Variant Also Negotiates",
572 507 => "Insufficient Storage",
573 508 => "Loop Detected",
574 510 => "Not Extended",
575 511 => "Network Authentication Required",
576 _ => "",
577 };
578
579 if !reason.is_empty() {
580 Some(reason)
581 } else {
582 None
583 }
584 }
585}
586
587impl From<StatusCode> for u16 {
588 fn from(code: StatusCode) -> Self {
589 code.0
590 }
591}
592
593impl From<u16> for StatusCode {
594 fn from(code: u16) -> Self {
595 StatusCode(code)
596 }
597}
598
599impl fmt::Display for StatusCode {
600 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
601 write!(f, "{}", self.0)
602 }
603}
604
605impl str::FromStr for StatusCode {
606 type Err = ParseErr;
607
608 fn from_str(s: &str) -> Result<StatusCode, ParseErr> {
609 Ok(StatusCode::new(s.parse()?))
610 }
611}
612
613pub fn find_slice<T>(data: &[T], e: &[T]) -> Option<usize>
615where
616 [T]: PartialEq,
617{
618 if data.len() > e.len() {
619 for i in 0..=data.len() - e.len() {
620 if data[i..(i + e.len())] == *e {
621 return Some(i + e.len());
622 }
623 }
624 }
625
626 None
627}
628
629#[cfg(test)]
630mod tests {
631 use super::*;
632 use std::convert::TryFrom;
633
634 const RESPONSE: &[u8; 129] = b"HTTP/1.1 200 OK\r\n\
635 Date: Sat, 11 Jan 2003 02:44:04 GMT\r\n\
636 Content-Type: text/html\r\n\
637 Content-Length: 100\r\n\r\n\
638 <html>hello</html>\r\n\r\nhello";
639 const RESPONSE_H: &[u8; 102] = b"HTTP/1.1 200 OK\r\n\
640 Date: Sat, 11 Jan 2003 02:44:04 GMT\r\n\
641 Content-Type: text/html\r\n\
642 Content-Length: 100\r\n\r\n";
643 const BODY: &[u8; 27] = b"<html>hello</html>\r\n\r\nhello";
644
645 const STATUS_LINE: &str = "HTTP/1.1 200 OK";
646 const VERSION: &str = "HTTP/1.1";
647 const CODE: u16 = 200;
648 const REASON: &str = "OK";
649
650 const HEADERS: &str = "Date: Sat, 11 Jan 2003 02:44:04 GMT\r\n\
651 Content-Type: text/html\r\n\
652 Content-Length: 100\r\n";
653 const CODE_S: StatusCode = StatusCode(200);
654
655 #[test]
656 fn status_code_new() {
657 assert_eq!(StatusCode::new(200), StatusCode(200));
658 assert_ne!(StatusCode::new(400), StatusCode(404));
659 }
660
661 #[test]
662 fn status_code_info() {
663 for i in 100..200 {
664 assert!(StatusCode::new(i).is_info())
665 }
666
667 for i in (0..1000).filter(|&i| i < 100 || i >= 200) {
668 assert!(!StatusCode::new(i).is_info())
669 }
670 }
671
672 #[test]
673 fn status_code_success() {
674 for i in 200..300 {
675 assert!(StatusCode::new(i).is_success())
676 }
677
678 for i in (0..1000).filter(|&i| i < 200 || i >= 300) {
679 assert!(!StatusCode::new(i).is_success())
680 }
681 }
682
683 #[test]
684 fn status_code_redirect() {
685 for i in 300..400 {
686 assert!(StatusCode::new(i).is_redirect())
687 }
688
689 for i in (0..1000).filter(|&i| i < 300 || i >= 400) {
690 assert!(!StatusCode::new(i).is_redirect())
691 }
692 }
693
694 #[test]
695 fn status_code_client_err() {
696 for i in 400..500 {
697 assert!(StatusCode::new(i).is_client_err())
698 }
699
700 for i in (0..1000).filter(|&i| i < 400 || i >= 500) {
701 assert!(!StatusCode::new(i).is_client_err())
702 }
703 }
704
705 #[test]
706 fn status_code_server_err() {
707 for i in 500..600 {
708 assert!(StatusCode::new(i).is_server_err())
709 }
710
711 for i in (0..1000).filter(|&i| i < 500 || i >= 600) {
712 assert!(!StatusCode::new(i).is_server_err())
713 }
714 }
715
716 #[test]
717 fn status_code_is() {
718 let check = |i| i % 3 == 0;
719
720 let code_1 = StatusCode::new(200);
721 let code_2 = StatusCode::new(300);
722
723 assert!(!code_1.is(check));
724 assert!(code_2.is(check));
725 }
726
727 #[test]
728 fn status_code_reason() {
729 assert_eq!(StatusCode(200).reason(), Some("OK"));
730 assert_eq!(StatusCode(400).reason(), Some("Bad Request"));
731 }
732
733 #[test]
734 fn status_code_from() {
735 assert_eq!(StatusCode::from(200), StatusCode(200));
736 }
737
738 #[test]
739 fn u16_from_status_code() {
740 assert_eq!(u16::from(CODE_S), 200);
741 }
742
743 #[test]
744 fn status_code_display() {
745 let code = format!("Status Code: {}", StatusCode::new(200));
746 const CODE_EXPECT: &str = "Status Code: 200";
747
748 assert_eq!(code, CODE_EXPECT);
749 }
750
751 #[test]
752 fn status_code_from_str() {
753 assert_eq!("200".parse::<StatusCode>(), Ok(StatusCode(200)));
754 assert_ne!("400".parse::<StatusCode>(), Ok(StatusCode(404)));
755 }
756
757 #[test]
758 fn status_from() {
759 let status = Status::from((VERSION, CODE, REASON));
760
761 assert_eq!(status.version, VERSION);
762 assert_eq!(status.code, CODE_S);
763 assert_eq!(status.reason, REASON);
764 }
765
766 #[test]
767 fn status_from_str() {
768 let status = STATUS_LINE.parse::<Status>().unwrap();
769
770 assert_eq!(status.version, VERSION);
771 assert_eq!(status.code, CODE_S);
772 assert_eq!(status.reason, REASON);
773 }
774
775 #[test]
776 fn headers_new() {
777 assert_eq!(Headers::new(), Headers(HashMap::new()));
778 }
779
780 #[test]
781 fn headers_get() {
782 let mut headers = Headers::with_capacity(2);
783 headers.insert("Date", "Sat, 11 Jan 2003 02:44:04 GMT");
784
785 assert_eq!(
786 headers.get("Date"),
787 Some(&"Sat, 11 Jan 2003 02:44:04 GMT".to_string())
788 );
789 }
790
791 #[test]
792 fn headers_insert() {
793 let mut headers_expect = HashMap::new();
794 headers_expect.insert(Ascii::new("Connection".to_string()), "Close".to_string());
795 let headers_expect = Headers(headers_expect);
796
797 let mut headers = Headers::new();
798 headers.insert("Connection", "Close");
799
800 assert_eq!(headers_expect, headers);
801 }
802
803 #[test]
804 fn headers_default_http() {
805 let uri = Uri::try_from("http://doc.rust-lang.org/std/string/index.html").unwrap();
806
807 let mut headers = Headers::with_capacity(4);
808 headers.insert("Host", "doc.rust-lang.org");
809 headers.insert("Referer", "http://doc.rust-lang.org/std/string/index.html");
810
811 assert_eq!(Headers::default_http(&uri), headers);
812 }
813
814 #[test]
815 fn headers_from_str() {
816 let mut headers_expect = HashMap::with_capacity(2);
817 headers_expect.insert(
818 Ascii::new("Date".to_string()),
819 "Sat, 11 Jan 2003 02:44:04 GMT".to_string(),
820 );
821 headers_expect.insert(
822 Ascii::new("Content-Type".to_string()),
823 "text/html".to_string(),
824 );
825 headers_expect.insert(Ascii::new("Content-Length".to_string()), "100".to_string());
826
827 let headers = HEADERS.parse::<Headers>().unwrap();
828 assert_eq!(headers, Headers::from(headers_expect));
829 }
830
831 #[test]
832 fn headers_from() {
833 let mut headers_expect = HashMap::with_capacity(4);
834 headers_expect.insert(
835 Ascii::new("Date".to_string()),
836 "Sat, 11 Jan 2003 02:44:04 GMT".to_string(),
837 );
838 headers_expect.insert(
839 Ascii::new("Content-Type".to_string()),
840 "text/html".to_string(),
841 );
842 headers_expect.insert(Ascii::new("Content-Length".to_string()), "100".to_string());
843
844 assert_eq!(
845 Headers(headers_expect.clone()),
846 Headers::from(headers_expect)
847 );
848 }
849
850 #[test]
851 fn headers_case_insensitive() {
852 let header_names = ["Host", "host", "HOST", "HoSt"];
853 let mut headers = Headers::with_capacity(1);
854 headers.insert("Host", "doc.rust-lang.org");
855
856 for name in header_names.iter() {
857 assert_eq!(headers.get(name), Some(&"doc.rust-lang.org".to_string()));
858 }
859 }
860
861 #[test]
862 fn hash_map_from_headers() {
863 let mut headers = Headers::with_capacity(4);
864 headers.insert("Date", "Sat, 11 Jan 2003 02:44:04 GMT");
865 headers.insert("Content-Type", "text/html");
866 headers.insert("Content-Length", "100");
867
868 let mut headers_expect = HashMap::with_capacity(4);
869 headers_expect.insert(
870 Ascii::new("Date".to_string()),
871 "Sat, 11 Jan 2003 02:44:04 GMT".to_string(),
872 );
873 headers_expect.insert(
874 Ascii::new("Content-Type".to_string()),
875 "text/html".to_string(),
876 );
877 headers_expect.insert(Ascii::new("Content-Length".to_string()), "100".to_string());
878
879 assert_eq!(HashMap::from(headers), headers_expect);
880 }
881
882 #[test]
883 fn find_slice_e() {
884 const WORDS: [&str; 8] = ["Good", "job", "Great", "work", "Have", "fun", "See", "you"];
885 const SEARCH: [&str; 3] = ["Great", "work", "Have"];
886 const TOO_LONG_SEARCH: [&str; 9] = [
887 "Good",
888 "job",
889 "Great",
890 "fascinating",
891 "work",
892 "Have",
893 "fun",
894 "See",
895 "you",
896 ];
897
898 assert_eq!(find_slice(&WORDS, &SEARCH), Some(5));
899 assert_eq!(find_slice(&WORDS, &TOO_LONG_SEARCH), None);
900 }
901
902 #[test]
903 fn res_from_head() {
904 Response::from_head(RESPONSE_H).unwrap();
905 }
906
907 #[test]
908 fn res_try_from() {
909 let mut writer = Vec::new();
910
911 Response::try_from(RESPONSE, &mut writer).unwrap();
912 Response::try_from(RESPONSE_H, &mut writer).unwrap();
913 }
914
915 #[test]
916 #[should_panic]
917 fn res_from_empty() {
918 let mut writer = Vec::new();
919 Response::try_from(&[], &mut writer).unwrap();
920 }
921
922 #[test]
923 fn res_status_code() {
924 let mut writer = Vec::new();
925 let res = Response::try_from(RESPONSE, &mut writer).unwrap();
926
927 assert_eq!(res.status_code(), CODE_S);
928 }
929
930 #[test]
931 fn res_version() {
932 let mut writer = Vec::new();
933 let res = Response::try_from(RESPONSE, &mut writer).unwrap();
934
935 assert_eq!(res.version(), "HTTP/1.1");
936 }
937
938 #[test]
939 fn res_reason() {
940 let mut writer = Vec::new();
941 let res = Response::try_from(RESPONSE, &mut writer).unwrap();
942
943 assert_eq!(res.reason(), "OK");
944 }
945
946 #[test]
947 fn res_headers() {
948 let mut writer = Vec::new();
949 let res = Response::try_from(RESPONSE, &mut writer).unwrap();
950
951 let mut headers = Headers::with_capacity(2);
952 headers.insert("Date", "Sat, 11 Jan 2003 02:44:04 GMT");
953 headers.insert("Content-Type", "text/html");
954 headers.insert("Content-Length", "100");
955
956 assert_eq!(res.headers(), &Headers::from(headers));
957 }
958
959 #[test]
960 fn res_content_len() {
961 let mut writer = Vec::with_capacity(101);
962 let res = Response::try_from(RESPONSE, &mut writer).unwrap();
963
964 assert_eq!(res.content_len(), Some(100));
965 }
966
967 #[test]
968 fn res_body() {
969 {
970 let mut writer = Vec::new();
971 Response::try_from(RESPONSE, &mut writer).unwrap();
972
973 assert_eq!(writer, BODY);
974 }
975 {
976 let mut writer = Vec::new();
977 Response::try_from(RESPONSE_H, &mut writer).unwrap();
978
979 assert_eq!(writer, &[]);
980 }
981 }
982}