playwright_rs/protocol/browser_context/mod.rs
1// BrowserContext protocol object
2//
3// Represents an isolated browser context (session) within a browser instance.
4// Multiple contexts can exist in a single browser, each with its own cookies,
5// cache, and local storage.
6
7use crate::error::Result;
8use crate::protocol::{Browser, Page, Request, ResponseObject, Route};
9use crate::server::channel_owner::{ChannelOwner, ChannelOwnerImpl};
10use std::collections::HashMap;
11use std::future::Future;
12use std::pin::Pin;
13use std::sync::atomic::AtomicBool;
14use std::sync::{Arc, Mutex};
15
16use crate::protocol::event_registry::EventRegistry;
17use tokio::sync::oneshot;
18
19/// Type alias for boxed route handler future
20type RouteHandlerFuture = Pin<Box<dyn Future<Output = Result<()>> + Send>>;
21
22/// Type alias for boxed binding callback future
23type BindingCallbackFuture = Pin<Box<dyn Future<Output = serde_json::Value> + Send>>;
24
25/// Type alias for boxed service worker handler future
26type ServiceWorkerHandlerFuture = Pin<Box<dyn Future<Output = Result<()>> + Send>>;
27
28/// Context-level service worker event handler
29type ServiceWorkerHandler =
30 Arc<dyn Fn(crate::protocol::Worker) -> ServiceWorkerHandlerFuture + Send + Sync>;
31
32/// Type alias for boxed context-level handler future
33type CtxHandlerFuture = Pin<Box<dyn Future<Output = Result<()>> + Send>>;
34
35/// Binding callback: receives deserialized JS args, returns a JSON value
36type BindingCallback = Arc<dyn Fn(Vec<serde_json::Value>) -> BindingCallbackFuture + Send + Sync>;
37
38/// Type alias for boxed WebSocketRoute handler future
39type WsRouteHandlerFuture = Pin<Box<dyn Future<Output = Result<()>> + Send>>;
40
41/// Storage for a single route handler
42#[derive(Clone)]
43struct RouteHandlerEntry {
44 pattern: String,
45 handler: Arc<dyn Fn(Route) -> RouteHandlerFuture + Send + Sync>,
46 /// Invocations of `handler` still running, for `unroute_all`.
47 in_flight: Arc<crate::protocol::in_flight::InFlight>,
48}
49
50/// Storage for a single WebSocket route handler entry
51#[derive(Clone)]
52struct ContextWsRouteHandlerEntry {
53 pattern: String,
54 handler: Arc<dyn Fn(crate::protocol::WebSocketRoute) -> WsRouteHandlerFuture + Send + Sync>,
55}
56
57/// BrowserContext represents an isolated browser session.
58///
59/// Contexts are isolated environments within a browser instance. Each context
60/// has its own cookies, cache, and local storage, enabling independent sessions
61/// without interference.
62///
63/// # Example
64///
65/// ```no_run
66/// use playwright_rs::protocol::Playwright;
67///
68/// #[tokio::main]
69/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
70/// let playwright = Playwright::launch().await?;
71/// let browser = playwright.chromium().launch().await?;
72///
73/// // Create isolated contexts
74/// let context1 = browser.new_context().await?;
75/// let context2 = browser.new_context().await?;
76///
77/// // Create pages in each context
78/// let page1 = context1.new_page().await?;
79/// let page2 = context2.new_page().await?;
80///
81/// // Access all pages in a context
82/// let pages = context1.pages();
83/// assert_eq!(pages.len(), 1);
84///
85/// // Access the browser from a context
86/// let ctx_browser = context1.browser().unwrap();
87/// assert_eq!(ctx_browser.name(), browser.name());
88///
89/// // App mode: access initial page created automatically
90/// let chromium = playwright.chromium();
91/// let app_context = chromium
92/// .launch_persistent_context_with_options(
93/// "/tmp/app-data",
94/// playwright_rs::protocol::BrowserContextOptions::builder()
95/// .args(vec!["--app=https://example.com".to_string()])
96/// .headless(true)
97/// .build()
98/// )
99/// .await?;
100///
101/// // Get the initial page (don't create a new one!)
102/// let app_pages = app_context.pages();
103/// if !app_pages.is_empty() {
104/// let initial_page = &app_pages[0];
105/// // Use the initial page...
106/// }
107///
108/// // Cleanup
109/// context1.close().await?;
110/// context2.close().await?;
111/// app_context.close().await?;
112/// browser.close().await?;
113/// Ok(())
114/// }
115/// ```
116///
117/// See: <https://playwright.dev/docs/api/class-browsercontext>
118#[derive(Clone)]
119pub struct BrowserContext {
120 base: ChannelOwnerImpl,
121 /// Browser instance that owns this context (None for persistent contexts)
122 browser: Option<Browser>,
123 /// All open pages in this context
124 pages: Arc<Mutex<Vec<Page>>>,
125 /// Route handlers for context-level network interception
126 route_handlers: Arc<Mutex<Vec<RouteHandlerEntry>>>,
127 /// APIRequestContext GUID from initializer (resolved lazily)
128 request_context_guid: Option<String>,
129 /// Tracing GUID from initializer (resolved lazily)
130 tracing_guid: Option<String>,
131 /// Debugger GUID from initializer (resolved lazily)
132 debugger_guid: Option<String>,
133 /// Default action timeout for all pages in this context (milliseconds), stored as f64 bits.
134 default_timeout_ms: Arc<std::sync::atomic::AtomicU64>,
135 /// Default navigation timeout for all pages in this context (milliseconds), stored as f64 bits.
136 default_navigation_timeout_ms: Arc<std::sync::atomic::AtomicU64>,
137 /// `page` event: handlers and one-shot `expect_page` waiters.
138 page_events: Arc<EventRegistry<Page>>,
139 /// `close` event: one-time transition; `dispatch_all` wakes every waiter.
140 close_events: Arc<EventRegistry<()>>,
141 /// `request` event: handlers and one-shot waiters.
142 request: Arc<EventRegistry<Request>>,
143 /// `requestFinished` event handlers (no `expect_*`; waiter queue stays empty).
144 request_finished: Arc<EventRegistry<Request>>,
145 /// `requestFailed` event handlers (no `expect_*`; waiter queue stays empty).
146 request_failed: Arc<EventRegistry<Request>>,
147 /// `response` event: handlers and one-shot waiters.
148 response: Arc<EventRegistry<ResponseObject>>,
149 /// `dialog` event handlers (no `expect_*`; waiter queue stays empty).
150 dialog: Arc<EventRegistry<crate::protocol::Dialog>>,
151 /// `dialogClosed` handlers, subscribed on the first one rather than
152 /// eagerly like `dialog`: nothing accumulates these passively.
153 dialog_closed: Arc<EventRegistry<crate::protocol::Dialog>>,
154 /// Registered binding callbacks keyed by name (for expose_function / expose_binding)
155 binding_callbacks: Arc<Mutex<HashMap<String, BindingCallback>>>,
156 /// `console` event: handlers and one-shot `expect_console_message` waiters.
157 console: Arc<EventRegistry<crate::protocol::ConsoleMessage>>,
158 /// `pageError`-derived weberror event: handlers and one-shot waiters.
159 weberror: Arc<EventRegistry<crate::protocol::WebError>>,
160 /// Context-level service worker event handlers (fired when a service worker is registered)
161 serviceworker_handlers: Arc<Mutex<Vec<ServiceWorkerHandler>>>,
162 /// Handlers for the events forwarded from each page.
163 forwarders: events::Forwarders,
164 /// One-shot senders waiting for the next "serviceworker" event (expect_event("serviceworker"))
165 serviceworker_waiters: Arc<Mutex<Vec<oneshot::Sender<crate::protocol::Worker>>>>,
166 /// Active service workers tracked via "serviceWorker" events
167 service_workers_list: Arc<Mutex<Vec<crate::protocol::Worker>>>,
168 /// WebSocketRoute handlers for route_web_socket()
169 ws_route_handlers: Arc<Mutex<Vec<ContextWsRouteHandlerEntry>>>,
170 /// Whether this context has been closed.
171 /// Set to true when close() is called or a "close" event is received.
172 is_closed: Arc<AtomicBool>,
173 /// The HAR the `record_har` option started, until `close()` writes it.
174 /// An async lock, held across the export, so a concurrent `close()`
175 /// waits for the file instead of closing the context under it.
176 option_har: Arc<tokio::sync::Mutex<Option<crate::protocol::tracing::HarRecording>>>,
177}
178
179// Each concern is its own `impl BrowserContext` block in a child module.
180// Rustdoc lists inherent impls in declaration order, so these follow the
181// order a reader meets the API. One comment per line on purpose: rustfmt
182// sorts adjacent `mod` lines alphabetically.
183// Construction, pages and companion objects, timeouts, close.
184mod lifecycle;
185// Cookies, storage state, headers, permissions, geolocation, credentials.
186mod state;
187// Routes and network interception.
188mod network;
189// Event subscriptions, page-event forwarders and waiters.
190mod events;
191// Init scripts, exposed functions and bindings.
192mod bindings;
193// `BrowserContextOptions` and the types it carries.
194mod options;
195// Server-to-registry event dispatch, last because it is internal.
196mod dispatch;
197
198pub use options::{
199 AcceptDownloads, BrowserContextOptions, BrowserContextOptionsBuilder, RecordHar, RecordVideo,
200 Viewport,
201};
202pub use state::{
203 ClearCookiesOptions, Cookie, Geolocation, GrantPermissionsOptions, HttpCredentials,
204 HttpCredentialsSend, LocalStorageItem, Origin, StorageState, StorageStateOptions,
205};
206
207impl std::fmt::Debug for BrowserContext {
208 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
209 f.debug_struct("BrowserContext")
210 .field("guid", &self.guid())
211 .finish()
212 }
213}