1use std::fmt;
2use std::net::{IpAddr, Ipv4Addr};
3
4use crate::reqres::HttpHeader;
5
6#[derive(Clone, Copy)]
8pub struct HttpVersion {
9 pub major: u8,
10 pub minor: u8,
11}
12
13impl HttpVersion {
14 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#[derive(Debug, Clone, PartialEq, Eq)]
28pub enum HttpMethod {
29 Get, Head, Post, Put, Delete, Connect, Options, Trace, Patch,
30 Other(String)
34}
35
36impl HttpMethod {
37 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#[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 pub len: u64,
86 pub addr: IpAddr,
88}
89
90impl HttpRequest {
91 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 pub fn has_header(&self, name: &str) -> bool {
105 self.get_header(name).is_some()
106 }
107
108 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}