microsoft/playwright

[BUG] Permission Denied Error when accessing cross-origin-isolated iframe in Firefox browser

Xewdy444 opened this issue ยท 12 comments

Context

Playwright Version: 1.31.1
Operating System: Windows 10
Python version: 3.11.0
Browser: Firefox

Code Snippet

from playwright.sync_api import sync_playwright

with sync_playwright() as playwright:
    browser = playwright.firefox.launch()
    page = browser.new_page()
    page.goto("https://forum.cfcybernews.eu/", wait_until="networkidle")
    page.locator("#challenge-spinner").wait_for(state="hidden")

    iframe_element = page.query_selector(
        'iframe[allow="cross-origin-isolated; fullscreen; autoplay"]'
    )

    iframe_element.content_frame()

Describe the bug

When attempting to access the content frame of an iframe with the allow="cross-origin-isolated" attribute set, Playwright fails with the following error message:

playwright._impl._api_types.Error: Protocol error (Page.describeNode): error in channel "content::11/14/2": exception while running method "describeNode" in namespace "page": Permission denied to access property "docShell" on cross-origin object _describeNode@chrome://juggler/content/content/PageAgent.js:440:47
_onMessage@chrome://juggler/content/SimpleChannel.js:194:37
bindToActor/actor.receiveMessage@chrome://juggler/content/SimpleChannel.js:53:44
 _onMessage@chrome://juggler/content/SimpleChannel.js:178:24
bindToActor/actor.receiveMessage@chrome://juggler/content/SimpleChannel.js:53:44

Additionally, the iframe element with the allow="cross-origin-isolated" attribute was not present in the page.frames list, even though it was present in the page. This behavior was observed only with the Firefox browser, while the same code worked as expected with the Chromium and WebKit browsers.

Expected behavior

The content frame of the iframe with the allow="cross-origin-isolated" attribute should be accessible using the content_frame() method of the ElementHandle object.

Steps to reproduce

Launch a Firefox browser instance using Playwright.
Navigate to a webpage that contains an iframe with the allow="cross-origin-isolated" attribute set.
Select the iframe using the query_selector() method of the Page object.
Attempt to access the content frame of the iframe using the content_frame() method of the ElementHandle object.

same issue, but when i change to headless=False, it works.

Same issue for python and set headless to False not working ,either T_T

Same issue with java and headless=false here.
Would this be solved soon?

Same issue with python 3.11 and playwright 1.38 and Firefox browser.
It is a major blocker for us.
Do you have some estimation when are you going to fix this? or maybe you can provide some workarround?
@mxschmitt

Any news here ?
It would be really helpful.

This issue seems to affect Playwright 1.26.x+. As a hacky solution, I've found that if you provide an older binary manually, you can still interact with OOPIF in later versions of Playwright. However, as the docs mention, you cannot just give a public release version of Firefox as Playwright patches the browser for it to work.

Note the below explanation is relevant to python-playwright but can probably be adapted (not that it should be).

Say you install Playwright 1.26.0, the manifest notes the browser version is 104.0 and revision is 1350. So if you look in the ms-playwright cache, you'll see a firefox-1350 directory. Find the binary within and give it at initialization in newer Playwright (tested with 1.40.0 here):

from playwright.async_api import async_playwright

playwright = await async_playwright().start()
browser = await playwright.firefox.launch(
    # MacOS cache path.
    executable_path='/Users/yourusername/Library/Caches/ms-playwright/firefox-1350/firefox/Nightly.app/Contents/MacOS/firefox',
)

However, note that this alone will given an error:

playwright._impl._errors.Error: Protocol error (Browser.enable): ERROR: failed to call method 'Browser.enable' with parameters {
  "attachToDefaultContext": false,
  "userPrefs": []
}
Found property "<root>.userPrefs" - [] which is not described in this scheme

It seems that the way user prefs were loaded or patched has changed. You can simply disable this by commenting this out in the server js. Open site-packages/playwright/driver/package/lib/server/firefox/ffBrowser.js and comment out the passing of userPrefs in FFBrowser.connect like so:

const promises = [browser.session.send('Browser.enable', {
      attachToDefaultContext: !!options.persistent,
      // userPrefs: Object.entries(firefoxUserPrefs).map(([name, value]) => ({
      //   name,
      //   value
      // }))
    }), browser._initVersion()];

Edit: You can also enable passing of user preferences by copying the logic from site-packages/playwright/driver/package/lib/server/firefox/firefox.js, too.

// With require blocks.
var _fs = _interopRequireDefault(require("fs"));

// Patch Firefox._defaultArgs method.
_defaultArgs(options, isPersistent, userDataDir) {
    // After "if (args.find...".
    const firefoxUserPrefs = isPersistent ? undefined : { ...kBandaidFirefoxUserPrefs,
      ...options.firefoxUserPrefs
    };
    if (firefoxUserPrefs) {
      const lines = [];
      for (const [name, value] of Object.entries(firefoxUserPrefs)) lines.push(`user_pref(${JSON.stringify(name)}, ${JSON.stringify(value)});`);
      _fs.default.writeFileSync(_path.default.join(userDataDir, 'user.js'), lines.join('\n'));
    }
    //...
}

// At end of file.
const kBandaidFirefoxUserPrefs = {
  'network.cookie.cookieBehavior': 4
};

After that, the browser launches and interactions within the iframe are successful!

Note that this is not well-tested, and absolutely not a long-term solution. It works for what I'm doing within an OOPIF but who knows what sort of undesirable behaviour this could lead to.

TL;DR: Can use the last OOPIF compatible Playwright-patched version of Firefox (v104 in python-playwright 1.26.0) with later versions of Playwright (tested with python-playwright 1.40.0), at the cost of losing Firefox preferences.

playwright: Protocol error (Page.describeNode): error in channel "content::9/12/2": exception while running method "describeNode" in namespace "page": Permission denied to access property "docShell" on cross-origin object _describeNode@chrome://juggler/content/content/PageAgent.js:416:62
_onMessageInternal@chrome://juggler/content/SimpleChannel.js:237:37
_onMessage@chrome://juggler/content/SimpleChannel.js:194:12
bindToActor/actor.receiveMessage@chrome://juggler/content/SimpleChannel.js:39:44

Any news here ?

Still error

*** playwright._impl._api_types.Error: Protocol error (Page.describeNode): error in channel "content::12/15/14": exception while running method "describeNode" in namespace "page": Permission denied to access property "docShell" on cross-origin object _describeNode@chrome://juggler/content/content/PageAgent.js:417:47
_onMessageInternal@chrome://juggler/content/SimpleChannel.js:222:37
_onMessage@chrome://juggler/content/SimpleChannel.js:191:12
bindToActor/actor.receiveMessage@chrome://juggler/content/SimpleChannel.js:54:44
 _onMessageInternal@chrome://juggler/content/SimpleChannel.js:206:24
_onMessage@chrome://juggler/content/SimpleChannel.js:191:12
bindToActor/actor.receiveMessage@chrome://juggler/content/SimpleChannel.js:54:44

Still have the same error. When you plan to add OOPIF's Firefox support?

Bumping this.

up this

This line just doesn't work cross-origin, because cross-origin frames don't have a docShell in the embedder process (it lives in the frame's process):

const browsingContextGroup = frame.docShell().browsingContext.group;

However it could be replaced by something like frame._browsingContext.group (probably exposing _browsingContext properly).