microsoft / playwright

Playwright is a framework for Web Testing and Automation. It allows testing Chromium, Firefox and WebKit with a single API.
https://playwright.dev
Apache License 2.0
66.78k stars 3.66k forks source link

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

Open Xewdy444 opened 1 year ago

Xewdy444 commented 1 year ago

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.

dreamhunter2333 commented 1 year ago

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

richmonde commented 1 year ago

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

ramsestom commented 1 year ago

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

VolodyaEsk commented 1 year ago

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

simonthemagico commented 1 year ago

Any news here ? It would be really helpful.

michaeleveringham commented 9 months ago

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.

Naist4869 commented 9 months ago
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 ?

meldonization commented 7 months ago

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
ZhezherP commented 7 months ago

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

FFace32 commented 6 months ago

Bumping this.

gmoreno90 commented 3 months ago

up this

emilio commented 3 months ago

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):

https://github.com/microsoft/playwright/blob/bff97b481092b7a5bbe199f359ad86c26d30e078/browser_patches/firefox/juggler/content/PageAgent.js#L411

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