http_io/
protocol.rs

1//! Types representing various parts of the HTTP protocol.
2
3// We do write! + '\r\n' and don't want to hide the line ending in a writeln!
4#![allow(clippy::write_with_newline)]
5
6use crate::error::{Error, Result};
7use crate::io::{self, Read, Write};
8#[cfg(not(feature = "std"))]
9use alloc::{
10    boxed::Box,
11    collections::{btree_map::Iter as BTreeMapIter, BTreeMap},
12    format,
13    string::String,
14    vec,
15    vec::Vec,
16};
17use core::cmp;
18use core::convert;
19use core::fmt;
20use core::iter;
21use core::str;
22#[cfg(feature = "std")]
23use std::collections::{btree_map::Iter as BTreeMapIter, BTreeMap};
24
25struct HttpBodyChunk<S: io::Read> {
26    inner: io::Take<HttpReadTilCloseBody<S>>,
27}
28
29pub struct HttpChunkedBody<S: io::Read> {
30    content_length: Option<u64>,
31    stream: Option<HttpReadTilCloseBody<S>>,
32    chunk: Option<HttpBodyChunk<S>>,
33}
34
35impl<S: io::Read> HttpChunkedBody<S> {
36    fn new(content_length: Option<u64>, stream: HttpReadTilCloseBody<S>) -> Self {
37        HttpChunkedBody {
38            content_length,
39            stream: Some(stream),
40            chunk: None,
41        }
42    }
43}
44
45impl<S: io::Read> HttpBodyChunk<S> {
46    fn new(mut stream: HttpReadTilCloseBody<S>) -> Result<Option<Self>> {
47        let mut ts = CrLfStream::new(&mut stream);
48        let size_str = ts.expect_next()?;
49        drop(ts);
50        let size = u64::from_str_radix(&size_str, 16)?;
51        Ok(if size == 0 {
52            None
53        } else {
54            Some(HttpBodyChunk {
55                inner: stream.take(size),
56            })
57        })
58    }
59
60    fn into_inner(self) -> HttpReadTilCloseBody<S> {
61        self.inner.into_inner()
62    }
63}
64
65impl<S: io::Read> io::Read for HttpBodyChunk<S> {
66    fn read(&mut self, buffer: &mut [u8]) -> io::Result<usize> {
67        self.inner.read(buffer)
68    }
69}
70
71impl<S: io::Read> io::Read for HttpChunkedBody<S> {
72    fn read(&mut self, buffer: &mut [u8]) -> io::Result<usize> {
73        if let Some(mut chunk) = self.chunk.take() {
74            let read = chunk.read(buffer)?;
75            if read == 0 {
76                let mut stream = chunk.into_inner();
77                let mut b = [0; 2];
78                stream.read_exact(&mut b)?;
79                self.stream = Some(stream);
80                self.read(buffer)
81            } else {
82                self.chunk.replace(chunk);
83                Ok(read)
84            }
85        } else if let Some(stream) = self.stream.take() {
86            let new_chunk = HttpBodyChunk::new(stream)?;
87            match new_chunk {
88                Some(chunk) => {
89                    self.chunk = Some(chunk);
90                    self.read(buffer)
91                }
92                None => Ok(0),
93            }
94        } else {
95            Ok(0)
96        }
97    }
98}
99
100#[cfg(test)]
101mod chunked_encoding_tests {
102    use super::HttpChunkedBody;
103    use crate::error::Result;
104    use std::io;
105    use std::io::Read;
106
107    fn chunk_test(i: &'static str) -> Result<String> {
108        let input = io::BufReader::new(io::Cursor::new(i));
109        let mut body = HttpChunkedBody::new(None, input);
110
111        let mut output = String::new();
112        body.read_to_string(&mut output)?;
113        Ok(output)
114    }
115
116    #[test]
117    fn simple_chunk() {
118        assert_eq!(
119            &chunk_test("a\r\n0123456789\r\n0\r\n").unwrap(),
120            "0123456789"
121        );
122    }
123
124    #[test]
125    fn chunk_missing_last_chunk() {
126        assert!(chunk_test("a\r\n0123456789\r\n").is_err());
127    }
128
129    #[test]
130    fn chunk_short_read() {
131        assert!(chunk_test("a\r\n012345678").is_err());
132    }
133}
134
135type HttpReadTilCloseBody<S> = io::BufReader<S>;
136type HttpLimitedBody<S> = io::Take<HttpReadTilCloseBody<S>>;
137
138pub enum HttpBody<S: io::Read> {
139    Chunked(HttpChunkedBody<S>),
140    Limited(HttpLimitedBody<S>),
141    ReadTilClose(HttpReadTilCloseBody<S>),
142}
143
144impl<S: io::Read> io::Read for HttpBody<S> {
145    fn read(&mut self, buffer: &mut [u8]) -> io::Result<usize> {
146        match self {
147            HttpBody::Chunked(i) => i.read(buffer),
148            HttpBody::Limited(i) => i.read(buffer),
149            HttpBody::ReadTilClose(i) => i.read(buffer),
150        }
151    }
152}
153
154impl<S: io::Read> HttpBody<S> {
155    pub fn new(
156        encoding: Option<&str>,
157        content_length: Option<u64>,
158        body: io::BufReader<S>,
159    ) -> Self {
160        if encoding == Some("chunked") {
161            HttpBody::Chunked(HttpChunkedBody::new(content_length, body))
162        } else if let Some(length) = content_length {
163            HttpBody::Limited(body.take(length))
164        } else {
165            HttpBody::ReadTilClose(body)
166        }
167    }
168
169    pub fn require_length(&self) -> Result<()> {
170        let has_length = match self {
171            HttpBody::Chunked(_) => true,
172            HttpBody::Limited(_) => true,
173            HttpBody::ReadTilClose(_) => false,
174        };
175
176        if !has_length {
177            Err(Error::LengthRequired)
178        } else {
179            Ok(())
180        }
181    }
182
183    pub fn content_length(&self) -> Option<u64> {
184        match self {
185            HttpBody::Chunked(c) => c.content_length.clone(),
186            HttpBody::Limited(c) => Some(c.limit()),
187            HttpBody::ReadTilClose(_) => None,
188        }
189    }
190}
191
192#[test]
193fn chunked_body_no_content_length() {
194    let body = HttpBody::new(Some("chunked"), None, io::BufReader::new(io::empty()));
195    assert_eq!(body.content_length(), None);
196}
197
198#[test]
199fn chunked_body_content_length() {
200    let body = HttpBody::new(Some("chunked"), Some(12), io::BufReader::new(io::empty()));
201    assert_eq!(body.content_length(), Some(12));
202}
203
204#[test]
205fn read_till_close_body_has_no_content_length() {
206    let body = HttpBody::new(None, None, io::BufReader::new(io::empty()));
207    assert_eq!(body.content_length(), None);
208}
209
210#[test]
211fn limited_body_content_length() {
212    let body = HttpBody::new(None, Some(12), io::BufReader::new(io::empty()));
213    assert_eq!(body.content_length(), Some(12));
214}
215
216pub struct CrLfStream<W> {
217    stream: io::Bytes<W>,
218}
219
220impl<W: io::Read> CrLfStream<W> {
221    pub fn new(stream: W) -> Self {
222        CrLfStream {
223            stream: stream.bytes(),
224        }
225    }
226}
227
228impl<W: io::Read> Iterator for CrLfStream<W> {
229    type Item = Result<String>;
230    fn next(&mut self) -> Option<Result<String>> {
231        match self.inner_next() {
232            Err(e) => Some(Err(e)),
233            Ok(v) => v.map(Ok),
234        }
235    }
236}
237
238impl<W: io::Read> CrLfStream<W> {
239    fn inner_next(&mut self) -> Result<Option<String>> {
240        let mut line = Vec::new();
241        while let Some(byte) = self.stream.next() {
242            let byte = byte?;
243            line.push(byte);
244            if line.len() >= 2
245                && line[line.len() - 2] as char == '\r'
246                && line[line.len() - 1] as char == '\n'
247            {
248                let before = &line[..(line.len() - 2)];
249                if before.is_empty() {
250                    return Ok(None);
251                } else {
252                    return Ok(Some(str::from_utf8(before)?.into()));
253                }
254            }
255        }
256        Err(Error::UnexpectedEof("Expected \\r\\n".into()))
257    }
258
259    pub fn expect_next(&mut self) -> Result<String> {
260        self.inner_next()?
261            .ok_or_else(|| Error::UnexpectedEof("Expected line".into()))
262    }
263}
264
265#[cfg(test)]
266mod cr_lf_tests {
267    use super::CrLfStream;
268
269    #[test]
270    fn success() {
271        let input = "line1\r\nline2\r\n\r\n";
272        let mut s = CrLfStream::new(input.as_bytes());
273        assert_eq!(&s.next().unwrap().unwrap(), "line1");
274        assert_eq!(&s.next().unwrap().unwrap(), "line2");
275        assert!(s.next().is_none());
276    }
277
278    #[test]
279    fn expect_next() {
280        let input = "line1\r\nline2\r\n\r\n";
281        let mut s = CrLfStream::new(input.as_bytes());
282        assert_eq!(&s.expect_next().unwrap(), "line1");
283        assert_eq!(&s.expect_next().unwrap(), "line2");
284        assert!(s.expect_next().is_err());
285    }
286
287    #[test]
288    fn fails_with_missing_empty_line() {
289        let input = "line1\r\nline2\r\n";
290        let mut s = CrLfStream::new(input.as_bytes());
291        assert_eq!(&s.next().unwrap().unwrap(), "line1");
292        assert_eq!(&s.next().unwrap().unwrap(), "line2");
293        assert!(s.next().unwrap().is_err());
294    }
295
296    #[test]
297    fn fails_finding_separator() {
298        let input = "line1";
299        let mut s = CrLfStream::new(input.as_bytes());
300        assert!(s.next().unwrap().is_err());
301    }
302}
303
304pub struct Parser<'a> {
305    s: &'a str,
306    position: usize,
307}
308
309impl<'a> Parser<'a> {
310    pub fn new(s: &'a str) -> Self {
311        Parser { s, position: 0 }
312    }
313
314    pub fn expect(&mut self, expected: &str) -> Result<()> {
315        if self.position >= self.s.len() {
316            return Err(Error::UnexpectedEof(format!("Expected {}", expected)));
317        }
318
319        let start = self.position;
320        let end = cmp::min(self.s.len(), self.position + expected.len());
321        let actual = &self.s[start..end];
322        if actual != expected {
323            return Err(Error::ParseError(format!(
324                "Expected '{}', got '{}'",
325                expected, actual
326            )));
327        }
328        self.position += expected.len();
329        Ok(())
330    }
331
332    pub fn parse_char(&mut self) -> Result<char> {
333        if self.position >= self.s.len() {
334            return Err(Error::UnexpectedEof("Expected char".into()));
335        }
336
337        let c = self.s[self.position..=self.position]
338            .chars()
339            .next()
340            .unwrap();
341        self.position += 1;
342        Ok(c)
343    }
344
345    pub fn parse_digit(&mut self) -> Result<u32> {
346        if self.position >= self.s.len() {
347            return Err(Error::UnexpectedEof("Expected digit".into()));
348        }
349
350        let digit = &self.s[self.position..=self.position];
351        self.position += 1;
352        Ok(digit.parse()?)
353    }
354
355    pub fn parse_until(&mut self, div: &str) -> Result<&'a str> {
356        if self.position >= self.s.len() {
357            return Err(Error::UnexpectedEof(format!("Expected '{}'", div)));
358        }
359
360        let remaining = &self.s[self.position..];
361        let pos = remaining
362            .find(div)
363            .ok_or_else(|| Error::ParseError(format!("Expected '{}' in '{}'", div, remaining)))?;
364        self.position += pos;
365        Ok(&remaining[..pos])
366    }
367
368    pub fn parse_until_any(&mut self, divs: &[char]) -> Result<&'a str> {
369        if self.position >= self.s.len() {
370            return Err(Error::UnexpectedEof(format!("Expected '{:?}'", divs)));
371        }
372
373        let remaining = &self.s[self.position..];
374        let pos = remaining.find(|c| divs.contains(&c)).ok_or_else(|| {
375            Error::ParseError(format!("Expected '{:?}' in '{}'", divs, remaining))
376        })?;
377        self.position += pos;
378        Ok(&remaining[..pos])
379    }
380
381    pub fn consume_whilespace(&mut self) {
382        while self.position < self.s.len()
383            && (self.s[self.position..].starts_with(' ')
384                || self.s[self.position..].starts_with('\t'))
385        {
386            self.position += 1
387        }
388    }
389
390    pub fn parse_token(&mut self) -> Result<&'a str> {
391        if self.position >= self.s.len() {
392            return Err(Error::UnexpectedEof("Expected token".into()));
393        }
394
395        let remaining = &self.s[self.position..];
396        let token = remaining.split(|c| c == ' ' || c == '\t').next().unwrap();
397        self.position += token.len();
398        self.consume_whilespace();
399
400        Ok(token)
401    }
402
403    pub fn parse_number(&mut self) -> Result<u32> {
404        Ok(self.parse_token()?.parse()?)
405    }
406
407    pub fn parse_remaining(&mut self) -> Result<&str> {
408        if self.position > self.s.len() {
409            return Err(Error::UnexpectedEof("Expected token".into()));
410        }
411        let remaining = &self.s[self.position..];
412        self.position = self.s.len() + 1;
413        Ok(remaining)
414    }
415}
416
417#[cfg(test)]
418mod parser_tests {
419    use super::Parser;
420
421    #[test]
422    fn parse_empty() {
423        let mut parser = Parser::new("");
424        assert!(parser.expect("a").is_err());
425        assert!(parser.parse_digit().is_err());
426        assert!(parser.parse_token().is_err());
427    }
428
429    #[test]
430    fn expect_success() {
431        let mut parser = Parser::new("abcdefg");
432        parser.expect("abc").unwrap();
433        parser.expect("def").unwrap();
434        parser.expect("g").unwrap();
435    }
436
437    #[test]
438    fn expect_failure() {
439        let mut parser = Parser::new("abcdefg");
440        parser.expect("abc").unwrap();
441        assert!(parser.expect("deg").is_err());
442        parser.expect("defg").unwrap();
443    }
444
445    #[test]
446    fn expect_failure_with_eof() {
447        let mut parser = Parser::new("abcdefg");
448        parser.expect("abcdefg").unwrap();
449        assert!(parser.expect("a").is_err());
450    }
451
452    #[test]
453    fn parse_token() {
454        let mut parser = Parser::new("abc def");
455        assert_eq!(parser.parse_token().unwrap(), "abc");
456        assert_eq!(parser.parse_token().unwrap(), "def");
457        assert!(parser.parse_token().is_err());
458    }
459
460    #[test]
461    fn parse_token_with_lots_of_space() {
462        let mut parser = Parser::new("abc  \t    def");
463        assert_eq!(parser.parse_token().unwrap(), "abc");
464        assert_eq!(parser.parse_token().unwrap(), "def");
465        assert!(parser.parse_token().is_err());
466    }
467
468    #[test]
469    fn parse_token_no_space() {
470        let mut parser = Parser::new("abcdef");
471        assert_eq!(parser.parse_token().unwrap(), "abcdef");
472        assert!(parser.parse_token().is_err());
473    }
474
475    #[test]
476    fn parse_until() {
477        let mut parser = Parser::new("abc_def");
478        assert_eq!(parser.parse_until("_").unwrap(), "abc");
479        parser.expect("_").unwrap();
480        assert!(parser.parse_until("_").is_err());
481    }
482
483    #[test]
484    fn parse_until_any() {
485        let mut parser = Parser::new("abc_def");
486        assert_eq!(parser.parse_until_any(&['_', '-']).unwrap(), "abc");
487        parser.expect("_").unwrap();
488        assert!(parser.parse_until_any(&['_', '-']).is_err());
489
490        let mut parser = Parser::new("abc-def");
491        assert_eq!(parser.parse_until_any(&['_', '-']).unwrap(), "abc");
492        parser.expect("-").unwrap();
493        assert!(parser.parse_until_any(&['_', '-']).is_err());
494    }
495
496    #[test]
497    fn parse_until_empty() {
498        let mut parser = Parser::new("_abc");
499        assert_eq!(parser.parse_until("_").unwrap(), "");
500    }
501
502    #[test]
503    fn parse_until_no_divider() {
504        let mut parser = Parser::new("abcdef");
505        assert!(parser.parse_until("_").is_err());
506    }
507
508    #[test]
509    fn parse_number() {
510        let mut parser = Parser::new("123 456");
511        assert_eq!(parser.parse_number().unwrap(), 123);
512        assert_eq!(parser.parse_number().unwrap(), 456);
513        assert!(parser.parse_number().is_err());
514    }
515
516    #[test]
517    fn parse_number_failure() {
518        let mut parser = Parser::new("123 abc");
519        assert_eq!(parser.parse_number().unwrap(), 123);
520        assert!(parser.parse_number().is_err());
521    }
522
523    #[test]
524    fn parse_remaining() {
525        let mut parser = Parser::new("123 abc");
526        assert_eq!(parser.parse_remaining().unwrap(), "123 abc");
527        assert!(parser.parse_remaining().is_err());
528    }
529
530    #[test]
531    fn parse_remaining_empty() {
532        let mut parser = Parser::new("123 abc");
533        parser.expect("123 abc").unwrap();
534        assert_eq!(parser.parse_remaining().unwrap(), "");
535        assert!(parser.parse_remaining().is_err());
536    }
537}
538
539#[derive(Debug, Copy, Clone, PartialEq, Eq)]
540struct HttpVersion {
541    major: u32,
542    minor: u32,
543}
544
545impl HttpVersion {
546    fn new(major: u32, minor: u32) -> Self {
547        HttpVersion { major, minor }
548    }
549}
550
551impl str::FromStr for HttpVersion {
552    type Err = Error;
553
554    fn from_str(s: &str) -> Result<Self> {
555        let mut parser = Parser::new(s);
556        parser.expect("HTTP/")?;
557
558        let major = parser.parse_digit()?;
559        parser.expect(".")?;
560        let minor = parser.parse_digit()?;
561        Ok(HttpVersion::new(major, minor))
562    }
563}
564
565impl fmt::Display for HttpVersion {
566    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
567        write!(f, "HTTP/{}.{}", self.major, self.minor)
568    }
569}
570
571#[cfg(test)]
572mod http_version_tests {
573    use super::HttpVersion;
574    use std::string::ToString;
575
576    #[test]
577    fn parse_success() {
578        assert_eq!(
579            "HTTP/1.1".parse::<HttpVersion>().unwrap(),
580            HttpVersion::new(1, 1)
581        );
582        assert_eq!(
583            "HTTP/1.2".parse::<HttpVersion>().unwrap(),
584            HttpVersion::new(1, 2)
585        );
586    }
587
588    #[test]
589    fn parse_error() {
590        assert!("HTTP/".parse::<HttpVersion>().is_err());
591        assert!("HTTP/11.1".parse::<HttpVersion>().is_err());
592        assert!("HTTP/1".parse::<HttpVersion>().is_err());
593        assert!("HRRP/1.2".parse::<HttpVersion>().is_err());
594    }
595
596    #[test]
597    fn display() {
598        assert_eq!(&HttpVersion::new(1, 3).to_string(), "HTTP/1.3");
599    }
600
601    #[test]
602    fn parse_display_round_trip() {
603        assert_eq!(
604            &"HTTP/1.4".parse::<HttpVersion>().unwrap().to_string(),
605            "HTTP/1.4"
606        );
607    }
608}
609
610#[derive(Debug, Clone, Copy, PartialEq, Eq)]
611pub enum HttpStatus {
612    Accepted,
613    BadGateway,
614    BadRequest,
615    Conflict,
616    Continue,
617    Created,
618    ExpectationFailed,
619    Forbidden,
620    Found,
621    GatewayTimeout,
622    Gone,
623    HttpVersionNotSupported,
624    InternalServerError,
625    LengthRequired,
626    MethodNotAllowed,
627    MovedPermanently,
628    MultipleChoices,
629    NoContent,
630    NonAuthoritativeInformation,
631    NotAcceptable,
632    NotFound,
633    NotImplemented,
634    NotModified,
635    OK,
636    PartialContent,
637    PaymentRequired,
638    PreconditionFailed,
639    ProxyAuthenticationRequired,
640    RequestEntityTooLarge,
641    RequestTimeout,
642    RequestUriTooLong,
643    RequestedRangeNotSatisfiable,
644    ResetContent,
645    SeeOther,
646    ServiceUnavailable,
647    SwitchingProtocols,
648    TemporaryRedirect,
649    Unauthorized,
650    UnsupportedMediaType,
651    UseProxy,
652    Unknown(u32),
653}
654
655#[derive(Debug, Copy, Clone, PartialEq, Eq)]
656pub enum HttpStatusCategory {
657    Informational,
658    Success,
659    Redirection,
660    ClientError,
661    ServerError,
662    Unknown,
663}
664
665impl HttpStatusCategory {
666    fn from_code(code: u32) -> Self {
667        match code {
668            1 => Self::Informational,
669            2 => Self::Success,
670            3 => Self::Redirection,
671            4 => Self::ClientError,
672            5 => Self::ServerError,
673            _ => Self::Unknown,
674        }
675    }
676}
677
678impl HttpStatus {
679    pub fn to_category(&self) -> HttpStatusCategory {
680        HttpStatusCategory::from_code(self.to_code() / 100)
681    }
682
683    pub fn to_code(&self) -> u32 {
684        match self {
685            Self::Continue => 100,
686            Self::SwitchingProtocols => 101,
687            Self::OK => 200,
688            Self::Created => 201,
689            Self::Accepted => 202,
690            Self::NonAuthoritativeInformation => 203,
691            Self::NoContent => 204,
692            Self::ResetContent => 205,
693            Self::PartialContent => 206,
694            Self::MultipleChoices => 300,
695            Self::MovedPermanently => 301,
696            Self::Found => 302,
697            Self::SeeOther => 303,
698            Self::NotModified => 304,
699            Self::UseProxy => 305,
700            Self::TemporaryRedirect => 307,
701            Self::BadRequest => 400,
702            Self::Unauthorized => 401,
703            Self::PaymentRequired => 402,
704            Self::Forbidden => 403,
705            Self::NotFound => 404,
706            Self::MethodNotAllowed => 405,
707            Self::NotAcceptable => 406,
708            Self::ProxyAuthenticationRequired => 407,
709            Self::RequestTimeout => 408,
710            Self::Conflict => 409,
711            Self::Gone => 410,
712            Self::LengthRequired => 411,
713            Self::PreconditionFailed => 412,
714            Self::RequestEntityTooLarge => 413,
715            Self::RequestUriTooLong => 414,
716            Self::UnsupportedMediaType => 415,
717            Self::RequestedRangeNotSatisfiable => 416,
718            Self::ExpectationFailed => 417,
719            Self::InternalServerError => 500,
720            Self::NotImplemented => 501,
721            Self::BadGateway => 502,
722            Self::ServiceUnavailable => 503,
723            Self::GatewayTimeout => 504,
724            Self::HttpVersionNotSupported => 505,
725            Self::Unknown(c) => *c,
726        }
727    }
728
729    pub fn from_code(code: u32) -> Self {
730        match code {
731            100 => Self::Continue,
732            101 => Self::SwitchingProtocols,
733            200 => Self::OK,
734            201 => Self::Created,
735            202 => Self::Accepted,
736            203 => Self::NonAuthoritativeInformation,
737            204 => Self::NoContent,
738            205 => Self::ResetContent,
739            206 => Self::PartialContent,
740            300 => Self::MultipleChoices,
741            301 => Self::MovedPermanently,
742            302 => Self::Found,
743            303 => Self::SeeOther,
744            304 => Self::NotModified,
745            305 => Self::UseProxy,
746            307 => Self::TemporaryRedirect,
747            400 => Self::BadRequest,
748            401 => Self::Unauthorized,
749            402 => Self::PaymentRequired,
750            403 => Self::Forbidden,
751            404 => Self::NotFound,
752            405 => Self::MethodNotAllowed,
753            406 => Self::NotAcceptable,
754            407 => Self::ProxyAuthenticationRequired,
755            408 => Self::RequestTimeout,
756            409 => Self::Conflict,
757            410 => Self::Gone,
758            411 => Self::LengthRequired,
759            412 => Self::PreconditionFailed,
760            413 => Self::RequestEntityTooLarge,
761            414 => Self::RequestUriTooLong,
762            415 => Self::UnsupportedMediaType,
763            416 => Self::RequestedRangeNotSatisfiable,
764            417 => Self::ExpectationFailed,
765            500 => Self::InternalServerError,
766            501 => Self::NotImplemented,
767            502 => Self::BadGateway,
768            503 => Self::ServiceUnavailable,
769            504 => Self::GatewayTimeout,
770            505 => Self::HttpVersionNotSupported,
771            v => Self::Unknown(v),
772        }
773    }
774}
775
776#[test]
777fn category_from_status_code() {
778    assert_eq!(
779        HttpStatus::Continue.to_category(),
780        HttpStatusCategory::Informational
781    );
782    assert_eq!(
783        HttpStatus::Accepted.to_category(),
784        HttpStatusCategory::Success
785    );
786    assert_eq!(
787        HttpStatus::MovedPermanently.to_category(),
788        HttpStatusCategory::Redirection
789    );
790    assert_eq!(
791        HttpStatus::Forbidden.to_category(),
792        HttpStatusCategory::ClientError
793    );
794    assert_eq!(
795        HttpStatus::InternalServerError.to_category(),
796        HttpStatusCategory::ServerError
797    );
798
799    assert_eq!(
800        HttpStatus::Unknown(200).to_category(),
801        HttpStatusCategory::Success
802    );
803    assert_eq!(
804        HttpStatus::Unknown(700).to_category(),
805        HttpStatusCategory::Unknown
806    );
807}
808
809#[test]
810fn from_code_to_code() {
811    for c in 0..600 {
812        assert_eq!(HttpStatus::from_code(c).to_code(), c);
813    }
814}
815
816impl str::FromStr for HttpStatus {
817    type Err = Error;
818
819    fn from_str(s: &str) -> Result<Self> {
820        let mut parser = Parser::new(s);
821        Ok(Self::from_code(parser.parse_number()?))
822    }
823}
824
825impl fmt::Display for HttpStatus {
826    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
827        match self {
828            HttpStatus::Accepted => write!(f, "202 Accepted"),
829            HttpStatus::BadGateway => write!(f, "502 Bad Gateway"),
830            HttpStatus::BadRequest => write!(f, "400 Bad Request"),
831            HttpStatus::Conflict => write!(f, "409 Conflict"),
832            HttpStatus::Continue => write!(f, "100 Continue"),
833            HttpStatus::Created => write!(f, "201 Created"),
834            HttpStatus::ExpectationFailed => write!(f, "417 Expectation Failed"),
835            HttpStatus::Forbidden => write!(f, "403 Forbidden"),
836            HttpStatus::Found => write!(f, "302 Found"),
837            HttpStatus::GatewayTimeout => write!(f, "504 Gateway Timeout"),
838            HttpStatus::Gone => write!(f, "410 Gone"),
839            HttpStatus::HttpVersionNotSupported => write!(f, "505 HTTP Version Not Supported"),
840            HttpStatus::InternalServerError => write!(f, "500 Internal Server Error"),
841            HttpStatus::LengthRequired => write!(f, "411 Length Required"),
842            HttpStatus::MethodNotAllowed => write!(f, "405 Method Not Allowed"),
843            HttpStatus::MovedPermanently => write!(f, "301 Moved Permanently"),
844            HttpStatus::MultipleChoices => write!(f, "300 Multiple Choices"),
845            HttpStatus::NoContent => write!(f, "204 No Content"),
846            HttpStatus::NonAuthoritativeInformation => {
847                write!(f, "203 No Authoritative Information")
848            }
849            HttpStatus::NotAcceptable => write!(f, "406 Not Acceptable"),
850            HttpStatus::NotFound => write!(f, "404 Not Found"),
851            HttpStatus::NotImplemented => write!(f, "501 Not Implemented"),
852            HttpStatus::NotModified => write!(f, "304 NotModified"),
853            HttpStatus::OK => write!(f, "200 OK"),
854            HttpStatus::PartialContent => write!(f, "206 Partial Content"),
855            HttpStatus::PaymentRequired => write!(f, "402 Payment Required"),
856            HttpStatus::PreconditionFailed => write!(f, "412 Precondition Failed"),
857            HttpStatus::ProxyAuthenticationRequired => {
858                write!(f, "407 Prozy Authentication Required")
859            }
860            HttpStatus::RequestEntityTooLarge => write!(f, "413 Request Entity Too Large"),
861            HttpStatus::RequestTimeout => write!(f, "408 Request Timeout"),
862            HttpStatus::RequestUriTooLong => write!(f, "414 Request URI Too Long"),
863            HttpStatus::RequestedRangeNotSatisfiable => {
864                write!(f, "416 Requested Range Not Satisfiable")
865            }
866            HttpStatus::ResetContent => write!(f, "205 Reset Content"),
867            HttpStatus::SeeOther => write!(f, "303 See Other"),
868            HttpStatus::ServiceUnavailable => write!(f, "503 Service Unavailable"),
869            HttpStatus::SwitchingProtocols => write!(f, "101 Switching Protocols"),
870            HttpStatus::TemporaryRedirect => write!(f, "307 Temporary Redirect"),
871            HttpStatus::Unauthorized => write!(f, "401 Unauthorized"),
872            HttpStatus::UnsupportedMediaType => write!(f, "415 Unsupported Media Type"),
873            HttpStatus::UseProxy => write!(f, "305 Use Proxy"),
874            HttpStatus::Unknown(v) => write!(f, "{}", v),
875        }
876    }
877}
878
879#[cfg(test)]
880mod http_status_tests {
881    use super::HttpStatus;
882    use std::string::ToString;
883
884    #[test]
885    fn parse_success() {
886        assert_eq!(
887            "301 Moved Permanently".parse::<HttpStatus>().unwrap(),
888            HttpStatus::MovedPermanently,
889        );
890        assert_eq!("100".parse::<HttpStatus>().unwrap(), HttpStatus::Continue);
891        assert_eq!(
892            "101".parse::<HttpStatus>().unwrap(),
893            HttpStatus::SwitchingProtocols
894        );
895        assert_eq!("200".parse::<HttpStatus>().unwrap(), HttpStatus::OK);
896        assert_eq!("201".parse::<HttpStatus>().unwrap(), HttpStatus::Created);
897        assert_eq!("202".parse::<HttpStatus>().unwrap(), HttpStatus::Accepted);
898        assert_eq!(
899            "203".parse::<HttpStatus>().unwrap(),
900            HttpStatus::NonAuthoritativeInformation
901        );
902        assert_eq!("204".parse::<HttpStatus>().unwrap(), HttpStatus::NoContent);
903        assert_eq!(
904            "205".parse::<HttpStatus>().unwrap(),
905            HttpStatus::ResetContent
906        );
907        assert_eq!(
908            "206".parse::<HttpStatus>().unwrap(),
909            HttpStatus::PartialContent
910        );
911        assert_eq!(
912            "300".parse::<HttpStatus>().unwrap(),
913            HttpStatus::MultipleChoices
914        );
915        assert_eq!(
916            "301".parse::<HttpStatus>().unwrap(),
917            HttpStatus::MovedPermanently
918        );
919        assert_eq!("302".parse::<HttpStatus>().unwrap(), HttpStatus::Found);
920        assert_eq!("303".parse::<HttpStatus>().unwrap(), HttpStatus::SeeOther);
921        assert_eq!(
922            "304".parse::<HttpStatus>().unwrap(),
923            HttpStatus::NotModified
924        );
925        assert_eq!("305".parse::<HttpStatus>().unwrap(), HttpStatus::UseProxy);
926        assert_eq!(
927            "307".parse::<HttpStatus>().unwrap(),
928            HttpStatus::TemporaryRedirect
929        );
930        assert_eq!("400".parse::<HttpStatus>().unwrap(), HttpStatus::BadRequest);
931        assert_eq!(
932            "401".parse::<HttpStatus>().unwrap(),
933            HttpStatus::Unauthorized
934        );
935        assert_eq!(
936            "402".parse::<HttpStatus>().unwrap(),
937            HttpStatus::PaymentRequired
938        );
939        assert_eq!("403".parse::<HttpStatus>().unwrap(), HttpStatus::Forbidden);
940        assert_eq!("404".parse::<HttpStatus>().unwrap(), HttpStatus::NotFound);
941        assert_eq!(
942            "405".parse::<HttpStatus>().unwrap(),
943            HttpStatus::MethodNotAllowed
944        );
945        assert_eq!(
946            "406".parse::<HttpStatus>().unwrap(),
947            HttpStatus::NotAcceptable
948        );
949        assert_eq!(
950            "407".parse::<HttpStatus>().unwrap(),
951            HttpStatus::ProxyAuthenticationRequired
952        );
953        assert_eq!(
954            "408".parse::<HttpStatus>().unwrap(),
955            HttpStatus::RequestTimeout
956        );
957        assert_eq!("409".parse::<HttpStatus>().unwrap(), HttpStatus::Conflict);
958        assert_eq!("410".parse::<HttpStatus>().unwrap(), HttpStatus::Gone);
959        assert_eq!(
960            "411".parse::<HttpStatus>().unwrap(),
961            HttpStatus::LengthRequired
962        );
963        assert_eq!(
964            "412".parse::<HttpStatus>().unwrap(),
965            HttpStatus::PreconditionFailed
966        );
967        assert_eq!(
968            "413".parse::<HttpStatus>().unwrap(),
969            HttpStatus::RequestEntityTooLarge
970        );
971        assert_eq!(
972            "414".parse::<HttpStatus>().unwrap(),
973            HttpStatus::RequestUriTooLong
974        );
975        assert_eq!(
976            "415".parse::<HttpStatus>().unwrap(),
977            HttpStatus::UnsupportedMediaType
978        );
979        assert_eq!(
980            "416".parse::<HttpStatus>().unwrap(),
981            HttpStatus::RequestedRangeNotSatisfiable
982        );
983        assert_eq!(
984            "417".parse::<HttpStatus>().unwrap(),
985            HttpStatus::ExpectationFailed
986        );
987        assert_eq!(
988            "500".parse::<HttpStatus>().unwrap(),
989            HttpStatus::InternalServerError
990        );
991        assert_eq!(
992            "501".parse::<HttpStatus>().unwrap(),
993            HttpStatus::NotImplemented
994        );
995        assert_eq!("502".parse::<HttpStatus>().unwrap(), HttpStatus::BadGateway);
996        assert_eq!(
997            "503".parse::<HttpStatus>().unwrap(),
998            HttpStatus::ServiceUnavailable
999        );
1000        assert_eq!(
1001            "504".parse::<HttpStatus>().unwrap(),
1002            HttpStatus::GatewayTimeout
1003        );
1004        assert_eq!(
1005            "505".parse::<HttpStatus>().unwrap(),
1006            HttpStatus::HttpVersionNotSupported
1007        );
1008        assert_eq!("200 OK".parse::<HttpStatus>().unwrap(), HttpStatus::OK);
1009        assert_eq!(
1010            "899".parse::<HttpStatus>().unwrap(),
1011            HttpStatus::Unknown(899)
1012        );
1013    }
1014
1015    #[test]
1016    fn parse_error() {
1017        assert!("abc".parse::<HttpStatus>().is_err());
1018        assert!("301a".parse::<HttpStatus>().is_err());
1019    }
1020
1021    #[test]
1022    fn display() {
1023        assert_eq!(&HttpStatus::Accepted.to_string(), "202 Accepted");
1024        assert_eq!(&HttpStatus::BadGateway.to_string(), "502 Bad Gateway");
1025        assert_eq!(&HttpStatus::BadRequest.to_string(), "400 Bad Request");
1026        assert_eq!(&HttpStatus::Conflict.to_string(), "409 Conflict");
1027        assert_eq!(&HttpStatus::Continue.to_string(), "100 Continue");
1028        assert_eq!(&HttpStatus::Created.to_string(), "201 Created");
1029        assert_eq!(
1030            &HttpStatus::ExpectationFailed.to_string(),
1031            "417 Expectation Failed"
1032        );
1033        assert_eq!(&HttpStatus::Forbidden.to_string(), "403 Forbidden");
1034        assert_eq!(&HttpStatus::Found.to_string(), "302 Found");
1035        assert_eq!(
1036            &HttpStatus::GatewayTimeout.to_string(),
1037            "504 Gateway Timeout"
1038        );
1039        assert_eq!(&HttpStatus::Gone.to_string(), "410 Gone");
1040        assert_eq!(
1041            &HttpStatus::HttpVersionNotSupported.to_string(),
1042            "505 HTTP Version Not Supported"
1043        );
1044        assert_eq!(
1045            &HttpStatus::InternalServerError.to_string(),
1046            "500 Internal Server Error"
1047        );
1048        assert_eq!(
1049            &HttpStatus::LengthRequired.to_string(),
1050            "411 Length Required"
1051        );
1052        assert_eq!(
1053            &HttpStatus::MethodNotAllowed.to_string(),
1054            "405 Method Not Allowed"
1055        );
1056        assert_eq!(
1057            &HttpStatus::MovedPermanently.to_string(),
1058            "301 Moved Permanently"
1059        );
1060        assert_eq!(
1061            &HttpStatus::MultipleChoices.to_string(),
1062            "300 Multiple Choices"
1063        );
1064        assert_eq!(&HttpStatus::NoContent.to_string(), "204 No Content");
1065        assert_eq!(
1066            &HttpStatus::NonAuthoritativeInformation.to_string(),
1067            "203 No Authoritative Information"
1068        );
1069        assert_eq!(&HttpStatus::NotAcceptable.to_string(), "406 Not Acceptable");
1070        assert_eq!(&HttpStatus::NotFound.to_string(), "404 Not Found");
1071        assert_eq!(
1072            &HttpStatus::NotImplemented.to_string(),
1073            "501 Not Implemented"
1074        );
1075        assert_eq!(&HttpStatus::NotModified.to_string(), "304 NotModified");
1076        assert_eq!(&HttpStatus::OK.to_string(), "200 OK");
1077        assert_eq!(
1078            &HttpStatus::PartialContent.to_string(),
1079            "206 Partial Content"
1080        );
1081        assert_eq!(
1082            &HttpStatus::PaymentRequired.to_string(),
1083            "402 Payment Required"
1084        );
1085        assert_eq!(
1086            &HttpStatus::PreconditionFailed.to_string(),
1087            "412 Precondition Failed"
1088        );
1089        assert_eq!(
1090            &HttpStatus::ProxyAuthenticationRequired.to_string(),
1091            "407 Prozy Authentication Required",
1092        );
1093        assert_eq!(
1094            &HttpStatus::RequestEntityTooLarge.to_string(),
1095            "413 Request Entity Too Large"
1096        );
1097        assert_eq!(
1098            &HttpStatus::RequestTimeout.to_string(),
1099            "408 Request Timeout"
1100        );
1101        assert_eq!(
1102            &HttpStatus::RequestUriTooLong.to_string(),
1103            "414 Request URI Too Long"
1104        );
1105        assert_eq!(
1106            &HttpStatus::RequestedRangeNotSatisfiable.to_string(),
1107            "416 Requested Range Not Satisfiable"
1108        );
1109        assert_eq!(&HttpStatus::ResetContent.to_string(), "205 Reset Content");
1110        assert_eq!(&HttpStatus::SeeOther.to_string(), "303 See Other");
1111        assert_eq!(
1112            &HttpStatus::ServiceUnavailable.to_string(),
1113            "503 Service Unavailable"
1114        );
1115        assert_eq!(
1116            &HttpStatus::SwitchingProtocols.to_string(),
1117            "101 Switching Protocols"
1118        );
1119        assert_eq!(
1120            &HttpStatus::TemporaryRedirect.to_string(),
1121            "307 Temporary Redirect"
1122        );
1123        assert_eq!(&HttpStatus::Unauthorized.to_string(), "401 Unauthorized");
1124        assert_eq!(
1125            &HttpStatus::UnsupportedMediaType.to_string(),
1126            "415 Unsupported Media Type"
1127        );
1128        assert_eq!(&HttpStatus::UseProxy.to_string(), "305 Use Proxy");
1129        assert_eq!(&HttpStatus::Unknown(899).to_string(), "899");
1130    }
1131
1132    #[test]
1133    fn parse_display_round_trip() {
1134        assert_eq!(
1135            "202 Accepted".parse::<HttpStatus>().unwrap().to_string(),
1136            "202 Accepted"
1137        );
1138        assert_eq!(
1139            "502 Bad Gateway".parse::<HttpStatus>().unwrap().to_string(),
1140            "502 Bad Gateway"
1141        );
1142        assert_eq!(
1143            "400 Bad Request".parse::<HttpStatus>().unwrap().to_string(),
1144            "400 Bad Request"
1145        );
1146        assert_eq!(
1147            "409 Conflict".parse::<HttpStatus>().unwrap().to_string(),
1148            "409 Conflict"
1149        );
1150        assert_eq!(
1151            "100 Continue".parse::<HttpStatus>().unwrap().to_string(),
1152            "100 Continue"
1153        );
1154        assert_eq!(
1155            "201 Created".parse::<HttpStatus>().unwrap().to_string(),
1156            "201 Created"
1157        );
1158        assert_eq!(
1159            "417 Expectation Failed"
1160                .parse::<HttpStatus>()
1161                .unwrap()
1162                .to_string(),
1163            "417 Expectation Failed"
1164        );
1165        assert_eq!(
1166            "403 Forbidden".parse::<HttpStatus>().unwrap().to_string(),
1167            "403 Forbidden"
1168        );
1169        assert_eq!(
1170            "302 Found".parse::<HttpStatus>().unwrap().to_string(),
1171            "302 Found"
1172        );
1173        assert_eq!(
1174            "504 Gateway Timeout"
1175                .parse::<HttpStatus>()
1176                .unwrap()
1177                .to_string(),
1178            "504 Gateway Timeout"
1179        );
1180        assert_eq!(
1181            "410 Gone".parse::<HttpStatus>().unwrap().to_string(),
1182            "410 Gone"
1183        );
1184        assert_eq!(
1185            "505 HTTP Version Not Supported"
1186                .parse::<HttpStatus>()
1187                .unwrap()
1188                .to_string(),
1189            "505 HTTP Version Not Supported"
1190        );
1191        assert_eq!(
1192            "500 Internal Server Error"
1193                .parse::<HttpStatus>()
1194                .unwrap()
1195                .to_string(),
1196            "500 Internal Server Error"
1197        );
1198        assert_eq!(
1199            "411 Length Required"
1200                .parse::<HttpStatus>()
1201                .unwrap()
1202                .to_string(),
1203            "411 Length Required"
1204        );
1205        assert_eq!(
1206            "405 Method Not Allowed"
1207                .parse::<HttpStatus>()
1208                .unwrap()
1209                .to_string(),
1210            "405 Method Not Allowed"
1211        );
1212        assert_eq!(
1213            "301 Moved Permanently"
1214                .parse::<HttpStatus>()
1215                .unwrap()
1216                .to_string(),
1217            "301 Moved Permanently"
1218        );
1219        assert_eq!(
1220            "300 Multiple Choices"
1221                .parse::<HttpStatus>()
1222                .unwrap()
1223                .to_string(),
1224            "300 Multiple Choices"
1225        );
1226        assert_eq!(
1227            "204 No Content".parse::<HttpStatus>().unwrap().to_string(),
1228            "204 No Content"
1229        );
1230        assert_eq!(
1231            "203 No Authoritative Information"
1232                .parse::<HttpStatus>()
1233                .unwrap()
1234                .to_string(),
1235            "203 No Authoritative Information"
1236        );
1237        assert_eq!(
1238            "406 Not Acceptable"
1239                .parse::<HttpStatus>()
1240                .unwrap()
1241                .to_string(),
1242            "406 Not Acceptable"
1243        );
1244        assert_eq!(
1245            "404 Not Found".parse::<HttpStatus>().unwrap().to_string(),
1246            "404 Not Found"
1247        );
1248        assert_eq!(
1249            "501 Not Implemented"
1250                .parse::<HttpStatus>()
1251                .unwrap()
1252                .to_string(),
1253            "501 Not Implemented"
1254        );
1255        assert_eq!(
1256            "304 NotModified".parse::<HttpStatus>().unwrap().to_string(),
1257            "304 NotModified"
1258        );
1259        assert_eq!(
1260            "200 OK".parse::<HttpStatus>().unwrap().to_string(),
1261            "200 OK"
1262        );
1263        assert_eq!(
1264            "206 Partial Content"
1265                .parse::<HttpStatus>()
1266                .unwrap()
1267                .to_string(),
1268            "206 Partial Content"
1269        );
1270        assert_eq!(
1271            "402 Payment Required"
1272                .parse::<HttpStatus>()
1273                .unwrap()
1274                .to_string(),
1275            "402 Payment Required"
1276        );
1277        assert_eq!(
1278            "412 Precondition Failed"
1279                .parse::<HttpStatus>()
1280                .unwrap()
1281                .to_string(),
1282            "412 Precondition Failed"
1283        );
1284        assert_eq!(
1285            "407 Prozy Authentication Required"
1286                .parse::<HttpStatus>()
1287                .unwrap()
1288                .to_string(),
1289            "407 Prozy Authentication Required"
1290        );
1291        assert_eq!(
1292            "413 Request Entity Too Large"
1293                .parse::<HttpStatus>()
1294                .unwrap()
1295                .to_string(),
1296            "413 Request Entity Too Large"
1297        );
1298        assert_eq!(
1299            "408 Request Timeout"
1300                .parse::<HttpStatus>()
1301                .unwrap()
1302                .to_string(),
1303            "408 Request Timeout"
1304        );
1305        assert_eq!(
1306            "414 Request URI Too Long"
1307                .parse::<HttpStatus>()
1308                .unwrap()
1309                .to_string(),
1310            "414 Request URI Too Long"
1311        );
1312        assert_eq!(
1313            "416 Requested Range Not Satisfiable"
1314                .parse::<HttpStatus>()
1315                .unwrap()
1316                .to_string(),
1317            "416 Requested Range Not Satisfiable"
1318        );
1319        assert_eq!(
1320            "205 Reset Content"
1321                .parse::<HttpStatus>()
1322                .unwrap()
1323                .to_string(),
1324            "205 Reset Content"
1325        );
1326        assert_eq!(
1327            "303 See Other".parse::<HttpStatus>().unwrap().to_string(),
1328            "303 See Other"
1329        );
1330        assert_eq!(
1331            "503 Service Unavailable"
1332                .parse::<HttpStatus>()
1333                .unwrap()
1334                .to_string(),
1335            "503 Service Unavailable"
1336        );
1337        assert_eq!(
1338            "101 Switching Protocols"
1339                .parse::<HttpStatus>()
1340                .unwrap()
1341                .to_string(),
1342            "101 Switching Protocols"
1343        );
1344        assert_eq!(
1345            "307 Temporary Redirect"
1346                .parse::<HttpStatus>()
1347                .unwrap()
1348                .to_string(),
1349            "307 Temporary Redirect"
1350        );
1351        assert_eq!(
1352            "401 Unauthorized"
1353                .parse::<HttpStatus>()
1354                .unwrap()
1355                .to_string(),
1356            "401 Unauthorized"
1357        );
1358        assert_eq!(
1359            "415 Unsupported Media Type"
1360                .parse::<HttpStatus>()
1361                .unwrap()
1362                .to_string(),
1363            "415 Unsupported Media Type"
1364        );
1365        assert_eq!(
1366            "305 Use Proxy".parse::<HttpStatus>().unwrap().to_string(),
1367            "305 Use Proxy"
1368        );
1369        assert_eq!(&"889".parse::<HttpStatus>().unwrap().to_string(), "889");
1370    }
1371}
1372
1373#[derive(Debug, PartialEq, Eq)]
1374struct HttpHeader {
1375    key: String,
1376    value: String,
1377}
1378
1379impl HttpHeader {
1380    fn new(key: impl AsRef<str>, value: impl Into<String>) -> Self {
1381        HttpHeader {
1382            key: key.as_ref().to_lowercase(),
1383            value: value.into(),
1384        }
1385    }
1386
1387    fn deserialize(s: &str) -> Result<Self> {
1388        let mut parser = Parser::new(s);
1389        let key = parser.parse_until(":")?;
1390        parser.expect(": ")?;
1391        let value = parser.parse_remaining()?;
1392
1393        Ok(HttpHeader::new(key.to_lowercase(), value))
1394    }
1395}
1396
1397#[cfg(test)]
1398mod http_header_tests {
1399    use super::HttpHeader;
1400
1401    #[test]
1402    fn parse_success() {
1403        assert_eq!(
1404            HttpHeader::deserialize("key: value").unwrap(),
1405            HttpHeader::new("key", "value")
1406        );
1407        assert_eq!(
1408            HttpHeader::deserialize("key: value1 value2").unwrap(),
1409            HttpHeader::new("key", "value1 value2")
1410        );
1411    }
1412
1413    #[test]
1414    fn parse_failure_no_value() {
1415        assert!(HttpHeader::deserialize("key").is_err());
1416    }
1417}
1418
1419#[derive(Debug, Default, PartialEq, Eq)]
1420pub struct HttpHeaders {
1421    headers: BTreeMap<String, String>,
1422}
1423
1424#[macro_export]
1425macro_rules! http_headers {
1426    ($($key:expr => $value:expr),* ,) => (
1427        $crate::hash_map!($($key => $value),*)
1428    );
1429    ($($key:expr => $value:expr),*) => ({
1430        ::core::iter::Iterator::collect::<$crate::protocol::HttpHeaders>(
1431            ::core::iter::IntoIterator::into_iter([
1432                $((
1433                    ::core::convert::From::from($key),
1434                    ::core::convert::From::from($value)
1435                ),)*
1436            ])
1437        )
1438    });
1439}
1440
1441impl HttpHeaders {
1442    fn new() -> Self {
1443        HttpHeaders {
1444            headers: BTreeMap::new(),
1445        }
1446    }
1447
1448    pub fn get(&self, key: impl AsRef<str>) -> Option<&str> {
1449        self.headers
1450            .get(&key.as_ref().to_lowercase())
1451            .map(convert::AsRef::as_ref)
1452    }
1453
1454    pub fn insert(&mut self, key: impl AsRef<str>, value: impl Into<String>) {
1455        self.headers
1456            .insert(key.as_ref().to_lowercase(), value.into());
1457    }
1458
1459    fn deserialize<R: io::Read>(s: &mut CrLfStream<R>) -> Result<Self> {
1460        let mut headers = vec![];
1461        let mut iter = s.peekable();
1462        while let Some(line) = iter.next() {
1463            let mut line = line?;
1464            while let Some(Ok(next_line)) = iter.peek() {
1465                if !next_line.starts_with(' ') && !next_line.starts_with('\t') {
1466                    break;
1467                }
1468                line.push_str(&iter.next().unwrap()?);
1469            }
1470            headers.push(HttpHeader::deserialize(&line)?);
1471        }
1472        Ok(HttpHeaders::from(headers))
1473    }
1474
1475    fn serialize<W: io::Write>(&self, mut w: W) -> Result<()> {
1476        for (key, value) in &self.headers {
1477            write!(&mut w, "{}: {}\r\n", key, value)?;
1478        }
1479        Ok(())
1480    }
1481}
1482
1483impl iter::FromIterator<(String, String)> for HttpHeaders {
1484    fn from_iter<T: IntoIterator<Item = (String, String)>>(iter: T) -> Self {
1485        Self {
1486            headers: iter.into_iter().collect(),
1487        }
1488    }
1489}
1490
1491impl<'a> IntoIterator for &'a HttpHeaders {
1492    type Item = (&'a String, &'a String);
1493    type IntoIter = BTreeMapIter<'a, String, String>;
1494
1495    fn into_iter(self) -> Self::IntoIter {
1496        self.headers.iter()
1497    }
1498}
1499
1500#[test]
1501fn http_headers_case_insensitive() {
1502    for k1 in ["FOO", "FoO", "foo"] {
1503        let mut headers = HttpHeaders::new();
1504        headers.insert(k1, "Bar");
1505        headers.insert(String::from(k1), "Bar");
1506
1507        for k2 in ["FOO", "FoO", "foo"] {
1508            assert_eq!(headers.get(k2), Some("Bar"));
1509            assert_eq!(headers.get(String::from(k2)), Some("Bar"));
1510        }
1511    }
1512}
1513
1514impl From<Vec<HttpHeader>> for HttpHeaders {
1515    fn from(mut headers: Vec<HttpHeader>) -> Self {
1516        let mut map = BTreeMap::new();
1517        for h in headers.drain(..) {
1518            map.insert(h.key, h.value);
1519        }
1520        HttpHeaders { headers: map }
1521    }
1522}
1523
1524#[cfg(test)]
1525mod http_headers_tests {
1526    use super::{CrLfStream, HttpHeader, HttpHeaders};
1527    use std::str;
1528
1529    #[test]
1530    fn to_string() {
1531        let headers = HttpHeaders::from(vec![HttpHeader::new("A", "B"), HttpHeader::new("c", "d")]);
1532        let mut data = Vec::new();
1533        headers.serialize(&mut data).unwrap();
1534        assert_eq!(str::from_utf8(&data).unwrap(), "a: B\r\nc: d\r\n");
1535    }
1536
1537    #[test]
1538    fn serialize_empty() {
1539        let headers = HttpHeaders::from(vec![]);
1540        let mut data = Vec::new();
1541        headers.serialize(&mut data).unwrap();
1542        assert_eq!(str::from_utf8(&data).unwrap(), "");
1543    }
1544
1545    #[test]
1546    fn deserialize_success() {
1547        let mut input = CrLfStream::new("A: b\r\nC: d\r\n\r\n".as_bytes());
1548        let actual = HttpHeaders::deserialize(&mut input).unwrap();
1549        let expected =
1550            HttpHeaders::from(vec![HttpHeader::new("a", "b"), HttpHeader::new("c", "d")]);
1551        assert_eq!(actual, expected);
1552    }
1553
1554    #[test]
1555    fn deserialize_success_header_continuation() {
1556        let mut input = CrLfStream::new("a: b\r\n e\r\nc: d\r\n\r\n".as_bytes());
1557        let actual = HttpHeaders::deserialize(&mut input).unwrap();
1558        let expected =
1559            HttpHeaders::from(vec![HttpHeader::new("a", "b e"), HttpHeader::new("c", "d")]);
1560        assert_eq!(actual, expected);
1561    }
1562}
1563
1564pub struct HttpResponse<B: io::Read> {
1565    version: HttpVersion,
1566    pub status: HttpStatus,
1567    pub headers: HttpHeaders,
1568    pub body: HttpBody<B>,
1569}
1570
1571impl HttpResponse<Box<dyn io::Read>> {
1572    pub fn from_string<S: Into<String>>(status: HttpStatus, s: S) -> Self {
1573        HttpResponse::new(status, Box::new(io::Cursor::new(s.into())))
1574    }
1575}
1576
1577impl<B: io::Read> HttpResponse<B> {
1578    pub fn new(status: HttpStatus, body: B) -> Self {
1579        let body = HttpBody::ReadTilClose(io::BufReader::new(body));
1580        HttpResponse {
1581            version: HttpVersion::new(1, 1),
1582            status,
1583            headers: HttpHeaders::new(),
1584            body,
1585        }
1586    }
1587
1588    pub fn deserialize(mut socket: B) -> Result<Self> {
1589        let mut s = CrLfStream::new(&mut socket);
1590        let first_line = s.expect_next()?;
1591        let mut parser = Parser::new(&first_line);
1592
1593        let version = parser.parse_token()?.parse()?;
1594        let status = parser.parse_remaining()?.parse()?;
1595
1596        let headers = HttpHeaders::deserialize(&mut s)?;
1597        drop(s);
1598
1599        let encoding = headers.get("Transfer-Encoding");
1600        let content_length = headers.get("Content-Length").map(str::parse).transpose()?;
1601
1602        let body = HttpBody::new(encoding, content_length, io::BufReader::new(socket));
1603
1604        Ok(HttpResponse {
1605            version,
1606            status,
1607            headers,
1608            body,
1609        })
1610    }
1611
1612    pub fn get_header(&self, key: &str) -> Option<&str> {
1613        self.headers.get(key)
1614    }
1615
1616    pub fn add_header(&mut self, key: impl AsRef<str>, value: impl Into<String>) {
1617        self.headers.insert(key, value);
1618    }
1619
1620    pub fn serialize<W: io::Write>(&self, mut w: W) -> Result<()> {
1621        write!(&mut w, "{} {}\r\n", self.version, self.status)?;
1622        self.headers.serialize(&mut w)?;
1623        write!(&mut w, "\r\n")?;
1624        Ok(())
1625    }
1626}
1627
1628#[cfg(test)]
1629mod http_response_tests {
1630    use super::{HttpResponse, HttpStatus};
1631    use std::io;
1632
1633    #[test]
1634    fn parse_success() {
1635        let input = "HTTP/1.1 200 OK\r\nA: B\r\nC: D\r\n\r\n".as_bytes();
1636        let actual = HttpResponse::deserialize(input).unwrap();
1637        let mut expected = HttpResponse::new(HttpStatus::OK, io::empty());
1638        expected.add_header("A", "B");
1639        expected.add_header("C", "D");
1640        assert_eq!(actual.version, expected.version);
1641        assert_eq!(actual.status, expected.status);
1642        assert_eq!(actual.headers, expected.headers);
1643    }
1644}
1645
1646#[derive(Debug, PartialEq, Eq, Clone, Copy)]
1647pub enum HttpMethod {
1648    Delete,
1649    Get,
1650    Head,
1651    Options,
1652    Post,
1653    Put,
1654    Trace,
1655}
1656
1657impl str::FromStr for HttpMethod {
1658    type Err = Error;
1659    fn from_str(s: &str) -> Result<Self> {
1660        match s.to_uppercase().as_ref() {
1661            "DELETE" => Ok(HttpMethod::Delete),
1662            "GET" => Ok(HttpMethod::Get),
1663            "HEAD" => Ok(HttpMethod::Head),
1664            "OPTIONS" => Ok(HttpMethod::Options),
1665            "POST" => Ok(HttpMethod::Post),
1666            "PUT" => Ok(HttpMethod::Put),
1667            "TRACE" => Ok(HttpMethod::Trace),
1668            m => Err(Error::ParseError(format!("Unknown method {}", m))),
1669        }
1670    }
1671}
1672
1673impl fmt::Display for HttpMethod {
1674    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1675        match self {
1676            HttpMethod::Delete => write!(f, "DELETE"),
1677            HttpMethod::Get => write!(f, "GET"),
1678            HttpMethod::Head => write!(f, "HEAD"),
1679            HttpMethod::Options => write!(f, "OPTIONS"),
1680            HttpMethod::Post => write!(f, "POST"),
1681            HttpMethod::Put => write!(f, "PUT"),
1682            HttpMethod::Trace => write!(f, "TRACE"),
1683        }
1684    }
1685}
1686
1687impl HttpMethod {
1688    pub fn has_body(&self) -> bool {
1689        match self {
1690            Self::Delete | Self::Post | Self::Put => true,
1691            Self::Trace | Self::Get | Self::Head | Self::Options => false,
1692        }
1693    }
1694}
1695
1696#[cfg(test)]
1697mod http_method_tests {
1698    use super::HttpMethod;
1699    use std::string::ToString;
1700
1701    #[test]
1702    fn parse_success() {
1703        assert_eq!("DELETE".parse::<HttpMethod>().unwrap(), HttpMethod::Delete);
1704        assert_eq!("GET".parse::<HttpMethod>().unwrap(), HttpMethod::Get);
1705        assert_eq!("HEAD".parse::<HttpMethod>().unwrap(), HttpMethod::Head);
1706        assert_eq!(
1707            "OPTIONS".parse::<HttpMethod>().unwrap(),
1708            HttpMethod::Options
1709        );
1710        assert_eq!("POST".parse::<HttpMethod>().unwrap(), HttpMethod::Post);
1711        assert_eq!("PUT".parse::<HttpMethod>().unwrap(), HttpMethod::Put);
1712        assert_eq!("TRACE".parse::<HttpMethod>().unwrap(), HttpMethod::Trace);
1713    }
1714
1715    #[test]
1716    fn parse_error() {
1717        assert!("GE".parse::<HttpMethod>().is_err());
1718        assert!("BLARG".parse::<HttpMethod>().is_err());
1719    }
1720
1721    #[test]
1722    fn display() {
1723        assert_eq!(&HttpMethod::Delete.to_string(), "DELETE");
1724        assert_eq!(&HttpMethod::Get.to_string(), "GET");
1725        assert_eq!(&HttpMethod::Head.to_string(), "HEAD");
1726        assert_eq!(&HttpMethod::Options.to_string(), "OPTIONS");
1727        assert_eq!(&HttpMethod::Post.to_string(), "POST");
1728        assert_eq!(&HttpMethod::Put.to_string(), "PUT");
1729        assert_eq!(&HttpMethod::Trace.to_string(), "TRACE");
1730    }
1731
1732    #[test]
1733    fn parse_display_round_trip() {
1734        assert_eq!(
1735            &"DELETE".parse::<HttpMethod>().unwrap().to_string(),
1736            "DELETE"
1737        );
1738        assert_eq!(&"GET".parse::<HttpMethod>().unwrap().to_string(), "GET");
1739        assert_eq!(&"HEAD".parse::<HttpMethod>().unwrap().to_string(), "HEAD");
1740        assert_eq!(&"POST".parse::<HttpMethod>().unwrap().to_string(), "POST");
1741        assert_eq!(
1742            &"OPTIONS".parse::<HttpMethod>().unwrap().to_string(),
1743            "OPTIONS"
1744        );
1745        assert_eq!(&"PUT".parse::<HttpMethod>().unwrap().to_string(), "PUT");
1746        assert_eq!(&"TRACE".parse::<HttpMethod>().unwrap().to_string(), "TRACE");
1747    }
1748}
1749
1750pub struct HttpRequest<B: io::Read> {
1751    pub method: HttpMethod,
1752    pub uri: String,
1753    version: HttpVersion,
1754    pub headers: HttpHeaders,
1755    pub body: HttpBody<B>,
1756}
1757
1758impl HttpRequest<io::Empty> {
1759    pub fn new<S: Into<String>>(method: HttpMethod, uri_in: S) -> Self {
1760        let uri_in = uri_in.into();
1761        let uri = if uri_in.is_empty() {
1762            "/".into()
1763        } else {
1764            uri_in
1765        };
1766
1767        HttpRequest {
1768            method,
1769            uri,
1770            version: HttpVersion::new(1, 1),
1771            headers: HttpHeaders::new(),
1772            body: HttpBody::ReadTilClose(io::BufReader::new(io::empty())),
1773        }
1774    }
1775}
1776
1777pub enum OutgoingRequest<S: io::Read + io::Write> {
1778    NoBody(S),
1779    WithBody(OutgoingBody<S>),
1780}
1781
1782impl<S: io::Read + io::Write> OutgoingRequest<S> {
1783    fn with_body(socket: io::BufWriter<S>) -> Self {
1784        Self::WithBody(OutgoingBody::new(socket))
1785    }
1786
1787    fn with_no_body(socket: S) -> Self {
1788        Self::NoBody(socket)
1789    }
1790
1791    pub fn finish(self) -> Result<HttpResponse<S>> {
1792        match self {
1793            Self::NoBody(mut socket) => {
1794                socket.flush()?;
1795                Ok(HttpResponse::deserialize(socket)?)
1796            }
1797            Self::WithBody(body) => body.finish(),
1798        }
1799    }
1800}
1801
1802impl<S: io::Read + io::Write> io::Write for OutgoingRequest<S> {
1803    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1804        match self {
1805            #[cfg(feature = "std")]
1806            Self::NoBody(_) => Err(io::Error::new(
1807                io::ErrorKind::InvalidInput,
1808                format!("Method does not support a body"),
1809            )),
1810            #[cfg(not(feature = "std"))]
1811            Self::NoBody(_) => Err(Error::Other(format!("Method does not support a body"))),
1812            Self::WithBody(b) => b.write(buf),
1813        }
1814    }
1815
1816    fn flush(&mut self) -> io::Result<()> {
1817        match self {
1818            Self::WithBody(b) => b.flush(),
1819            _ => Ok(()),
1820        }
1821    }
1822}
1823
1824pub struct OutgoingBody<S: io::Read + io::Write> {
1825    socket: io::BufWriter<S>,
1826}
1827
1828impl<S: io::Read + io::Write> io::Write for OutgoingBody<S> {
1829    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1830        let len = buf.len();
1831        if len == 0 {
1832            return Ok(0);
1833        }
1834        write!(&mut self.socket, "{:x}\r\n", len)?;
1835        self.socket.write_all(buf)?;
1836        write!(&mut self.socket, "\r\n")?;
1837        Ok(len)
1838    }
1839
1840    fn flush(&mut self) -> io::Result<()> {
1841        self.socket.flush()
1842    }
1843}
1844
1845impl<S: io::Read + io::Write> OutgoingBody<S> {
1846    fn new(socket: io::BufWriter<S>) -> Self {
1847        OutgoingBody { socket }
1848    }
1849
1850    pub fn finish(mut self) -> Result<HttpResponse<S>> {
1851        write!(&mut self.socket, "0\r\n\r\n")?;
1852        self.socket.flush()?;
1853
1854        let socket = self.socket.into_inner()?;
1855        Ok(HttpResponse::deserialize(socket)?)
1856    }
1857}
1858
1859impl<B: io::Read> HttpRequest<B> {
1860    pub fn add_header(&mut self, key: impl AsRef<str>, value: impl Into<String>) {
1861        self.headers.insert(key, value);
1862    }
1863
1864    pub fn deserialize(mut stream: io::BufReader<B>) -> Result<Self> {
1865        let mut ts = CrLfStream::new(&mut stream);
1866        let first_line = ts.expect_next()?;
1867        let mut parser = Parser::new(&first_line);
1868
1869        let method = parser.parse_token()?.parse()?;
1870        let uri = parser.parse_token()?.into();
1871        let version = parser.parse_token()?.parse()?;
1872        let headers = HttpHeaders::deserialize(&mut ts)?;
1873        drop(ts);
1874
1875        let encoding = headers.get("Transfer-Encoding");
1876        let content_length = headers.get("Content-Length").map(str::parse).transpose()?;
1877        let body = HttpBody::new(encoding, content_length, stream);
1878
1879        Ok(HttpRequest {
1880            method,
1881            uri,
1882            version,
1883            headers,
1884            body,
1885        })
1886    }
1887}
1888
1889impl<B: io::Read> HttpRequest<B> {
1890    pub fn serialize<S: io::Read + io::Write>(
1891        &self,
1892        mut w: io::BufWriter<S>,
1893    ) -> Result<OutgoingRequest<S>> {
1894        write!(&mut w, "{} {} {}\r\n", self.method, self.uri, self.version)?;
1895        self.headers.serialize(&mut w)?;
1896        write!(&mut w, "\r\n")?;
1897        if self.method.has_body() {
1898            Ok(OutgoingRequest::with_body(w))
1899        } else {
1900            Ok(OutgoingRequest::with_no_body(w.into_inner()?))
1901        }
1902    }
1903}
1904
1905#[cfg(test)]
1906mod http_request_tests {
1907    use super::{HttpMethod, HttpRequest};
1908    use std::io;
1909
1910    #[test]
1911    fn parse_success() {
1912        let mut input = "GET /a/b HTTP/1.1\r\nA: B\r\nC: D\r\n\r\n".as_bytes();
1913        let actual = HttpRequest::deserialize(io::BufReader::new(&mut input)).unwrap();
1914        let mut expected = HttpRequest::new(HttpMethod::Get, "/a/b");
1915        expected.add_header("A", "B");
1916        expected.add_header("C", "D");
1917        assert_eq!(actual.version, expected.version);
1918        assert_eq!(actual.method, expected.method);
1919        assert_eq!(actual.headers, expected.headers);
1920    }
1921}