Open Bug 2055817 Opened 3 months ago Updated 3 months ago

Unexpected realms created during navigation, Chrome creates transient about:blank lazily

Categories

(Core :: DOM: Navigation, defect, P3)

defect

Tracking

()

People

(Reporter: hbenl, Unassigned)

References

()

Details

(Keywords: perf)

I've noticed that Firefox creates more javascript realms during navigations than I would expect and wanted to file this for discussion.
I used the following wdspec "test" to see the corresponding events during the initial navigations of a page containing a cross-origin iframe:

import asyncio
import json
import pytest

pytestmark = pytest.mark.asyncio

CAPTURED_EVENTS = [
    "browsingContext.contextCreated",
    "browsingContext.navigationStarted",
    "browsingContext.navigationCommitted",
    "script.realmCreated",
    "script.realmDestroyed"
]

async def test_capture_events(
    bidi_session,
    subscribe_events,
    inline,
    iframe,
    top_context,
):
    captured = []

    async def on_event(method, data):
        captured.append({"method": method, "data": data})

    remove_listeners = [
        bidi_session.add_event_listener(event, on_event) for event in CAPTURED_EVENTS
    ]

    await subscribe_events(events=CAPTURED_EVENTS)

    page_url = inline(iframe("<div>hello</div>", domain="alt"))
    await bidi_session.browsing_context.navigate(
        context=top_context["context"], url=page_url, wait="complete"
    )

    await asyncio.sleep(0.5)

    for remove in remove_listeners:
        remove()

    print("\n===== captured events =====")
    for entry in captured:
        print(json.dumps(entry, default=str))
    print(f"===== {len(captured)} events =====")

This is what I see with Firefox:

1  {"method": "browsingContext.contextCreated", "data": {"context": "a14f2b3d-cd23-4e78-bbdb-c667b77db06d", ...}}
2  {"method": "script.realmCreated", "data": {"realm": "974ab1bd-9a24-43c0-902a-512530e2bd48", "origin": "null", "context": "a14f2b3d-cd23-4e78-bbdb-c667b77db06d", ...}}
3  {"method": "browsingContext.navigationStarted", "data": {"context": "a14f2b3d-cd23-4e78-bbdb-c667b77db06d", "url": "https://web-platform.test:8443/...", ...}}
4  {"method": "script.realmDestroyed", "data": {"realm": "974ab1bd-9a24-43c0-902a-512530e2bd48"}}
5  {"method": "script.realmCreated", "data": {"realm": "d49051e5-df6e-4c41-9d2c-312d611ef422", "origin": "null", "context": "a14f2b3d-cd23-4e78-bbdb-c667b77db06d", ...}}
6  {"method": "script.realmDestroyed", "data": {"realm": "d49051e5-df6e-4c41-9d2c-312d611ef422"}}
7  {"method": "script.realmCreated", "data": {"realm": "7bc15886-972f-4583-a4aa-580d5c510085", "origin": "https://web-platform.test:8443", "context": "a14f2b3d-cd23-4e78-bbdb-c667b77db06d", ...}}
8  {"method": "browsingContext.navigationCommitted", "data": {"context": "a14f2b3d-cd23-4e78-bbdb-c667b77db06d", "url": "https://web-platform.test:8443/...", ...}}
9  {"method": "browsingContext.contextCreated", "data": {"context": "19327352833", "parent": "a14f2b3d-cd23-4e78-bbdb-c667b77db06d", ...}}
10 {"method": "script.realmCreated", "data": {"realm": "45f92f52-ff0a-4a79-bc71-fb5fbdbc80f8", "origin": "https://web-platform.test:8443", "context": "19327352833", ...}}
11 {"method": "browsingContext.navigationStarted", "data": {"context": "19327352833", "url": "https://not-web-platform.test:8443/...", ...}}
12 {"method": "script.realmDestroyed", "data": {"realm": "45f92f52-ff0a-4a79-bc71-fb5fbdbc80f8"}}
13 {"method": "script.realmCreated", "data": {"realm": "afef10c8-f84d-4fae-b4cd-cfd016641a5a", "origin": "null", "context": "19327352833", ...}}
14 {"method": "script.realmDestroyed", "data": {"realm": "afef10c8-f84d-4fae-b4cd-cfd016641a5a"}}
15 {"method": "script.realmCreated", "data": {"realm": "f6a804f6-7f9e-4df9-b890-09c51f8f0e6d", "origin": "https://not-web-platform.test:8443", "context": "19327352833", ...}}
16 {"method": "browsingContext.navigationCommitted", "data": {"context": "19327352833", "url": "https://not-web-platform.test:8443/...", ...}}

