pub struct Page { /* private fields */ }Expand description
Wrapper around rustenium’s FirefoxBrowser.
Implementations§
Source§impl Page
impl Page
Sourcepub async fn launch(config: Option<FoxBrowserConfig>) -> Result<Self>
pub async fn launch(config: Option<FoxBrowserConfig>) -> Result<Self>
Launch a new Firefox instance and return its first page.
Sourcepub async fn evaluate(
&self,
expr: impl Into<String>,
) -> Result<EvaluationResult>
pub async fn evaluate( &self, expr: impl Into<String>, ) -> Result<EvaluationResult>
Evaluate a JavaScript expression in the active context.
The returned value is NOT promise-awaited: if expr evaluates to a
Promise, the opaque promise handle is returned, not its resolved value.
Use Self::evaluate_await for expressions that may be async.
Sourcepub async fn evaluate_await(
&self,
expr: impl Into<String>,
) -> Result<EvaluationResult>
pub async fn evaluate_await( &self, expr: impl Into<String>, ) -> Result<EvaluationResult>
Evaluate a JavaScript expression, awaiting the result if it is a Promise.
This sets the BiDi awaitPromise flag, so an expression that returns a
Promise resolves to its fulfilled value before serialization. A
non-promise expression is returned unchanged, so this is a safe superset
of Self::evaluate for any caller that wants the resolved value (e.g.
surfaces backed by MediaCapabilities.decodingInfo, Worker/
ServiceWorker message round-trips, or any async probe).
Sourcepub async fn evaluate_in_context(
&self,
expr: impl Into<String>,
context: &FrameId,
) -> Result<EvaluationResult>
pub async fn evaluate_in_context( &self, expr: impl Into<String>, context: &FrameId, ) -> Result<EvaluationResult>
Evaluate in a specific browsing context (frame).
Sourcepub async fn find_element(&self, selector: &str) -> Result<Element>
pub async fn find_element(&self, selector: &str) -> Result<Element>
Find the first element matching selector.
Sourcepub async fn find_elements(&self, selector: &str) -> Result<Vec<Element>>
pub async fn find_elements(&self, selector: &str) -> Result<Vec<Element>>
Find all elements matching selector.
Sourcepub async fn set_files(&self, selector: &str, files: Vec<String>) -> Result<()>
pub async fn set_files(&self, selector: &str, files: Vec<String>) -> Result<()>
Set the file(s) on a <input type=file> element via BiDi input.setFiles.
This is the trusted file-upload primitive: it attaches real local files to
the input the same way a human’s file picker does (no synthetic events), so
the entire file-upload attack surface, path-traversal filenames,
content-type bypass, SVG/XML XXE, RCE-via-upload, SSRF (becomes testable).
selector must resolve to the file input; files are absolute local paths.
Sourcepub async fn screenshot(&self) -> Result<Vec<u8>>
pub async fn screenshot(&self) -> Result<Vec<u8>>
Capture a viewport screenshot and return raw PNG bytes.
Sourcepub async fn frames(&self) -> Result<Vec<FrameId>>
pub async fn frames(&self) -> Result<Vec<FrameId>>
List all browsing-context IDs (main page + every iframe).
Sourcepub async fn mainframe(&self) -> Result<Option<FrameId>>
pub async fn mainframe(&self) -> Result<Option<FrameId>>
Return the active (main) browsing context.
Sourcepub async fn frame_execution_context(
&self,
frame_id: FrameId,
) -> Result<Option<FrameId>>
pub async fn frame_execution_context( &self, frame_id: FrameId, ) -> Result<Option<FrameId>>
Verify a browsing context still exists.
Sourcepub async fn list_frames(&self) -> Result<Vec<FrameInfo>>
pub async fn list_frames(&self) -> Result<Vec<FrameInfo>>
List every browsing context (main document + all iframes) with the
metadata an agent needs to target one: opaque id, current url,
window.name, and whether it is the main frame.
This is the discovery primitive for cross-origin iframe interaction
embedded apps, OAuth/payment widgets, postMessage surfaces, captcha tiles.
Pass a returned id back as the frame target to
Page::eval_in_frame / Page::click_in_frame /
Page::type_in_frame.
Sourcepub async fn frame_tree(&self) -> Result<Vec<FrameTreeNode>>
pub async fn frame_tree(&self) -> Result<Vec<FrameTreeNode>>
Walk the live frame tree via WebDriver BiDi browsingContext.getTree.
Returns every browsing context, the main document plus every nested iframe at any origin, in pre-order (a parent always precedes its children), each carrying true parent linkage, committed URL, and depth.
This is the structural primitive Page::frames cannot provide: that
method flattens the tree to a bare id list, discarding which iframe is
nested inside which. Cross-origin captcha challenges (reCAPTCHA’s
bframe inside its anchor, an hCaptcha challenge inside its checkbox)
are exactly the topologies that flattening destroys, so the solver must
re-derive structure every pass. getTree recovers it in one round-trip,
and, unlike reading document.URL from inside each frame, reports the
URL of a cross-origin frame the browser knows but in-frame JS may not yet
expose.
Sourcepub async fn resolve_frame(&self, spec: &str) -> Result<FrameId>
pub async fn resolve_frame(&self, spec: &str) -> Result<FrameId>
Resolve a frame target spec to a concrete FrameId, polling briefly so
an iframe that attaches asynchronously (captcha widgets, lazy embeds,
post-navigation frames) is found rather than racing to a “no such frame”.
Accepts every shape an agent naturally has on hand, so it never has to
call list_frames first:
- exact browsing-context id (from
Page::list_frames) index:<n>or a bare 0-based integer into the frame listurl:<substr>: first frame whose URL contains the substringname:<name>: first frame whosewindow.nameequals it- any other string, tried as an exact id, then as a URL substring
- empty /
main/top→ the main document
Sourcepub async fn resolve_frame_within(
&self,
spec: &str,
timeout: Duration,
) -> Result<FrameId>
pub async fn resolve_frame_within( &self, spec: &str, timeout: Duration, ) -> Result<FrameId>
Page::resolve_frame with an explicit overall timeout for the attach
poll. timeout of zero means a single attempt.
Sourcepub async fn eval_in_frame(
&self,
spec: &str,
expr: impl Into<String>,
) -> Result<EvaluationResult>
pub async fn eval_in_frame( &self, spec: &str, expr: impl Into<String>, ) -> Result<EvaluationResult>
Evaluate expr inside the frame named by spec (id, index, or
main/top). Full read/write JS runs in that frame’s own context, so the
agent can read or mutate a cross-origin iframe’s DOM, drive postMessage,
or land a DOM-XSS PoC inside an embedded document.
Sourcepub async fn click_in_frame(&self, spec: &str, selector: &str) -> Result<()>
pub async fn click_in_frame(&self, spec: &str, selector: &str) -> Result<()>
TRUSTED click on selector inside the frame named by spec.
Resolves the element’s centre in the frame’s own viewport, then dispatches
a real BiDi pointer event in that context via Page::click_at_in, so
event.isTrusted is true even for a cross-origin iframe. Returns an
error if the selector matches nothing visible in the frame.
Sourcepub async fn type_in_frame(
&self,
spec: &str,
selector: &str,
text: &str,
) -> Result<()>
pub async fn type_in_frame( &self, spec: &str, selector: &str, text: &str, ) -> Result<()>
Focus selector inside the frame named by spec and type text into it
with human-like timing. The keystrokes are dispatched in the frame’s own
context so they land in the cross-origin iframe’s focused element.
Sourcepub async fn start_dialog_log(&self) -> Result<DialogLog>
pub async fn start_dialog_log(&self) -> Result<DialogLog>
Start capturing JS dialogs and page-initiated downloads via BiDi
browsingContext.* events. Returns a crate::dialog::DialogLog handle
(cheap to clone) that accumulates events for the life of the page.
This is how the agent confirms alert-based XSS (the alert() message is
recorded even when the prompt auto-handles, so there is no hang), reads
confirm/prompt text, and inspects downloads. Pair with
Page::handle_user_prompt to answer a prompt left open by the ignore
handler. Mirrors Page::start_network_log.
Sourcepub async fn start_sensors(&self) -> Result<String>
pub async fn start_sensors(&self) -> Result<String>
Install the passive instrumentation grid (see crate::sensors) so the
page reports DOM-XSS sink writes, console output, uncaught errors, CSP
violations, and inbound postMessage on its own.
Injected twice: as a preload (runs in the MAIN world before page scripts
on every future navigation) AND evaluated once on the current document so
a page already loaded at launch is covered. The script is idempotent, so
the double-install is safe. Read what it captured with
Page::read_signals. Mirrors Page::start_network_log.
Sourcepub async fn read_signals(&self, clear: bool) -> Result<Value>
pub async fn read_signals(&self, clear: bool) -> Result<Value>
Read the captured signal buffer. With clear true the buffer is emptied
after the snapshot so the next read returns only NEW signals (deltas)
the basis for “what did my last action trigger?” telemetry.
Sourcepub async fn handle_user_prompt(
&self,
context: Option<&FrameId>,
accept: bool,
user_text: Option<&str>,
) -> Result<()>
pub async fn handle_user_prompt( &self, context: Option<&FrameId>, accept: bool, user_text: Option<&str>, ) -> Result<()>
Answer an open JS user prompt in context (or the active frame when
None): accept true clicks OK / accepts beforeunload; user_text
fills a prompt() box before accepting. Only effective when the page was
launched with the ignore prompt handler (otherwise Firefox auto-handles
the prompt before this runs). Mirrors the Page::set_files command path.
Sourcepub async fn mouse_move_human(
&self,
x0: f64,
y0: f64,
x1: f64,
y1: f64,
) -> Result<()>
pub async fn mouse_move_human( &self, x0: f64, y0: f64, x1: f64, y1: f64, ) -> Result<()>
Move the mouse from (x0, y0) to (x1, y1) using human-like curves.
Sourcepub async fn mouse_down(&self, x: f64, y: f64) -> Result<()>
pub async fn mouse_down(&self, x: f64, y: f64) -> Result<()>
Mouse-down at (x, y) in the active context.
Sourcepub async fn mouse_up(&self, _x: f64, _y: f64) -> Result<()>
pub async fn mouse_up(&self, _x: f64, _y: f64) -> Result<()>
Mouse-up at (x, y) in the active context.
Sourcepub async fn click_at(&self, x: f64, y: f64) -> Result<()>
pub async fn click_at(&self, x: f64, y: f64) -> Result<()>
Click at (x, y) in the active (top-level) context with realistic
press/release timing.
NOTE: for a target inside a cross-origin iframe (the production captcha
case: Turnstile/hCaptcha/reCAPTCHA all render their checkbox in an
OOPIF), prefer Page::click_at_in with the iframe’s context. A
pointer action dispatched in the top context does not reliably route
across a Fission process boundary, which is why a top-context viewport
click on a captcha checkbox silently fails to deliver.
Sourcepub async fn click_at_in(&self, context: &FrameId, x: f64, y: f64) -> Result<()>
pub async fn click_at_in(&self, context: &FrameId, x: f64, y: f64) -> Result<()>
Click at (x, y) within a SPECIFIC browsing context.
This is the cross-origin-correct click path: BiDi
input.performActions is dispatched in context, so the trusted
pointer event is delivered into that frame’s content process. For a
cross-origin iframe checkbox, pass the iframe’s FrameId (from
Page::frames) with coordinates in that frame’s own viewport space
(origin at the iframe’s top-left). Because the event is real BiDi input
(not a synthetic JS MouseEvent), event.isTrusted is true: the
property every modern captcha gates its checkbox on.
Sourcepub async fn move_mouse_to(&self, x: f64, y: f64) -> Result<()>
pub async fn move_mouse_to(&self, x: f64, y: f64) -> Result<()>
Move the pointer to an absolute viewport coordinate as a single
TRUSTED BiDi input.performActions PointerMove (no synthetic JS
MouseEvent).
This is the trusted primitive that human-trajectory generators must
dispatch each interpolated point through. A document.dispatchEvent(new MouseEvent('mousemove', …)) produces isTrusted === false, which every
modern anti-bot scorer flags on sight, so a beautifully shaped but
JS-dispatched path is worse than useless. Routing each point through
here makes the whole trajectory trusted and lets it cross into
cross-origin frames by viewport hit-test.
Sourcepub async fn scroll(&self, dx: i64, dy: i64) -> Result<()>
pub async fn scroll(&self, dx: i64, dy: i64) -> Result<()>
Scroll the wheel at the current mouse position.
Sourcepub async fn scroll_realistic(
&self,
direction: ScrollDirection,
amount: u32,
) -> Result<()>
pub async fn scroll_realistic( &self, direction: ScrollDirection, amount: u32, ) -> Result<()>
Human-like scroll (smooth easing with noise).
Sourcepub async fn type_text(&self, text: &str) -> Result<()>
pub async fn type_text(&self, text: &str) -> Result<()>
Type text into the active context with human-like delays.
Sourcepub async fn key_press(&self, key: &str) -> Result<()>
pub async fn key_press(&self, key: &str) -> Result<()>
Press and release a key in the active context.
Sourcepub async fn add_preload_script(&self, source: &str) -> Result<String>
pub async fn add_preload_script(&self, source: &str) -> Result<String>
Inject a preload script that runs in the page’s main world before any page script, on every new document.
source is a SCRIPT BODY (statements), matching CDP’s
Page.addScriptToEvaluateOnNewDocument semantics. WebDriver BiDi’s
script.addPreloadScript instead takes a functionDeclaration that it
invokes as a function, so a bare body, or a self-invoking IIFE like
(() => {…})() (which evaluates to undefined, not a callable), is
silently never run, nullifying the script. We therefore wrap the body in
an arrow function here so callers can pass a plain body and have it
actually execute. This is the single point that made guise’s stealth
preloads (all written as IIFE bodies) no-ops.
Capture all cookies (including HttpOnly) via BiDi storage.getCookies.
Set a cookie via BiDi storage.setCookie.
Sourcepub fn profile_dir(&self) -> Option<&str>
pub fn profile_dir(&self) -> Option<&str>
Return the Firefox profile directory path, if known.
Sourcepub async fn start_network_log(&self) -> Result<NetworkLog>
pub async fn start_network_log(&self) -> Result<NetworkLog>
Start capturing all network traffic (requests + responses) via BiDi.
Returns a crate::network::NetworkLog handle that can be queried at
any time while the browser is alive. The log is shared (Clone is cheap)
and accumulates events until the page is closed.
§Example
let log = page.start_network_log().await?;
page.goto("https://example.com").await?;
let entries = log.entries().await;
let tokens = log.extract_tokens().await;Sourcepub async fn close(&self) -> Result<()>
pub async fn close(&self) -> Result<()>
Close the browser. For a self-managed (Remote-attach) child this performs a CLEAN quit so the profile’s localStorage / IndexedDB / cookies are flushed to disk before exit; capped so a hung engine still tears down.
Persistence depends on this being called, a dropped Page (see Drop)
can only best-effort SIGTERM/SIGKILL, which does NOT flush localStorage on
this engine, so a reused profile_dir would lose recent writes.
Trait Implementations§
Auto Trait Implementations§
impl !Freeze for Page
impl !RefUnwindSafe for Page
impl !UnwindSafe for Page
impl Send for Page
impl Sync for Page
impl Unpin for Page
impl UnsafeUnpin for Page
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more