146 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			146 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| //! Pieces pertaining to the HTTP message protocol.
 | |
| use http::{HeaderMap, Method, StatusCode, Uri, Version};
 | |
| 
 | |
| pub(crate) use self::body_length::DecodedLength;
 | |
| pub(crate) use self::h1::{dispatch, Conn, ServerTransaction};
 | |
| 
 | |
| pub(crate) mod h1;
 | |
| pub(crate) mod h2;
 | |
| 
 | |
| /// An Incoming Message head. Includes request/status line, and headers.
 | |
| #[derive(Clone, Debug, Default, PartialEq)]
 | |
| pub struct MessageHead<S> {
 | |
|     /// HTTP version of the message.
 | |
|     pub version: Version,
 | |
|     /// Subject (request line or status line) of Incoming message.
 | |
|     pub subject: S,
 | |
|     /// Headers of the Incoming message.
 | |
|     pub headers: HeaderMap,
 | |
| }
 | |
| 
 | |
| /// An incoming request message.
 | |
| pub type RequestHead = MessageHead<RequestLine>;
 | |
| 
 | |
| #[derive(Debug, Default, PartialEq)]
 | |
| pub struct RequestLine(pub Method, pub Uri);
 | |
| 
 | |
| /// An incoming response message.
 | |
| pub type ResponseHead = MessageHead<StatusCode>;
 | |
| 
 | |
| #[derive(Debug)]
 | |
| pub enum BodyLength {
 | |
|     /// Content-Length
 | |
|     Known(u64),
 | |
|     /// Transfer-Encoding: chunked (if h1)
 | |
|     Unknown,
 | |
| }
 | |
| 
 | |
| /// Status of when a Disaptcher future completes.
 | |
| pub(crate) enum Dispatched {
 | |
|     /// Dispatcher completely shutdown connection.
 | |
|     Shutdown,
 | |
|     /// Dispatcher has pending upgrade, and so did not shutdown.
 | |
|     Upgrade(crate::upgrade::Pending),
 | |
| }
 | |
| 
 | |
| /// A separate module to encapsulate the invariants of the DecodedLength type.
 | |
| mod body_length {
 | |
|     use std::fmt;
 | |
| 
 | |
|     #[derive(Clone, Copy, PartialEq, Eq)]
 | |
|     pub(crate) struct DecodedLength(u64);
 | |
| 
 | |
|     const MAX_LEN: u64 = std::u64::MAX - 2;
 | |
| 
 | |
|     impl DecodedLength {
 | |
|         pub(crate) const CLOSE_DELIMITED: DecodedLength = DecodedLength(::std::u64::MAX);
 | |
|         pub(crate) const CHUNKED: DecodedLength = DecodedLength(::std::u64::MAX - 1);
 | |
|         pub(crate) const ZERO: DecodedLength = DecodedLength(0);
 | |
| 
 | |
|         #[cfg(test)]
 | |
|         pub(crate) fn new(len: u64) -> Self {
 | |
|             debug_assert!(len <= MAX_LEN);
 | |
|             DecodedLength(len)
 | |
|         }
 | |
| 
 | |
|         /// Takes the length as a content-length without other checks.
 | |
|         ///
 | |
|         /// Should only be called if previously confirmed this isn't
 | |
|         /// CLOSE_DELIMITED or CHUNKED.
 | |
|         #[inline]
 | |
|         pub(crate) fn danger_len(self) -> u64 {
 | |
|             debug_assert!(self.0 < Self::CHUNKED.0);
 | |
|             self.0
 | |
|         }
 | |
| 
 | |
|         /// Converts to an Option<u64> representing a Known or Unknown length.
 | |
|         pub(crate) fn into_opt(self) -> Option<u64> {
 | |
|             match self {
 | |
|                 DecodedLength::CHUNKED | DecodedLength::CLOSE_DELIMITED => None,
 | |
|                 DecodedLength(known) => Some(known),
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// Checks the `u64` is within the maximum allowed for content-length.
 | |
|         pub(crate) fn checked_new(len: u64) -> Result<Self, crate::error::Parse> {
 | |
|             if len <= MAX_LEN {
 | |
|                 Ok(DecodedLength(len))
 | |
|             } else {
 | |
|                 warn!("content-length bigger than maximum: {} > {}", len, MAX_LEN);
 | |
|                 Err(crate::error::Parse::TooLarge)
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         pub(crate) fn sub_if(&mut self, amt: u64) {
 | |
|             match *self {
 | |
|                 DecodedLength::CHUNKED | DecodedLength::CLOSE_DELIMITED => (),
 | |
|                 DecodedLength(ref mut known) => {
 | |
|                     *known -= amt;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     impl fmt::Debug for DecodedLength {
 | |
|         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | |
|             match *self {
 | |
|                 DecodedLength::CLOSE_DELIMITED => f.write_str("CLOSE_DELIMITED"),
 | |
|                 DecodedLength::CHUNKED => f.write_str("CHUNKED"),
 | |
|                 DecodedLength(n) => f.debug_tuple("DecodedLength").field(&n).finish(),
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     impl fmt::Display for DecodedLength {
 | |
|         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | |
|             match *self {
 | |
|                 DecodedLength::CLOSE_DELIMITED => f.write_str("close-delimited"),
 | |
|                 DecodedLength::CHUNKED => f.write_str("chunked encoding"),
 | |
|                 DecodedLength::ZERO => f.write_str("empty"),
 | |
|                 DecodedLength(n) => write!(f, "content-length ({} bytes)", n),
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     #[cfg(test)]
 | |
|     mod tests {
 | |
|         use super::*;
 | |
| 
 | |
|         #[test]
 | |
|         fn sub_if_known() {
 | |
|             let mut len = DecodedLength::new(30);
 | |
|             len.sub_if(20);
 | |
| 
 | |
|             assert_eq!(len.0, 10);
 | |
|         }
 | |
| 
 | |
|         #[test]
 | |
|         fn sub_if_chunked() {
 | |
|             let mut len = DecodedLength::CHUNKED;
 | |
|             len.sub_if(20);
 | |
| 
 | |
|             assert_eq!(len, DecodedLength::CHUNKED);
 | |
|         }
 | |
|     }
 | |
| }
 |