fix(browser,cdp,js): about:blank navigation, real getBoxModel/getContentQuads, expose _wrap and self

- about: URL scheme now handled in navigate_single instead of
  hitting validate_url and failing with "Forbidden URL scheme"
- DOM.getBoxModel calls getBoundingClientRect via JS instead of
  returning hardcoded pixel coords
- DOM.getContentQuads added (was missing, needed by Playwright click)
- globalThis._wrap exposed so CDP eval code can look up nodes by id
- globalThis.self = globalThis for webpack/bundler worker detection
This commit is contained in:
SGavrl committed 2026-05-18 10:11:54 +00:00
1 parent 913e6a4865
commit 1950048138
3 files changed
+64 -5

No files matched your search

+6
View File
@@ -611,6 +611,12 @@ impl Page {
} }
} }
if url.scheme() == "about" {
self.navigate_blank();
self.init_js();
return Ok(());
}
let response = if url.scheme() == "data" { let response = if url.scheme() == "data" {
let content_type = url_str.strip_prefix("data:") let content_type = url_str.strip_prefix("data:")
.and_then(|s| s.split(',').next()) .and_then(|s| s.split(',').next())
+55 -5
View File
@@ -138,16 +138,66 @@ pub async fn handle(
"setAttributeValue" => Ok(json!({})), "setAttributeValue" => Ok(json!({})),
"removeNode" => Ok(json!({})), "removeNode" => Ok(json!({})),
"getBoxModel" => { "getBoxModel" => {
let node_id = params.get("nodeId").and_then(|v| v.as_u64())
.or_else(|| params.get("backendNodeId").and_then(|v| v.as_u64()))
.unwrap_or(0);
let page = ctx.get_session_page_mut(session_id).ok_or("No page")?;
let code = format!(
"(function() {{\
var el = globalThis._wrap && globalThis._wrap({0});\
if (!el || typeof el.getBoundingClientRect !== 'function') return null;\
var r = el.getBoundingClientRect();\
return [r.left, r.top, r.right, r.top, r.right, r.bottom, r.left, r.bottom,\
r.width, r.height];\
}})()",
node_id
);
let val = page.evaluate(&code);
let (quad, w, h) = if let Some(arr) = val.as_array() {
let nums: Vec<f64> = arr.iter().filter_map(|v| v.as_f64()).collect();
if nums.len() >= 10 {
let q: Vec<Value> = nums[..8].iter().map(|n| json!(n)).collect();
(q, nums[8], nums[9])
} else {
(vec![json!(8),json!(8),json!(108),json!(8),json!(108),json!(28),json!(8),json!(28)], 100.0, 20.0)
}
} else {
(vec![json!(8),json!(8),json!(108),json!(8),json!(108),json!(28),json!(8),json!(28)], 100.0, 20.0)
};
Ok(json!({ Ok(json!({
"model": { "model": {
"content": [8,8, 108,8, 108,28, 8,28], "content": quad.clone(),
"padding": [8,8, 108,8, 108,28, 8,28], "padding": quad.clone(),
"border": [8,8, 108,8, 108,28, 8,28], "border": quad.clone(),
"margin": [0,0, 116,0, 116,36, 0,36], "margin": quad,
"width": 100, "height": 20, "width": w, "height": h,
} }
})) }))
} }
"getContentQuads" => {
let node_id = params.get("nodeId").and_then(|v| v.as_u64())
.or_else(|| params.get("backendNodeId").and_then(|v| v.as_u64()))
.unwrap_or(0);
let page = ctx.get_session_page_mut(session_id).ok_or("No page")?;
let code = format!(
"(function() {{\
var el = globalThis._wrap && globalThis._wrap({0});\
if (!el || typeof el.getBoundingClientRect !== 'function') return null;\
var r = el.getBoundingClientRect();\
return [r.left, r.top, r.right, r.top, r.right, r.bottom, r.left, r.bottom];\
}})()",
node_id
);
let val = page.evaluate(&code);
let quad = if let Some(arr) = val.as_array() {
let nums: Vec<f64> = arr.iter().filter_map(|v| v.as_f64()).collect();
if nums.len() == 8 { nums.iter().map(|n| json!(n)).collect::<Vec<_>>() }
else { vec![json!(8),json!(8),json!(108),json!(8),json!(108),json!(28),json!(8),json!(28)] }
} else {
vec![json!(8),json!(8),json!(108),json!(8),json!(108),json!(28),json!(8),json!(28)]
};
Ok(json!({ "quads": [quad] }))
}
_ => Err(format!("Unknown DOM method: {}", method)), _ => Err(format!("Unknown DOM method: {}", method)),
} }
} }
+3
View File
@@ -1076,6 +1076,9 @@ function _wrapEl(nid) {
return n; return n;
} }
globalThis._wrap = _wrap;
globalThis.self = globalThis;
globalThis.document = null; globalThis.document = null;
function _resolveUrl(url) { function _resolveUrl(url) {
if (!url) return url; if (!url) return url;