1pub mod common;
2pub mod languages;
3pub mod observable;
4
5pub use common::{
6 get_diagnostic, HeaderSource, HttpCookie, HttpHeader, HttpParser, HttpProcessor,
7 ParsingMetadata,
8};
9pub use languages::get_highest_quality_language;
10pub use observable::*;
11
12#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
13pub enum Version {
14 V10,
16 V11,
18 V20,
20 V30,
22 Any,
24}
25
26impl Version {
27 pub fn parse(version_str: &str) -> Option<Self> {
28 match version_str {
29 "HTTP/1.0" => Some(Version::V10),
30 "HTTP/1.1" => Some(Version::V11),
31 "HTTP/2" | "HTTP/2.0" => Some(Version::V20),
32 "HTTP/3" | "HTTP/3.0" => Some(Version::V30),
33 _ => None,
34 }
35 }
36
37 pub fn as_str(&self) -> &'static str {
38 match self {
39 Version::V10 => "HTTP/1.0",
40 Version::V11 => "HTTP/1.1",
41 Version::V20 => "HTTP/2",
42 Version::V30 => "HTTP/3",
43 Version::Any => "Any",
44 }
45 }
46}
47
48impl std::str::FromStr for Version {
49 type Err = ();
50
51 fn from_str(s: &str) -> Result<Self, Self::Err> {
52 Self::parse(s).ok_or(())
53 }
54}
55
56impl core::fmt::Display for Version {
57 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
58 f.write_str(match self {
59 Version::V10 => "0",
60 Version::V11 => "1",
61 Version::V20 => "2",
62 Version::V30 => "3",
63 Version::Any => "*",
64 })
65 }
66}
67
68#[derive(Clone, Debug, PartialEq)]
73pub struct Header {
74 pub optional: bool,
75 pub name: String,
76 pub value: Option<String>,
77}
78
79impl Header {
80 pub fn new<S: AsRef<str>>(name: S) -> Self {
81 Header { optional: false, name: name.as_ref().to_owned(), value: None }
82 }
83
84 pub fn with_value<S: AsRef<str>>(mut self, value: S) -> Self {
85 self.value = Some(value.as_ref().to_owned());
86 self
87 }
88
89 pub fn with_optional_value<S: AsRef<str>>(mut self, value: Option<S>) -> Self {
90 self.value = value.map(|v| v.as_ref().to_owned());
91 self
92 }
93
94 pub fn optional(mut self) -> Self {
95 self.optional = true;
96 self
97 }
98}
99
100impl core::fmt::Display for Header {
101 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
102 if self.optional {
103 f.write_str("?")?;
104 }
105 f.write_str(&self.name)?;
106 if let Some(ref value) = self.value {
107 write!(f, "=[{value}]")?;
108 }
109 Ok(())
110 }
111}
112
113#[derive(Clone, Debug, PartialEq)]
116pub enum HttpDiagnosis {
117 Dishonest,
118 Anonymous,
119 Generic,
120 None,
121}
122
123impl core::fmt::Display for HttpDiagnosis {
124 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
125 f.write_str(match self {
126 HttpDiagnosis::Dishonest => "dishonest",
127 HttpDiagnosis::Anonymous => "anonymous",
128 HttpDiagnosis::Generic => "generic",
129 HttpDiagnosis::None => "none",
130 })
131 }
132}
133
134pub fn request_optional_headers() -> Vec<&'static str> {
135 vec![
136 "Cookie",
137 "Referer",
138 "Origin",
139 "Range",
140 "If-Modified-Since",
141 "If-None-Match",
142 "Via",
143 "X-Forwarded-For",
144 "Authorization",
145 "Proxy-Authorization",
146 "Cache-Control",
147 ]
148}
149
150pub fn response_optional_headers() -> Vec<&'static str> {
151 vec![
152 "Set-Cookie",
153 "Last-Modified",
154 "ETag",
155 "Content-Length",
156 "Content-Disposition",
157 "Cache-Control",
158 "Expires",
159 "Pragma",
160 "Location",
161 "Refresh",
162 "Content-Range",
163 "Vary",
164 ]
165}
166
167pub fn request_skip_value_headers() -> Vec<&'static str> {
168 vec!["Host", "User-Agent"]
169}
170
171pub fn response_skip_value_headers() -> Vec<&'static str> {
172 vec!["Date", "Content-Type", "Server"]
173}
174
175pub fn request_common_headers() -> Vec<&'static str> {
176 vec![
177 "Host",
178 "User-Agent",
179 "Connection",
180 "Accept",
181 "Accept-Encoding",
182 "Accept-Language",
183 "Accept-Charset",
184 "Keep-Alive",
185 ]
186}
187
188pub fn response_common_headers() -> Vec<&'static str> {
189 vec!["Content-Type", "Connection", "Keep-Alive", "Accept-Ranges", "Date"]
190}