Support a crossorigin= attribute for webundle subresource loading

There are several changes in this CL. Let me summarize at first.

The current behavior is:

- No support crossorigin= attribute
- request's mode is set to "cors" in default.
- request's creditial-mode is "omit"; UA never sends a credential.

This CL changes the behavior as follows:

- If crossorigin= attribute is not specified,
  - request's mode is set to "no-cors"
  - request's credential-mode is set to "include"
- If crossorigin= attribute is "anonymous" or empty (See [1] for details)
  - request's mode is set to "cors"
  - request's credential-mode is set to "same-origin"
- If crossorigin= attribute is "use-credential",
  - request's mode is set to "cors"
  - request's credential-mode is set to "include"

Note: In the current implementation, subresources can be loaded from a
cross-origin bundle which the server returns without a valid
"Access-Control-Allow-Origin" response header. That should be considered
as a bug. This Cl changes request's mode to no-cors correctly in
default.

Regarding tests,

A general behavior of a crossorigin attribute is well tested in existing
tests, such as fast/dom/HTMLLinkElement/link-crossOrigin.htm.

This CL tests only the effects of crossorign= attributes for a bundle
as follows:

1. Test for credentials:
   subresource-loading-credential.tentative.sub.html
2. Test for CORS behavior:
    subresource-loading-cors.tentative.html
3. Test for CORS behavior (error case):
   subresource-loading-cors-error.tentative.html

The existing test, subresource-loading-cross-origin.tentative.html is
rewritten and split into 2 and 3.

Due to https://crbug.com/1168449, the test 3 is marked as TIMEOUT.
This bug will be fixed as another CL.

[1]: https://html.spec.whatwg.org/multipage/#cors-settings-attribute

BUG=1149816, 1168449

