Skip to content

Commit dc1456f

Browse files
Handle CDP messages with different order
The 'method' still needs to be the first or the second key (in this case after the 'id'). Signed-off-by: Francis Bouvier <[email protected]>
1 parent 3ad19df commit dc1456f

File tree

8 files changed

+257
-213
lines changed

8 files changed

+257
-213
lines changed

src/cdp/browser.zig

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const server = @import("../server.zig");
44
const Ctx = server.Cmd;
55
const cdp = @import("cdp.zig");
66
const result = cdp.result;
7-
const getParams = cdp.getParams;
7+
const getMsg = cdp.getMsg;
88

99
const BrowserMethods = enum {
1010
getVersion,
@@ -15,7 +15,7 @@ const BrowserMethods = enum {
1515

1616
pub fn browser(
1717
alloc: std.mem.Allocator,
18-
id: u64,
18+
id: ?u16,
1919
action: []const u8,
2020
scanner: *std.json.Scanner,
2121
ctx: *Ctx,
@@ -38,10 +38,12 @@ const JsVersion = "12.4.254.8";
3838

3939
fn browserGetVersion(
4040
alloc: std.mem.Allocator,
41-
id: u64,
42-
_: *std.json.Scanner,
41+
id: ?u16,
42+
scanner: *std.json.Scanner,
4343
_: *Ctx,
4444
) ![]const u8 {
45+
const msg = try getMsg(alloc, void, scanner);
46+
4547
const Res = struct {
4648
protocolVersion: []const u8,
4749
product: []const u8,
@@ -57,12 +59,12 @@ fn browserGetVersion(
5759
.userAgent = UserAgent,
5860
.jsVersion = JsVersion,
5961
};
60-
return result(alloc, id, Res, res, null);
62+
return result(alloc, id orelse msg.id.?, Res, res, null);
6163
}
6264

6365
fn browserSetDownloadBehavior(
6466
alloc: std.mem.Allocator,
65-
id: u64,
67+
id: ?u16,
6668
scanner: *std.json.Scanner,
6769
_: *Ctx,
6870
) ![]const u8 {
@@ -72,15 +74,15 @@ fn browserSetDownloadBehavior(
7274
downloadPath: ?[]const u8 = null,
7375
eventsEnabled: ?bool = null,
7476
};
75-
_ = try getParams(alloc, Params, scanner);
76-
return result(alloc, id, null, null, null);
77+
const msg = try getMsg(alloc, Params, scanner);
78+
return result(alloc, id orelse msg.id.?, null, null, null);
7779
}
7880

7981
const DevToolsWindowID = 1923710101;
8082

8183
fn getWindowForTarget(
8284
alloc: std.mem.Allocator,
83-
id: u64,
85+
id: ?u16,
8486
scanner: *std.json.Scanner,
8587
_: *Ctx,
8688
) ![]const u8 {
@@ -89,8 +91,8 @@ fn getWindowForTarget(
8991
const Params = struct {
9092
targetId: ?[]const u8 = null,
9193
};
92-
const content = try cdp.getContent(alloc, ?Params, scanner);
93-
std.debug.assert(content.sessionID != null);
94+
const msg = try cdp.getMsg(alloc, ?Params, scanner);
95+
std.debug.assert(msg.sessionID != null);
9496

9597
// output
9698
const Resp = struct {
@@ -103,16 +105,16 @@ fn getWindowForTarget(
103105
windowState: []const u8 = "normal",
104106
} = .{},
105107
};
106-
return result(alloc, id, Resp, Resp{}, content.sessionID.?);
108+
return result(alloc, id orelse msg.id.?, Resp, Resp{}, msg.sessionID.?);
107109
}
108110

109111
fn setWindowBounds(
110112
alloc: std.mem.Allocator,
111-
id: u64,
113+
id: ?u16,
112114
scanner: *std.json.Scanner,
113115
_: *Ctx,
114116
) ![]const u8 {
115117
// NOTE: noop
116-
const content = try cdp.getContent(alloc, void, scanner);
117-
return result(alloc, id, null, null, content.sessionID);
118+
const msg = try cdp.getMsg(alloc, void, scanner);
119+
return result(alloc, id orelse msg.id.?, null, null, msg.sessionID);
118120
}

src/cdp/cdp.zig

Lines changed: 71 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -53,26 +53,22 @@ pub fn do(
5353
// handle 2 possible orders:
5454
// - id, method <...>
5555
// - method, id <...>
56-
var id_key = (try scanner.next()).string;
57-
var id_token = try scanner.next();
5856
var method_key = (try scanner.next()).string;
59-
var method_token = try scanner.next();
57+
var method_token: std.json.Token = undefined;
58+
var id: ?u16 = null;
6059
// check swap order
61-
if (!std.mem.eql(u8, id_key, "id")) {
62-
const swap_key = method_key;
63-
const swap_token = method_token;
64-
method_key = id_key;
65-
method_token = id_token;
66-
id_key = swap_key;
67-
id_token = swap_token;
60+
if (std.mem.eql(u8, method_key, "id")) {
61+
id = try getId(&scanner, method_key);
62+
method_key = (try scanner.next()).string;
63+
method_token = try scanner.next();
64+
} else {
65+
method_token = try scanner.next();
6866
}
69-
try checkKey(id_key, "id");
7067
try checkKey(method_key, "method");
7168

72-
// retrieve id and method
73-
const id = try std.fmt.parseUnsigned(u64, id_token.number, 10);
69+
// retrieve method
7470
const method_name = method_token.string;
75-
std.log.debug("cmd: id {any}, method {s}", .{ id, method_name });
71+
std.log.debug("cmd: method {s}, id {any}", .{ method_name, id });
7672

7773
// retrieve domain from method
7874
var iter = std.mem.splitScalar(u8, method_name, '.');
@@ -128,7 +124,7 @@ const resultNullSession = "{{\"id\": {d}, \"result\": {{}}, \"sessionId\": \"{s}
128124
// caller owns the slice returned
129125
pub fn result(
130126
alloc: std.mem.Allocator,
131-
id: u64,
127+
id: u16,
132128
comptime T: ?type,
133129
res: anytype,
134130
sessionID: ?[]const u8,
@@ -142,7 +138,7 @@ pub fn result(
142138
}
143139

144140
const Resp = struct {
145-
id: u64,
141+
id: u16,
146142
result: T.?,
147143
sessionId: ?[]const u8,
148144
};
@@ -171,108 +167,94 @@ pub fn sendEvent(
171167
try server.sendSync(ctx, event_msg);
172168
}
173169

174-
pub fn getParams(
170+
fn getParams(
175171
alloc: std.mem.Allocator,
176172
comptime T: type,
177173
scanner: *std.json.Scanner,
174+
key: []const u8,
178175
) !?T {
179176

180-
// if next token is the end of the object, there is no "params"
181-
const t = try scanner.next();
182-
if (t == .object_end) return null;
183-
184-
// if next token is not "params" there is no "params"
185-
if (!std.mem.eql(u8, "params", t.string)) return null;
177+
// check key key is "params"
178+
if (!std.mem.eql(u8, "params", key)) return null;
179+
180+
// skip "params" if not requested
181+
if (T == void) {
182+
var finished: usize = 0;
183+
while (true) {
184+
switch (try scanner.next()) {
185+
.object_begin => finished += 1,
186+
.object_end => finished -= 1,
187+
else => continue,
188+
}
189+
if (finished == 0) break;
190+
}
191+
return void{};
192+
}
186193

187194
// parse "params"
188195
const options = std.json.ParseOptions{
189196
.max_value_len = scanner.input.len,
190197
.allocate = .alloc_if_needed,
191198
};
192-
const params = try std.json.innerParse(T, alloc, scanner, options);
193-
return params;
199+
return try std.json.innerParse(T, alloc, scanner, options);
194200
}
195201

196-
pub fn getSessionID(scanner: *std.json.Scanner) !?[]const u8 {
202+
fn getId(scanner: *std.json.Scanner, key: []const u8) !?u16 {
197203

198-
// if next token is the end of the object, there is no "sessionId"
199-
const t = try scanner.next();
200-
if (t == .object_end) return null;
204+
// check key is "id"
205+
if (!std.mem.eql(u8, "id", key)) return null;
201206

202-
var n = t.string;
207+
// parse "id"
208+
return try std.fmt.parseUnsigned(u16, (try scanner.next()).number, 10);
209+
}
203210

204-
// if next token is "params" ignore them
205-
// NOTE: will panic if it's not an empty "params" object
206-
// TODO: maybe we should return a custom error here
207-
if (std.mem.eql(u8, n, "params")) {
208-
// ignore empty params
209-
_ = (try scanner.next()).object_begin;
210-
_ = (try scanner.next()).object_end;
211-
n = (try scanner.next()).string;
212-
}
211+
fn getSessionId(scanner: *std.json.Scanner, key: []const u8) !?[]const u8 {
213212

214-
// if next token is not "sessionId" there is no "sessionId"
215-
if (!std.mem.eql(u8, n, "sessionId")) return null;
213+
// check key is "sessionId"
214+
if (!std.mem.eql(u8, "sessionId", key)) return null;
216215

217216
// parse "sessionId"
218217
return (try scanner.next()).string;
219218
}
220219

221-
pub fn getContent(
220+
pub fn getMsg(
222221
alloc: std.mem.Allocator,
223-
comptime T: type,
222+
comptime params_T: type,
224223
scanner: *std.json.Scanner,
225-
) !struct { params: T, sessionID: ?[]const u8 } {
226-
227-
// if next token is the end of the object, error
228-
const t = try scanner.next();
229-
if (t == .object_end) return error.CDPNoContent;
230-
231-
var params: T = undefined;
224+
) !struct { id: ?u16, params: ?params_T, sessionID: ?[]const u8 } {
225+
var id: ?u16 = null;
226+
var params: ?params_T = null;
232227
var sessionID: ?[]const u8 = null;
233228

234-
var n = t.string;
235-
236-
// params
237-
if (std.mem.eql(u8, n, "params")) {
238-
if (T == void) {
239-
240-
// ignore params
241-
var finished: usize = 0;
242-
while (true) {
243-
switch (try scanner.next()) {
244-
.object_begin => finished += 1,
245-
.object_end => finished -= 1,
246-
else => continue,
247-
}
248-
if (finished == 0) break;
249-
}
250-
params = void{};
251-
} else {
252-
253-
// parse "params"
254-
const options = std.json.ParseOptions{
255-
.max_value_len = scanner.input.len,
256-
.allocate = .alloc_if_needed,
257-
};
258-
params = try std.json.innerParse(T, alloc, scanner, options);
259-
}
260-
261-
// go next
262-
n = (try scanner.next()).string;
263-
} else {
264-
params = switch (@typeInfo(T)) {
265-
.Void => void{},
266-
.Optional => null,
267-
else => return error.CDPNoParams,
268-
};
269-
}
229+
var t: std.json.Token = undefined;
270230

271-
if (std.mem.eql(u8, n, "sessionId")) {
272-
sessionID = (try scanner.next()).string;
231+
while (true) {
232+
t = try scanner.next();
233+
if (t == .object_end) break;
234+
if (t != .string) {
235+
return error.CDPMsgWrong;
236+
}
237+
if (id == null) {
238+
id = try getId(scanner, t.string);
239+
if (id != null) continue;
240+
}
241+
if (params == null) {
242+
params = try getParams(alloc, params_T, scanner, t.string);
243+
if (params != null) continue;
244+
}
245+
if (sessionID == null) {
246+
sessionID = try getSessionId(scanner, t.string);
247+
}
273248
}
274249

275-
return .{ .params = params, .sessionID = sessionID };
250+
// end
251+
std.log.debug(
252+
"id {any}, params {any}, sessionID: {any}, token {any}",
253+
.{ id, params, sessionID, t },
254+
);
255+
t = try scanner.next();
256+
if (t != .end_of_document) return error.CDPMsgEnd;
257+
return .{ .id = id, .params = params, .sessionID = sessionID };
276258
}
277259

278260
// Common

0 commit comments

Comments
 (0)