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<()> {
252 let options = options.into();
253 self.handled.store(true, Ordering::SeqCst);
254 let opts = options.unwrap_or_default();
255
256 let mut response = json!({
258 "status": opts.status.unwrap_or(200),
259 "headers": []
260 });
261
262 let mut headers_map = opts.headers.unwrap_or_default();
264
265 let body_bytes = opts.body.as_ref();
267 if let Some(body) = body_bytes {
268 let content_length = body.len().to_string();
269 headers_map.insert("content-length".to_string(), content_length);
270 }
271
272 if let Some(ref ct) = opts.content_type {
274 headers_map.insert("content-type".to_string(), ct.clone());
275 }
276
277 let headers_array: Vec<Value> = headers_map
279 .into_iter()
280 .map(|(name, value)| json!({"name": name, "value": value}))
281 .collect();
282 response["headers"] = json!(headers_array);
283
284 if let Some(body) = body_bytes {
286 if let Ok(body_str) = std::str::from_utf8(body) {
288 response["body"] = json!(body_str);
289 } else {
290 use base64::Engine;
291 let encoded = base64::engine::general_purpose::STANDARD.encode(body);
292 response["body"] = json!(encoded);
293 response["isBase64"] = json!(true);
294 }
295 }
296
297 let params = json!({
298 "response": response
299 });
300
301 self.channel()
302 .send::<_, serde_json::Value>("fulfill", params)
303 .await
304 .map(|_| ())
305 }
306
307 pub async fn fetch(&self, options: impl Into<Option<FetchOptions>>) -> Result<FetchResponse> {
319 let options = options.into();
320 self.handled.store(true, Ordering::SeqCst);
321
322 let api_ctx = self
323 .api_request_context
324 .lock()
325 .unwrap()
326 .clone()
327 .ok_or_else(|| {
328 crate::error::Error::ProtocolError(
329 "No APIRequestContext available for route.fetch(). \
330 This can happen if the route was not dispatched through \
331 a BrowserContext with an associated request context."
332 .to_string(),
333 )
334 })?;
335
336 let request = self.request();
337 let opts = options.unwrap_or_default();
338
339 let url = opts.url.unwrap_or_else(|| request.url().to_string());
341
342 let inner_opts = InnerFetchOptions {
343 method: opts.method.or_else(|| Some(request.method().to_string())),
344 headers: opts.headers,
345 post_data: opts.post_data,
346 post_data_bytes: opts.post_data_bytes,
347 max_redirects: opts.max_redirects,
348 max_retries: opts.max_retries,
349 timeout: opts.timeout,
350 };
351
352 api_ctx.inner_fetch(&url, Some(inner_opts)).await
353 }
354}
355
356pub(crate) fn matches_pattern(pattern: &str, url: &str) -> bool {
363 use glob::Pattern;
364
365 match Pattern::new(pattern) {
366 Ok(glob_pattern) => glob_pattern.matches(url),
367 Err(_) => {
368 pattern == url
370 }
371 }
372}
373
374#[derive(Debug, Clone, Copy, PartialEq, Eq)]
378#[non_exhaustive]
379pub enum UnrouteBehavior {
380 Wait,
382 IgnoreErrors,
384 Default,
386}
387
388#[derive(Debug, Clone)]
392#[non_exhaustive]
393pub struct FetchResponse {
394 pub status: u16,
396 pub status_text: String,
398 pub headers: Vec<(String, String)>,
400 pub body: Vec<u8>,
402}
403
404impl FetchResponse {
405 pub fn status(&self) -> u16 {
407 self.status
408 }
409
410 pub fn status_text(&self) -> &str {
412 &self.status_text
413 }
414
415 pub fn headers(&self) -> &[(String, String)] {
417 &self.headers
418 }
419
420 pub fn body(&self) -> &[u8] {
422 &self.body
423 }
424
425 pub fn text(&self) -> Result<String> {
427 String::from_utf8(self.body.clone()).map_err(|e| {
428 crate::error::Error::ProtocolError(format!("Response body is not valid UTF-8: {}", e))
429 })
430 }
431
432 pub fn json<T: serde::de::DeserializeOwned>(&self) -> Result<T> {
434 serde_json::from_slice(&self.body).map_err(|e| {
435 crate::error::Error::ProtocolError(format!("Failed to parse response JSON: {}", e))
436 })
437 }
438
439 pub fn ok(&self) -> bool {
441 (200..300).contains(&self.status)
442 }
443}
444
445#[derive(Debug, Clone, Default)]
452#[non_exhaustive]
453pub struct ContinueOptions {
454 pub headers: Option<std::collections::HashMap<String, String>>,
456 pub method: Option<String>,
458 pub post_data: Option<String>,
460 pub post_data_bytes: Option<Vec<u8>>,
462 pub url: Option<String>,
464}
465
466impl ContinueOptions {
467 pub fn builder() -> ContinueOptionsBuilder {
469 ContinueOptionsBuilder::default()
470 }
471}
472
473#[derive(Debug, Clone, Default)]
475pub struct ContinueOptionsBuilder {
476 headers: Option<std::collections::HashMap<String, String>>,
477 method: Option<String>,
478 post_data: Option<String>,
479 post_data_bytes: Option<Vec<u8>>,
480 url: Option<String>,
481}
482
483impl ContinueOptionsBuilder {
484 pub fn headers(mut self, headers: std::collections::HashMap<String, String>) -> Self {
486 self.headers = Some(headers);
487 self
488 }
489
490 pub fn method(mut self, method: String) -> Self {
492 self.method = Some(method);
493 self
494 }
495
496 pub fn post_data(mut self, post_data: String) -> Self {
498 self.post_data = Some(post_data);
499 self.post_data_bytes = None; self
501 }
502
503 pub fn post_data_bytes(mut self, post_data_bytes: Vec<u8>) -> Self {
505 self.post_data_bytes = Some(post_data_bytes);
506 self.post_data = None; self
508 }
509
510 pub fn url(mut self, url: String) -> Self {
512 self.url = Some(url);
513 self
514 }
515
516 pub fn build(self) -> ContinueOptions {
518 ContinueOptions {
519 headers: self.headers,
520 method: self.method,
521 post_data: self.post_data,
522 post_data_bytes: self.post_data_bytes,
523 url: self.url,
524 }
525 }
526}
527
528#[derive(Debug, Clone, Default)]
532#[non_exhaustive]
533pub struct FulfillOptions {
534 pub status: Option<u16>,
536 pub headers: Option<std::collections::HashMap<String, String>>,
538 pub body: Option<Vec<u8>>,
540 pub content_type: Option<String>,
542}
543
544impl FulfillOptions {
545 pub fn builder() -> FulfillOptionsBuilder {
547 FulfillOptionsBuilder::default()
548 }
549}
550
551#[derive(Debug, Clone, Default)]
553pub struct FulfillOptionsBuilder {
554 status: Option<u16>,
555 headers: Option<std::collections::HashMap<String, String>>,
556 body: Option<Vec<u8>>,
557 content_type: Option<String>,
558}
559
560impl FulfillOptionsBuilder {
561 pub fn status(mut self, status: u16) -> Self {
563 self.status = Some(status);
564 self
565 }
566
567 pub fn headers(mut self, headers: std::collections::HashMap<String, String>) -> Self {
569 self.headers = Some(headers);
570 self
571 }
572
573 pub fn body(mut self, body: Vec<u8>) -> Self {
575 self.body = Some(body);
576 self
577 }
578
579 pub fn body_string(mut self, body: impl Into<String>) -> Self {
581 self.body = Some(body.into().into_bytes());
582 self
583 }
584
585 pub fn json(mut self, value: &impl serde::Serialize) -> Result<Self> {
587 let json_str = serde_json::to_string(value).map_err(|e| {
588 crate::error::Error::ProtocolError(format!("JSON serialization failed: {}", e))
589 })?;
590 self.body = Some(json_str.into_bytes());
591 self.content_type = Some("application/json".to_string());
592 Ok(self)
593 }
594
595 pub fn content_type(mut self, content_type: impl Into<String>) -> Self {
597 self.content_type = Some(content_type.into());
598 self
599 }
600
601 pub fn build(self) -> FulfillOptions {
603 FulfillOptions {
604 status: self.status,
605 headers: self.headers,
606 body: self.body,
607 content_type: self.content_type,
608 }
609 }
610}
611
612#[derive(Debug, Clone, Default)]
616#[non_exhaustive]
617pub struct FetchOptions {
618 pub headers: Option<std::collections::HashMap<String, String>>,
620 pub method: Option<String>,
622 pub post_data: Option<String>,
624 pub post_data_bytes: Option<Vec<u8>>,
626 pub url: Option<String>,
628 pub max_redirects: Option<u32>,
630 pub max_retries: Option<u32>,
632 pub timeout: Option<f64>,
634}
635
636impl FetchOptions {
637 pub fn builder() -> FetchOptionsBuilder {
639 FetchOptionsBuilder::default()
640 }
641}
642
643#[derive(Debug, Clone, Default)]
645pub struct FetchOptionsBuilder {
646 headers: Option<std::collections::HashMap<String, String>>,
647 method: Option<String>,
648 post_data: Option<String>,
649 post_data_bytes: Option<Vec<u8>>,
650 url: Option<String>,
651 max_redirects: Option<u32>,
652 max_retries: Option<u32>,
653 timeout: Option<f64>,
654}
655
656impl FetchOptionsBuilder {
657 pub fn headers(mut self, headers: std::collections::HashMap<String, String>) -> Self {
659 self.headers = Some(headers);
660 self
661 }
662
663 pub fn method(mut self, method: String) -> Self {
665 self.method = Some(method);
666 self
667 }
668
669 pub fn post_data(mut self, post_data: String) -> Self {
671 self.post_data = Some(post_data);
672 self.post_data_bytes = None;
673 self
674 }
675
676 pub fn post_data_bytes(mut self, post_data_bytes: Vec<u8>) -> Self {
678 self.post_data_bytes = Some(post_data_bytes);
679 self.post_data = None;
680 self
681 }
682
683 pub fn url(mut self, url: String) -> Self {
685 self.url = Some(url);
686 self
687 }
688
689 pub fn max_redirects(mut self, n: u32) -> Self {
691 self.max_redirects = Some(n);
692 self
693 }
694
695 pub fn max_retries(mut self, n: u32) -> Self {
697 self.max_retries = Some(n);
698 self
699 }
700
701 pub fn timeout(mut self, ms: f64) -> Self {
703 self.timeout = Some(ms);
704 self
705 }
706
707 pub fn build(self) -> FetchOptions {
709 FetchOptions {
710 headers: self.headers,
711 method: self.method,
712 post_data: self.post_data,
713 post_data_bytes: self.post_data_bytes,
714 url: self.url,
715 max_redirects: self.max_redirects,
716 max_retries: self.max_retries,
717 timeout: self.timeout,
718 }
719 }
720}
721
722impl ChannelOwner for Route {
723 fn guid(&self) -> &str {
724 self.base.guid()
725 }
726
727 fn type_name(&self) -> &str {
728 self.base.type_name()
729 }
730
731 fn parent(&self) -> Option<Arc<dyn ChannelOwner>> {
732 self.base.parent()
733 }
734
735 fn connection(&self) -> Arc<dyn crate::server::connection::ConnectionLike> {
736 self.base.connection()
737 }
738
739 fn initializer(&self) -> &Value {
740 self.base.initializer()
741 }
742
743 fn channel(&self) -> &crate::server::channel::Channel {
744 self.base.channel()
745 }
746
747 fn dispose(&self, reason: crate::server::channel_owner::DisposeReason) {
748 self.base.dispose(reason)
749 }
750
751 fn adopt(&self, child: Arc<dyn ChannelOwner>) {
752 self.base.adopt(child)
753 }
754
755 fn add_child(&self, guid: Arc<str>, child: Arc<dyn ChannelOwner>) {
756 self.base.add_child(guid, child)
757 }
758
759 fn remove_child(&self, guid: &str) {
760 self.base.remove_child(guid)
761 }
762
763 fn on_event(&self, _method: &str, _params: Value) {
764 }
766
767 fn was_collected(&self) -> bool {
768 self.base.was_collected()
769 }
770
771 fn as_any(&self) -> &dyn Any {
772 self
773 }
774}
775
776impl std::fmt::Debug for Route {
777 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
778 f.debug_struct("Route")
779 .field("guid", &self.guid())
780 .field("request", &self.request().guid())
781 .finish()
782 }
783}