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>(
127 &self,
128 ) -> Result<Option<T>, serde_json::Error> {
129 match &self.post_data {
130 Some(data) => serde_json::from_str(data).map(Some),
131 None => Ok(None),
132 }
133 }
134
135 pub fn resource_type(&self) -> ResourceType {
137 self.resource_type
138 }
139
140 pub fn frame_id(&self) -> &str {
142 &self.frame_id
143 }
144
145 pub fn is_navigation_request(&self) -> bool {
147 self.is_navigation
148 }
149
150 pub fn redirected_from(&self) -> Option<&Request> {
152 self.redirected_from.as_deref()
153 }
154
155 pub fn redirected_to(&self) -> Option<&Request> {
157 self.redirected_to.as_deref()
158 }
159
160 pub fn timing(&self) -> Option<&RequestTiming> {
162 self.timing.as_ref()
163 }
164
165 pub async fn sizes(&self) -> RequestSizes {
169 let body_size = self.post_data.as_ref().map_or(0, std::string::String::len);
170 let headers_size = self
171 .headers
172 .iter()
173 .map(|(k, v)| k.len() + v.len() + 4) .sum();
175
176 RequestSizes {
177 request_body_size: body_size,
178 request_headers_size: headers_size,
179 }
180 }
181
182 pub fn failure(&self) -> Option<&str> {
184 self.failure_text.as_deref()
185 }
186
187 pub(crate) fn set_is_navigation(&mut self, is_navigation: bool) {
189 self.is_navigation = is_navigation;
190 }
191
192 pub(crate) fn set_redirected_from(&mut self, from: Request) {
194 self.redirected_from = Some(Box::new(from));
195 }
196
197 pub(crate) fn set_redirected_to(&mut self, to: Request) {
199 self.redirected_to = Some(Box::new(to));
200 }
201
202 pub(crate) fn set_timing(&mut self, timing: RequestTiming) {
204 self.timing = Some(timing);
205 }
206
207 pub(crate) fn set_failure_text(&mut self, text: String) {
209 self.failure_text = Some(text);
210 }
211}
212
213#[derive(Debug, Clone)]
215pub struct RequestTiming {
216 pub start_time: f64,
218 pub proxy_start: f64,
220 pub proxy_end: f64,
221 pub dns_start: f64,
223 pub dns_end: f64,
224 pub connect_start: f64,
226 pub connect_end: f64,
227 pub ssl_start: f64,
229 pub ssl_end: f64,
230 pub send_start: f64,
232 pub send_end: f64,
233 pub receive_headers_start: f64,
235 pub receive_headers_end: f64,
236}
237
238impl From<viewpoint_cdp::protocol::network::ResourceTiming> for RequestTiming {
239 fn from(timing: viewpoint_cdp::protocol::network::ResourceTiming) -> Self {
240 Self {
241 start_time: timing.request_time * 1000.0,
242 proxy_start: timing.proxy_start,
243 proxy_end: timing.proxy_end,
244 dns_start: timing.dns_start,
245 dns_end: timing.dns_end,
246 connect_start: timing.connect_start,
247 connect_end: timing.connect_end,
248 ssl_start: timing.ssl_start,
249 ssl_end: timing.ssl_end,
250 send_start: timing.send_start,
251 send_end: timing.send_end,
252 receive_headers_start: timing.receive_headers_start.unwrap_or(0.0),
253 receive_headers_end: timing.receive_headers_end.unwrap_or(0.0),
254 }
255 }
256}
257
258#[derive(Debug, Clone, Copy)]
260pub struct RequestSizes {
261 pub request_body_size: usize,
263 pub request_headers_size: usize,
265}
266
267#[cfg(test)]
268mod tests;