Commit Graph

1436 Commits

Author SHA1 Message Date
Pierre Tachoire
4802a2ce82 Merge pull request #460 from karlseguin/playwright
Remove CDP FrameId
2025-03-11 08:41:39 +01:00
Karl Seguin
e3409a27e7 fix test 2025-03-11 10:51:40 +08:00
Karl Seguin
5182edce6f Remove CDP FrameId
I don't know if FrameId is related to an <iframe>, and whether each Page has
1 implicit "frame". But, playwright seems to treat frameId and targetId as
interchangeable, and chrome seems to agree (at leas to some degree); chrome will
return a targetId and reuse that value for the frameId.

So the simplest solution is just to remove our concept of a frameId and use
targetId exclusively. This doesn't seem to cause any issues with puppeteer.
2025-03-11 10:37:43 +08:00
Pierre Tachoire
763d8d025e Merge pull request #453 from lightpanda-io/loop-reset
Some checks failed
e2e-test / zig build release (push) Waiting to run
e2e-test / puppeteer-perf (push) Blocked by required conditions
e2e-test / demo-scripts (push) Blocked by required conditions
wpt / web platform tests (push) Waiting to run
wpt / perf-fmt (push) Blocked by required conditions
zig-test / zig build dev (push) Waiting to run
zig-test / zig test (push) Waiting to run
zig-test / perf-fmt (push) Blocked by required conditions
nightly build / build-linux-x86_64 (push) Has been cancelled
nightly build / build-macos-aarch64 (push) Has been cancelled
Reset loop event after page stop.
2025-03-10 16:07:34 +01:00
Pierre Tachoire
a3045c9808 ci: run demo's puppeteer scripts 2025-03-10 15:59:46 +01:00
Pierre Tachoire
6b78b011b7 upgrade zig-jsruntime 2025-03-10 15:59:46 +01:00
Pierre Tachoire
bd7b84e136 loop: reset the loop after page end 2025-03-10 15:59:46 +01:00
Pierre Tachoire
2a9bab3f13 Merge pull request #450 from lightpanda-io/cdp-playwright
cdp: improve playwright support
2025-03-10 15:56:41 +01:00
Pierre Tachoire
6ca1e6c6dd cdp: let the inspector return the response
When a command is forwarded to the inspector, it handles directly the
reponse to the message.
2025-03-10 14:57:10 +01:00
Pierre Tachoire
f3a1a6a191 cdp: add a Page.getFrameTree unit test 2025-03-10 14:57:10 +01:00
Pierre Tachoire
675932c65b cdp: improve playwright support
The getTargetInfo result must return a `targetInfo` key.

Here is an example returned by Chrome:
```json
{
  "id": 16,
  "result": {
    "targetInfo": {
      "targetId": "d93a1bbc-f906-4bbb-bb4d-a2285234b091",
      "type": "browser",
      "title": "",
      "url": "",
      "attached": true,
      "canAccessOpener": false
    }
  }
}
```
2025-03-10 14:57:05 +01:00
Pierre Tachoire
708abb0e30 Merge pull request #459 from lightpanda-io/browser_context
Make CDP server more authoritative with respect to IDs
2025-03-10 14:49:53 +01:00
Karl Seguin
9de84aee2e Don't send CDP result when message is forward to inspector.
Rely on inspector to send the result, otherwise we'll send 2 responses to the
same message (one ourselves and one from the inspector), which Playwright does
not like.
2025-03-10 14:34:32 +01:00
Karl Seguin
adb8779d00 allow Target.getTargetInfo to be called without parameters 2025-03-10 14:34:32 +01:00
Karl Seguin
fbb0e675f5 send attach events before result 2025-03-10 14:34:32 +01:00
Karl Seguin
a3e2b5246e Make CDP server more authoritative with respect to IDs
The TL;DR is that this commit enforces the use of correct IDs, introduces a
BrowserContext, and adds some CDP tests.

These are the ids we need to be aware of when talking about CDP:
- id
- browserContextId
- targetId
- sessionId
- loaderId
- frameId

