dhttp/reqres/
req.rs

1use std::fmt;
2use std::net::{IpAddr, Ipv4Addr};
3
4use crate::reqres::HttpHeader;
5
6/// Version used in request
7#[derive(Clone, Copy)]
8pub struct HttpVersion {
9    pub major: u8,
10    pub minor: u8,
11}
12
13impl HttpVersion {
14    /// Compares this version for equality
15    pub fn is(self, major: u8, minor: u8) -> bool {
16        self.major == major && self.minor == minor
17    }
18}
19
20impl fmt::Debug for HttpVersion {
21    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
22        write!(fmt, "HTTP/{}.{}", self.major, self.minor)
23    }
24}
25
26/// Method of request
27#[derive(Debug, Clone, PartialEq, Eq)]
28pub enum HttpMethod {
29    Get, Head, Post, Put, Delete, Connect, Options, Trace, Patch,
30    // it is not possible to add new variants here because for example
31    // Get and Other("GET") would not be equal
32    // but it is not possible to private enum variants in rust
33    Other(String)
34}
35
36impl HttpMethod {
37    /// Parses method from provided str
38    pub fn new(method: &str) -> HttpMethod {
39        let method = method.to_ascii_uppercase();
40        match method.as_str() {
41            "GET" => HttpMethod::Get,
42            "HEAD" => HttpMethod::Head,
43            "POST" => HttpMethod::Post,
44            "PUT" => HttpMethod::Put,
45            "DELETE" => HttpMethod::Delete,
46            "CONNECT" => HttpMethod::Connect,
47            "OPTIONS" => HttpMethod::Options,
48            "TRACE" => HttpMethod::Trace,
49            "PATCH" => HttpMethod::Patch,
50            _ => HttpMethod::Other(method),
51        }
52    }
53
54    pub fn as_str(&self) -> &str {
55        match self {
56            HttpMethod::Get => "GET",
57            HttpMethod::Head => "HEAD",
58            HttpMethod::Post => "POST",
59            HttpMethod::Put => "PUT",
60            HttpMethod::Delete => "DELETE",
61            HttpMethod::Connect => "CONNECT",
62            HttpMethod::Options => "OPTIONS",
63            HttpMethod::Trace => "TRACE",
64            HttpMethod::Patch => "PATCH",
65            HttpMethod::Other(other) => other,
66        }
67    }
68}
69
70impl fmt::Display for HttpMethod {
71    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
72        fmt.write_str(self.as_str())
73    }
74}
75
76/// Request from client to handle
77#[derive(Debug, Clone)]
78#[non_exhaustive]
79pub struct HttpRequest {
80    pub method: HttpMethod,
81    pub route: String,
82    pub version: HttpVersion,
83    pub headers: Vec<HttpHeader>,
84    /// Contents of the `Content-Length` header
85    pub len: u64,
86    /// IP address of this request (`0.0.0.0` if none)
87    pub addr: IpAddr,
88}
89
90impl HttpRequest {
91    /// Retrieves a header value, if any
92    pub fn get_header<'a>(&'a self, name: &str) -> Option<&'a str> {
93        let mut header = None;
94        for h in &self.headers {
95            if h.name.eq_ignore_ascii_case(name) {
96                header = Some(h.value.as_str());
97                break;
98            }
99        }
100        header
101    }
102
103    /// Checks if this header exists
104    pub fn has_header(&self, name: &str) -> bool {
105        self.get_header(name).is_some()
106    }
107
108    /// Compares equality of header values
109    pub fn cmp_header(&self, name: &str, value: &str) -> bool {
110        let hdr = self.get_header(name);
111        hdr.is_some() && hdr.unwrap().eq_ignore_ascii_case(value)
112    }
113}
114
115impl Default for HttpRequest {
116    fn default() -> HttpRequest {
117        HttpRequest {
118            method: HttpMethod::Get,
119            route: String::new(),
120            version: HttpVersion { major: 0, minor: 0 },
121            headers: vec![],
122            len: 0,
123            addr: IpAddr::V4(Ipv4Addr::UNSPECIFIED),
124        }
125    }
126}