Skip to content

Commit 9319e4a

Browse files
Handle Runtime.callFunctionOn
Signed-off-by: Francis Bouvier <[email protected]>
1 parent 4d756b5 commit 9319e4a

File tree

1 file changed

+76
-0
lines changed

1 file changed

+76
-0
lines changed

src/cdp/runtime.zig

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const RuntimeMethods = enum {
1414
runIfWaitingForDebugger,
1515
evaluate,
1616
addBinding,
17+
callFunctionOn,
1718
};
1819

1920
pub fn runtime(
@@ -30,6 +31,7 @@ pub fn runtime(
3031
.runIfWaitingForDebugger => runIfWaitingForDebugger(alloc, id, scanner, ctx),
3132
.evaluate => evaluate(alloc, id, scanner, ctx),
3233
.addBinding => addBinding(alloc, id, scanner, ctx),
34+
.callFunctionOn => callFunctionOn(alloc, id, scanner, ctx),
3335
};
3436
}
3537

@@ -194,6 +196,80 @@ fn addBinding(
194196
return result(alloc, id, null, null, msg.sessionID);
195197
}
196198

199+
fn callFunctionOn(
200+
alloc: std.mem.Allocator,
201+
_id: ?u16,
202+
scanner: *std.json.Scanner,
203+
ctx: *Ctx,
204+
) ![]const u8 {
205+
206+
// input
207+
const Params = struct {
208+
functionDeclaration: []const u8,
209+
objectId: ?[]const u8 = null,
210+
executionContextId: ?u8 = null,
211+
arguments: ?[]struct {
212+
value: ?[]const u8 = null,
213+
} = null,
214+
returnByValue: ?bool = null,
215+
awaitPromise: ?bool = null,
216+
userGesture: ?bool = null,
217+
};
218+
const msg = try getMsg(alloc, Params, scanner);
219+
const id = _id orelse msg.id.?;
220+
const params = msg.params.?;
221+
std.debug.assert(params.objectId != null or params.executionContextId != null);
222+
if (params.executionContextId) |contextID| {
223+
std.debug.assert(contextID == ctx.state.executionContextId);
224+
}
225+
const name = "callFunctionOn";
226+
227+
// save script in file at debug mode
228+
std.log.debug("{s} script id {d}, length: {d}", .{ name, id, params.functionDeclaration.len });
229+
if (std.log.defaultLogEnabled(.debug)) {
230+
try cdp.dumpFile(alloc, id, params.functionDeclaration);
231+
}
232+
233+
// parse function
234+
if (!std.mem.startsWith(u8, params.functionDeclaration, "function ")) {
235+
return error.CDPRuntimeCallFunctionOnNotFunction;
236+
}
237+
const pos = std.mem.indexOfScalar(u8, params.functionDeclaration, '(');
238+
if (pos == null) return error.CDPRuntimeCallFunctionOnWrongFunction;
239+
var function = params.functionDeclaration[9..pos.?];
240+
function = try std.fmt.allocPrint(alloc, "{s}(", .{function});
241+
defer alloc.free(function);
242+
if (params.arguments) |args| {
243+
for (args, 0..) |arg, i| {
244+
if (i > 0) {
245+
function = try std.fmt.allocPrint(alloc, "{s}, ", .{function});
246+
}
247+
if (arg.value) |value| {
248+
function = try std.fmt.allocPrint(alloc, "{s}\"{s}\"", .{ function, value });
249+
} else {
250+
function = try std.fmt.allocPrint(alloc, "{s}undefined", .{function});
251+
}
252+
}
253+
}
254+
function = try std.fmt.allocPrint(alloc, "{s});", .{function});
255+
std.log.debug("{s} id {d}, function parsed: {s}", .{ name, id, function });
256+
257+
const session = ctx.browser.currentSession();
258+
// TODO: should we use the page's allocator instead of the session's allocator?
259+
// the following code does not work:
260+
// const page_alloc = ctx.browser.currentSession().page.?.arena.allocator();
261+
262+
// first evaluate the function declaration
263+
const decl = try runtimeEvaluate(session.alloc, id, session.env, params.functionDeclaration, name);
264+
defer decl.deinit(session.alloc);
265+
266+
// then call the function on the arguments
267+
const res = try runtimeEvaluate(session.alloc, id, session.env, function, name);
268+
defer res.deinit(session.alloc);
269+
270+
return result(alloc, id, null, "{\"type\":\"undefined\"}", msg.sessionID);
271+
}
272+
197273
// caller is the owner of JSResult returned
198274
fn runtimeEvaluate(
199275
alloc: std.mem.Allocator,

0 commit comments

Comments
 (0)