The `id` is the only one that _should_ originate from the driver. It's attached
to most messages and it's how we maintain a request -> response flow: when
the server responds to a specific message, it echo's back the id from the
requested message. (As opposed to out-of-band events sent from the server which
won't have an `id`). When I say "id" from this point forward, I mean every id
except for this req->res id.

Every other id is created by the browser.

Prior to this commit, we didn't really check incoming ids from the driver. If
the driver said "attachToTarget" and included a targetId, we just assumed that
this was the current targetId. This was aided by the fact that we only used
hard-coded IDS. If _we_ only "create" a frameId of "FRAME-1", then it's tempting
to think the driver will only ever send a frameId of "FRAME-1".

The issue with this approach is that _if_ the browser and driver fall out of sync
and there's only ever 1 browserContextId, 1 sessionId and 1 frameId, it's not
impossible to imagine cases where we behave on the thing.

Imagine this flow:
- Driver asks for a new BrowserContext
- Browser says OK, your browserContextId is 1
- Driver, for whatever reason, says close browserContextId 2
- Browser says, OK, but it doesn't check the id and just closes the only
  BrowserContext it knows about (which is 1)

By both re-using the same hard-coded ids, and not verifying that the ids sent
from the client correspond to the correct ids, any issues are going to be hard
to debug.

Currently LOADER_ID and FRAEM_ID are still hard-coded. Baby steps.
2025-03-10 14:34:32 +01:00
Pierre Tachoire
ccacac0597 Merge pull request #458 from karlseguin/serialized_writes
Some checks are pending
e2e-test / zig build release (push) Waiting to run
e2e-test / puppeteer (push) Blocked by required conditions
wpt / web platform tests (push) Waiting to run
wpt / perf-fmt (push) Blocked by required conditions
zig-test / zig build dev (push) Waiting to run
zig-test / zig test (push) Waiting to run
zig-test / perf-fmt (push) Blocked by required conditions
Serialize socket writes + consider client pending completions when sh…
2025-03-10 10:24:57 +01:00
Karl Seguin
ca230aa230 Serialize socket writes + consider client pending completions when shutting down
Previously, we could have multiple in-flight messages from the server to a
single client. This isn't safe and can lead to message interleaving. While
write / send are atomic, they are only atomic for the N bytes which they write,
which may not be the entire buffer. Consider this writeAll function:

```
pub fn writeAll(socket: socket_t, bytes: []const u8) !void {
    var index: usize = 0;
    while (index < bytes.len) {
        index += try posix.write(socket, bytes[index..]);
    }
}
```

If we're trying to send "abc123", this could take anywhere from 1 to 6 calls
to posix.write (it would take 6 calls, for example, if every call to
posix.write only wrote a single byte). Now if you're trying to write other data
to this same socket at the same time, messages _will_ get interleaved.

In order for this to work, the client now has a send_queue (doubly linked list).
When one message is sent, it sends the next.

In addition to the above change, the Client is now self-contained with respect
to its lifetime. This is necessary so that completions which come in AFTER our
concept of its lifetime ends, can still be processed. I think all types that
receive completions need to follow this model. This relies on the fact that
kqueue (which I know for a fact) and io_uring (which people seem to imply) handle
socket shutdown properly. It's still a bit messy because of timeout and not
wanting to wait until timeout to accept new connections, but needing to wait
until timeout to cleanup the client.

The self-contained nature of Client makes it difficult to test as a generic. I
removed Client(T). Tests now use real sockets. Some tests had to be removed
because they're too difficult to test over a real connection :(
2025-03-07 20:29:57 +08:00
Pierre Tachoire
7b775d2ad7 Merge pull request #452 from lightpanda-io/katie-lpd-patch-1
Update README.md
2025-03-04 17:16:34 +01:00
Pierre Tachoire
c5397bfbe2 Merge pull request #448 from karlseguin/set_cookie
Some checks failed
e2e-test / zig build release (push) Has been cancelled
wpt / web platform tests (push) Has been cancelled
zig-test / zig build dev (push) Has been cancelled
zig-test / zig test (push) Has been cancelled
e2e-test / puppeteer (push) Has been cancelled
wpt / perf-fmt (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled
Add Set-Cookie parsing
2025-03-04 13:20:33 +01:00
Karl Seguin
9fec6ebc66 fix typo, improve comment, add 1 test case 2025-03-04 19:46:36 +08:00
Pierre Tachoire
6bc38c5782 Merge pull request #455 from lightpanda-io/upgrade-zig-azync-io
upgrade vendor/zig-async-io
2025-03-04 11:37:30 +01:00
Pierre Tachoire
7f9d585d7f upgrade vendor/zig-async-io 2025-03-04 11:29:17 +01:00
Pierre Tachoire
0b14d36c95 Merge pull request #454 from lightpanda-io/upgrade-zig-jsruntime
upgrade vendor/zig-js-runtime
2025-03-04 11:07:26 +01:00
Pierre Tachoire
e22ca2d082 upgrade vendor/zig-js-runtime 2025-03-03 15:37:43 +01:00
katie-lpd
52a70cb7f5 Update README.md
A really important visual change in the readme :)
2025-03-01 19:43:28 +01:00
Karl Seguin
a00d1d068a Cookie with SameSite=None is only valid when Secure 2025-02-27 16:47:39 +08:00
Pierre Tachoire
6ae4ed9fc3 Merge pull request #449 from karlseguin/longer_timeout
Some checks failed
e2e-test / zig build release (push) Has been cancelled
wpt / web platform tests (push) Has been cancelled
zig-test / zig build dev (push) Has been cancelled
zig-test / zig test (push) Has been cancelled
e2e-test / puppeteer (push) Has been cancelled
wpt / perf-fmt (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled
allow longer timeouts (u8 -> u16)
2025-02-27 09:11:25 +01:00
Karl Seguin
6f5028612a add cookie jar 2025-02-27 16:09:10 +08:00
Karl Seguin
c31c12d31a add test for Storage shed, use map.getOrPut 2025-02-27 11:57:46 +08:00
Karl Seguin
28008d835e allow longer timeouts (u8 -> u16) 2025-02-27 11:00:37 +08:00
Pierre Tachoire
08e99a32cb Merge pull request #445 from karlseguin/capture_git_commit
Some checks are pending
e2e-test / zig build release (push) Waiting to run
e2e-test / puppeteer (push) Blocked by required conditions
wpt / web platform tests (push) Waiting to run
wpt / perf-fmt (push) Blocked by required conditions
zig-test / zig build dev (push) Waiting to run
zig-test / zig test (push) Waiting to run
zig-test / perf-fmt (push) Blocked by required conditions
Make the the short git SHA available within the program
2025-02-26 14:10:24 +01:00
Karl Seguin
68fc87bc01 Add Set-Cookie parsing 2025-02-26 21:00:43 +08:00
Karl Seguin
d0ba06c44b Add git_commit to build and build-dev target
Add "version" command to cli.
2025-02-26 20:44:44 +08:00
Karl Seguin
d501cbf765 Make the the short git SHA available within the program 2025-02-26 20:44:44 +08:00
Pierre Tachoire
488c7e6c27 Merge pull request #447 from lightpanda-io/mem-regression
Some checks are pending
e2e-test / zig build release (push) Waiting to run
e2e-test / puppeteer (push) Blocked by required conditions
wpt / web platform tests (push) Waiting to run
wpt / perf-fmt (push) Blocked by required conditions
zig-test / zig build dev (push) Waiting to run
zig-test / zig test (push) Waiting to run
zig-test / perf-fmt (push) Blocked by required conditions
ci: increase the max memory value to detect regression
2025-02-26 11:38:54 +01:00
Pierre Tachoire
155559c2c4 ci: increase the max memory value to detect regression 2025-02-26 10:55:19 +01:00
Pierre Tachoire
a22e1bc5e5 Merge pull request #442 from karlseguin/cli_commands
Some checks are pending
e2e-test / zig build release (push) Waiting to run
e2e-test / puppeteer (push) Blocked by required conditions
wpt / web platform tests (push) Waiting to run
wpt / perf-fmt (push) Blocked by required conditions
zig-test / zig build dev (push) Waiting to run
zig-test / zig test (push) Waiting to run
zig-test / perf-fmt (push) Blocked by required conditions
Add explicit commands to binary
2025-02-25 09:17:45 +01:00
Karl Seguin
9519d3f7ce use an arena for the args 2025-02-22 20:25:01 +08:00
Pierre Tachoire
3f23e07c02 Merge pull request #443 from karlseguin/logging
Some checks failed
e2e-test / zig build release (push) Has been cancelled
wpt / web platform tests (push) Has been cancelled
zig-test / zig build dev (push) Has been cancelled
zig-test / zig test (push) Has been cancelled
e2e-test / puppeteer (push) Has been cancelled
wpt / perf-fmt (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled
Add a structured logger
2025-02-22 12:28:12 +01:00
Pierre Tachoire
6c75177edc Merge pull request #444 from karlseguin/id
Add an id generator
2025-02-22 12:25:54 +01:00
Karl Seguin
85df280447 When explicit mode (serve/fetch/help) isn't given, infer it from the options 2025-02-22 13:54:05 +08:00
Karl Seguin
734cf243f6 update workflow to launch lightpanda in serve mode 2025-02-22 12:40:47 +08:00
Karl Seguin
d8f7817eeb Add explicit commands to binary
./lightpanda serve --host ...
./lightpanda fetch https://...

Makes it easier to communicate / document which command has which options.

Internally added a "usage" command for displaying the usage - removing the need
for error.NoError :|
2025-02-22 12:40:47 +08:00
Karl Seguin
94b6b2636a Add an id generator
Create UUID v4.

Create prefixed ids. To support more of the CDP protocol, we need to remove the
hard-coded IDs (session, browser context, frame, loader, ...) and be able to
dynamically create them, i.e. creating a new BrowserContextId when
Target.createBrowserContext is called.

var frame_id = id.Incremental(u16, "FRM"){};
frame_id.next() == "FRM-1"
frame_id.next() == "FRM-2"

Generation is allocation-free (the returned string is only valid until the
next call to next()). This is not thread safe, each CDP instance will have its
own generator (for each id it needs to generate).

The generated IDs are different than what Chrome uses, i.e.
BROWSERSESSIONID597D9875C664CAC0. I looked at various drivers and none have
any expectations beyond a string. Shorter IDs will be more efficient. Also, the
ID can cheeply be converted to and from an integer, allowing for lookups via
AutoHashMap(u16) instead of StringHashMap.
2025-02-22 09:11:40 +08:00
Karl Seguin
1036f7580f Add a structured logger
In debug mode, it has a more user-friendly output:

level | the log messge | ms since last message | key=value key=value

In release mode, it logs using logfmt, which is supported by most log
ingestion frameworks.

Not being used anywhere right now, keeping this PR small with no impact on
existing code.
2025-02-22 09:10:40 +08:00
Pierre Tachoire
908febb363 Merge pull request #441 from karlseguin/cdp_tests
Some checks are pending
e2e-test / zig build release (push) Waiting to run
e2e-test / puppeteer (push) Blocked by required conditions
wpt / web platform tests (push) Waiting to run
wpt / perf-fmt (push) Blocked by required conditions
zig-test / zig build dev (push) Waiting to run
zig-test / zig test (push) Waiting to run
zig-test / perf-fmt (push) Blocked by required conditions
Turn CDP into a generic so that mocks can be injected for testing
2025-02-21 17:49:47 +01:00
Pierre Tachoire
aefd091b44 Merge pull request #440 from karlseguin/managed_completions
Ensure completions are executed on the currently connected client
2025-02-21 17:39:22 +01:00
Karl Seguin
99fb82e244 Turn CDP into a generic so that mocks can be injected for testing
ADD CDP testing helpers (mock Browser, Session, Page and Client). These are
placeholders until tests are added which use them.

Added a couple CDP tests.
2025-02-21 13:17:35 +08:00
Karl Seguin
756d6620cc Ensure completions are executed on the currently connected client
For the time being, given that we only allow 1 client at a time, I took a
shortcut to implement this. The server has an incrementing "current_client_id"
which is part of every completion. On completion callback, we just check if
its client_id is still equal to the server's current_client_id.
2025-02-21 09:35:51 +08:00