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