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 mut params = json!({
183 "isFallback": is_fallback
184 });
185
186 if let Some(opts) = overrides {
188 if let Some(headers) = opts.headers {
190 let headers_array: Vec<serde_json::Value> = headers
191 .into_iter()
192 .map(|(name, value)| json!({"name": name, "value": value}))
193 .collect();
194 params["headers"] = json!(headers_array);
195 }
196
197 if let Some(method) = opts.method {
199 params["method"] = json!(method);
200 }
201
202 if let Some(post_data) = opts.post_data {
204 params["postData"] = json!(post_data);
205 } else if let Some(post_data_bytes) = opts.post_data_bytes {
206 use base64::Engine;
207 let encoded = base64::engine::general_purpose::STANDARD.encode(&post_data_bytes);
208 params["postData"] = json!(encoded);
209 }
210
211 if let Some(url) = opts.url {
213 params["url"] = json!(url);
214 }
215 }
216
217 self.channel()
218 .send::<_, serde_json::Value>("continue", params)
219 .await
220 .map(|_| ())
221 }
222
223 pub async fn fulfill(&self, options: impl Into<Option<FulfillOptions>>) -> Result<()> {
254 let options = options.into();
255 self.handled.store(true, Ordering::SeqCst);
256 let opts = options.unwrap_or_default();
257
258 let mut response = json!({
260 "status": opts.status.unwrap_or(200),
261 "headers": []
262 });
263
264 let mut headers_map = opts.headers.unwrap_or_default();
266
267 let body_bytes = opts.body.as_ref();
269 if let Some(body) = body_bytes {
270 let content_length = body.len().to_string();
271 headers_map.insert("content-length".to_string(), content_length);
272 }
273
274 if let Some(ref ct) = opts.content_type {
276 headers_map.insert("content-type".to_string(), ct.clone());
277 }
278
279 let headers_array: Vec<Value> = headers_map
281 .into_iter()
282 .map(|(name, value)| json!({"name": name, "value": value}))
283 .collect();
284 response["headers"] = json!(headers_array);
285
286 if let Some(body) = body_bytes {
288 if let Ok(body_str) = std::str::from_utf8(body) {
290 response["body"] = json!(body_str);
291 } else {
292 use base64::Engine;
293 let encoded = base64::engine::general_purpose::STANDARD.encode(body);
294 response["body"] = json!(encoded);
295 response["isBase64"] = json!(true);
296 }
297 }
298
299 let params = json!({
300 "response": response
301 });
302
303 self.channel()
304 .send::<_, serde_json::Value>("fulfill", params)
305 .await
306 .map(|_| ())
307 }
308
309 pub async fn fetch(&self, options: impl Into<Option<FetchOptions>>) -> Result<FetchResponse> {
321 let options = options.into();
322 self.handled.store(true, Ordering::SeqCst);
323
324 let api_ctx = self
325 .api_request_context
326 .lock()
327 .unwrap()
328 .clone()
329 .ok_or_else(|| {
330 crate::error::Error::ProtocolError(
331 "No APIRequestContext available for route.fetch(). \
332 This can happen if the route was not dispatched through \
333 a BrowserContext with an associated request context."
334 .to_string(),
335 )
336 })?;
337
338 let request = self.request();
339 let opts = options.unwrap_or_default();
340
341 let url = opts.url.unwrap_or_else(|| request.url().to_string());
343
344 let inner_opts = InnerFetchOptions {
345 method: opts.method.or_else(|| Some(request.method().to_string())),
346 headers: opts.headers,
347 post_data: opts.post_data,
348 post_data_bytes: opts.post_data_bytes,
349 max_redirects: opts.max_redirects,
350 max_retries: opts.max_retries,
351 timeout: opts.timeout,
352 };
353
354 api_ctx.inner_fetch(&url, Some(inner_opts)).await
355 }
356}
357
358pub(crate) fn matches_pattern(pattern: &str, url: &str) -> bool {
365 use glob::Pattern;
366
367 match Pattern::new(pattern) {
368 Ok(glob_pattern) => glob_pattern.matches(url),
369 Err(_) => {
370 pattern == url
372 }
373 }
374}
375
376#[derive(Debug, Clone, Copy, PartialEq, Eq)]
380#[non_exhaustive]
381pub enum UnrouteBehavior {
382 Wait,
384 IgnoreErrors,
386 Default,
388}
389
390#[derive(Debug, Clone)]
394#[non_exhaustive]
395pub struct FetchResponse {
396 pub status: u16,
398 pub status_text: String,
400 pub headers: Vec<(String, String)>,
402 pub body: Vec<u8>,
404}
405
406impl FetchResponse {
407 pub fn status(&self) -> u16 {
409 self.status
410 }
411
412 pub fn status_text(&self) -> &str {
414 &self.status_text
415 }
416
417 pub fn headers(&self) -> &[(String, String)] {
419 &self.headers
420 }
421
422 pub fn body(&self) -> &[u8] {
424 &self.body
425 }
426
427 pub fn text(&self) -> Result<String> {
429 String::from_utf8(self.body.clone()).map_err(|e| {
430 crate::error::Error::ProtocolError(format!("Response body is not valid UTF-8: {}", e))
431 })
432 }
433
434 pub fn json<T: serde::de::DeserializeOwned>(&self) -> Result<T> {
436 serde_json::from_slice(&self.body).map_err(|e| {
437 crate::error::Error::ProtocolError(format!("Failed to parse response JSON: {}", e))
438 })
439 }
440
441 pub fn ok(&self) -> bool {
443 (200..300).contains(&self.status)
444 }
445}
446
447#[derive(Debug, Clone, Default)]
454#[non_exhaustive]
455pub struct ContinueOptions {
456 pub headers: Option<std::collections::HashMap<String, String>>,
458 pub method: Option<String>,
460 pub post_data: Option<String>,
462 pub post_data_bytes: Option<Vec<u8>>,
464 pub url: Option<String>,
466}
467
468impl ContinueOptions {
469 pub fn builder() -> ContinueOptionsBuilder {
471 ContinueOptionsBuilder::default()
472 }
473}
474
475#[derive(Debug, Clone, Default)]
477pub struct ContinueOptionsBuilder {
478 headers: Option<std::collections::HashMap<String, String>>,
479 method: Option<String>,
480 post_data: Option<String>,
481 post_data_bytes: Option<Vec<u8>>,
482 url: Option<String>,
483}
484
485impl ContinueOptionsBuilder {
486 pub fn headers(mut self, headers: std::collections::HashMap<String, String>) -> Self {
488 self.headers = Some(headers);
489 self
490 }
491
492 pub fn method(mut self, method: String) -> Self {
494 self.method = Some(method);
495 self
496 }
497
498 pub fn post_data(mut self, post_data: String) -> Self {
500 self.post_data = Some(post_data);
501 self.post_data_bytes = None; self
503 }
504
505 pub fn post_data_bytes(mut self, post_data_bytes: Vec<u8>) -> Self {
507 self.post_data_bytes = Some(post_data_bytes);
508 self.post_data = None; self
510 }
511
512 pub fn url(mut self, url: String) -> Self {
514 self.url = Some(url);
515 self
516 }
517
518 pub fn build(self) -> ContinueOptions {
520 ContinueOptions {
521 headers: self.headers,
522 method: self.method,
523 post_data: self.post_data,
524 post_data_bytes: self.post_data_bytes,
525 url: self.url,
526 }
527 }
528}
529
530#[derive(Debug, Clone, Default)]
534#[non_exhaustive]
535pub struct FulfillOptions {
536 pub status: Option<u16>,
538 pub headers: Option<std::collections::HashMap<String, String>>,
540 pub body: Option<Vec<u8>>,
542 pub content_type: Option<String>,
544}
545
546impl FulfillOptions {
547 pub fn builder() -> FulfillOptionsBuilder {
549 FulfillOptionsBuilder::default()
550 }
551}
552
553#[derive(Debug, Clone, Default)]
555pub struct FulfillOptionsBuilder {
556 status: Option<u16>,
557 headers: Option<std::collections::HashMap<String, String>>,
558 body: Option<Vec<u8>>,
559 content_type: Option<String>,
560}
561
562impl FulfillOptionsBuilder {
563 pub fn status(mut self, status: u16) -> Self {
565 self.status = Some(status);
566 self
567 }
568
569 pub fn headers(mut self, headers: std::collections::HashMap<String, String>) -> Self {
571 self.headers = Some(headers);
572 self
573 }
574
575 pub fn body(mut self, body: Vec<u8>) -> Self {
577 self.body = Some(body);
578 self
579 }
580
581 pub fn body_string(mut self, body: impl Into<String>) -> Self {
583 self.body = Some(body.into().into_bytes());
584 self
585 }
586
587 pub fn json(mut self, value: &impl serde::Serialize) -> Result<Self> {
589 let json_str = serde_json::to_string(value).map_err(|e| {
590 crate::error::Error::ProtocolError(format!("JSON serialization failed: {}", e))
591 })?;
592 self.body = Some(json_str.into_bytes());
593 self.content_type = Some("application/json".to_string());
594 Ok(self)
595 }
596
597 pub fn content_type(mut self, content_type: impl Into<String>) -> Self {
599 self.content_type = Some(content_type.into());
600 self
601 }
602
603 pub fn build(self) -> FulfillOptions {
605 FulfillOptions {
606 status: self.status,
607 headers: self.headers,
608 body: self.body,
609 content_type: self.content_type,
610 }
611 }
612}
613
614#[derive(Debug, Clone, Default)]
618#[non_exhaustive]
619pub struct FetchOptions {
620 pub headers: Option<std::collections::HashMap<String, String>>,
622 pub method: Option<String>,
624 pub post_data: Option<String>,
626 pub post_data_bytes: Option<Vec<u8>>,
628 pub url: Option<String>,
630 pub max_redirects: Option<u32>,
632 pub max_retries: Option<u32>,
634 pub timeout: Option<f64>,
636}
637
638impl FetchOptions {
639 pub fn builder() -> FetchOptionsBuilder {
641 FetchOptionsBuilder::default()
642 }
643}
644
645#[derive(Debug, Clone, Default)]
647pub struct FetchOptionsBuilder {
648 headers: Option<std::collections::HashMap<String, String>>,
649 method: Option<String>,
650 post_data: Option<String>,
651 post_data_bytes: Option<Vec<u8>>,
652 url: Option<String>,
653 max_redirects: Option<u32>,
654 max_retries: Option<u32>,
655 timeout: Option<f64>,
656}
657
658impl FetchOptionsBuilder {
659 pub fn headers(mut self, headers: std::collections::HashMap<String, String>) -> Self {
661 self.headers = Some(headers);
662 self
663 }
664
665 pub fn method(mut self, method: String) -> Self {
667 self.method = Some(method);
668 self
669 }
670
671 pub fn post_data(mut self, post_data: String) -> Self {
673 self.post_data = Some(post_data);
674 self.post_data_bytes = None;
675 self
676 }
677
678 pub fn post_data_bytes(mut self, post_data_bytes: Vec<u8>) -> Self {
680 self.post_data_bytes = Some(post_data_bytes);
681 self.post_data = None;
682 self
683 }
684
685 pub fn url(mut self, url: String) -> Self {
687 self.url = Some(url);
688 self
689 }
690
691 pub fn max_redirects(mut self, n: u32) -> Self {
693 self.max_redirects = Some(n);
694 self
695 }
696
697 pub fn max_retries(mut self, n: u32) -> Self {
699 self.max_retries = Some(n);
700 self
701 }
702
703 pub fn timeout(mut self, ms: f64) -> Self {
705 self.timeout = Some(ms);
706 self
707 }
708
709 pub fn build(self) -> FetchOptions {
711 FetchOptions {
712 headers: self.headers,
713 method: self.method,
714 post_data: self.post_data,
715 post_data_bytes: self.post_data_bytes,
716 url: self.url,
717 max_redirects: self.max_redirects,
718 max_retries: self.max_retries,
719 timeout: self.timeout,
720 }
721 }
722}
723
724impl ChannelOwner for Route {
725 fn guid(&self) -> &str {
726 self.base.guid()
727 }
728
729 fn type_name(&self) -> &str {
730 self.base.type_name()
731 }
732
733 fn parent(&self) -> Option<Arc<dyn ChannelOwner>> {
734 self.base.parent()
735 }
736
737 fn connection(&self) -> Arc<dyn crate::server::connection::ConnectionLike> {
738 self.base.connection()
739 }
740
741 fn initializer(&self) -> &Value {
742 self.base.initializer()
743 }
744
745 fn channel(&self) -> &crate::server::channel::Channel {
746 self.base.channel()
747 }
748
749 fn dispose(&self, reason: crate::server::channel_owner::DisposeReason) {
750 self.base.dispose(reason)
751 }
752
753 fn adopt(&self, child: Arc<dyn ChannelOwner>) {
754 self.base.adopt(child)
755 }
756
757 fn add_child(&self, guid: Arc<str>, child: Arc<dyn ChannelOwner>) {
758 self.base.add_child(guid, child)
759 }
760
761 fn remove_child(&self, guid: &str) {
762 self.base.remove_child(guid)
763 }
764
765 fn on_event(&self, _method: &str, _params: Value) {
766 }
768
769 fn was_collected(&self) -> bool {
770 self.base.was_collected()
771 }
772
773 fn as_any(&self) -> &dyn Any {
774 self
775 }
776}
777
778impl std::fmt::Debug for Route {
779 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
780 f.debug_struct("Route")
781 .field("guid", &self.guid())
782 .field("request", &self.request().guid())
783 .finish()
784 }
785}