1use crate::error::Result;
9use crate::protocol::Request;
10use crate::protocol::api_request_context::{APIRequestContext, InnerFetchOptions};
11use crate::server::channel_owner::{ChannelOwner, ChannelOwnerImpl, ParentOrConnection};
12use crate::server::connection::downcast_parent;
13use serde_json::{Value, json};
14use std::any::Any;
15use std::sync::atomic::{AtomicBool, Ordering};
16use std::sync::{Arc, Mutex};
17
18#[derive(Clone)]
24pub struct Route {
25 base: ChannelOwnerImpl,
26 handled: Arc<AtomicBool>,
29 api_request_context: Arc<Mutex<Option<APIRequestContext>>>,
32}
33
34impl Route {
35 pub fn new(
40 parent: Arc<dyn ChannelOwner>,
41 type_name: String,
42 guid: Arc<str>,
43 initializer: Value,
44 ) -> Result<Self> {
45 let base = ChannelOwnerImpl::new(
46 ParentOrConnection::Parent(parent.clone()),
47 type_name,
48 guid,
49 initializer,
50 );
51
52 Ok(Self {
53 base,
54 handled: Arc::new(AtomicBool::new(false)),
55 api_request_context: Arc::new(Mutex::new(None)),
56 })
57 }
58
59 pub(crate) fn was_handled(&self) -> bool {
64 self.handled.load(Ordering::SeqCst)
65 }
66
67 pub(crate) fn set_api_request_context(&self, ctx: APIRequestContext) {
72 *self.api_request_context.lock().unwrap() = Some(ctx);
73 }
74
75 pub fn request(&self) -> Request {
79 if let Some(request) = downcast_parent::<Request>(self) {
81 return request;
82 }
83
84 let request_data = self
87 .initializer()
88 .get("request")
89 .cloned()
90 .unwrap_or_else(|| {
91 serde_json::json!({
92 "url": "",
93 "method": "GET"
94 })
95 });
96
97 let parent = self
98 .parent()
99 .unwrap_or_else(|| Arc::new(self.clone()) as Arc<dyn ChannelOwner>);
100
101 let request_guid = request_data
102 .get("guid")
103 .and_then(|v| v.as_str())
104 .unwrap_or("request-stub");
105
106 Request::new(
107 parent,
108 "Request".to_string(),
109 Arc::from(request_guid),
110 request_data,
111 )
112 .expect("stub Request construction cannot fail")
113 }
114
115 pub async fn abort(&self, error_code: Option<&str>) -> Result<()> {
134 self.handled.store(true, Ordering::SeqCst);
135 let params = json!({
136 "errorCode": error_code.unwrap_or("failed")
137 });
138
139 self.channel()
140 .send::<_, serde_json::Value>("abort", params)
141 .await
142 .map(|_| ())
143 }
144
145 pub async fn continue_(&self, overrides: Option<ContinueOptions>) -> Result<()> {
156 self.handled.store(true, Ordering::SeqCst);
157 self.continue_internal(overrides, false).await
158 }
159
160 pub async fn fallback(&self, overrides: Option<ContinueOptions>) -> Result<()> {
172 self.continue_internal(overrides, true).await
174 }
175
176 async fn continue_internal(
178 &self,
179 overrides: Option<ContinueOptions>,
180 is_fallback: bool,
181 ) -> Result<()> {
182 let params = super::route_params::continue_params(overrides, is_fallback);
183
184 self.channel()
185 .send::<_, serde_json::Value>("continue", params)
186 .await
187 .map(|_| ())
188 }
189
190 pub async fn fulfill(&self, options: impl Into<Option<FulfillOptions>>) -> Result<()> {
203 let options = options.into();
204 self.handled.store(true, Ordering::SeqCst);
205 let opts = options.unwrap_or_default();
206
207 let params = super::route_params::fulfill_params(opts);
208
209 self.channel()
210 .send::<_, serde_json::Value>("fulfill", params)
211 .await
212 .map(|_| ())
213 }
214
215 pub async fn fetch(&self, options: impl Into<Option<FetchOptions>>) -> Result<FetchResponse> {
227 let options = options.into();
228 self.handled.store(true, Ordering::SeqCst);
229
230 let api_ctx = self
231 .api_request_context
232 .lock()
233 .unwrap()
234 .clone()
235 .ok_or_else(|| {
236 crate::error::Error::ProtocolError(
237 "No APIRequestContext available for route.fetch(). \
238 This can happen if the route was not dispatched through \
239 a BrowserContext with an associated request context."
240 .to_string(),
241 )
242 })?;
243
244 let request = self.request();
245 let opts = options.unwrap_or_default();
246
247 let url = opts.url.unwrap_or_else(|| request.url().to_string());
249
250 let inner_opts = InnerFetchOptions {
251 method: opts.method.or_else(|| Some(request.method().to_string())),
252 headers: opts.headers,
253 post_data: opts.post_data,
254 post_data_bytes: opts.post_data_bytes,
255 max_redirects: opts.max_redirects,
256 max_retries: opts.max_retries,
257 timeout: opts.timeout,
258 };
259
260 api_ctx.inner_fetch(&url, Some(inner_opts)).await
261 }
262}
263
264pub(crate) fn matches_pattern(pattern: &str, url: &str) -> bool {
279 crate::protocol::glob::glob_match(pattern, url)
280}
281
282#[derive(Debug, Clone, Copy, PartialEq, Eq)]
286#[non_exhaustive]
287pub enum UnrouteBehavior {
288 Wait,
290 IgnoreErrors,
292 Default,
294}
295
296#[derive(Debug, Clone)]
300#[non_exhaustive]
301pub struct FetchResponse {
302 pub status: u16,
304 pub status_text: String,
306 pub headers: Vec<(String, String)>,
308 pub body: Vec<u8>,
310}
311
312impl FetchResponse {
313 pub fn status(&self) -> u16 {
315 self.status
316 }
317
318 pub fn status_text(&self) -> &str {
320 &self.status_text
321 }
322
323 pub fn headers(&self) -> &[(String, String)] {
325 &self.headers
326 }
327
328 pub fn body(&self) -> &[u8] {
330 &self.body
331 }
332
333 pub fn text(&self) -> Result<String> {
335 String::from_utf8(self.body.clone()).map_err(|e| {
336 crate::error::Error::ProtocolError(format!("Response body is not valid UTF-8: {}", e))
337 })
338 }
339
340 pub fn json<T: serde::de::DeserializeOwned>(&self) -> Result<T> {
342 serde_json::from_slice(&self.body).map_err(|e| {
343 crate::error::Error::ProtocolError(format!("Failed to parse response JSON: {}", e))
344 })
345 }
346
347 pub fn ok(&self) -> bool {
349 (200..300).contains(&self.status)
350 }
351}
352
353#[derive(Debug, Clone, Default)]
360#[non_exhaustive]
361pub struct ContinueOptions {
362 pub headers: Option<std::collections::HashMap<String, String>>,
364 pub method: Option<String>,
366 pub post_data: Option<String>,
368 pub post_data_bytes: Option<Vec<u8>>,
370 pub url: Option<String>,
372}
373
374impl ContinueOptions {
375 pub fn builder() -> ContinueOptionsBuilder {
377 ContinueOptionsBuilder::default()
378 }
379}
380
381#[derive(Debug, Clone, Default)]
383pub struct ContinueOptionsBuilder {
384 headers: Option<std::collections::HashMap<String, String>>,
385 method: Option<String>,
386 post_data: Option<String>,
387 post_data_bytes: Option<Vec<u8>>,
388 url: Option<String>,
389}
390
391impl ContinueOptionsBuilder {
392 pub fn headers(mut self, headers: std::collections::HashMap<String, String>) -> Self {
394 self.headers = Some(headers);
395 self
396 }
397
398 pub fn method(mut self, method: String) -> Self {
400 self.method = Some(method);
401 self
402 }
403
404 pub fn post_data(mut self, post_data: String) -> Self {
406 self.post_data = Some(post_data);
407 self.post_data_bytes = None; self
409 }
410
411 pub fn post_data_bytes(mut self, post_data_bytes: Vec<u8>) -> Self {
413 self.post_data_bytes = Some(post_data_bytes);
414 self.post_data = None; self
416 }
417
418 pub fn url(mut self, url: String) -> Self {
420 self.url = Some(url);
421 self
422 }
423
424 pub fn build(self) -> ContinueOptions {
426 ContinueOptions {
427 headers: self.headers,
428 method: self.method,
429 post_data: self.post_data,
430 post_data_bytes: self.post_data_bytes,
431 url: self.url,
432 }
433 }
434}
435
436#[derive(Debug, Clone, Default)]
440#[non_exhaustive]
441pub struct FulfillOptions {
442 pub status: Option<u16>,
444 pub headers: Option<std::collections::HashMap<String, String>>,
446 pub body: Option<Vec<u8>>,
448 pub content_type: Option<String>,
450}
451
452impl FulfillOptions {
453 pub fn builder() -> FulfillOptionsBuilder {
455 FulfillOptionsBuilder::default()
456 }
457}
458
459#[derive(Debug, Clone, Default)]
461pub struct FulfillOptionsBuilder {
462 status: Option<u16>,
463 headers: Option<std::collections::HashMap<String, String>>,
464 body: Option<Vec<u8>>,
465 content_type: Option<String>,
466}
467
468impl FulfillOptionsBuilder {
469 pub fn status(mut self, status: u16) -> Self {
471 self.status = Some(status);
472 self
473 }
474
475 pub fn headers(mut self, headers: std::collections::HashMap<String, String>) -> Self {
477 self.headers = Some(headers);
478 self
479 }
480
481 pub fn body(mut self, body: Vec<u8>) -> Self {
483 self.body = Some(body);
484 self
485 }
486
487 pub fn body_string(mut self, body: impl Into<String>) -> Self {
489 self.body = Some(body.into().into_bytes());
490 self
491 }
492
493 pub fn json(mut self, value: &impl serde::Serialize) -> Result<Self> {
495 let json_str = serde_json::to_string(value).map_err(|e| {
496 crate::error::Error::ProtocolError(format!("JSON serialization failed: {}", e))
497 })?;
498 self.body = Some(json_str.into_bytes());
499 self.content_type = Some("application/json".to_string());
500 Ok(self)
501 }
502
503 pub fn content_type(mut self, content_type: impl Into<String>) -> Self {
505 self.content_type = Some(content_type.into());
506 self
507 }
508
509 pub fn build(self) -> FulfillOptions {
511 FulfillOptions {
512 status: self.status,
513 headers: self.headers,
514 body: self.body,
515 content_type: self.content_type,
516 }
517 }
518}
519
520#[derive(Debug, Clone, Default)]
524#[non_exhaustive]
525pub struct FetchOptions {
526 pub headers: Option<std::collections::HashMap<String, String>>,
528 pub method: Option<String>,
530 pub post_data: Option<String>,
532 pub post_data_bytes: Option<Vec<u8>>,
534 pub url: Option<String>,
536 pub max_redirects: Option<u32>,
538 pub max_retries: Option<u32>,
540 pub timeout: Option<f64>,
542}
543
544impl FetchOptions {
545 pub fn builder() -> FetchOptionsBuilder {
547 FetchOptionsBuilder::default()
548 }
549}
550
551#[derive(Debug, Clone, Default)]
553pub struct FetchOptionsBuilder {
554 headers: Option<std::collections::HashMap<String, String>>,
555 method: Option<String>,
556 post_data: Option<String>,
557 post_data_bytes: Option<Vec<u8>>,
558 url: Option<String>,
559 max_redirects: Option<u32>,
560 max_retries: Option<u32>,
561 timeout: Option<f64>,
562}
563
564impl FetchOptionsBuilder {
565 pub fn headers(mut self, headers: std::collections::HashMap<String, String>) -> Self {
567 self.headers = Some(headers);
568 self
569 }
570
571 pub fn method(mut self, method: String) -> Self {
573 self.method = Some(method);
574 self
575 }
576
577 pub fn post_data(mut self, post_data: String) -> Self {
579 self.post_data = Some(post_data);
580 self.post_data_bytes = None;
581 self
582 }
583
584 pub fn post_data_bytes(mut self, post_data_bytes: Vec<u8>) -> Self {
586 self.post_data_bytes = Some(post_data_bytes);
587 self.post_data = None;
588 self
589 }
590
591 pub fn url(mut self, url: String) -> Self {
593 self.url = Some(url);
594 self
595 }
596
597 pub fn max_redirects(mut self, n: u32) -> Self {
599 self.max_redirects = Some(n);
600 self
601 }
602
603 pub fn max_retries(mut self, n: u32) -> Self {
605 self.max_retries = Some(n);
606 self
607 }
608
609 pub fn timeout(mut self, ms: f64) -> Self {
611 self.timeout = Some(ms);
612 self
613 }
614
615 pub fn build(self) -> FetchOptions {
617 FetchOptions {
618 headers: self.headers,
619 method: self.method,
620 post_data: self.post_data,
621 post_data_bytes: self.post_data_bytes,
622 url: self.url,
623 max_redirects: self.max_redirects,
624 max_retries: self.max_retries,
625 timeout: self.timeout,
626 }
627 }
628}
629
630impl ChannelOwner for Route {
631 fn guid(&self) -> &str {
632 self.base.guid()
633 }
634
635 fn type_name(&self) -> &str {
636 self.base.type_name()
637 }
638
639 fn parent(&self) -> Option<Arc<dyn ChannelOwner>> {
640 self.base.parent()
641 }
642
643 fn connection(&self) -> Arc<dyn crate::server::connection::ConnectionLike> {
644 self.base.connection()
645 }
646
647 fn initializer(&self) -> &Value {
648 self.base.initializer()
649 }
650
651 fn channel(&self) -> &crate::server::channel::Channel {
652 self.base.channel()
653 }
654
655 fn dispose(&self, reason: crate::server::channel_owner::DisposeReason) {
656 self.base.dispose(reason)
657 }
658
659 fn adopt(&self, child: Arc<dyn ChannelOwner>) {
660 self.base.adopt(child)
661 }
662
663 fn add_child(&self, guid: Arc<str>, child: Arc<dyn ChannelOwner>) {
664 self.base.add_child(guid, child)
665 }
666
667 fn remove_child(&self, guid: &str) {
668 self.base.remove_child(guid)
669 }
670
671 fn on_event(&self, _method: &str, _params: Value) {
672 }
674
675 fn was_collected(&self) -> bool {
676 self.base.was_collected()
677 }
678
679 fn as_any(&self) -> &dyn Any {
680 self
681 }
682}
683
684impl std::fmt::Debug for Route {
685 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
686 f.debug_struct("Route")
687 .field("guid", &self.guid())
688 .field("request", &self.request().guid())
689 .finish()
690 }
691}