viewpoint_core/network/request/
mod.rs1use std::collections::HashMap;
6use std::sync::Arc;
7
8use viewpoint_cdp::CdpConnection;
9
10use super::types::ResourceType;
11
12#[derive(Debug, Clone)]
17pub struct Request {
18 pub(crate) url: String,
20 pub(crate) method: String,
22 pub(crate) headers: HashMap<String, String>,
24 pub(crate) post_data: Option<String>,
26 pub(crate) resource_type: ResourceType,
28 pub(crate) frame_id: String,
30 pub(crate) is_navigation: bool,
32 pub(crate) connection: Option<Arc<CdpConnection>>,
34 pub(crate) session_id: Option<String>,
36 pub(crate) request_id: Option<String>,
38 pub(crate) redirected_from: Option<Box<Request>>,
40 pub(crate) redirected_to: Option<Box<Request>>,
43 pub(crate) timing: Option<RequestTiming>,
45 pub(crate) failure_text: Option<String>,
47}
48
49impl Request {
50 pub(crate) fn from_cdp(
52 cdp_request: viewpoint_cdp::protocol::network::Request,
53 resource_type: viewpoint_cdp::protocol::network::ResourceType,
54 frame_id: String,
55 connection: Option<Arc<CdpConnection>>,
56 session_id: Option<String>,
57 request_id: Option<String>,
58 ) -> Self {
59 Self {
60 url: cdp_request.url,
61 method: cdp_request.method,
62 headers: cdp_request.headers,
63 post_data: cdp_request.post_data,
64 resource_type: resource_type.into(),
65 frame_id,
66 is_navigation: false, connection,
68 session_id,
69 request_id,
70 redirected_from: None,
71 redirected_to: None,
72 timing: None,
73 failure_text: None,
74 }
75 }
76
77 pub fn url(&self) -> &str {
79 &self.url
80 }
81
82 pub fn method(&self) -> &str {
84 &self.method
85 }
86
87 pub fn headers(&self) -> &HashMap<String, String> {
91 &self.headers
92 }
93
94 pub fn header_value(&self, name: &str) -> Option<&str> {
96 self.headers
97 .iter()
98 .find(|(k, _)| k.eq_ignore_ascii_case(name))
99 .map(|(_, v)| v.as_str())
100 }
101
102 pub async fn all_headers(&self) -> HashMap<String, String> {
106 self.headers.clone()
109 }
110
111 pub fn post_data(&self) -> Option<&str> {
113 self.post_data.as_deref()
114 }
115
116 pub fn post_data_buffer(&self) -> Option<Vec<u8>> {
118 self.post_data.as_ref().map(|s| s.as_bytes().to_vec())
119 }
120
121 pub fn post_data_json<T: serde::de::DeserializeOwned>(&self) -> Result<Option<T>, serde_json::Error> {
127 match &self.post_data {
128 Some(data) => serde_json::from_str(data).map(Some),
129 None => Ok(None),
130 }
131 }
132
133 pub fn resource_type(&self) -> ResourceType {
135 self.resource_type
136 }
137
138 pub fn frame_id(&self) -> &str {
140 &self.frame_id
141 }
142
143 pub fn is_navigation_request(&self) -> bool {
145 self.is_navigation
146 }
147
148 pub fn redirected_from(&self) -> Option<&Request> {
150 self.redirected_from.as_deref()
151 }
152
153 pub fn redirected_to(&self) -> Option<&Request> {
155 self.redirected_to.as_deref()
156 }
157
158 pub fn timing(&self) -> Option<&RequestTiming> {
160 self.timing.as_ref()
161 }
162
163 pub async fn sizes(&self) -> RequestSizes {
167 let body_size = self.post_data.as_ref().map_or(0, std::string::String::len);
168 let headers_size = self
169 .headers
170 .iter()
171 .map(|(k, v)| k.len() + v.len() + 4) .sum();
173
174 RequestSizes {
175 request_body_size: body_size,
176 request_headers_size: headers_size,
177 }
178 }
179
180 pub fn failure(&self) -> Option<&str> {
182 self.failure_text.as_deref()
183 }
184
185 pub(crate) fn set_is_navigation(&mut self, is_navigation: bool) {
187 self.is_navigation = is_navigation;
188 }
189
190 pub(crate) fn set_redirected_from(&mut self, from: Request) {
192 self.redirected_from = Some(Box::new(from));
193 }
194
195 pub(crate) fn set_redirected_to(&mut self, to: Request) {
197 self.redirected_to = Some(Box::new(to));
198 }
199
200 pub(crate) fn set_timing(&mut self, timing: RequestTiming) {
202 self.timing = Some(timing);
203 }
204
205 pub(crate) fn set_failure_text(&mut self, text: String) {
207 self.failure_text = Some(text);
208 }
209}
210
211#[derive(Debug, Clone)]
213pub struct RequestTiming {
214 pub start_time: f64,
216 pub proxy_start: f64,
218 pub proxy_end: f64,
219 pub dns_start: f64,
221 pub dns_end: f64,
222 pub connect_start: f64,
224 pub connect_end: f64,
225 pub ssl_start: f64,
227 pub ssl_end: f64,
228 pub send_start: f64,
230 pub send_end: f64,
231 pub receive_headers_start: f64,
233 pub receive_headers_end: f64,
234}
235
236impl From<viewpoint_cdp::protocol::network::ResourceTiming> for RequestTiming {
237 fn from(timing: viewpoint_cdp::protocol::network::ResourceTiming) -> Self {
238 Self {
239 start_time: timing.request_time * 1000.0,
240 proxy_start: timing.proxy_start,
241 proxy_end: timing.proxy_end,
242 dns_start: timing.dns_start,
243 dns_end: timing.dns_end,
244 connect_start: timing.connect_start,
245 connect_end: timing.connect_end,
246 ssl_start: timing.ssl_start,
247 ssl_end: timing.ssl_end,
248 send_start: timing.send_start,
249 send_end: timing.send_end,
250 receive_headers_start: timing.receive_headers_start.unwrap_or(0.0),
251 receive_headers_end: timing.receive_headers_end.unwrap_or(0.0),
252 }
253 }
254}
255
256#[derive(Debug, Clone, Copy)]
258pub struct RequestSizes {
259 pub request_body_size: usize,
261 pub request_headers_size: usize,
263}
264
265#[cfg(test)]
266mod tests;