Commit e903b6cc authored by Kunihiko Sakamoto's avatar Kunihiko Sakamoto Committed by Commit Bot

Implement subresource loading with Web Bundles

- Adds WebBundleLoader class which loads a WebBundle resource using
  ThreadableLoader, and creates a WebBundleSubresourceLoaderFactory.

- LinkWebBundle is registered in ResourceFetcher, and used to forward
  subresource requests that match the corresponding <link>'s resources=
  attribute to the WebBundleSubresourceLoaderFactory. This is done via
  the SubresourceWebBundle interface.

Bug: 1082020
Change-Id: I3f26bd6b1fbd5855caa5175cdcb3db0fe103a093
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2291809Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Reviewed-by: default avatarTsuyoshi Horo <horo@chromium.org>
Reviewed-by: default avatarHayato Ito <hayato@chromium.org>
Commit-Queue: Kunihiko Sakamoto <ksakamoto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#788842}
parent e6c6e456
...@@ -4,12 +4,134 @@ ...@@ -4,12 +4,134 @@
#include "third_party/blink/renderer/core/html/link_web_bundle.h" #include "third_party/blink/renderer/core/html/link_web_bundle.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/renderer/core/html/html_link_element.h"
#include "third_party/blink/renderer/core/loader/threadable_loader.h"
#include "third_party/blink/renderer/core/loader/threadable_loader_client.h"
#include "third_party/blink/renderer/platform/loader/cors/cors.h"
#include "third_party/blink/renderer/platform/loader/fetch/bytes_consumer.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/loader/fetch/url_loader/web_bundle_subresource_loader.h"
namespace blink { namespace blink {
// WebBundleLoader is responsible for loading a WebBundle resource.
class WebBundleLoader : public GarbageCollected<WebBundleLoader>,
public ThreadableLoaderClient {
USING_GARBAGE_COLLECTED_MIXIN(WebBundleLoader);
public:
WebBundleLoader(LinkWebBundle& link_web_bundle,
ExecutionContext& execution_context,
const KURL& url)
: link_web_bundle_(&link_web_bundle),
pending_factory_receiver_(
loader_factory_.BindNewPipeAndPassReceiver()) {
ResourceRequest request(url);
request.SetUseStreamOnResponse(true);
// TODO(crbug.com/1082020): Revisit these once the fetch and process the
// linked resource algorithm [1] for <link rel=webbundle> is defined.
// [1]
// https://html.spec.whatwg.org/multipage/semantics.html#fetch-and-process-the-linked-resource
request.SetRequestContext(mojom::blink::RequestContextType::SUBRESOURCE);
request.SetMode(network::mojom::blink::RequestMode::kCors);
request.SetCredentialsMode(network::mojom::blink::CredentialsMode::kOmit);
ResourceLoaderOptions resource_loader_options;
resource_loader_options.data_buffering_policy = kDoNotBufferData;
loader_ = MakeGarbageCollected<ThreadableLoader>(execution_context, this,
resource_loader_options);
loader_->Start(std::move(request));
}
void Trace(Visitor* visitor) const override {
visitor->Trace(link_web_bundle_);
visitor->Trace(loader_);
}
bool HasLoaded() const { return !failed_; }
mojo::PendingRemote<network::mojom::blink::URLLoaderFactory>
GetURLLoaderFactory() {
mojo::PendingRemote<network::mojom::blink::URLLoaderFactory> factory_clone;
loader_factory_->Clone(factory_clone.InitWithNewPipeAndPassReceiver());
return factory_clone;
}
// ThreadableLoaderClient
void DidReceiveResponse(uint64_t, const ResourceResponse& response) override {
if (!cors::IsOkStatus(response.HttpStatusCode()))
failed_ = true;
// TODO(crbug.com/1082020): Check response headers, as spec'ed in
// https://wicg.github.io/webpackage/draft-yasskin-wpack-bundled-exchanges.html#name-serving-constraints.
}
void DidStartLoadingResponseBody(BytesConsumer& consumer) override {
DCHECK(pending_factory_receiver_);
CreateWebBundleSubresourceLoaderFactory(
mojo::PendingReceiver<network::mojom::URLLoaderFactory>(
pending_factory_receiver_.PassPipe()),
consumer.DrainAsDataPipe());
// TODO(crbug.com/1082020): Set |failed_| to true on metadata parse error,
// so that "error" event is dispatched.
}
void DidFinishLoading(uint64_t) override { link_web_bundle_->NotifyLoaded(); }
void DidFail(const ResourceError&) override { DidFailInternal(); }
void DidFailRedirectCheck() override { DidFailInternal(); }
private:
void DidFailInternal() {
if (pending_factory_receiver_) {
// If we haven't create a WebBundleSubresourceLoaderFactory, create it
// with an empty bundle body so that requests to
// |pending_factory_receiver_| are processed (and fail).
CreateWebBundleSubresourceLoaderFactory(
mojo::PendingReceiver<network::mojom::URLLoaderFactory>(
pending_factory_receiver_.PassPipe()),
mojo::ScopedDataPipeConsumerHandle());
}
failed_ = true;
link_web_bundle_->NotifyLoaded();
}
Member<LinkWebBundle> link_web_bundle_;
Member<ThreadableLoader> loader_;
mojo::Remote<network::mojom::blink::URLLoaderFactory> loader_factory_;
mojo::PendingReceiver<network::mojom::blink::URLLoaderFactory>
pending_factory_receiver_;
bool failed_ = false;
};
LinkWebBundle::LinkWebBundle(HTMLLinkElement* owner) : LinkResource(owner) {} LinkWebBundle::LinkWebBundle(HTMLLinkElement* owner) : LinkResource(owner) {}
LinkWebBundle::~LinkWebBundle() = default;
void LinkWebBundle::Trace(Visitor* visitor) const {
visitor->Trace(bundle_loader_);
LinkResource::Trace(visitor);
SubresourceWebBundle::Trace(visitor);
}
void LinkWebBundle::NotifyLoaded() {
if (owner_)
owner_->ScheduleEvent();
}
void LinkWebBundle::Process() { void LinkWebBundle::Process() {
// TODO(crbug.com/1082020): Implement this. if (!owner_ || !owner_->GetDocument().GetFrame())
return;
if (!owner_->ShouldLoadLink())
return;
ResourceFetcher* resource_fetcher = owner_->GetDocument().Fetcher();
if (!resource_fetcher)
return;
bundle_loader_ = MakeGarbageCollected<WebBundleLoader>(
*this, *owner_->GetDocument().GetExecutionContext(), owner_->Href());
resource_fetcher->AddSubresourceWebBundle(*this);
} }
LinkResource::LinkResourceType LinkWebBundle::GetType() const { LinkResource::LinkResourceType LinkWebBundle::GetType() const {
...@@ -17,10 +139,28 @@ LinkResource::LinkResourceType LinkWebBundle::GetType() const { ...@@ -17,10 +139,28 @@ LinkResource::LinkResourceType LinkWebBundle::GetType() const {
} }
bool LinkWebBundle::HasLoaded() const { bool LinkWebBundle::HasLoaded() const {
return false; return bundle_loader_ && bundle_loader_->HasLoaded();
}
void LinkWebBundle::OwnerRemoved() {
if (!owner_)
return;
ResourceFetcher* resource_fetcher = owner_->GetDocument().Fetcher();
if (!resource_fetcher)
return;
resource_fetcher->RemoveSubresourceWebBundle(*this);
bundle_loader_ = nullptr;
} }
void LinkWebBundle::OwnerRemoved() {} bool LinkWebBundle::CanHandleRequest(const KURL& url) const {
return owner_ && owner_->ValidResourceUrls().Contains(url);
}
mojo::PendingRemote<network::mojom::blink::URLLoaderFactory>
LinkWebBundle::GetURLLoaderFactory() {
DCHECK(bundle_loader_);
return bundle_loader_->GetURLLoaderFactory();
}
// static // static
KURL LinkWebBundle::ParseResourceUrl(const AtomicString& str) { KURL LinkWebBundle::ParseResourceUrl(const AtomicString& str) {
......
...@@ -5,31 +5,50 @@ ...@@ -5,31 +5,50 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_LINK_WEB_BUNDLE_H_ #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_LINK_WEB_BUNDLE_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_LINK_WEB_BUNDLE_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_LINK_WEB_BUNDLE_H_
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "services/network/public/mojom/url_loader_factory.mojom-blink.h"
#include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/html/link_resource.h" #include "third_party/blink/renderer/core/html/link_resource.h"
#include "third_party/blink/renderer/platform/loader/fetch/subresource_web_bundle.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h"
namespace blink { namespace blink {
class WebBundleLoader;
// LinkWebBundle is used in the Subresource loading with Web Bundles feature. // LinkWebBundle is used in the Subresource loading with Web Bundles feature.
// See crbug.com/1082020 for details. // See crbug.com/1082020 for details.
// A <link rel="webbundle" ...> element creates LinkWebBundle. // A <link rel="webbundle" ...> element creates LinkWebBundle.
class CORE_EXPORT LinkWebBundle final : public LinkResource { class CORE_EXPORT LinkWebBundle final : public LinkResource,
public SubresourceWebBundle {
USING_GARBAGE_COLLECTED_MIXIN(LinkWebBundle);
public: public:
explicit LinkWebBundle(HTMLLinkElement* owner); explicit LinkWebBundle(HTMLLinkElement* owner);
~LinkWebBundle() override = default; ~LinkWebBundle() override;
void Trace(Visitor* visitor) const override;
void NotifyLoaded();
// LinkResource overrides:
void Process() override; void Process() override;
LinkResourceType GetType() const override; LinkResourceType GetType() const override;
bool HasLoaded() const override; bool HasLoaded() const override;
void OwnerRemoved() override; void OwnerRemoved() override;
// SubresourceWebBundle overrides:
bool CanHandleRequest(const KURL& url) const override;
mojo::PendingRemote<network::mojom::blink::URLLoaderFactory>
GetURLLoaderFactory() override;
// Parse the given |str| as a url. If |str| doesn't meet the criteria which // Parse the given |str| as a url. If |str| doesn't meet the criteria which
// WebBundles specification requires, this returns invalid empty KURL as an // WebBundles specification requires, this returns invalid empty KURL as an
// error. // error.
// See // See
// https://wicg.github.io/webpackage/draft-yasskin-wpack-bundled-exchanges.html#name-parsing-the-index-section // https://wicg.github.io/webpackage/draft-yasskin-wpack-bundled-exchanges.html#name-parsing-the-index-section
static KURL ParseResourceUrl(const AtomicString& str); static KURL ParseResourceUrl(const AtomicString& str);
Member<WebBundleLoader> bundle_loader_;
}; };
} // namespace blink } // namespace blink
......
...@@ -104,6 +104,7 @@ blink_platform_sources("loader") { ...@@ -104,6 +104,7 @@ blink_platform_sources("loader") {
"fetch/source_keyed_cached_metadata_handler.h", "fetch/source_keyed_cached_metadata_handler.h",
"fetch/stale_revalidation_resource_client.cc", "fetch/stale_revalidation_resource_client.cc",
"fetch/stale_revalidation_resource_client.h", "fetch/stale_revalidation_resource_client.h",
"fetch/subresource_web_bundle.h",
"fetch/text_resource_decoder_options.cc", "fetch/text_resource_decoder_options.cc",
"fetch/text_resource_decoder_options.h", "fetch/text_resource_decoder_options.h",
"fetch/trust_token_params_conversion.cc", "fetch/trust_token_params_conversion.cc",
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "services/network/public/cpp/request_mode.h" #include "services/network/public/cpp/request_mode.h"
#include "services/network/public/mojom/url_loader_factory.mojom-blink.h"
#include "third_party/blink/public/common/features.h" #include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/mime_util/mime_util.h" #include "third_party/blink/public/common/mime_util/mime_util.h"
#include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h" #include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
...@@ -69,6 +70,7 @@ ...@@ -69,6 +70,7 @@
#include "third_party/blink/renderer/platform/loader/fetch/resource_loading_log.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_loading_log.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h"
#include "third_party/blink/renderer/platform/loader/fetch/stale_revalidation_resource_client.h" #include "third_party/blink/renderer/platform/loader/fetch/stale_revalidation_resource_client.h"
#include "third_party/blink/renderer/platform/loader/fetch/subresource_web_bundle.h"
#include "third_party/blink/renderer/platform/loader/fetch/unique_identifier.h" #include "third_party/blink/renderer/platform/loader/fetch/unique_identifier.h"
#include "third_party/blink/renderer/platform/mhtml/archive_resource.h" #include "third_party/blink/renderer/platform/mhtml/archive_resource.h"
#include "third_party/blink/renderer/platform/mhtml/mhtml_archive.h" #include "third_party/blink/renderer/platform/mhtml/mhtml_archive.h"
...@@ -1260,6 +1262,15 @@ std::unique_ptr<WebURLLoader> ResourceFetcher::CreateURLLoader( ...@@ -1260,6 +1262,15 @@ std::unique_ptr<WebURLLoader> ResourceFetcher::CreateURLLoader(
const ResourceLoaderOptions& options) { const ResourceLoaderOptions& options) {
DCHECK(!GetProperties().IsDetached()); DCHECK(!GetProperties().IsDetached());
DCHECK(loader_factory_); DCHECK(loader_factory_);
for (auto& bundle : subresource_web_bundles_) {
if (!bundle->CanHandleRequest(request.Url()))
continue;
ResourceLoaderOptions new_options(options);
new_options.url_loader_factory = base::MakeRefCounted<base::RefCountedData<
mojo::PendingRemote<network::mojom::blink::URLLoaderFactory>>>(
bundle->GetURLLoaderFactory());
return loader_factory_->CreateURLLoader(request, new_options, task_runner_);
}
return loader_factory_->CreateURLLoader(request, options, task_runner_); return loader_factory_->CreateURLLoader(request, options, task_runner_);
} }
...@@ -2227,6 +2238,17 @@ FrameOrWorkerScheduler* ResourceFetcher::GetFrameOrWorkerScheduler() { ...@@ -2227,6 +2238,17 @@ FrameOrWorkerScheduler* ResourceFetcher::GetFrameOrWorkerScheduler() {
return frame_or_worker_scheduler_.get(); return frame_or_worker_scheduler_.get();
} }
void ResourceFetcher::AddSubresourceWebBundle(
SubresourceWebBundle& subresource_web_bundle) {
DCHECK(RuntimeEnabledFeatures::SubresourceWebBundlesEnabled());
subresource_web_bundles_.insert(&subresource_web_bundle);
}
void ResourceFetcher::RemoveSubresourceWebBundle(
SubresourceWebBundle& subresource_web_bundle) {
subresource_web_bundles_.erase(&subresource_web_bundle);
}
void ResourceFetcher::Trace(Visitor* visitor) const { void ResourceFetcher::Trace(Visitor* visitor) const {
visitor->Trace(context_); visitor->Trace(context_);
visitor->Trace(properties_); visitor->Trace(properties_);
...@@ -2245,6 +2267,7 @@ void ResourceFetcher::Trace(Visitor* visitor) const { ...@@ -2245,6 +2267,7 @@ void ResourceFetcher::Trace(Visitor* visitor) const {
visitor->Trace(matched_preloads_); visitor->Trace(matched_preloads_);
visitor->Trace(resource_timing_info_map_); visitor->Trace(resource_timing_info_map_);
visitor->Trace(blob_registry_remote_); visitor->Trace(blob_registry_remote_);
visitor->Trace(subresource_web_bundles_);
} }
// static // static
......
...@@ -61,6 +61,7 @@ class Resource; ...@@ -61,6 +61,7 @@ class Resource;
class ResourceError; class ResourceError;
class ResourceLoadObserver; class ResourceLoadObserver;
class ResourceTimingInfo; class ResourceTimingInfo;
class SubresourceWebBundle;
class WebURLLoader; class WebURLLoader;
struct ResourceFetcherInit; struct ResourceFetcherInit;
struct ResourceLoaderOptions; struct ResourceLoaderOptions;
...@@ -282,6 +283,9 @@ class PLATFORM_EXPORT ResourceFetcher ...@@ -282,6 +283,9 @@ class PLATFORM_EXPORT ResourceFetcher
scheduler_->SetThrottleOptionOverride(throttle_option_override); scheduler_->SetThrottleOptionOverride(throttle_option_override);
} }
void AddSubresourceWebBundle(SubresourceWebBundle& subresource_web_bundle);
void RemoveSubresourceWebBundle(SubresourceWebBundle& subresource_web_bundle);
private: private:
friend class ResourceCacheValidationSuppressor; friend class ResourceCacheValidationSuppressor;
enum class StopFetchingTarget { enum class StopFetchingTarget {
...@@ -437,6 +441,8 @@ class PLATFORM_EXPORT ResourceFetcher ...@@ -437,6 +441,8 @@ class PLATFORM_EXPORT ResourceFetcher
HeapMojoWrapperMode::kWithoutContextObserver> HeapMojoWrapperMode::kWithoutContextObserver>
blob_registry_remote_; blob_registry_remote_;
HeapHashSet<Member<SubresourceWebBundle>> subresource_web_bundles_;
// This is not in the bit field below because we want to use AutoReset. // This is not in the bit field below because we want to use AutoReset.
bool is_in_request_resource_ = false; bool is_in_request_resource_ = false;
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_SUBRESOURCE_WEB_BUNDLE_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_SUBRESOURCE_WEB_BUNDLE_H_
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "services/network/public/mojom/url_loader_factory.mojom-blink-forward.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/platform_export.h"
namespace blink {
class KURL;
// SubresourceWebBundle is attached to ResourceFetcher and used to intercept
// subresource requests for a certain set of URLs and serve responses from a
// WebBundle. This is used for Subresource loading with Web Bundles
// (https://github.com/WICG/webpackage/blob/master/explainers/subresource-loading.md).
class PLATFORM_EXPORT SubresourceWebBundle : public GarbageCollectedMixin {
public:
void Trace(Visitor* visitor) const override {}
virtual bool CanHandleRequest(const KURL& url) const = 0;
virtual mojo::PendingRemote<network::mojom::blink::URLLoaderFactory>
GetURLLoaderFactory() = 0;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_SUBRESOURCE_WEB_BUNDLE_H_
...@@ -45,6 +45,7 @@ TRAILING WHITESPACE, INDENT TABS, CR AT EOL: *.ico ...@@ -45,6 +45,7 @@ TRAILING WHITESPACE, INDENT TABS, CR AT EOL: *.ico
TRAILING WHITESPACE, INDENT TABS, CR AT EOL: *.wasm TRAILING WHITESPACE, INDENT TABS, CR AT EOL: *.wasm
TRAILING WHITESPACE, INDENT TABS, CR AT EOL: *.bmp TRAILING WHITESPACE, INDENT TABS, CR AT EOL: *.bmp
TRAILING WHITESPACE, INDENT TABS, CR AT EOL: *.sxg TRAILING WHITESPACE, INDENT TABS, CR AT EOL: *.sxg
TRAILING WHITESPACE, INDENT TABS, CR AT EOL: *.wbn
## .gitignore ## .gitignore
W3C-TEST.ORG: .gitignore W3C-TEST.ORG: .gitignore
...@@ -706,6 +707,7 @@ WEB-PLATFORM.TEST:signed-exchange/resources/generate-test-sxgs.sh ...@@ -706,6 +707,7 @@ WEB-PLATFORM.TEST:signed-exchange/resources/generate-test-sxgs.sh
# Web Bundle files have hard-coded URLs # Web Bundle files have hard-coded URLs
WEB-PLATFORM.TEST:web-bundle/resources/generate-test-wbns.sh WEB-PLATFORM.TEST:web-bundle/resources/generate-test-wbns.sh
WEB-PLATFORM.TEST:web-bundle/resources/wbn/*.wbn WEB-PLATFORM.TEST:web-bundle/resources/wbn/*.wbn
WEB-PLATFORM.TEST:web-bundle/subresource-loading/subresource-loading-from-web-bundle.tentative.html
# Tests that depend on resources in /gen/ in Chromium: # Tests that depend on resources in /gen/ in Chromium:
# https://github.com/web-platform-tests/wpt/issues/16455 # https://github.com/web-platform-tests/wpt/issues/16455
......
...@@ -10,11 +10,33 @@ fi ...@@ -10,11 +10,33 @@ fi
# TODO: Stop hard-coding "web-platform.test" when generating Web Bundles on the # TODO: Stop hard-coding "web-platform.test" when generating Web Bundles on the
# fly. # fly.
wpt_test_origin=https://web-platform.test:8444 wpt_test_https_origin=https://web-platform.test:8444
wpt_test_http_origin=http://web-platform.test:8001
gen-bundle \ gen-bundle \
-version b1 \ -version b1 \
-baseURL $wpt_test_origin/web-bundle/resources/wbn/ \ -baseURL $wpt_test_https_origin/web-bundle/resources/wbn/ \
-primaryURL $wpt_test_origin/web-bundle/resources/wbn/location.html \ -primaryURL $wpt_test_https_origin/web-bundle/resources/wbn/location.html \
-dir location/ \ -dir location/ \
-o wbn/location.wbn -o wbn/location.wbn
gen-bundle \
-version b1 \
-baseURL https://subresource-wbn.example/ \
-primaryURL https://subresource-wbn.example/root.js \
-dir subresource/ \
-o wbn/subresource.wbn
gen-bundle \
-version b1 \
-baseURL $wpt_test_http_origin/web-bundle/resources/dynamic/ \
-primaryURL $wpt_test_http_origin/web-bundle/resources/dynamic/resource1.js \
-dir dynamic1/ \
-o wbn/dynamic1.wbn
gen-bundle \
-version b1 \
-baseURL $wpt_test_http_origin/web-bundle/resources/dynamic/ \
-primaryURL $wpt_test_http_origin/web-bundle/resources/dynamic/resource1.js \
-dir dynamic2/ \
-o wbn/dynamic2.wbn
<!DOCTYPE html>
<title>Subresource loading with link rel="webbundle"</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>
<link rel="webbundle" href="../resources/wbn/subresource.wbn"
resources="https://subresource-wbn.example/root.js https://subresource-wbn.example/submodule.js" />
<script>
promise_test(async () => {
const module = await import('https://subresource-wbn.example/root.js');
assert_equals(module.result, 'OK');
}, "Subresource loading with WebBundle");
promise_test(async () => {
const link = document.createElement("link");
link.rel = "webbundle";
link.href = "../resources/wbn/dynamic1.wbn";
link.resources.add('http://web-platform.test:8001/web-bundle/resources/dynamic/resource1.js',
'http://web-platform.test:8001/web-bundle/resources/dynamic/resource2.js',
'http://web-platform.test:8001/web-bundle/resources/dynamic/resource4.js');
document.body.appendChild(link);
const module = await import('http://web-platform.test:8001/web-bundle/resources/dynamic/resource1.js');
assert_equals(module.result, 'resource1 from dynamic1.wbn');
link.href = "../resources/wbn/dynamic2.wbn";
const module2 = await import('http://web-platform.test:8001/web-bundle/resources/dynamic/resource2.js');
assert_equals(module2.result, 'resource2 from dynamic2.wbn');
// A resource not specified in the resources attribute, but in the bundle.
const module3 = await import('http://web-platform.test:8001/web-bundle/resources/dynamic/resource3.js');
assert_equals(module3.result, 'resource3 from network');
document.body.removeChild(link);
const module4 = await import('http://web-platform.test:8001/web-bundle/resources/dynamic/resource4.js');
assert_equals(module4.result, 'resource4 from network');
}, 'Dynamically adding / updating / removing "<link rel=webbundle>"');
promise_test(() => {
return new Promise((resolve, reject) => {
const link = document.createElement("link");
link.rel = "webbundle";
link.href = "../resources/wbn/dynamic1.wbn?test-event";
link.onload = resolve;
link.onerror = reject;
document.body.appendChild(link);
});
}, '<link rel="webbundle"> fires a load event on load success');
promise_test(() => {
return new Promise((resolve, reject) => {
const link = document.createElement("link");
link.rel = "webbundle";
link.href = "../resources/wbn/nonexistent.wbn";
link.onload = reject;
link.onerror = resolve;
document.body.appendChild(link);
});
}, '<link rel="webbundle"> fires an error event on load failure');
</script>
</body>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment