async_h1/server/
encode.rs

1//! Process HTTP connections on the server.
2
3use std::io::Write;
4use std::pin::Pin;
5use std::task::{Context, Poll};
6use std::time::SystemTime;
7
8use futures_lite::io::{self, AsyncRead as Read, Cursor};
9use http_types::headers::{CONTENT_LENGTH, DATE, TRANSFER_ENCODING};
10use http_types::{Method, Response};
11
12use crate::body_encoder::BodyEncoder;
13use crate::date::fmt_http_date;
14use crate::read_to_end;
15use crate::EncoderState;
16
17/// A streaming HTTP encoder.
18#[derive(Debug)]
19pub struct Encoder {
20    response: Response,
21    state: EncoderState,
22    method: Method,
23}
24
25impl Read for Encoder {
26    fn poll_read(
27        mut self: Pin<&mut Self>,
28        cx: &mut Context<'_>,
29        buf: &mut [u8],
30    ) -> Poll<io::Result<usize>> {
31        loop {
32            self.state = match self.state {
33                EncoderState::Start => EncoderState::Head(self.compute_head()?),
34
35                EncoderState::Head(ref mut cursor) => {
36                    read_to_end!(Pin::new(cursor).poll_read(cx, buf));
37
38                    if self.method == Method::Head {
39                        EncoderState::End
40                    } else {
41                        EncoderState::Body(BodyEncoder::new(self.response.take_body()))
42                    }
43                }
44
45                EncoderState::Body(ref mut encoder) => {
46                    read_to_end!(Pin::new(encoder).poll_read(cx, buf));
47                    EncoderState::End
48                }
49
50                EncoderState::End => return Poll::Ready(Ok(0)),
51            }
52        }
53    }
54}
55
56impl Encoder {
57    /// Create a new instance of Encoder.
58    pub fn new(response: Response, method: Method) -> Self {
59        Self {
60            method,
61            response,
62            state: EncoderState::Start,
63        }
64    }
65
66    fn finalize_headers(&mut self) {
67        // If the body isn't streaming, we can set the content-length ahead of time. Else we need to
68        // send all items in chunks.
69        if let Some(len) = self.response.len() {
70            self.response.insert_header(CONTENT_LENGTH, len.to_string());
71        } else {
72            self.response.insert_header(TRANSFER_ENCODING, "chunked");
73        }
74
75        if self.response.header(DATE).is_none() {
76            let date = fmt_http_date(SystemTime::now());
77            self.response.insert_header(DATE, date);
78        }
79    }
80
81    /// Encode the headers to a buffer, the first time we poll.
82    fn compute_head(&mut self) -> io::Result<Cursor<Vec<u8>>> {
83        let mut head = Vec::with_capacity(128);
84        let reason = self.response.status().canonical_reason();
85        let status = self.response.status();
86        write!(head, "HTTP/1.1 {} {}\r\n", status, reason)?;
87
88        self.finalize_headers();
89        let mut headers = self.response.iter().collect::<Vec<_>>();
90        headers.sort_unstable_by_key(|(h, _)| h.as_str());
91        for (header, values) in headers {
92            for value in values.iter() {
93                write!(head, "{}: {}\r\n", header, value)?;
94            }
95        }
96        write!(head, "\r\n")?;
97        Ok(Cursor::new(head))
98    }
99}