Reject unsuccessful script responses

This commit is contained in:
SGavrl committed 2026-07-30 23:25:09 +00:00
1 parent caaf02e11c
commit f61493fbd1
5 files changed
+132 -4

No files matched your search

+10 -1
View File
@@ -253,7 +253,16 @@ async function __processDynScriptQueue() {
body = _decodeDataScriptUrl(task.url);
} else {
const raw = await Deno.core.ops.op_fetch_url(task.url, "GET", "{}", "", task.pageOrigin, "no-cors");
body = JSON.parse(raw).body;
const parsed = JSON.parse(raw);
// The HTML script-fetch algorithm treats an unsuccessful HTTP
// response as a network error. Evaluating its response body is both
// observably unlike browsers and dangerous: JSON error payloads
// become JavaScript source, while servers can return diagnostic
// HTML that mutates global state before throwing.
if (!(parsed.status >= 200 && parsed.status <= 299)) {
throw new Error('HTTP ' + (parsed.status || 0));
}
body = parsed.body;
}
if (body) {
globalThis.__currentScriptNid = task.nid;
+46
View File
@@ -4893,6 +4893,52 @@ mod tests {
);
}
#[tokio::test(flavor = "current_thread")]
async fn unsuccessful_dynamic_script_response_fires_error_without_evaluating_body() {
let mut rt = setup_runtime("<html><head></head><body></body></html>");
let result = rt
.call_function_on_for_cdp(
r#"async () => {
const originalFetchOp = Deno.core.ops.op_fetch_url;
try {
Deno.core.ops.op_fetch_url = (url) => JSON.stringify({
status: 401,
headers: { "content-type": "application/json" },
body: "globalThis.__executedFailedScript = true",
url,
});
const script = document.createElement("script");
script.src = "/unauthorized.js";
const outcome = await new Promise(resolve => {
script.onload = () => resolve("load");
script.onerror = () => resolve("error");
document.head.appendChild(script);
});
return {
outcome,
executed: globalThis.__executedFailedScript === true,
};
} finally {
Deno.core.ops.op_fetch_url = originalFetchOp;
}
}"#,
None,
&[],
true,
true,
)
.await
.unwrap();
assert_eq!(
result.value.unwrap(),
serde_json::json!({
"outcome": "error",
"executed": false,
})
);
}
#[tokio::test(flavor = "current_thread")]
async fn test_response_array_buffer_preserves_typed_array_view() {
let mut rt = setup_runtime("<html><body></body></html>");