Merge pull request #908 from lightpanda-io/guard_against_double_script_execution
Some checks failed
e2e-test / zig build release (push) Has been cancelled
e2e-test / demo-scripts (push) Has been cancelled
e2e-test / cdp-and-hyperfine-bench (push) Has been cancelled
e2e-test / perf-fmt (push) Has been cancelled
zig-test / zig build dev (push) Has been cancelled
zig-test / browser fetch (push) Has been cancelled
zig-test / zig test (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled

Prevent double-execution of script tags.
This commit is contained in:
Karl Seguin
2025-07-23 21:33:52 +08:00
committed by GitHub
3 changed files with 34 additions and 1 deletions

View File

@@ -2885,3 +2885,15 @@ pub fn buttonGetType(button: *Button) ![]const u8 {
const s = s_ orelse return "button"; const s = s_ orelse return "button";
return strToData(s); return strToData(s);
} }
pub fn scriptGetProcessed(script: *Script) !bool {
var processed: bool = false;
const err = c.dom_html_script_element_get_processed(script, &processed);
try DOMErr(err);
return processed;
}
pub fn scriptSetProcessed(script: *Script, processed: bool) !void {
const err = c.dom_html_script_element_set_processed(script, processed);
try DOMErr(err);
}

View File

@@ -451,6 +451,12 @@ pub const Page = struct {
// if no src is present, we evaluate the text source. // if no src is present, we evaluate the text source.
// https://html.spec.whatwg.org/multipage/scripting.html#script-processing-model // https://html.spec.whatwg.org/multipage/scripting.html#script-processing-model
fn tryEvalScript(self: *Page, script: *const Script) !void { fn tryEvalScript(self: *Page, script: *const Script) !void {
if (try script.alreadyProcessed()) {
return;
}
try script.markAsProcessed();
const html_doc = self.window.document; const html_doc = self.window.document;
try parser.documentHTMLSetCurrentScript(html_doc, @ptrCast(script.element)); try parser.documentHTMLSetCurrentScript(html_doc, @ptrCast(script.element));
@@ -998,6 +1004,21 @@ const Script = struct {
return null; return null;
} }
// If a script tag gets dynamically created and added to the dom:
// document.getElementsByTagName('head')[0].appendChild(script)
// that script tag will immediately get executed by our scriptAddedCallback.
// However, if the location where the script tag is inserted happens to be
// below where processHTMLDoc curently is, then we'll re-run that same script
// again in processHTMLDoc. This flag is used to let us know if a specific
// <script> has already been processed.
fn alreadyProcessed(self: *const Script) !bool {
return parser.scriptGetProcessed(@ptrCast(self.element));
}
fn markAsProcessed(self: *const Script) !void {
return parser.scriptSetProcessed(@ptrCast(self.element), true);
}
fn eval(self: *const Script, page: *Page, body: []const u8) !void { fn eval(self: *const Script, page: *Page, body: []const u8) !void {
var try_catch: Env.TryCatch = undefined; var try_catch: Env.TryCatch = undefined;
try_catch.init(page.main_context); try_catch.init(page.main_context);