firefox_webdriver/browser/network.rs
1//! Network interception types.
2//!
3//! Types for request/response interception callbacks.
4//!
5//! # Request Interception
6//!
7//! ```ignore
8//! use firefox_webdriver::RequestAction;
9//!
10//! let intercept_id = tab.intercept_request(|req| {
11//! if req.url.contains("ads") {
12//! RequestAction::block()
13//! } else {
14//! RequestAction::allow()
15//! }
16//! }).await?;
17//! ```
18//!
19//! # Response Interception
20//!
21//! ```ignore
22//! use firefox_webdriver::BodyAction;
23//!
24//! let intercept_id = tab.intercept_response_body(|res| {
25//! if res.url.contains("config.json") {
26//! BodyAction::modify_body(r#"{"modified": true}"#)
27//! } else {
28//! BodyAction::allow()
29//! }
30//! }).await?;
31//! ```
32
33// ============================================================================
34// Imports
35// ============================================================================
36
37use std::collections::HashMap;
38
39// ============================================================================
40// InterceptedRequest
41// ============================================================================
42
43/// Data about an intercepted network request.
44#[derive(Debug, Clone)]
45pub struct InterceptedRequest {
46 /// Unique request ID.
47 pub request_id: String,
48
49 /// Request URL.
50 pub url: String,
51
52 /// HTTP method (GET, POST, etc.).
53 pub method: String,
54
55 /// Resource type (document, script, xhr, etc.).
56 pub resource_type: String,
57
58 /// Tab ID where request originated.
59 pub tab_id: u32,
60
61 /// Frame ID where request originated.
62 pub frame_id: u64,
63
64 /// Request body (if available).
65 pub body: Option<RequestBody>,
66}
67
68// ============================================================================
69// RequestBody
70// ============================================================================
71
72/// Request body data.
73#[derive(Debug, Clone)]
74pub enum RequestBody {
75 /// Form data (application/x-www-form-urlencoded or multipart/form-data).
76 FormData(HashMap<String, Vec<String>>),
77
78 /// Raw bytes (base64 encoded).
79 Raw(Vec<u8>),
80
81 /// Error reading body.
82 Error(String),
83}
84
85// ============================================================================
86// RequestAction
87// ============================================================================
88
89/// Action to take for an intercepted request.
90#[derive(Debug, Clone)]
91pub enum RequestAction {
92 /// Allow the request to proceed.
93 Allow,
94
95 /// Block/cancel the request.
96 Block,
97
98 /// Redirect to a different URL.
99 Redirect(String),
100}
101
102// ============================================================================
103// RequestAction - Constructors
104// ============================================================================
105
106impl RequestAction {
107 /// Creates an Allow action.
108 #[inline]
109 #[must_use]
110 pub fn allow() -> Self {
111 Self::Allow
112 }
113
114 /// Creates a Block action.
115 #[inline]
116 #[must_use]
117 pub fn block() -> Self {
118 Self::Block
119 }
120
121 /// Creates a Redirect action.
122 #[inline]
123 #[must_use]
124 pub fn redirect(url: impl Into<String>) -> Self {
125 Self::Redirect(url.into())
126 }
127}
128
129// ============================================================================
130// InterceptedRequestBody
131// ============================================================================
132
133/// Data about an intercepted request body (read-only, cannot be modified).
134///
135/// Browser limitation: request body cannot be modified, only inspected.
136#[derive(Debug, Clone)]
137pub struct InterceptedRequestBody {
138 /// Unique request ID.
139 pub request_id: String,
140
141 /// Request URL.
142 pub url: String,
143
144 /// HTTP method.
145 pub method: String,
146
147 /// Resource type (document, script, xhr, etc.).
148 pub resource_type: String,
149
150 /// Tab ID.
151 pub tab_id: u32,
152
153 /// Frame ID.
154 pub frame_id: u64,
155
156 /// Request body (if available).
157 pub body: Option<RequestBody>,
158}
159
160// ============================================================================
161// InterceptedRequestHeaders
162// ============================================================================
163
164/// Data about intercepted request headers.
165#[derive(Debug, Clone)]
166pub struct InterceptedRequestHeaders {
167 /// Unique request ID.
168 pub request_id: String,
169
170 /// Request URL.
171 pub url: String,
172
173 /// HTTP method.
174 pub method: String,
175
176 /// Request headers.
177 pub headers: HashMap<String, String>,
178
179 /// Tab ID.
180 pub tab_id: u32,
181
182 /// Frame ID.
183 pub frame_id: u64,
184}
185
186// ============================================================================
187// HeadersAction
188// ============================================================================
189
190/// Action to take for intercepted headers.
191#[derive(Debug, Clone)]
192pub enum HeadersAction {
193 /// Allow headers to proceed unchanged.
194 Allow,
195
196 /// Modify headers.
197 ModifyHeaders(HashMap<String, String>),
198}
199
200// ============================================================================
201// HeadersAction - Constructors
202// ============================================================================
203
204impl HeadersAction {
205 /// Creates an Allow action.
206 #[inline]
207 #[must_use]
208 pub fn allow() -> Self {
209 Self::Allow
210 }
211
212 /// Creates a ModifyHeaders action.
213 #[inline]
214 #[must_use]
215 pub fn modify_headers(headers: HashMap<String, String>) -> Self {
216 Self::ModifyHeaders(headers)
217 }
218}
219
220// ============================================================================
221// InterceptedResponse
222// ============================================================================
223
224/// Data about an intercepted network response.
225#[derive(Debug, Clone)]
226pub struct InterceptedResponse {
227 /// Unique request ID.
228 pub request_id: String,
229
230 /// Request URL.
231 pub url: String,
232
233 /// HTTP status code.
234 pub status: u16,
235
236 /// HTTP status text.
237 pub status_text: String,
238
239 /// Response headers.
240 pub headers: HashMap<String, String>,
241
242 /// Tab ID where request originated.
243 pub tab_id: u32,
244
245 /// Frame ID where request originated.
246 pub frame_id: u64,
247}
248
249// ============================================================================
250// ResponseAction
251// ============================================================================
252
253/// Action to take for intercepted response headers.
254///
255/// Alias for [`HeadersAction`].
256pub type ResponseAction = HeadersAction;
257
258// ============================================================================
259// InterceptedResponseBody
260// ============================================================================
261
262/// Data about an intercepted response body.
263#[derive(Debug, Clone)]
264pub struct InterceptedResponseBody {
265 /// Unique request ID.
266 pub request_id: String,
267
268 /// Request URL.
269 pub url: String,
270
271 /// Tab ID.
272 pub tab_id: u32,
273
274 /// Frame ID.
275 pub frame_id: u64,
276
277 /// Response body as string.
278 pub body: String,
279
280 /// Content length.
281 pub content_length: usize,
282}
283
284// ============================================================================
285// BodyAction
286// ============================================================================
287
288/// Action to take for intercepted response body.
289#[derive(Debug, Clone)]
290pub enum BodyAction {
291 /// Allow body to proceed unchanged.
292 Allow,
293
294 /// Modify body content.
295 ModifyBody(String),
296}
297
298// ============================================================================
299// BodyAction - Constructors
300// ============================================================================
301
302impl BodyAction {
303 /// Creates an Allow action.
304 #[inline]
305 #[must_use]
306 pub fn allow() -> Self {
307 Self::Allow
308 }
309
310 /// Creates a ModifyBody action.
311 #[inline]
312 #[must_use]
313 pub fn modify_body(body: impl Into<String>) -> Self {
314 Self::ModifyBody(body.into())
315 }
316}
317
318// ============================================================================
319// Tests
320// ============================================================================
321
322#[cfg(test)]
323mod tests {
324 use super::{BodyAction, HeadersAction, RequestAction};
325
326 use std::collections::HashMap;
327
328 #[test]
329 fn test_request_action_allow() {
330 let action = RequestAction::allow();
331 assert!(matches!(action, RequestAction::Allow));
332 }
333
334 #[test]
335 fn test_request_action_block() {
336 let action = RequestAction::block();
337 assert!(matches!(action, RequestAction::Block));
338 }
339
340 #[test]
341 fn test_request_action_redirect() {
342 let action = RequestAction::redirect("https://example.com");
343 if let RequestAction::Redirect(url) = action {
344 assert_eq!(url, "https://example.com");
345 } else {
346 panic!("Expected Redirect action");
347 }
348 }
349
350 #[test]
351 fn test_headers_action_allow() {
352 let action = HeadersAction::allow();
353 assert!(matches!(action, HeadersAction::Allow));
354 }
355
356 #[test]
357 fn test_headers_action_modify() {
358 let mut headers = HashMap::new();
359 headers.insert("X-Custom".to_string(), "value".to_string());
360
361 let action = HeadersAction::modify_headers(headers);
362 if let HeadersAction::ModifyHeaders(h) = action {
363 assert_eq!(h.get("X-Custom"), Some(&"value".to_string()));
364 } else {
365 panic!("Expected ModifyHeaders action");
366 }
367 }
368
369 #[test]
370 fn test_body_action_allow() {
371 let action = BodyAction::allow();
372 assert!(matches!(action, BodyAction::Allow));
373 }
374
375 #[test]
376 fn test_body_action_modify() {
377 let action = BodyAction::modify_body("new body");
378 if let BodyAction::ModifyBody(body) = action {
379 assert_eq!(body, "new body");
380 } else {
381 panic!("Expected ModifyBody action");
382 }
383 }
384}