Change-Id: I354e203a3a536bc829ef7ba6a97d4edd6a6340a0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2670486
Reviewed-by: Tsuyoshi Horo <horo@chromium.org>
Reviewed-by: Kinuko Yasuda <kinuko@chromium.org>
Reviewed-by: Kunihiko Sakamoto <ksakamoto@chromium.org>
Commit-Queue: Hayato Ito <hayato@chromium.org>
Cr-Commit-Position: refs/heads/master@{#853942}
diff --git a/web-bundle/resources/cross-origin-no-cors.har b/web-bundle/resources/cross-origin-no-cors.har
index 96d0b4e..983024b 100644
--- a/web-bundle/resources/cross-origin-no-cors.har
+++ b/web-bundle/resources/cross-origin-no-cors.har
@@ -4,7 +4,7 @@
       {
         "request": {
           "method": "GET",
-          "url": "https://web-platform.test:8444/web-bundle/resources/wbn/no-cors/resource.cors.json",
+          "url": "https://web-platform.test:8444/web-bundle/resources/wbn/no-cors/resource.cors.js",
           "headers": []
         },
         "response": {
@@ -12,7 +12,7 @@
           "headers": [
             {
               "name": "Content-type",
-              "value": "application/json"
+              "value": "text/javascript"
             },
             {
               "name": "Access-Control-Allow-Origin",
@@ -20,14 +20,14 @@
             }
           ],
           "content": {
-            "text": "{ cors: 1 }"
+            "text": "scriptLoaded('resource.cors.js');"
           }
         }
       },
       {
         "request": {
           "method": "GET",
-          "url": "https://web-platform.test:8444/web-bundle/resources/wbn/no-cors/resource.no-cors.json",
+          "url": "https://web-platform.test:8444/web-bundle/resources/wbn/no-cors/resource.no-cors.js",
           "headers": []
         },
         "response": {
@@ -35,11 +35,11 @@
           "headers": [
             {
               "name": "Content-type",
-              "value": "application/json"
+              "value": "text/javascript"
             }
           ],
           "content": {
-            "text": "{ no_cors: 1 }"
+            "text": "scriptLoaded('resource.no-cors.js');"
           }
         }
       }
diff --git a/web-bundle/resources/cross-origin.har b/web-bundle/resources/cross-origin.har
index 7435393..2197dea 100644
--- a/web-bundle/resources/cross-origin.har
+++ b/web-bundle/resources/cross-origin.har
@@ -4,7 +4,7 @@
       {
         "request": {
           "method": "GET",
-          "url": "https://web-platform.test:8444/web-bundle/resources/wbn/cors/resource.cors.json",
+          "url": "https://web-platform.test:8444/web-bundle/resources/wbn/cors/resource.cors.js",
           "headers": []
         },
         "response": {
@@ -12,7 +12,7 @@
           "headers": [
             {
               "name": "Content-type",
-              "value": "application/json"
+              "value": "text/javascript"
             },
             {
               "name": "Access-Control-Allow-Origin",
@@ -20,14 +20,14 @@
             }
           ],
           "content": {
-            "text": "{ cors: 1 }"
+            "text": "scriptLoaded('resource.cors.js');"
           }
         }
       },
       {
         "request": {
           "method": "GET",
-          "url": "https://web-platform.test:8444/web-bundle/resources/wbn/cors/resource.no-cors.json",
+          "url": "https://web-platform.test:8444/web-bundle/resources/wbn/cors/resource.no-cors.js",
           "headers": []
         },
         "response": {
@@ -35,11 +35,11 @@
           "headers": [
             {
               "name": "Content-type",
-              "value": "application/json"
+              "value": "text/javascript"
             }
           ],
           "content": {
-            "text": "{ no_cors: 1}"
+            "text": "scriptLoaded('resource.no-cors.js');"
           }
         }
       }
diff --git a/web-bundle/resources/generate-test-wbns.sh b/web-bundle/resources/generate-test-wbns.sh
index 5a205c9..36a8078 100755
--- a/web-bundle/resources/generate-test-wbns.sh
+++ b/web-bundle/resources/generate-test-wbns.sh
@@ -81,11 +81,11 @@
 gen-bundle \
   -version b1 \
   -har cross-origin.har \
-  -primaryURL $wpt_test_https_origin/web-bundle/resources/wbn/cors/resource.cors.json \
+  -primaryURL $wpt_test_https_origin/web-bundle/resources/wbn/cors/resource.cors.js \
   -o wbn/cors/cross-origin.wbn
 
 gen-bundle \
   -version b1 \
   -har cross-origin-no-cors.har \
-  -primaryURL $wpt_test_https_origin/web-bundle/resources/wbn/no-cors/resource.cors.json \
+  -primaryURL $wpt_test_https_origin/web-bundle/resources/wbn/no-cors/resource.cors.js \
   -o wbn/no-cors/cross-origin.wbn
diff --git a/web-bundle/resources/test-helpers.js b/web-bundle/resources/test-helpers.js
new file mode 100644
index 0000000..d4f420e
--- /dev/null
+++ b/web-bundle/resources/test-helpers.js
@@ -0,0 +1,73 @@
+// Helper functions used in web-bundle tests.
+
+function addElementAndWaitForLoad(element) {
+  return new Promise((resolve, reject) => {
+    element.onload = resolve;
+    element.onerror = reject;
+    document.body.appendChild(element);
+  });
+}
+
+function addElementAndWaitForError(element) {
+  return new Promise((resolve, reject) => {
+    element.onload = reject;
+    element.onerror = resolve;
+    document.body.appendChild(element);
+  });
+}
+
+function fetchAndWaitForReject(url) {
+  return new Promise((resolve, reject) => {
+    fetch(url)
+      .then(() => {
+        reject();
+      })
+      .catch(() => {
+        resolve();
+      });
+  });
+}
+
+function addLinkAndWaitForLoad(url, resources, crossorigin) {
+  return new Promise((resolve, reject) => {
+    const link = document.createElement("link");
+    link.rel = "webbundle";
+    link.href = url;
+    if (crossorigin) {
+      link.crossOrigin = crossorigin;
+    }
+    for (const resource of resources) {
+      link.resources.add(resource);
+    }
+    link.onload = () => resolve(link);
+    link.onerror = () => reject(link);
+    document.body.appendChild(link);
+  });
+}
+
+function addLinkAndWaitForError(url, resources, crossorigin) {
+  return new Promise((resolve, reject) => {
+    const link = document.createElement("link");
+    link.rel = "webbundle";
+    link.href = url;
+    if (crossorigin) {
+      link.crossOrigin = crossorigin;
+    }
+    for (const resource of resources) {
+      link.resources.add(resource);
+    }
+    link.onload = () => reject(link);
+    link.onerror = () => resolve(link);
+    document.body.appendChild(link);
+  });
+}
+
+function addScriptAndWaitForError(url) {
+  return new Promise((resolve, reject) => {
+    const script = document.createElement("script");
+    script.src = url;
+    script.onload = reject;
+    script.onerror = resolve;
+    document.body.appendChild(script);
+  });
+}
diff --git a/web-bundle/resources/wbn/cors/cross-origin.wbn b/web-bundle/resources/wbn/cors/cross-origin.wbn
index bed9bf2..8043ba7 100644
--- a/web-bundle/resources/wbn/cors/cross-origin.wbn
+++ b/web-bundle/resources/wbn/cors/cross-origin.wbn
Binary files differ
diff --git a/web-bundle/resources/wbn/no-cors/cross-origin.wbn b/web-bundle/resources/wbn/no-cors/cross-origin.wbn
index b2adba6..7004673 100644
--- a/web-bundle/resources/wbn/no-cors/cross-origin.wbn
+++ b/web-bundle/resources/wbn/no-cors/cross-origin.wbn
Binary files differ
diff --git a/web-bundle/subresource-loading/check-cookie-and-return-bundle.py b/web-bundle/subresource-loading/check-cookie-and-return-bundle.py
new file mode 100644
index 0000000..32765e8
--- /dev/null
+++ b/web-bundle/subresource-loading/check-cookie-and-return-bundle.py
@@ -0,0 +1,25 @@
+import os
+
+
+def main(request, response):
+    origin = request.headers.get(b"origin")
+
+    if origin is not None:
+        response.headers.set(b"Access-Control-Allow-Origin", origin)
+        response.headers.set(b"Access-Control-Allow-Methods", b"GET")
+        response.headers.set(b"Access-Control-Allow-Credentials", b"true")
+
+    headers = [
+        (b"Content-Type", b"application/webbundle"),
+        (b"X-Content-Type-Options", b"nosniff"),
+    ]
+
+    cookie = request.cookies.first(b"milk", None)
+    if (cookie is not None) and cookie.value == b"1":
+        with open(
+            os.path.join(os.path.dirname(__file__), "../resources/wbn/subresource.wbn"),
+            "rb",
+        ) as f:
+            return (200, headers, f.read())
+    else:
+        return (400, [], "")
diff --git a/web-bundle/subresource-loading/subresource-loading-cors-error.tentative.html b/web-bundle/subresource-loading/subresource-loading-cors-error.tentative.html
new file mode 100644
index 0000000..31ad66e
--- /dev/null
+++ b/web-bundle/subresource-loading/subresource-loading-cors-error.tentative.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<title>Cross origin WebBundle subresource loading (error case)</title>
+<link
+  rel="help"
+  href="https://github.com/WICG/webpackage/blob/master/explainers/subresource-loading.md"
+/>
+<link
+  rel="help"
+  href="https://html.spec.whatwg.org/multipage/#cors-settings-attribute"
+/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/test-helpers.js"></script>
+<body>
+  <!--
+       This wpt should run on an origin different from https://web-platform.test:8444/,
+       from where cross-orign WebBundles are served.
+
+       This test uses a cross-origin WebBundle,
+       https://web-platform.test:8444/web-bundle/resources/wbn/no-cors/cross-origin.wbn,
+       which is served *without* an Access-Control-Allow-Origin response header.
+
+       `cross-origin.wbn` includes two subresources:
+       a. `resource.cors.js`, which includes an Access-Control-Allow-Origin response header.
+       b. `resource.no-cors.js`, which doesn't include an Access-Control-Allow-Origin response header.
+  -->
+  <script>
+    promise_test(async () => {
+      const prefix =
+        "https://web-platform.test:8444/web-bundle/resources/wbn/no-cors/";
+      const resources = [
+        prefix + "resource.cors.js",
+        prefix + "resource.no-cors.js",
+      ];
+      for (const crossorigin_attribute_value of [
+        "anonymous",
+        "use-credential",
+      ]) {
+        const link = await addLinkAndWaitForError(
+          prefix + "cross-origin.wbn",
+          resources,
+          crossorigin_attribute_value
+        );
+
+        // A subresource in the bundle can not be used in any case.
+        for (const resource of resources) {
+          await fetchAndWaitForReject(resource);
+          await addScriptAndWaitForError(resource);
+        }
+        link.remove();
+      }
+    }, "Use CORS if crossorigin=anonymous or crossorigin=use-credential is specified. A cross origin bundle must not be loaded unless a server returns a valid Access-Control-Allow-Origin header.");
+  </script>
+</body>
diff --git a/web-bundle/subresource-loading/subresource-loading-cors.tentative.html b/web-bundle/subresource-loading/subresource-loading-cors.tentative.html
new file mode 100644
index 0000000..b1b2595
--- /dev/null
+++ b/web-bundle/subresource-loading/subresource-loading-cors.tentative.html
@@ -0,0 +1,110 @@
+<!DOCTYPE html>
+<title>Cross origin WebBundle subresource loading</title>
+<link
+  rel="help"
+  href="https://github.com/WICG/webpackage/blob/master/explainers/subresource-loading.md"
+/>
+<link
+  rel="help"
+  href="https://html.spec.whatwg.org/multipage/#cors-settings-attribute"
+/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/test-helpers.js"></script>
+<body>
+  <!--
+       This wpt should run on an origin different from https://web-platform.test:8444/,
+       from where cross-orign WebBundles are served.
+
+       This test uses the two cross-origin WebBundles:
+
+       1. https://web-platform.test:8444/web-bundle/resources/wbn/cors/cross-origin.wbn,
+          which is served with an Access-Control-Allow-Origin response header.
+       2. https://web-platform.test:8444/web-bundle/resources/wbn/no-cors/cross-origin.wbn,
+          which is served *without* an Access-Control-Allow-Origin response header.
+
+       Each `cross-origin.wbn` includes two subresources:
+       a. `resource.cors.json`, which includes an Access-Control-Allow-Origin response header.
+       b. `resource.no-cors.json`, which doesn't include an Access-Control-Allow-Origin response header.
+  -->
+  <script>
+    promise_test(async () => {
+      for (const prefix of [
+        "https://web-platform.test:8444/web-bundle/resources/wbn/cors/",
+        "https://web-platform.test:8444/web-bundle/resources/wbn/no-cors/",
+      ]) {
+        const resources = [
+          prefix + "resource.cors.js",
+          prefix + "resource.no-cors.js",
+        ];
+        const link = await addLinkAndWaitForLoad(
+          prefix + "cross-origin.wbn",
+          resources
+        );
+
+        // Can fetch a subresource which has a valid Access-Control-Allow-Origin response header.
+        const response = await fetch(prefix + "resource.cors.js");
+        assert_true(response.ok);
+        const text = await response.text();
+        assert_equals(text, "scriptLoaded('resource.cors.js');");
+
+        // Can not fetch a subresource which does NOT have a valid
+        // Access-Control-Allow-Origin response header.
+        await fetchAndWaitForReject(prefix + "resource.no-cors.js");
+
+        // Both subresource js can be loaded via a <script> element, which doesn't use cors.
+        for (const resource of resources) {
+          const scriptEvaluted = new Promise((resolve, reject) => {
+            window.scriptLoaded = resolve;
+          });
+          const script = document.createElement("script");
+          script.src = resource;
+          document.body.appendChild(script);
+          await scriptEvaluted;
+        }
+        link.remove();
+      }
+    }, "Use no-cors if crossorigin=attribute is not specified");
+
+    promise_test(async () => {
+      const prefix =
+        "https://web-platform.test:8444/web-bundle/resources/wbn/cors/";
+      const resources = [
+        prefix + "resource.cors.js",
+        prefix + "resource.no-cors.js",
+      ];
+      for (const crossorigin_attribute_value of [
+        "anonymous",
+        "use-credential",
+      ]) {
+        const link = await addLinkAndWaitForLoad(
+          prefix + "cross-origin.wbn",
+          resources,
+          crossorigin_attribute_value
+        );
+
+        // Can fetch a subresource which has a valid Access-Control-Allow-Origin response header.
+        const response = await fetch(prefix + "resource.cors.js");
+        assert_true(response.ok);
+        const text = await response.text();
+        assert_equals(text, "scriptLoaded('resource.cors.js');");
+
+        // Can not fetch a subresource which does NOT have a valid
+        // Access-Control-Allow-Origin response header.
+        await fetchAndWaitForReject(prefix + "resource.no-cors.js");
+
+        // Both subresource js can be loaded via a <script> element, which doesn't use cors.
+        for (const resource of resources) {
+          const scriptEvaluted = new Promise((resolve, reject) => {
+            window.scriptLoaded = resolve;
+          });
+          const script = document.createElement("script");
+          script.src = resource;
+          document.body.appendChild(script);
+          await scriptEvaluted;
+        }
+        link.remove();
+      }
+    }, "Use CORS if crossorigin=anonymous or crossorigin=use-credential is specified. A server should return a valid Access-Control-Allow-Origin header if a bundle is a cross origin bundle.");
+  </script>
+</body>
diff --git a/web-bundle/subresource-loading/subresource-loading-credential.tentative.sub.html b/web-bundle/subresource-loading/subresource-loading-credential.tentative.sub.html
new file mode 100644
index 0000000..d7d8e52
--- /dev/null
+++ b/web-bundle/subresource-loading/subresource-loading-credential.tentative.sub.html
@@ -0,0 +1,98 @@
+<!DOCTYPE html>
+<title>
+  crossorigin= attribute and credentials in WebBundle subresource loading
+</title>
+<link
+  rel="help"
+  href="https://github.com/WICG/webpackage/blob/master/explainers/subresource-loading.md"
+/>
+<link
+  rel="help"
+  href="https://html.spec.whatwg.org/multipage/#cors-settings-attribute"
+/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/test-helpers.js"></script>
+<body>
+  <script>
+    // In this wpt, we only test request's credential mode, which controls
+    // whether UA sends a credential or not.
+    // We assume that a <link> element fires a load event correctly if
+    // check-cookie-and-return-bundle.py returns a valid format webbundle. That
+    // happens only when UA sends a credential. We don't care of the contents of
+    // a bundle. That's out of scope of this wpt.
+
+    // See subresoruce-loading-cors{-error}.tentative.html, where we test subresource
+    // loading with crossorigin= attribute, in terms of request's mode (cors or no-cors).
+
+    document.cookie = "milk=1";
+
+    // Make sure to set a cookie for a cross-origin domain from where a cross
+    // origin bundle is served.
+    const setCookiePromise = fetch(
+      "http://{{domains[www2]}}:{{ports[http][0]}}/cookies/resources/set-cookie.py?name=milk&path=/web-bundle/subresource-loading/",
+      {
+        mode: "no-cors",
+        credentials: "include",
+      }
+    );
+
+    const same_origin_bundle = "./check-cookie-and-return-bundle.py";
+    const cross_origin_bundle = "http://{{domains[www2]}}:{{ports[http][0]}}/web-bundle/subresource-loading/check-cookie-and-return-bundle.py";
+
+    promise_test(async () => {
+      const link = document.createElement("link");
+      link.rel = "webbundle";
+      link.href = same_origin_bundle;
+      await addElementAndWaitForLoad(link);
+      link.remove()
+    }, "'no crossorigin attribute' should send a credential to a same origin bundle");
+
+    promise_test(async () => {
+      await setCookiePromise;
+      const link = document.createElement("link");
+      link.rel = "webbundle";
+      link.href = cross_origin_bundle;
+      await addElementAndWaitForLoad(link);
+      link.remove()
+    }, "'no crossorigin attribute' should send a credential to a cross origin bundle");
+
+    promise_test(async () => {
+      const link = document.createElement("link");
+      link.rel = "webbundle";
+      link.href = same_origin_bundle;
+      link.crossOrigin = "anonymous";
+      await addElementAndWaitForLoad(link);
+      link.remove()
+    }, "'anonymous' should send a credential to a same origin bundle");
+
+    promise_test(async () => {
+      await setCookiePromise;
+      const link = document.createElement("link");
+      link.rel = "webbundle";
+      link.href = cross_origin_bundle;
+      link.crossOrigin = "anonymous";
+      await addElementAndWaitForError(link);
+      link.remove()
+    }, "'anonymous' should not send a credential to a cross origin bundle");
+
+    promise_test(async () => {
+      const link = document.createElement("link");
+      link.rel = "webbundle";
+      link.href = same_origin_bundle;
+      link.crossOrigin = "use-credentials";
+      await addElementAndWaitForLoad(link);
+      link.remove()
+    }, "'use-credentials' should send a credential to a same origin bundle");
+
+    promise_test(async () => {
+      await setCookiePromise;
+      const link = document.createElement("link");
+      link.rel = "webbundle";
+      link.href = cross_origin_bundle;
+      link.crossOrigin = "use-credentials";
+      await addElementAndWaitForLoad(link);
+      link.remove()
+    }, "'use-credentials' should send a credential to a cross origin bundle");
+  </script>
+</body>
diff --git a/web-bundle/subresource-loading/subresource-loading-cross-origin.tentative.html b/web-bundle/subresource-loading/subresource-loading-cross-origin.tentative.html
deleted file mode 100644
index b0072dd..0000000
--- a/web-bundle/subresource-loading/subresource-loading-cross-origin.tentative.html
+++ /dev/null
@@ -1,93 +0,0 @@
-<!DOCTYPE html>
-<title>Cross-origin WebBundle subresource loading</title>
-<link
-  rel="help"
-  href="https://github.com/WICG/webpackage/blob/master/explainers/subresource-loading.md"
-/>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<body>
-  <!--
-       This wpt should run on an origin different from https://web-platform.test:8444/,
-       from where cross-orign WebBundles are served.
-
-       This test uses the two cross-origin WebBundles:
-
-       1. https://web-platform.test:8444/web-bundle/resources/wbn/cors/cross-origin.wbn,
-          which is served with an Access-Control-Allow-Origin response header.
-       2. http://web-platform.test:8444/web-bundle/resources/wbn/no-cors/cross-origin.wbn,
-          which is served *without* an Access-Control-Allow-Origin response header.
-
-       Each `cross-origin.wbn` includes two subresources:
-       a. `resource.cors.json`, which includes an Access-Control-Allow-Origin response header.
-       b. `resource.no-cors.json`, which doesn't include an Access-Control-Allow-Origin response header.
-  -->
-  <link
-    rel="webbundle"
-    href="https://web-platform.test:8444/web-bundle/resources/wbn/cors/cross-origin.wbn"
-    resources="https://web-platform.test:8444/web-bundle/resources/wbn/cors/resource.cors.json
-         https://web-platform.test:8444/web-bundle/resources/wbn/cors/resource.no-cors.json"
-  />
-  <script>
-    promise_test(async () => {
-      const response = await fetch(
-        "https://web-platform.test:8444/web-bundle/resources/wbn/cors/resource.cors.json"
-      );
-      assert_true(response.ok);
-      const text = await response.text();
-      assert_equals(text, "{ cors: 1 }");
-    }, "A subresource which includes an Access-Control-Allow-Origin response header can be fetched");
-
-    promise_test(async (t) => {
-      return promise_rejects_js(
-        t,
-        TypeError,
-        fetch(
-          "https://web-platform.test:8444/web-bundle/resources/wbn/cors/resource.no-cors.json"
-        )
-      );
-    }, "A subresource which does not include an Access-Control-Allow-Origin response header can not be fetched");
-
-    promise_test(async (t) => {
-      const prefix =
-        "http://web-platform.test:8444/web-bundle/resources/wbn/no-cors/";
-      const resources = [
-        prefix + "resource.cors.json",
-        prefix + "resource.no-cors.json",
-      ]
-      // Should fire an error event on loading webbundle.
-      await addLinkAndWaitForError(prefix + "cross-origin.wbn", resources);
-      // A fetch should fail for any subresource specified in resources attribute.
-      for (const url of resources) {
-        await fetchAndWaitForReject(url);
-      }
-    }, "A cross-origin WebBundle which does not include an Access-Control-Allow-Origin response header should fire an error event on load, and a fetch should fail for any subresource");
-
-    function addLinkAndWaitForError(url, resources) {
-      return new Promise((resolve, reject) => {
-        const link = document.createElement("link");
-        link.rel = "webbundle";
-        link.href = url;
-        for (const resource of resources) {
-          link.resources.add(resource);
-        }
-        link.onload = reject;
-        link.onerror = () => resolve(link);
-        document.body.appendChild(link);
-      });
-    }
-
-    function fetchAndWaitForReject(url) {
-      return new Promise((resolve, reject) => {
-        fetch(url)
-          .then(() => {
-            reject();
-          })
-          .catch(() => {
-           resolve();
-          });
-      });
-    }
-
-  </script>
-</body>