So 3 realms are created for the top frame:

  • one with a null origin (2) before the navigation started (3) that is destroyed (4) after it started
  • another one with a null origin (5) after the first one was destroyed that is also immediately destroyed (6)
  • one with a web-platform.test origin (7) before the navigation is committed (8)

And 3 realms are created for the iframe:

  • one with a web-platform.test origin (10) before the navigation started (11) that is destroyed (12) after it started
  • one with a null origin (13) after the first one was destroyed that is also immediately destroyed (14)
  • one with a not-web-platform.test origin (15) before the navigation is committed (16)

And this is the output for Chrome:

1  {"method": "browsingContext.contextCreated", "data": {"context": "AAB5418CA969F1DBFB3D6B7D2B400289", ...}}
2  {"method": "script.realmCreated", "data": {"context": "AAB5418CA969F1DBFB3D6B7D2B400289", "origin": "null", "realm": "-6492386953078869370.-4245529794647379188", ...}}
3  {"method": "browsingContext.navigationStarted", "data": {"context": "AAB5418CA969F1DBFB3D6B7D2B400289", "url": "https://web-platform.test:8443/...", ...}}
4  {"method": "script.realmDestroyed", "data": {"realm": "-6492386953078869370.-4245529794647379188"}}
5  {"method": "browsingContext.navigationCommitted", "data": {"context": "AAB5418CA969F1DBFB3D6B7D2B400289", "url": "https://web-platform.test:8443/", ...}}
6  {"method": "script.realmCreated", "data": {"context": "AAB5418CA969F1DBFB3D6B7D2B400289", "origin": "https://web-platform.test:8443", "realm": "-4278116245310742500.-8365422557588411416", ...}}
7  {"method": "browsingContext.contextCreated", "data": {"context": "EC38335457D37CE444D0C496F481E1AB", "parent": "AAB5418CA969F1DBFB3D6B7D2B400289", ...}}
8  {"method": "browsingContext.navigationStarted", "data": {"context": "EC38335457D37CE444D0C496F481E1AB", "url": "https://not-web-platform.test:8443/", ...}}
9  {"method": "browsingContext.navigationCommitted", "data": {"context": "EC38335457D37CE444D0C496F481E1AB", "url": "https://not-web-platform.test:8443/...", ...}}
10 {"method": "script.realmCreated", "data": {"context": "EC38335457D37CE444D0C496F481E1AB", "origin": "https://not-web-platform.test:8443", "realm": "1109801154655824700.1230005629383590687", ...}}

2 realms are created for the top frame:

  • one with a null origin (2) before the navigation started (3) that is destroyed (4) after it started
  • one with a web-platform.test origin (6) after the navigation is committed (5)

1 realm is created for the iframe:

  • with a not-web-platform.test origin (10) after the navigation is committed (9)

Note how Chrome doesn't create any realms for the iframe before its navigation. For the top frame it doesn't know in advance that it will be navigated so it needs to create a null origin realm at first (but not a second one during the navigation like Firefox).

Profile containing BiDi markers: https://share.firefox.dev/44Kzn98

Vincent, are these short-lived javascript realms expected? Are there plans to remove them (possibly improving performance)?

Flags: needinfo?(vhilla)

