http_req/
response.rs

1//! parsing server response
2use 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///Represents an HTTP response.
17///
18///It contains `Headers` and `Status` parsed from response.
19#[derive(Debug, PartialEq, Clone)]
20pub struct Response {
21    status: Status,
22    headers: Headers,
23}
24
25impl Response {
26    ///Creates new `Response` with head - status and headers - parsed from a slice of bytes
27    ///
28    ///# Examples
29    ///```
30    ///use http_req::response::Response;
31    ///
32    ///const HEAD: &[u8; 102] = b"HTTP/1.1 200 OK\r\n\
33    ///                         Date: Sat, 11 Jan 2003 02:44:04 GMT\r\n\
34    ///                         Content-Type: text/html\r\n\
35    ///                         Content-Length: 100\r\n\r\n";
36    ///
37    ///let response = Response::from_head(HEAD).unwrap();
38    ///```
39    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    ///Parses `Response` from slice of bytes. Writes it's body to `writer`.
49    ///
50    ///# Examples
51    ///```
52    ///use http_req::response::Response;
53    ///
54    ///const RESPONSE: &[u8; 129] = b"HTTP/1.1 200 OK\r\n\
55    ///                             Date: Sat, 11 Jan 2003 02:44:04 GMT\r\n\
56    ///                             Content-Type: text/html\r\n\
57    ///                             Content-Length: 100\r\n\r\n\
58    ///                             <html>hello\r\n\r\nhello</html>";
59    ///let mut body = Vec::new();
60    ///
61    ///let response = Response::try_from(RESPONSE, &mut body).unwrap();
62    ///```
63    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    ///Returns status code of this `Response`.
80    ///
81    ///# Examples
82    ///```
83    ///use http_req::response::{Response, StatusCode};
84    ///
85    ///const RESPONSE: &[u8; 129] = b"HTTP/1.1 200 OK\r\n\
86    ///                             Date: Sat, 11 Jan 2003 02:44:04 GMT\r\n\
87    ///                             Content-Type: text/html\r\n\
88    ///                             Content-Length: 100\r\n\r\n\
89    ///                             <html>hello\r\n\r\nhello</html>";
90    ///let mut body = Vec::new();
91    ///
92    ///let response = Response::try_from(RESPONSE, &mut body).unwrap();
93    ///assert_eq!(response.status_code(), StatusCode::new(200));
94    ///```
95    pub const fn status_code(&self) -> StatusCode {
96        self.status.code
97    }
98
99    ///Returns HTTP version of this `Response`.
100    ///
101    ///# Examples
102    ///```
103    ///use http_req::response::Response;
104    ///
105    ///const RESPONSE: &[u8; 129] = b"HTTP/1.1 200 OK\r\n\
106    ///                             Date: Sat, 11 Jan 2003 02:44:04 GMT\r\n\
107    ///                             Content-Type: text/html\r\n\
108    ///                             Content-Length: 100\r\n\r\n\
109    ///                             <html>hello\r\n\r\nhello</html>";
110    ///let mut body = Vec::new();
111    ///
112    ///let response = Response::try_from(RESPONSE, &mut body).unwrap();
113    ///assert_eq!(response.version(), "HTTP/1.1");
114    ///```
115    pub fn version(&self) -> &str {
116        &self.status.version
117    }
118
119    ///Returns reason of this `Response`.
120    ///
121    ///# Examples
122    ///```
123    ///use http_req::response::Response;
124    ///
125    ///const RESPONSE: &[u8; 129] = b"HTTP/1.1 200 OK\r\n\
126    ///                             Date: Sat, 11 Jan 2003 02:44:04 GMT\r\n\
127    ///                             Content-Type: text/html\r\n\
128    ///                             Content-Length: 100\r\n\r\n\
129    ///                             <html>hello\r\n\r\nhello</html>";
130    ///let mut body = Vec::new();
131    ///
132    ///let response = Response::try_from(RESPONSE, &mut body).unwrap();
133    ///assert_eq!(response.reason(), "OK");
134    ///```
135    pub fn reason(&self) -> &str {
136        &self.status.reason
137    }
138
139    ///Returns headers of this `Response`.
140    ///
141    ///# Examples
142    ///```
143    ///use http_req::response::Response;
144    ///
145    ///const RESPONSE: &[u8; 129] = b"HTTP/1.1 200 OK\r\n\
146    ///                             Date: Sat, 11 Jan 2003 02:44:04 GMT\r\n\
147    ///                             Content-Type: text/html\r\n\
148    ///                             Content-Length: 100\r\n\r\n\
149    ///                             <html>hello\r\n\r\nhello</html>";
150    ///let mut body = Vec::new();
151    ///
152    ///let response = Response::try_from(RESPONSE, &mut body).unwrap();
153    ///let headers = response.headers();
154    ///```
155    pub fn headers(&self) -> &Headers {
156        &self.headers
157    }
158
159    ///Returns length of the content of this `Response` as a `Option`, according to information
160    ///included in headers. If there is no such an information, returns `None`.
161    ///
162    ///# Examples
163    ///```
164    ///use http_req::response::Response;
165    ///
166    ///const RESPONSE: &[u8; 129] = b"HTTP/1.1 200 OK\r\n\
167    ///                             Date: Sat, 11 Jan 2003 02:44:04 GMT\r\n\
168    ///                             Content-Type: text/html\r\n\
169    ///                             Content-Length: 100\r\n\r\n\
170    ///                             <html>hello\r\n\r\nhello</html>";
171    ///let mut body = Vec::new();
172    ///
173    ///let response = Response::try_from(RESPONSE, &mut body).unwrap();
174    ///assert_eq!(response.content_len().unwrap(), 100);
175    ///```
176    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///Status of HTTP response
191#[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///Wrapper around HashMap<Ascii<String>, String> with additional functionality for parsing HTTP headers
237///
238///# Example
239///```
240///use http_req::response::Headers;
241///
242///let mut headers = Headers::new();
243///headers.insert("Connection", "Close");
244///
245///assert_eq!(headers.get("Connection"), Some(&"Close".to_string()))
246///```
247#[derive(Debug, PartialEq, Clone, Default)]
248pub struct Headers(HashMap<Ascii<String>, String>);
249
250impl Headers {
251    ///Creates an empty `Headers`.
252    ///
253    ///The headers are initially created with a capacity of 0, so they will not allocate until
254    ///it is first inserted into.
255    ///
256    ///# Examples
257    ///```
258    ///use http_req::response::Headers;
259    ///
260    ///let mut headers = Headers::new();
261    ///```
262    pub fn new() -> Headers {
263        Headers(HashMap::new())
264    }
265
266    ///Creates empty `Headers` with the specified capacity.
267    ///
268    ///The headers will be able to hold at least capacity elements without reallocating.
269    ///If capacity is 0, the headers will not allocate.
270    ///
271    ///# Examples
272    ///```
273    ///use http_req::response::Headers;
274    ///
275    ///let mut headers = Headers::with_capacity(200);
276    ///```
277    pub fn with_capacity(capacity: usize) -> Headers {
278        Headers(HashMap::with_capacity(capacity))
279    }
280
281    ///An iterator visiting all key-value pairs in arbitrary order.
282    ///The iterator's element type is (&Ascii<String>, &String).
283    ///
284    ///# Examples
285    ///```
286    ///use http_req::response::Headers;
287    ///
288    ///let mut headers = Headers::new();
289    ///headers.insert("Accept-Charset", "utf-8");
290    ///headers.insert("Accept-Language", "en-US");
291    ///headers.insert("Connection", "Close");
292    ///
293    ///let mut iterator = headers.iter();
294    ///```
295    pub fn iter(&self) -> hash_map::Iter<Ascii<String>, String> {
296        self.0.iter()
297    }
298
299    ///Returns a reference to the value corresponding to the key.
300    ///
301    ///# Examples
302    ///```
303    ///use http_req::response::Headers;
304    ///
305    ///let mut headers = Headers::new();
306    ///headers.insert("Accept-Charset", "utf-8");
307    ///
308    ///assert_eq!(headers.get("Accept-Charset"), Some(&"utf-8".to_string()))
309    ///```
310    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    ///Inserts a key-value pair into the headers.
315    ///
316    ///If the headers did not have this key present, None is returned.
317    ///
318    ///If the headers did have this key present, the value is updated, and the old value is returned.
319    ///The key is not updated, though; this matters for types that can be == without being identical.
320    ///
321    ///# Examples
322    ///```
323    ///use http_req::response::Headers;
324    ///
325    ///let mut headers = Headers::new();
326    ///headers.insert("Accept-Language", "en-US");
327    ///```
328    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    ///Creates default headers for a HTTP request
337    ///
338    ///# Examples
339    ///```
340    ///use http_req::{response::Headers, uri::Uri};
341    ///use std::convert::TryFrom;
342    ///
343    ///let uri: Uri = Uri::try_from("https://www.rust-lang.org/learn").unwrap();
344    ///let headers = Headers::default_http(&uri);
345    ///```
346    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///Code sent by a server in response to a client's request.
403///
404///# Example
405///```
406///use http_req::response::StatusCode;
407///
408///const code: StatusCode = StatusCode::new(200);
409///assert!(code.is_success())
410///```
411#[derive(Debug, PartialEq, Clone, Copy)]
412pub struct StatusCode(u16);
413
414impl StatusCode {
415    ///Creates new StatusCode from `u16` value.
416    ///
417    ///# Examples
418    ///```
419    ///use http_req::response::StatusCode;
420    ///
421    ///const code: StatusCode = StatusCode::new(200);
422    ///```
423    pub const fn new(code: u16) -> StatusCode {
424        StatusCode(code)
425    }
426
427    ///Checks if this `StatusCode` is within 100-199, which indicates that it's Informational.
428    ///
429    ///# Examples
430    ///```
431    ///use http_req::response::StatusCode;
432    ///
433    ///const code: StatusCode = StatusCode::new(101);
434    ///assert!(code.is_info())
435    ///```
436    pub const fn is_info(self) -> bool {
437        self.0 >= 100 && self.0 < 200
438    }
439
440    ///Checks if this `StatusCode` is within 200-299, which indicates that it's Successful.
441    ///
442    ///# Examples
443    ///```
444    ///use http_req::response::StatusCode;
445    ///
446    ///const code: StatusCode = StatusCode::new(204);
447    ///assert!(code.is_success())
448    ///```
449    pub const fn is_success(self) -> bool {
450        self.0 >= 200 && self.0 < 300
451    }
452
453    ///Checks if this `StatusCode` is within 300-399, which indicates that it's Redirection.
454    ///
455    ///# Examples
456    ///```
457    ///use http_req::response::StatusCode;
458    ///
459    ///const code: StatusCode = StatusCode::new(301);
460    ///assert!(code.is_redirect())
461    ///```
462    pub const fn is_redirect(self) -> bool {
463        self.0 >= 300 && self.0 < 400
464    }
465
466    ///Checks if this `StatusCode` is within 400-499, which indicates that it's Client Error.
467    ///
468    ///# Examples
469    ///```
470    ///use http_req::response::StatusCode;
471    ///
472    ///const code: StatusCode = StatusCode::new(400);
473    ///assert!(code.is_client_err())
474    ///```
475    pub const fn is_client_err(self) -> bool {
476        self.0 >= 400 && self.0 < 500
477    }
478
479    ///Checks if this `StatusCode` is within 500-599, which indicates that it's Server Error.
480    ///
481    ///# Examples
482    ///```
483    ///use http_req::response::StatusCode;
484    ///
485    ///const code: StatusCode = StatusCode::new(503);
486    ///assert!(code.is_server_err())
487    ///```
488    pub const fn is_server_err(self) -> bool {
489        self.0 >= 500 && self.0 < 600
490    }
491
492    ///Checks this `StatusCode` using closure `f`
493    ///
494    ///# Examples
495    ///```
496    ///use http_req::response::StatusCode;
497    ///
498    ///const code: StatusCode = StatusCode::new(203);
499    ///assert!(code.is(|i| i > 199 && i < 250))
500    ///```
501    pub fn is<F: FnOnce(u16) -> bool>(self, f: F) -> bool {
502        f(self.0)
503    }
504
505    ///Returns `Reason-Phrase` corresponding to this `StatusCode`
506    ///
507    ///# Examples
508    ///```
509    ///use http_req::response::StatusCode;
510    ///
511    ///const code: StatusCode = StatusCode::new(200);
512    ///assert_eq!(code.reason(), Some("OK"))
513    ///```
514    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
613///Finds elements slice `e` inside slice `data`. Returns position of the end of first match.
614pub 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}