viewpoint_core/network/route/
mod.rs1use std::future::Future;
4use std::pin::Pin;
5use std::sync::Arc;
6use std::time::Duration;
7
8use tokio::sync::Mutex;
9use viewpoint_cdp::CdpConnection;
10use viewpoint_cdp::protocol::fetch::{
11 ContinueRequestParams, ErrorReason, FailRequestParams, FulfillRequestParams,
12 GetResponseBodyParams, GetResponseBodyResult, HeaderEntry,
13};
14
15use super::request::Request;
16use super::route_builders::{ContinueBuilder, FulfillBuilder};
17use super::route_fetch::{FetchBuilder, FetchedResponse};
18use super::types::AbortError;
19use crate::error::NetworkError;
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum RouteAction {
27 Handled,
29 Fallback,
31}
32
33pub type RouteHandler = Box<
35 dyn Fn(Route) -> Pin<Box<dyn Future<Output = Result<(), NetworkError>> + Send>> + Send + Sync,
36>;
37
38#[derive(Debug, Clone)]
44pub struct Route {
45 request: Request,
47 request_id: String,
49 connection: Arc<CdpConnection>,
51 session_id: String,
53 handled: Arc<Mutex<bool>>,
55 response_status: Option<u16>,
57 response_headers: Option<Vec<HeaderEntry>>,
59}
60
61impl Route {
62 pub(crate) fn new(
64 request: Request,
65 request_id: String,
66 connection: Arc<CdpConnection>,
67 session_id: String,
68 response_status: Option<u16>,
69 response_headers: Option<Vec<HeaderEntry>>,
70 ) -> Self {
71 Self {
72 request,
73 request_id,
74 connection,
75 session_id,
76 handled: Arc::new(Mutex::new(false)),
77 response_status,
78 response_headers,
79 }
80 }
81
82 pub fn request(&self) -> &Request {
84 &self.request
85 }
86
87 pub(super) fn request_id(&self) -> &str {
89 &self.request_id
90 }
91
92 pub(super) fn connection(&self) -> &Arc<CdpConnection> {
94 &self.connection
95 }
96
97 pub(super) fn session_id(&self) -> &str {
99 &self.session_id
100 }
101
102 pub async fn is_handled(&self) -> bool {
104 *self.handled.lock().await
105 }
106
107 pub fn is_response_stage(&self) -> bool {
109 self.response_status.is_some()
110 }
111
112 pub fn response_status(&self) -> Option<u16> {
114 self.response_status
115 }
116
117 pub fn response_headers(&self) -> Option<&[HeaderEntry]> {
119 self.response_headers.as_deref()
120 }
121
122 pub async fn response_body(&self) -> Result<Option<Vec<u8>>, NetworkError> {
128 if !self.is_response_stage() {
129 return Ok(None);
130 }
131 self.get_response_body(&self.request_id).await
132 }
133
134 pub fn fulfill(&self) -> FulfillBuilder<'_> {
151 FulfillBuilder::new(self)
152 }
153
154 pub fn continue_(&self) -> ContinueBuilder<'_> {
176 ContinueBuilder::new(self)
177 }
178
179 pub async fn abort(&self) -> Result<(), NetworkError> {
185 self.abort_with(AbortError::Failed).await
186 }
187
188 pub async fn abort_with(&self, error: AbortError) -> Result<(), NetworkError> {
194 {
196 let mut handled = self.handled.lock().await;
197 if *handled {
198 return Err(NetworkError::AlreadyHandled);
199 }
200 *handled = true;
201 }
202
203 let error_reason = match error {
204 AbortError::Aborted => ErrorReason::Aborted,
205 AbortError::AccessDenied => ErrorReason::AccessDenied,
206 AbortError::AddressUnreachable => ErrorReason::AddressUnreachable,
207 AbortError::BlockedByClient => ErrorReason::BlockedByClient,
208 AbortError::BlockedByResponse => ErrorReason::BlockedByResponse,
209 AbortError::ConnectionAborted => ErrorReason::ConnectionAborted,
210 AbortError::ConnectionClosed => ErrorReason::ConnectionClosed,
211 AbortError::ConnectionFailed => ErrorReason::ConnectionFailed,
212 AbortError::ConnectionRefused => ErrorReason::ConnectionRefused,
213 AbortError::ConnectionReset => ErrorReason::ConnectionReset,
214 AbortError::InternetDisconnected => ErrorReason::InternetDisconnected,
215 AbortError::NameNotResolved => ErrorReason::NameNotResolved,
216 AbortError::TimedOut => ErrorReason::TimedOut,
217 AbortError::Failed => ErrorReason::Failed,
218 };
219
220 let params = FailRequestParams {
221 request_id: self.request_id.clone(),
222 error_reason,
223 };
224
225 self.connection
226 .send_command::<_, serde_json::Value>(
227 "Fetch.failRequest",
228 Some(params),
229 Some(&self.session_id),
230 )
231 .await
232 .map_err(NetworkError::from)?;
233
234 Ok(())
235 }
236
237 pub async fn fallback(&self) -> Result<(), NetworkError> {
245 let params = ContinueRequestParams {
248 request_id: self.request_id.clone(),
249 url: None,
250 method: None,
251 post_data: None,
252 headers: None,
253 intercept_response: None,
254 };
255
256 self.connection
257 .send_command::<_, serde_json::Value>(
258 "Fetch.continueRequest",
259 Some(params),
260 Some(&self.session_id),
261 )
262 .await
263 .map_err(NetworkError::from)?;
264
265 Ok(())
266 }
267
268 pub fn fetch(&self) -> FetchBuilder<'_> {
288 FetchBuilder::new(self)
289 }
290
291 pub async fn fetch_with_timeout(
293 &self,
294 timeout: Duration,
295 ) -> Result<FetchedResponse<'_>, NetworkError> {
296 self.fetch().timeout(timeout).send().await
297 }
298
299 pub(super) async fn send_fulfill(
305 &self,
306 params: FulfillRequestParams,
307 ) -> Result<(), NetworkError> {
308 {
310 let mut handled = self.handled.lock().await;
311 if *handled {
312 return Err(NetworkError::AlreadyHandled);
313 }
314 *handled = true;
315 }
316
317 self.connection
318 .send_command::<_, serde_json::Value>(
319 "Fetch.fulfillRequest",
320 Some(params),
321 Some(&self.session_id),
322 )
323 .await
324 .map_err(NetworkError::from)?;
325
326 Ok(())
327 }
328
329 pub(super) async fn send_continue(
331 &self,
332 params: ContinueRequestParams,
333 ) -> Result<(), NetworkError> {
334 {
336 let mut handled = self.handled.lock().await;
337 if *handled {
338 return Err(NetworkError::AlreadyHandled);
339 }
340 *handled = true;
341 }
342
343 self.connection
344 .send_command::<_, serde_json::Value>(
345 "Fetch.continueRequest",
346 Some(params),
347 Some(&self.session_id),
348 )
349 .await
350 .map_err(NetworkError::from)?;
351
352 Ok(())
353 }
354
355 pub(super) async fn get_response_body(
357 &self,
358 request_id: &str,
359 ) -> Result<Option<Vec<u8>>, NetworkError> {
360 use base64::Engine;
361
362 let result: GetResponseBodyResult = self
363 .connection
364 .send_command(
365 "Fetch.getResponseBody",
366 Some(GetResponseBodyParams {
367 request_id: request_id.to_string(),
368 }),
369 Some(&self.session_id),
370 )
371 .await
372 .map_err(NetworkError::from)?;
373
374 let body = if result.base64_encoded {
375 base64::engine::general_purpose::STANDARD
376 .decode(&result.body)
377 .ok()
378 } else {
379 Some(result.body.into_bytes())
380 };
381
382 Ok(body)
383 }
384}
385
386#[cfg(test)]
387mod tests;