forked from WebKit/WebKit
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Partition Blob Registry by the top-level main document origin
https://bugs.webkit.org/show_bug.cgi?id=260035 rdar://problem/113705298 Reviewed by Alex Christensen and Sihui Liu. Public blob URLs are only accessible from same-origin dcuments, but access is not restricted by the top-level origin. This means that Blob URLs can be used as a cross-origin tracking mechanism within iframes. In this patch we partition public blob URLs within the Blob Registry by top-level origin. This partitioning is controlled by a feature flag that is disabled by default. I took a few approaches at solving this. The most difficult challenge was finding a solution that allowed retrieving BlobData using a public blob URL from WKWebView APIs. In that case, the relevant top document may not be obvious, or may not exist. As a result, the design of this partitioning is more like access control rather than adding another key into the hashmap. Two alternative designs I considered include creating a second hashmap that is keyed by <URL, SecurityOriginData> and we lookup the BlobData in that map if we have a SecurityOriginData, otherwise we use the unpartitioned map. Or, we create a new map from URL -> SecurityOriginData where we can lookup the associated top origin SecurityOriginData if we don't already know it. However, both of these options are more complex than the chosen implementation, and neither of them seemed safer. This change also enforces a noopener policy on new windows when the top origin of the opener is cross-origin with the blob's security origin. This is a mitigation that was discussed in the blob URL storage partitioning issue [0] with cross-engine support, and that seemed reasonable to me. [0] w3c/FileAPI#153 * LayoutTests/TestExpectations: * LayoutTests/http/tests/local/blob/download-blob-from-iframe-expected.txt: Added. * LayoutTests/http/tests/local/blob/download-blob-from-iframe.html: Added. * LayoutTests/http/tests/local/blob/navigate-blob-expected.txt: Added. * LayoutTests/http/tests/local/blob/navigate-blob.html: Added. * LayoutTests/http/tests/local/blob/resources/broadcast-channel-proxy.html: Added. * LayoutTests/http/tests/local/blob/resources/iframe-creating-or-downloading-blob.html: Added. * LayoutTests/http/tests/local/blob/resources/iframe-for-creating-and-navigating-to-blob.html: Added. * LayoutTests/http/tests/local/blob/resources/main-frame-with-iframe-creating-or-navigating-to-blob.html: Added. * LayoutTests/http/tests/local/blob/resources/main-frame-with-iframe-downloading-blob.html: Added. * LayoutTests/http/tests/security/blob-null-url-location-origin-expected.txt: * LayoutTests/http/tests/security/blob-null-url-location-origin.html: * LayoutTests/http/tests/security/cross-origin-blob-transfer-expected.txt: Added. * LayoutTests/http/tests/security/cross-origin-blob-transfer.html: Added. * LayoutTests/http/tests/security/resources/iframe-cross-origin-blob-transfer.html: Added. * LayoutTests/http/tests/security/top-level-unique-origin2.https.html: * LayoutTests/platform/gtk-wk2/http/tests/local/blob/download-blob-from-iframe-expected.txt: Added. * LayoutTests/platform/mac-wk1/TestExpectations: * Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml: * Source/WebCore/fileapi/BlobURL.cpp: (WebCore::BlobURL::isInternalURL): * Source/WebCore/fileapi/BlobURL.h: * Source/WebCore/fileapi/ThreadableBlobRegistry.cpp: (WebCore::ThreadableBlobRegistry::registerInternalFileBlobURL): (WebCore::ThreadableBlobRegistry::registerInternalBlobURL): (WebCore::ThreadableBlobRegistry::registerInternalBlobURLOptionallyFileBacked): (WebCore::ThreadableBlobRegistry::registerInternalBlobURLForSlice): (WebCore::isInternalBlobURL): Deleted. * Source/WebCore/loader/FrameLoader.cpp: (WebCore::FrameLoader::loadURL): (WebCore::FrameLoader::loadPostRequest): (WebCore::createWindow): * Source/WebCore/platform/network/BlobRegistryImpl.cpp: (WebCore::BlobRegistryImpl::registerBlobURLOptionallyFileBacked): (WebCore::BlobRegistryImpl::unregisterBlobURL): (WebCore::BlobRegistryImpl::getBlobDataFromURL const): (WebCore::BlobRegistryImpl::addBlobData): (WebCore::BlobRegistryImpl::registerBlobURLHandle): (WebCore::BlobRegistryImpl::unregisterBlobURLHandle): * Source/WebCore/platform/network/BlobRegistryImpl.h: Canonical link: https://commits.webkit.org/267172@main
- Loading branch information
Showing
25 changed files
with
787 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
60 changes: 60 additions & 0 deletions
60
LayoutTests/http/tests/local/blob/download-blob-from-iframe-expected.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
Download started. | ||
Downloading URL with suggested filename "testBlobFileName.html" | ||
Download completed. | ||
Download started. | ||
Download failed. | ||
Failed: WebKitBlobResource, code=1, description=The operation couldn’t be completed. (WebKitBlobResource error 1.) | ||
Download started. | ||
Download failed. | ||
Failed: WebKitBlobResource, code=1, description=The operation couldn’t be completed. (WebKitBlobResource error 1.) | ||
Download started. | ||
Download failed. | ||
Failed: WebKitBlobResource, code=1, description=The operation couldn’t be completed. (WebKitBlobResource error 1.) | ||
Download started. | ||
Download failed. | ||
Failed: WebKitBlobResource, code=1, description=The operation couldn’t be completed. (WebKitBlobResource error 1.) | ||
Download started. | ||
Download failed. | ||
Failed: WebKitBlobResource, code=1, description=The operation couldn’t be completed. (WebKitBlobResource error 1.) | ||
Download started. | ||
Download failed. | ||
Failed: WebKitBlobResource, code=1, description=The operation couldn’t be completed. (WebKitBlobResource error 1.) | ||
Download started. | ||
Downloading URL with suggested filename "testBlobFileName.html" | ||
Download completed. | ||
PASS successfullyParsed is true | ||
|
||
TEST COMPLETE | ||
Opening https://localhost:8443 as main frame with iframe origin https://localhost:8443, creating blob | ||
PASS Opened window | ||
PASS iframe: created blob | ||
Opening https://localhost:8443 as main frame with iframe origin https://localhost:8443, downloading blob | ||
PASS Opened window | ||
PASS iframe: downloading blob | ||
Opening http://localhost:8000 as main frame with iframe origin https://localhost:8443, downloading blob | ||
PASS Opened window | ||
PASS iframe: downloading blob | ||
Opening http://127.0.0.1:8000 as main frame with iframe origin https://localhost:8443, downloading blob | ||
PASS Opened window | ||
PASS iframe: downloading blob | ||
Opening https://127.0.0.1:8443 as main frame with iframe origin https://localhost:8443, downloading blob | ||
PASS Opened window | ||
PASS iframe: downloading blob | ||
Opening https://127.0.0.1:8443 as main frame with iframe origin https://localhost:8443, creating blob | ||
PASS Opened window | ||
PASS iframe: created blob | ||
Opening https://localhost:8443 as main frame with iframe origin https://localhost:8443, downloading blob | ||
PASS Opened window | ||
PASS iframe: downloading blob | ||
Opening http://localhost:8000 as main frame with iframe origin https://localhost:8443, downloading blob | ||
PASS Opened window | ||
PASS iframe: downloading blob | ||
Opening http://127.0.0.1:8000 as main frame with iframe origin https://localhost:8443, downloading blob | ||
PASS Opened window | ||
PASS iframe: downloading blob | ||
Opening https://127.0.0.1:8443 as main frame with iframe origin https://localhost:8443, downloading blob | ||
PASS Opened window | ||
PASS iframe: downloading blob | ||
|
||
PASS Test for creating blob in iframe and then downloading to it in same-origin iframe and same-origin, same-site, and cross-site main frames. | ||
|
103 changes: 103 additions & 0 deletions
103
LayoutTests/http/tests/local/blob/download-blob-from-iframe.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"><!-- webkit-test-runner [ BlobRegistryTopOriginPartitioningEnabled=true ] --> | ||
<html> | ||
<head> | ||
<script src="../../../../resources/testharness.js"></script> | ||
<script src="../../../../resources/testharnessreport.js"></script> | ||
<script src="../../../../resources/js-test-pre.js"></script> | ||
</head> | ||
<body> | ||
<p id="description"></p> | ||
<div id="console"></div> | ||
<script> | ||
var test = async_test("Test for creating blob in iframe and then downloading to it in same-origin iframe and same-origin, same-site, and cross-site main frames."); | ||
|
||
if (window.testRunner) | ||
testRunner.setShouldLogDownloadCallbacks(true); | ||
|
||
let blobURL = ""; | ||
let timeoutId; | ||
let handle; | ||
let shouldDownloadSameOriginBlob = true; | ||
let shouldDownloadSameSiteBlob = true; | ||
let shouldDownloadCrossSiteBlob = true; | ||
let shouldDownloadSecondCrossSiteBlob = true; | ||
let shouldCreateCrossSiteBlob = true; | ||
|
||
function openBlobCreatingFrame(origin) | ||
{ | ||
debug(`Opening ${origin} as main frame with iframe origin https://localhost:8443, creating blob`); | ||
handle = open(`${origin}/local/blob/resources/main-frame-with-iframe-downloading-blob.html`, "test-main-frame-create-blob"); | ||
assert_true(!!handle, `Opening ${origin} for blob creation failed`); | ||
timeoutId = setTimeout(() => window.postMessage({ "status": "donefail", "message": `Opening ${origin} timed out.` }, '*'), 2000); | ||
} | ||
|
||
function openBlobDownloadingFrame(origin) | ||
{ | ||
debug(`Opening ${origin} as main frame with iframe origin https://localhost:8443, downloading blob`); | ||
handle = open(`${origin}/local/blob/resources/main-frame-with-iframe-downloading-blob.html?url=${blobURL}`, "test-main-frame-download-blob"); | ||
assert_true(!!handle, `Opening ${origin} main frame for downloading blob failed`); | ||
timeoutId = setTimeout(() => window.postMessage({ "status": "donefail", "message": `Opening ${origin} timed out.` }, '*'), 2000); | ||
} | ||
|
||
window.onload = () => { | ||
// Load main frame from localhost, iframe is loaded from localhost, blob is partitioned as https://localhost:8443 under https://localhost:8443. Blob is accessible from https://localhost:8443. | ||
openBlobCreatingFrame(`https://localhost:8443`); | ||
} | ||
|
||
window.addEventListener("message", (e) => { | ||
if (timeoutId) { | ||
clearTimeout(timeoutId); | ||
timeoutId = undefined; | ||
handle = undefined; | ||
} else if (handle == e.source) { | ||
// If the timeout callback was already called, then don't handle this message, it's too late. | ||
return; | ||
} | ||
|
||
if (e.data.status) { | ||
if (e.data.status == "pass" || e.data.status == "done") | ||
testPassed(`${e.data.message}`); | ||
else if (e.data.status == "fail" || e.data.status == "donefail") | ||
testFailed(`${e.data.message}`); | ||
else | ||
testFailed(`Unexpected status: ${e.data.status}`); | ||
if (e.data.status == "done" || e.data.status == "donefail") { | ||
if (shouldDownloadSameOriginBlob) { | ||
assert_true(e.data.url && e.data.url !== "", `Blob URL is not defined in same-origin download`); | ||
blobURL = encodeURI(e.data.url); | ||
openBlobDownloadingFrame(`https://localhost:8443`); | ||
shouldDownloadSameOriginBlob = false; | ||
} else if (shouldDownloadSameSiteBlob) { | ||
assert_true(e.data.url && e.data.url !== "", `Blob URL is not defined in same-site download`); | ||
blobURL = encodeURI(e.data.url); | ||
openBlobDownloadingFrame(`http://localhost:8000`); | ||
shouldDownloadSameSiteBlob = false; | ||
} else if (shouldDownloadCrossSiteBlob) { | ||
assert_true(e.data.url && e.data.url !== "", `Blob URL is not defined in first cross-site download`); | ||
blobURL = encodeURI(e.data.url); | ||
openBlobDownloadingFrame(`http://127.0.0.1:8000`); | ||
shouldDownloadCrossSiteBlob = false; | ||
} else if (shouldDownloadSecondCrossSiteBlob) { | ||
assert_true(e.data.url && e.data.url !== "", `Blob URL is not defined in second cross-site download`); | ||
blobURL = encodeURI(e.data.url); | ||
openBlobDownloadingFrame(`https://127.0.0.1:8443`); | ||
shouldDownloadSecondCrossSiteBlob = false; | ||
} else if (shouldCreateCrossSiteBlob) { | ||
// Load main frame from localhost, iframe is loaded from localhost, blob is partitioned as https://localhost:8443 under https://127.0.0.1:8443. Blob is not accessible from https://localhost:8443. | ||
openBlobCreatingFrame(`https://127.0.0.1:8443`); | ||
shouldCreateCrossSiteBlob = false; | ||
shouldDownloadSameOriginBlob = true; | ||
shouldDownloadSameSiteBlob = true; | ||
shouldDownloadCrossSiteBlob = true; | ||
shouldDownloadSecondCrossSiteBlob = true; | ||
} else { | ||
test.done(); | ||
} | ||
} | ||
} else | ||
testFailed(`Unexpected message: ${e.data}`); | ||
}); | ||
</script> | ||
<script src="../../../../resources/js-test-post.js"></script> | ||
</body> | ||
</html> |
48 changes: 48 additions & 0 deletions
48
LayoutTests/http/tests/local/blob/navigate-blob-expected.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
PASS successfullyParsed is true | ||
|
||
TEST COMPLETE | ||
Opening https://localhost:8443 as main frame with iframe origin https://localhost:8443 creating blob | ||
PASS iframe: created blob | ||
PASS main frame: Fetched Blob | ||
PASS main frame: open() succeeded. Received message from blob: successfully navigated, have opener: true | ||
Opening http://127.0.0.1:8000 as main frame with iframe origin https://localhost:8443 | ||
FAIL iframe: Fetching blob failed: Load failed | ||
FAIL iframe: WindowProxy handle is null (probably opened blob url with noopener) | ||
FAIL iframe: Could not open blob url, timed out | ||
FAIL main frame: Fetching blob failed: Load failed | ||
FAIL main frame: Could not open blob url, timed out | ||
Opening http://localhost:8000 as main frame with iframe origin https://localhost:8443 | ||
FAIL iframe: Fetching blob failed: Load failed | ||
FAIL iframe: WindowProxy handle is null (probably opened blob url with noopener) | ||
FAIL iframe: Could not open blob url, timed out | ||
FAIL main frame: Fetching blob failed: Load failed | ||
FAIL main frame: Could not open blob url, timed out | ||
Opening https://localhost:8443 as main frame with iframe origin https://localhost:8443 | ||
PASS iframe: Fetched Blob | ||
PASS iframe: open() succeeded. Received message from blob: successfully navigated, have opener: true | ||
PASS main frame: Fetched Blob | ||
PASS main frame: open() succeeded. Received message from blob: successfully navigated, have opener: true | ||
Opening http://127.0.0.1:8000 as main frame with iframe origin https://localhost:8443 creating blob | ||
PASS iframe: created blob | ||
FAIL main frame: Fetching blob failed: Load failed | ||
FAIL main frame: Could not open blob url, timed out | ||
Opening https://localhost:8443 as main frame with iframe origin https://localhost:8443 | ||
FAIL iframe: Fetching blob failed: Load failed | ||
FAIL iframe: Could not open blob url, timed out | ||
FAIL main frame: Fetching blob failed: Load failed | ||
FAIL main frame: Could not open blob url, timed out | ||
Opening http://localhost:8000 as main frame with iframe origin https://localhost:8443 | ||
FAIL iframe: Fetching blob failed: Load failed | ||
FAIL iframe: WindowProxy handle is null (probably opened blob url with noopener) | ||
FAIL iframe: Could not open blob url, timed out | ||
FAIL main frame: Fetching blob failed: Load failed | ||
FAIL main frame: Could not open blob url, timed out | ||
Opening http://127.0.0.1:8000 as main frame with iframe origin https://localhost:8443 | ||
PASS iframe: Fetched Blob | ||
FAIL iframe: WindowProxy handle is null (probably opened blob url with noopener) | ||
PASS iframe: open() succeeded. Received message from blob: successfully navigated, have opener: false | ||
FAIL main frame: Fetching blob failed: Load failed | ||
FAIL main frame: Could not open blob url, timed out | ||
|
||
PASS Test for creating blob in iframe and then navigating to it from same-origin iframe and cross-origin main frames. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"><!-- webkit-test-runner [ BlobRegistryTopOriginPartitioningEnabled=true BroadcastChannelOriginPartitioningEnabled=true ] --> | ||
<html> | ||
<head> | ||
<script src="../../../../resources/testharness.js"></script> | ||
<script src="../../../../resources/testharnessreport.js"></script> | ||
<script src="../../../../resources/js-test-pre.js"></script> | ||
</head> | ||
<body> | ||
<p id="description"></p> | ||
<div id="console"></div> | ||
<script> | ||
var test = async_test("Test for creating blob in iframe and then navigating to it from same-origin iframe and cross-origin main frames."); | ||
|
||
let blobURL = ""; | ||
let step = 0; | ||
let timeoutId; | ||
let handle; | ||
|
||
function openBlobCreatingFrame(origin, step) | ||
{ | ||
debug(`Opening ${origin} as main frame with iframe origin https://localhost:8443 creating blob`); | ||
handle = open(`${origin}/local/blob/resources/main-frame-with-iframe-creating-or-navigating-to-blob.html`, "test-main-frame-create-blob"); | ||
assert_true(!!handle, `Opening ${origin} main frame for blob creation in step ${step} failed`); | ||
timeoutId = setTimeout(() => window.postMessage({ "status": "donefail", "message": `step ${step} timed out.` }, '*'), 2000); | ||
} | ||
|
||
function handleMessage(e, nextOrigin) | ||
{ | ||
let shouldStep = false; | ||
if (e.data.status) { | ||
if (e.data.status == "pass" || e.data.status == "done") | ||
testPassed(`${e.data.message}`); | ||
else if (e.data.status == "fail" || e.data.status == "donefail") | ||
testFailed(`${e.data.message}`); | ||
else | ||
testfailed(`Unexpected status: ${e.data.status}`); | ||
if (e.data.status == "done" || e.data.status == "donefail") { | ||
assert_true(e.data.url && e.data.url !== "", `Blob URL is not defined in step ${step}, status: ${e.data.status}, message: ${e.data.message}`); | ||
blobURL = encodeURI(e.data.url); | ||
shouldStep = true; | ||
} | ||
} else { | ||
testFailed(`Unexpected message: ${e.data.message}`); | ||
shouldStep = true; | ||
} | ||
|
||
if (shouldStep) { | ||
if (handle) { | ||
handle.close(); | ||
handle = undefined; | ||
} | ||
step = step + 1; | ||
if (step == 4) { | ||
// Load main frame from 127.0.0.1, iframe is loaded from localhost, create blob that is partitioned as https://localhost:8443 under http://127.0.0.1:8000. | ||
openBlobCreatingFrame(nextOrigin, step); | ||
} else if (!nextOrigin) | ||
return; | ||
else { | ||
debug(`Opening ${nextOrigin} as main frame with iframe origin https://localhost:8443`); | ||
assert_true(blobURL && blobURL !== ""); | ||
handle = open(`${nextOrigin}/local/blob/resources/main-frame-with-iframe-creating-or-navigating-to-blob.html?url=${blobURL}`, "test-main-frame"); | ||
assert_true(!!handle, `Opening ${origin} main frame for blob navigation in step ${step} failed`); | ||
timeoutId = setTimeout(() => window.postMessage({ "status": "donefail", "message": `step ${step} timed out.`, "url": blobURL }, '*'), 2000); | ||
} | ||
} | ||
} | ||
|
||
window.onload = () => { | ||
// Load main frame from localhost, iframe is loaded from localhost, blob is partitioned as https://localhost:8443 under https://localhost:8443. Blob is accessible from https://localhost:8443. | ||
openBlobCreatingFrame(`https://localhost:8443`, step); | ||
} | ||
|
||
window.addEventListener("message", (e) => { | ||
if (timeoutId) { | ||
clearTimeout(timeoutId); | ||
timeoutId = undefined; | ||
handle = undefined; | ||
} else if (handle == e.source) { | ||
// If the timeout callback was already called, then don't handle this message, it's too late. | ||
return; | ||
} | ||
|
||
if (step == 0) { | ||
// On next step, load main frame from 127.0.0.1, iframe is loaded from localhost. Blob is not accessible from http://127.0.0.1:8000 iframe. | ||
handleMessage(e, "http://127.0.0.1:8000"); | ||
} else if (step == 1) { | ||
// On next step, load main frame from http://localhost, iframe is loaded from https://localhost. Blob is not accessible from http://localhost:8000 iframe. | ||
handleMessage(e, "http://localhost:8000"); | ||
} else if (step == 2) { | ||
// On next step, load main frame from https://localhost, iframe is loaded from https://localhost. Blob is accessible from https://localhost:8443 iframe. | ||
handleMessage(e, "https://localhost:8443"); | ||
} else if (step == 3) { | ||
// On next step, load main frame from http://127.0.0.1, iframe is loaded from https://localhost. Blob is not accessible from https://localhost:8443 iframe. | ||
handleMessage(e, "http://127.0.0.1:8000"); | ||
} else if (step == 4) { | ||
// On next step, load main frame from https://localhost, iframe is loaded from https://localhost. Blob is not accessible from https://localhost iframe. | ||
handleMessage(e, "https://localhost:8443"); | ||
} else if (step == 5) { | ||
// On next step, load main frame from http://localhost, iframe is loaded from https://localhost. Blob is not accessible from http://localhost:8000 iframe. | ||
handleMessage(e, "http://localhost:8000"); | ||
} else if (step == 6) { | ||
// On next step, load main frame from http://127.0.0.1, iframe is loaded from https://localhost. Blob is accessible from http://localhost:8000 iframe. | ||
handleMessage(e, "http://127.0.0.1:8000"); | ||
} else if (step == 7) { | ||
handleMessage(e); | ||
if (step == 8 && e.data.status) { | ||
if (e.data.status == "done" || e.data.status == "donefail") | ||
test.done(); | ||
} | ||
} else { | ||
testFailed(`Unexpected step: ${step}, ${e.data.message}`); | ||
} | ||
}); | ||
</script> | ||
<script src="../../../../resources/js-test-post.js"></script> | ||
</body> | ||
</html> |
12 changes: 12 additions & 0 deletions
12
LayoutTests/http/tests/local/blob/resources/broadcast-channel-proxy.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> | ||
<html> | ||
<head> | ||
<script> | ||
if (window.opener) { | ||
const bc = new BroadcastChannel("blob-bc"); | ||
bc.onmessage = (e) => window.opener.postMessage(e.data, '*'); | ||
} | ||
</script> | ||
</head> | ||
</html> | ||
|
28 changes: 28 additions & 0 deletions
28
LayoutTests/http/tests/local/blob/resources/iframe-creating-or-downloading-blob.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> | ||
<html> | ||
<body> | ||
<script> | ||
|
||
function download(blobURL) | ||
{ | ||
let downloadAnchor = document.createElement("a"); | ||
downloadAnchor.href = blobURL; | ||
downloadAnchor.download = "testBlobFileName"; | ||
document.body.appendChild(downloadAnchor); | ||
downloadAnchor.click(); | ||
} | ||
|
||
if (window.location.search) { | ||
let params = new URLSearchParams(document.location.search); | ||
let blobURL = decodeURI(params.get("url")); | ||
|
||
download(blobURL); | ||
window.top.postMessage({ "from": "iframe", "status": "done", "message": "iframe: downloading blob", "url": blobURL }, "*");; | ||
} else { | ||
const documentContent = 'Downloaded!'; | ||
let blob = new Blob([documentContent], { "type" : "text/html" }); | ||
window.top.postMessage({ "from": "iframe", "status": "done", "message": "iframe: created blob", "url": URL.createObjectURL(blob) }, "*");; | ||
} | ||
</script> | ||
</body> | ||
</html> |
Oops, something went wrong.