glass/browser/session/
intercept.rs1use super::*;
12
13#[derive(Debug, Clone)]
15pub struct RequestPattern {
16 pub url_pattern: String,
18 pub resource_type: Option<String>,
21 pub request_stage: String,
23}
24
25impl Default for RequestPattern {
26 fn default() -> Self {
27 Self {
28 url_pattern: "*".to_string(),
29 resource_type: None,
30 request_stage: "Request".to_string(),
31 }
32 }
33}
34
35pub struct InterceptGuard {
43 cdp: CdpClient,
44 session_id: String,
45 armed: bool,
46}
47
48impl InterceptGuard {
49 async fn enable(cdp: CdpClient, pattern: &RequestPattern) -> BrowserResult<Self> {
51 let session_id = cdp
52 .current_session_id()
53 .ok_or("intercept requires an active page session")?;
54 let resource_type = pattern.resource_type.as_deref().unwrap_or("*");
55 cdp.send_to_session(
56 &session_id,
57 "Fetch.enable",
58 Some(serde_json::json!({
59 "patterns": [{
60 "urlPattern": pattern.url_pattern,
61 "resourceType": resource_type,
62 "requestStage": pattern.request_stage
63 }]
64 })),
65 )
66 .await?;
67 Ok(Self {
68 cdp,
69 session_id,
70 armed: true,
71 })
72 }
73
74 pub async fn disable(mut self) -> BrowserResult<()> {
76 self.armed = false;
77 disable_fetch_for(&self.cdp, Some(&self.session_id)).await
78 }
79}
80
81impl Drop for InterceptGuard {
82 fn drop(&mut self) {
83 if self.armed {
84 let cdp = self.cdp.clone();
85 let session_id = self.session_id.clone();
86 tokio::spawn(async move {
87 let _ = disable_fetch_for(&cdp, Some(&session_id)).await;
88 });
89 }
90 }
91}
92
93impl BrowserSession {
94 pub async fn intercept_request(
100 &self,
101 pattern: &RequestPattern,
102 ) -> BrowserResult<InterceptGuard> {
103 self.cdp
104 .with_current_route(async { InterceptGuard::enable(self.cdp.clone(), pattern).await })
105 .await
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112
113 #[test]
114 fn request_pattern_default_matches_all_urls() {
115 let pattern = RequestPattern::default();
116 assert_eq!(pattern.url_pattern, "*");
117 assert_eq!(pattern.request_stage, "Request");
118 assert!(pattern.resource_type.is_none());
119 }
120
121 #[test]
122 fn request_pattern_custom_resource_type() {
123 let pattern = RequestPattern {
124 url_pattern: "https://example.com/*".to_string(),
125 resource_type: Some("XHR".to_string()),
126 request_stage: "Response".to_string(),
127 };
128 assert_eq!(pattern.url_pattern, "https://example.com/*");
129 assert_eq!(pattern.resource_type.as_deref(), Some("XHR"));
130 assert_eq!(pattern.request_stage, "Response");
131 }
132
133 #[test]
134 fn request_pattern_is_cloneable() {
135 let pattern = RequestPattern {
136 url_pattern: "/api/*".to_string(),
137 resource_type: Some("Fetch".to_string()),
138 request_stage: "Request".to_string(),
139 };
140 let cloned = pattern.clone();
141 assert_eq!(cloned.url_pattern, "/api/*");
142 assert_eq!(cloned.resource_type.as_deref(), Some("Fetch"));
143 assert_eq!(cloned.request_stage, "Request");
144 assert_eq!(pattern.url_pattern, "/api/*");
146 }
147
148 #[test]
149 fn request_pattern_debug_output_includes_fields() {
150 let pattern = RequestPattern::default();
151 let debug = format!("{:?}", pattern);
152 assert!(debug.contains("*"));
153 assert!(debug.contains("Request"));
154 }
155}