Skip to content

Commit

Permalink
Support uuid-in-package: URLs in Subresource WebBundles
Browse files Browse the repository at this point in the history
This allows subresource and subframe loading from WebBundles with
uuid-in-package: scheme URLs. We have been using urn:uuid: for this
purpose, but since urn: scheme can be handled by custom protocol
handler, there was a possibility of conflict.

Explainer change: WICG/webpackage#677

The semantics is the same as currently we have for urn:uuid.

Temporarily, we support both uuid-in-package: and urn:uuid: resources so
that this will not break currently running origin trial. We will remove
the urn:uuid: support before shipping this feature.

Bug: 1257045
Change-Id: Ie86d3a3207fdaa6a4b0b4337cac2f1c6457e132b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3104651
Reviewed-by: Daniel Cheng <[email protected]>
Reviewed-by: Alex Moshchuk <[email protected]>
Reviewed-by: Takashi Toyoshima <[email protected]>
Reviewed-by: Hayato Ito <[email protected]>
Commit-Queue: Kunihiko Sakamoto <[email protected]>
Cr-Commit-Position: refs/heads/main@{#931822}
  • Loading branch information
irori authored and pull[bot] committed Mar 15, 2022
1 parent f223ef2 commit 1512224
Show file tree
Hide file tree
Showing 7 changed files with 218 additions and 72 deletions.
5 changes: 5 additions & 0 deletions web-bundle/resources/generate-test-wbns.sh
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,8 @@ gen-bundle \
-version b2 \
-har cross-origin-no-cors.har \
-o wbn/no-cors/cross-origin-b2.wbn

gen-bundle \
-version b2 \
-har uuid-in-package.har \
-o wbn/uuid-in-package.wbn
44 changes: 44 additions & 0 deletions web-bundle/resources/uuid-in-package.har
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"log": {
"entries": [
{
"request": {
"method": "GET",
"url": "uuid-in-package:020111b3-437a-4c5c-ae07-adb6bbffb720",
"headers": []
},
"response": {
"status": 200,
"headers": [
{
"name": "Content-type",
"value": "application/javascript"
}
],
"content": {
"text": "window.report_result('OK');"
}
}
},
{
"request": {
"method": "GET",
"url": "uuid-in-package:429fcc4e-0696-4bad-b099-ee9175f023ae",
"headers": []
},
"response": {
"status": 200,
"headers": [
{
"name": "Content-type",
"value": "text/html"
}
],
"content": {
"text": "<script>\nwindow.addEventListener('message', (e) =>{e.source.postMessage(eval(e.data), e.origin);});\n</script>"
}
}
}
]
}
}
Binary file added web-bundle/resources/wbn/uuid-in-package.wbn
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
content="
script-src
https://web-platform.test:8444/web-bundle/resources/wbn/urn-uuid.wbn
https://web-platform.test:8444/web-bundle/resources/wbn/uuid-in-package.wbn
https://web-platform.test:8444/resources/testharness.js
https://web-platform.test:8444/resources/testharnessreport.js
'unsafe-inline';
img-src
https://web-platform.test:8444/web-bundle/resources/wbn/pass.png;
frame-src
https://web-platform.test:8444/web-bundle/resources/wbn/urn-uuid.wbn"
https://web-platform.test:8444/web-bundle/resources/wbn/urn-uuid.wbn
https://web-platform.test:8444/web-bundle/resources/wbn/uuid-in-package.wbn"
>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
Expand All @@ -25,6 +27,9 @@
<link rel="webbundle" href="../resources/wbn/urn-uuid.wbn"
resources="urn:uuid:020111b3-437a-4c5c-ae07-adb6bbffb720
urn:uuid:429fcc4e-0696-4bad-b099-ee9175f023ae" />
<link rel="webbundle" href="../resources/wbn/uuid-in-package.wbn"
resources="uuid-in-package:020111b3-437a-4c5c-ae07-adb6bbffb720
uuid-in-package:429fcc4e-0696-4bad-b099-ee9175f023ae" />
<script>
promise_test(() => {
return new Promise((resolve, reject) => {
Expand All @@ -49,6 +54,18 @@
}, 'URL matching of script-src CSP should be done based on the bundle URL ' +
'when the subresource URL is urn:uuid URL.');

promise_test(async () => {
const result = await new Promise((resolve) => {
// This function will be called from the script.
window.report_result = resolve;
const script = document.createElement('script');
script.src = 'uuid-in-package:020111b3-437a-4c5c-ae07-adb6bbffb720';
document.body.appendChild(script);
});
assert_equals(result, 'OK');
}, 'URL matching of script-src CSP should be done based on the bundle URL ' +
'when the subresource URL is uuid-in-package: URL.');

promise_test(async () => {
const frame_url = 'urn:uuid:429fcc4e-0696-4bad-b099-ee9175f023ae';
const iframe = document.createElement('iframe');
Expand All @@ -64,6 +81,21 @@
}, 'URL matching of frame-src CSP should be done based on the bundle URL ' +
'when the frame URL is urn:uuid URL.');

promise_test(async () => {
const frame_url = 'uuid-in-package:429fcc4e-0696-4bad-b099-ee9175f023ae';
const iframe = document.createElement('iframe');
iframe.src = frame_url;
const load_promise = new Promise((resolve) => {
iframe.addEventListener('load', resolve);
});
document.body.appendChild(iframe);
await load_promise;
assert_equals(
await evalInIframe(iframe, 'location.href'),
frame_url);
}, 'URL matching of frame-src CSP should be done based on the bundle URL ' +
'when the frame URL is uuid-in-package: URL.');

async function evalInIframe(iframe, code) {
const message_promise = new Promise((resolve) => {
window.addEventListener(
Expand Down
119 changes: 70 additions & 49 deletions web-bundle/subresource-loading/link-csp-blocked.https.tentative.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,12 @@
<link rel="webbundle" href="../resources/wbn/urn-uuid.wbn"
resources="urn:uuid:020111b3-437a-4c5c-ae07-adb6bbffb720
urn:uuid:429fcc4e-0696-4bad-b099-ee9175f023ae" />
<link rel="webbundle" href="../resources/wbn/uuid-in-package.wbn"
resources="uuid-in-package:020111b3-437a-4c5c-ae07-adb6bbffb720
uuid-in-package:429fcc4e-0696-4bad-b099-ee9175f023ae" />
<script>
const bundle_url = 'https://web-platform.test:8444/web-bundle/resources/wbn/urn-uuid.wbn';
const urn_bundle_url = 'https://web-platform.test:8444/web-bundle/resources/wbn/urn-uuid.wbn';
const uuid_bundle_url = 'https://web-platform.test:8444/web-bundle/resources/wbn/uuid-in-package.wbn';

function expect_violation() {
return new Promise(resolve => {
Expand All @@ -51,10 +55,10 @@
}

function sortReportsByEffectiveDirective(reports) {
reports.sort(function(report1, report2) {
return report1.body.effectiveDirective.localeCompare(
report2.body.effectiveDirective);
});
reports.sort((report1, report2) =>
report1.body.effectiveDirective.localeCompare(report2.body.effectiveDirective)
|| report1.body.blockedURL.localeCompare(report2.body.blockedURL)
);
}

promise_test(async () => {
Expand All @@ -71,47 +75,60 @@
}, 'URL matching of CSP should be done based on the subresource URL, ' +
'not on the bundle URL, when the subresource URL is HTTPS URL.');

promise_test(async () => {
const urn_uuid = 'urn:uuid:020111b3-437a-4c5c-ae07-adb6bbffb720';
const p = expect_violation();
const script = document.createElement('script');
script.src = urn_uuid;
document.body.appendChild(script);
const e = await p;
// Currently Chromium is reporting the bundle URL.
// TODO(crbug.com/1208659): Consider deeper integration with CSP for
// providing the both URLs.
assert_equals(e.blockedURI, bundle_url);
assert_equals(e.violatedDirective, 'script-src-elem');
}, 'URL matching of script-src CSP should be done based on the bundle URL ' +
'when the subresource URL is urn:uuid URL.');
const testCases = [
{
prefix: 'urn:uuid:',
bundle_url: urn_bundle_url
},
{
prefix: 'uuid-in-package:',
bundle_url: uuid_bundle_url
}
];
for (const params of testCases) {

promise_test(async () => {
const urn_uuid = 'urn:uuid:429fcc4e-0696-4bad-b099-ee9175f023ae';
const p = expect_violation();
const iframe = document.createElement('iframe');
iframe.src = urn_uuid;
const load_promise = new Promise(resolve => {
iframe.addEventListener('load', resolve);
});
document.body.appendChild(iframe);
const e = await p;
// Currently Chromium is reporting the bundle URL.
// TODO(crbug.com/1208659): Consider deeper integration with CSP for
// providing the both URLs.
assert_equals(e.blockedURI, bundle_url);
assert_equals(e.violatedDirective, 'frame-src');
promise_test(async () => {
const urn_uuid = params.prefix + '020111b3-437a-4c5c-ae07-adb6bbffb720';
const p = expect_violation();
const script = document.createElement('script');
script.src = urn_uuid;
document.body.appendChild(script);
const e = await p;
// Currently Chromium is reporting the bundle URL.
// TODO(crbug.com/1208659): Consider deeper integration with CSP for
// providing the both URLs.
assert_equals(e.blockedURI, params.bundle_url);
assert_equals(e.violatedDirective, 'script-src-elem');
}, 'URL matching of script-src CSP should be done based on the bundle URL ' +
`when the subresource URL is ${params.prefix} URL.`);

// Make sure that the blocked iframe load is finished.
await load_promise;
promise_test(async () => {
const urn_uuid = params.prefix + '429fcc4e-0696-4bad-b099-ee9175f023ae';
const p = expect_violation();
const iframe = document.createElement('iframe');
iframe.src = urn_uuid;
const load_promise = new Promise(resolve => {
iframe.addEventListener('load', resolve);
});
document.body.appendChild(iframe);
const e = await p;
// Currently Chromium is reporting the bundle URL.
// TODO(crbug.com/1208659): Consider deeper integration with CSP for
// providing the both URLs.
assert_equals(e.blockedURI, params.bundle_url);
assert_equals(e.violatedDirective, 'frame-src');

// The blocked iframe is cross-origin. So accessing
// iframe.contentWindow.location should throw a SecurityError.
assert_throws_dom(
"SecurityError",
() => { iframe.contentWindow.location.href; });
}, 'URL matching of frame-src CSP should be done based on the bundle URL ' +
'when the frame URL is urn:uuid URL.');
// Make sure that the blocked iframe load is finished.
await load_promise;

// The blocked iframe is cross-origin. So accessing
// iframe.contentWindow.location should throw a SecurityError.
assert_throws_dom(
"SecurityError",
() => { iframe.contentWindow.location.href; });
}, 'URL matching of frame-src CSP should be done based on the bundle URL ' +
`when the frame URL is ${params.prefix} URL.`);
}

promise_test(async () => {
const retrieve_report_url =
Expand All @@ -120,18 +137,22 @@
const reports = await (await fetch(retrieve_report_url)).json();
sortReportsByEffectiveDirective(reports);

assert_equals(reports.length, 3, "Report count.");
assert_equals(reports.length, 5, "Report count.");

assert_equals(reports[0].body.blockedURL, bundle_url);
assert_equals(reports[0].body.blockedURL, urn_bundle_url);
assert_equals(reports[0].body.effectiveDirective, 'frame-src');
assert_equals(reports[1].body.blockedURL, uuid_bundle_url);
assert_equals(reports[1].body.effectiveDirective, 'frame-src');

assert_equals(
reports[1].body.blockedURL,
reports[2].body.blockedURL,
'https://web-platform.test:8444/web-bundle/resources/wbn/fail.png');
assert_equals(reports[1].body.effectiveDirective, 'img-src',);
assert_equals(reports[2].body.effectiveDirective, 'img-src',);

assert_equals(reports[2].body.blockedURL, bundle_url);
assert_equals(reports[2].body.effectiveDirective, 'script-src-elem');
assert_equals(reports[3].body.blockedURL, urn_bundle_url);
assert_equals(reports[3].body.effectiveDirective, 'script-src-elem');
assert_equals(reports[4].body.blockedURL, uuid_bundle_url);
assert_equals(reports[4].body.effectiveDirective, 'script-src-elem');
}, 'Check the CSP violation reports.');
</script>
</body>
Original file line number Diff line number Diff line change
@@ -1,20 +1,32 @@
const frame_url = 'urn:uuid:429fcc4e-0696-4bad-b099-ee9175f023ae';

promise_test(async (t) => {
const iframe = await createWebBundleElementAndIframe(t);
// The urn:uuid URL iframe is cross-origin. So accessing
// iframe.contentWindow.location should throws a SecurityError.
const bundle_url = '../resources/wbn/urn-uuid.wbn';
const frame_url = 'urn:uuid:429fcc4e-0696-4bad-b099-ee9175f023ae';
const iframe = await createWebBundleElementAndIframe(t, bundle_url, frame_url);
// The iframe is cross-origin. So accessing iframe.contentWindow.location
// should throw a SecurityError.
assert_throws_dom(
"SecurityError",
() => { iframe.contentWindow.location.href; });
}, 'The urn:uuid URL iframe must be cross-origin.');

urn_uuid_iframe_test(
promise_test(async (t) => {
const bundle_url = '../resources/wbn/uuid-in-package.wbn';
const frame_url = 'uuid-in-package:429fcc4e-0696-4bad-b099-ee9175f023ae';
const iframe = await createWebBundleElementAndIframe(t, bundle_url, frame_url);
// The iframe is cross-origin. So accessing iframe.contentWindow.location
// should throw a SecurityError.
assert_throws_dom(
"SecurityError",
() => { iframe.contentWindow.location.href; });
}, 'The uuid-in-package: URL iframe must be cross-origin.');

uuid_iframe_test(
'location.href',
frame_url,
'location.href in urn uuid iframe.');
['urn:uuid:429fcc4e-0696-4bad-b099-ee9175f023ae',
'uuid-in-package:429fcc4e-0696-4bad-b099-ee9175f023ae'],
'location.href in opaque-origin iframe.');

urn_uuid_iframe_test(
uuid_iframe_test(
'(' + (() => {
try {
let result = window.localStorage;
Expand All @@ -26,7 +38,7 @@ urn_uuid_iframe_test(
'SecurityError',
'Accesing window.localStorage should throw a SecurityError.');

urn_uuid_iframe_test(
uuid_iframe_test(
'(' + (() => {
try {
let result = window.sessionStorage;
Expand All @@ -38,7 +50,7 @@ urn_uuid_iframe_test(
'SecurityError',
'Accesing window.sessionStorage should throw a SecurityError.');

urn_uuid_iframe_test(
uuid_iframe_test(
'(' + (() => {
try {
let result = document.cookie;
Expand All @@ -50,7 +62,7 @@ urn_uuid_iframe_test(
'SecurityError',
'Accesing document.cookie should throw a SecurityError.');

urn_uuid_iframe_test(
uuid_iframe_test(
'(' + (() => {
try {
let request = window.indexedDB.open("db");
Expand All @@ -62,22 +74,32 @@ urn_uuid_iframe_test(
'SecurityError',
'Opening an indexedDB should throw a SecurityError.');

urn_uuid_iframe_test(
uuid_iframe_test(
'window.caches === undefined',
true,
'window.caches should be undefined.');

function urn_uuid_iframe_test(code, expected, name) {
function uuid_iframe_test(code, expected, name) {
if (!Array.isArray(expected)) {
expected = [expected, expected];
}
promise_test(async (t) => {
const bundle_url = '../resources/wbn/urn-uuid.wbn';
const frame_url = 'urn:uuid:429fcc4e-0696-4bad-b099-ee9175f023ae';
const iframe = await createWebBundleElementAndIframe(t, bundle_url, frame_url);
assert_equals(await evalInIframe(iframe, code), expected[0]);
}, name + '(urn:uuid)');

promise_test(async (t) => {
const iframe = await createWebBundleElementAndIframe(t);
assert_equals(await evalInIframe(iframe, code), expected);
}, name);
const bundle_url = '../resources/wbn/uuid-in-package.wbn';
const frame_url = 'uuid-in-package:429fcc4e-0696-4bad-b099-ee9175f023ae';
const iframe = await createWebBundleElementAndIframe(t, bundle_url, frame_url);
assert_equals(await evalInIframe(iframe, code), expected[1]);
}, name + 'uuid-in-package');
}

async function createWebBundleElementAndIframe(t) {
const element = createWebBundleElement(
'../resources/wbn/urn-uuid.wbn',
[frame_url]);
async function createWebBundleElementAndIframe(t, bundle_url, frame_url) {
const element = createWebBundleElement(bundle_url, [frame_url]);
document.body.appendChild(element);
const iframe = document.createElement('iframe');
t.add_cleanup(() => {
Expand Down
Loading

0 comments on commit 1512224

Please sign in to comment.