Improve support for sandboxed iframes (#1704)
* Add more tests * Improve handling of errors from setupFrame * Passively handle errors when contentDocument is null
This commit is contained in:
parent
ce340d7a19
commit
41c0132c59
@ -228,20 +228,31 @@ class Popup extends EventDispatcher {
|
|||||||
_inject() {
|
_inject() {
|
||||||
let injectPromise = this._injectPromise;
|
let injectPromise = this._injectPromise;
|
||||||
if (injectPromise === null) {
|
if (injectPromise === null) {
|
||||||
injectPromise = this._createInjectPromise();
|
injectPromise = this._injectInner1();
|
||||||
this._injectPromise = injectPromise;
|
this._injectPromise = injectPromise;
|
||||||
injectPromise.then(
|
injectPromise.then(
|
||||||
() => {
|
() => {
|
||||||
if (injectPromise !== this._injectPromise) { return; }
|
if (injectPromise !== this._injectPromise) { return; }
|
||||||
this._injectPromiseComplete = true;
|
this._injectPromiseComplete = true;
|
||||||
},
|
},
|
||||||
() => { this._resetFrame(); }
|
() => {}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return injectPromise;
|
return injectPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
async _createInjectPromise() {
|
async _injectInner1() {
|
||||||
|
try {
|
||||||
|
await this._injectInner2();
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
this._resetFrame();
|
||||||
|
if (e.source === this) { return false; } // Passive error
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async _injectInner2() {
|
||||||
if (this._options === null) {
|
if (this._options === null) {
|
||||||
throw new Error('Options not initialized');
|
throw new Error('Options not initialized');
|
||||||
}
|
}
|
||||||
@ -255,9 +266,16 @@ class Popup extends EventDispatcher {
|
|||||||
frame.removeAttribute('srcdoc');
|
frame.removeAttribute('srcdoc');
|
||||||
this._observeFullscreen(true);
|
this._observeFullscreen(true);
|
||||||
this._onFullscreenChanged();
|
this._onFullscreenChanged();
|
||||||
|
const {contentDocument} = frame;
|
||||||
|
if (contentDocument === null) {
|
||||||
|
// This can occur when running inside a sandboxed frame without "allow-same-origin"
|
||||||
|
const error = new Error('Popup not supoprted in this context');
|
||||||
|
error.source = this; // Used to detect a passive error which should be ignored
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
const url = chrome.runtime.getURL('/popup.html');
|
const url = chrome.runtime.getURL('/popup.html');
|
||||||
if (useSecurePopupFrameUrl) {
|
if (useSecurePopupFrameUrl) {
|
||||||
frame.contentDocument.location.href = url;
|
contentDocument.location.href = url;
|
||||||
} else {
|
} else {
|
||||||
frame.setAttribute('src', url);
|
frame.setAttribute('src', url);
|
||||||
}
|
}
|
||||||
@ -366,7 +384,8 @@ class Popup extends EventDispatcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async _show(elementRect, writingMode) {
|
async _show(elementRect, writingMode) {
|
||||||
await this._inject();
|
const injected = await this._inject();
|
||||||
|
if (!injected) { return; }
|
||||||
|
|
||||||
const optionsGeneral = this._options.general;
|
const optionsGeneral = this._options.general;
|
||||||
const {popupDisplayMode} = optionsGeneral;
|
const {popupDisplayMode} = optionsGeneral;
|
||||||
|
@ -156,7 +156,12 @@ class FrameClient {
|
|||||||
// Prevent unhandled rejections
|
// Prevent unhandled rejections
|
||||||
frameLoadedPromise.catch(() => {}); // NOP
|
frameLoadedPromise.catch(() => {}); // NOP
|
||||||
|
|
||||||
setupFrame(frame);
|
try {
|
||||||
|
setupFrame(frame);
|
||||||
|
} catch (e) {
|
||||||
|
cleanup();
|
||||||
|
reject(e);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,9 @@
|
|||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
|
}
|
||||||
|
.danger {
|
||||||
|
color: #c83c28;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<body>
|
<body>
|
||||||
@ -108,7 +111,20 @@
|
|||||||
|
|
||||||
<y-test>
|
<y-test>
|
||||||
<y-description><iframe> element with srcdoc.</y-description>
|
<y-description><iframe> element with srcdoc.</y-description>
|
||||||
<iframe id="iframe-with-srcdoc" allowfullscreen="true" class="container"></iframe>
|
<iframe allowfullscreen="true" class="iframe-with-srcdoc container"></iframe>
|
||||||
|
</y-test>
|
||||||
|
|
||||||
|
<y-test>
|
||||||
|
<y-description><iframe> element with srcdoc and <code>sandbox="allow-same-origin allow-scripts"</code>.</y-description>
|
||||||
|
<iframe allowfullscreen="true" class="iframe-with-srcdoc container" sandbox="allow-same-origin allow-scripts"></iframe>
|
||||||
|
</y-test>
|
||||||
|
|
||||||
|
<y-test>
|
||||||
|
<y-description>
|
||||||
|
<iframe> element with srcdoc and <code>sandbox="allow-scripts"</code>.<br>
|
||||||
|
<span class="danger">This element is expected to not work.</span>
|
||||||
|
</y-description>
|
||||||
|
<iframe allowfullscreen="true" class="iframe-with-srcdoc container" sandbox="allow-scripts"></iframe>
|
||||||
</y-test>
|
</y-test>
|
||||||
|
|
||||||
<y-test>
|
<y-test>
|
||||||
@ -180,9 +196,10 @@
|
|||||||
|
|
||||||
const iframeWithDataUrl = document.querySelector('#iframe-with-data-url');
|
const iframeWithDataUrl = document.querySelector('#iframe-with-data-url');
|
||||||
const iframeWithBlobUrl = document.querySelector('#iframe-with-blob-url');
|
const iframeWithBlobUrl = document.querySelector('#iframe-with-blob-url');
|
||||||
const iframeWithSrcdoc = document.querySelector('#iframe-with-srcdoc');
|
|
||||||
iframeWithBlobUrl.src = URL.createObjectURL(dataUrlToBlob(iframeWithDataUrl.src));
|
iframeWithBlobUrl.src = URL.createObjectURL(dataUrlToBlob(iframeWithDataUrl.src));
|
||||||
iframeWithSrcdoc.srcdoc = dataUrlToContent(iframeWithDataUrl.src).content;
|
for (const iframeWithSrcdoc of document.querySelectorAll('.iframe-with-srcdoc')) {
|
||||||
|
iframeWithSrcdoc.srcdoc = dataUrlToContent(iframeWithDataUrl.src).content;
|
||||||
|
}
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user