1#![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}