Changing the test to do

    iframe_url = inline("<div>hello</div>", domain="alt")
    page_url = inline(
        f"<iframe src='{iframe_url}'></iframe>"
        f"<script>document.querySelector('iframe').contentWindow</script>"
    )

Causes Chrome to have an additional realm.

1  {"method": "browsingContext.contextCreated", "data": {"context": "AAA0A38CD6444EBCF5E35D9E594AD166", ...}}
2  {"method": "script.realmCreated", "data": {"context": "AAA0A38CD6444EBCF5E35D9E594AD166", "origin": "null", "realm": "2471961748984939551.7253893889736993845", ...}}
3  {"method": "browsingContext.navigationStarted", "data": {"context": "AAA0A38CD6444EBCF5E35D9E594AD166", ...}}
4  {"method": "script.realmDestroyed", "data": {"realm": "2471961748984939551.7253893889736993845"}}
5  {"method": "browsingContext.navigationCommitted", "data": {"context": "AAA0A38CD6444EBCF5E35D9E594AD166", ...}}
6  {"method": "script.realmCreated", "data": {"context": "AAA0A38CD6444EBCF5E35D9E594AD166", "origin": "https://web-platform.test:8443", ...}}
7  {"method": "browsingContext.contextCreated", "data": {"context": "0F9E14F6C2C37E8900B5419980A3AD5D", "parent": "AAA0A38CD6444EBCF5E35D9E594AD166", ...}}
8  {"method": "browsingContext.navigationStarted", "data": {"context": "0F9E14F6C2C37E8900B5419980A3AD5D", ...}}
9  {"method": "script.realmCreated", "data": {"context": "0F9E14F6C2C37E8900B5419980A3AD5D", "origin": "https://web-platform.test:8443", ...}}
10 {"method": "browsingContext.navigationCommitted", "data": {"context": "0F9E14F6C2C37E8900B5419980A3AD5D", ...}}
11 {"method": "script.realmDestroyed", "data": {"realm": "-5062409688364969126.2133376247048350284"}}
12 {"method": "script.realmCreated", "data": {"context": "0F9E14F6C2C37E8900B5419980A3AD5D", "origin": "https://not-web-platform.test:8443", ...}}

Considering the spec: The iframe HTML element post-connection steps are to create a new child navigable and process the iframe attributes. The former does create a new browsing context and document which creates a new Document with is initial about:blank being true. The later will navigate the iframe and cause a second realm creation.

It seems, Chrome deviates from spec in a not web-observable way to avoid work here by creating the initial about:blank lazily. That is unfortunate because bug 543435 just changed our about:blank to be eager and not lazy created.


My guess is we have these three realms for top level: one null before navigation started, one about:blank after the process switch for web-platform.test and a third one after the navigation. Here's a pernosco trace, I haven't yet looked for the specific realms / browsing contexts.

https://pernos.co/debug/a7fGP4xVNTdG8pzr60J4MA/index.html

Flags: needinfo?(vhilla)
See Also: → sync-about-blank

Thanks for the bug, it's a good catch. I think it fits better in the DOM component given it's not really webdrivers fault.

I can see this being useful for performance, though the cost of an unnecessary about:blank is likely small compared to fetching resources over the internet.

The effort here is probably large, we'd have to reintroduce a nsDocShell::EnsureDocumentViewer() as it existed before bug 543435 that creates the about:blank lazily when some GetDocument vs GetExtantDocument is called. A big part of bug 543435 was changing how things are inherited to that new document, i.e. they are now passed through at docshell construction via nsIOpenWindowInfo rather than looking back to the creator at document creation.

Severity: -- → S3
Component: WebDriver BiDi → DOM: Navigation
Keywords: perf
Priority: -- → P3
Product: Remote Protocol → Core
Summary: Unexpected realms created during navigation → Unexpected realms created during navigation, Chrome creates transient about:blank lazily
You need to log in before you can comment on or make changes to this bug.