Skip to content

Commit

Permalink
Implement subresource loading with Web Bundles
Browse files Browse the repository at this point in the history
- 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/+/2291809
Reviewed-by: Kinuko Yasuda <kinuko@chromium.org>
Reviewed-by: Tsuyoshi Horo <horo@chromium.org>
Reviewed-by: Hayato Ito <hayato@chromium.org>
Commit-Queue: Kunihiko Sakamoto <ksakamoto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#788842}
  • Loading branch information
irori authored and Commit Bot committed Jul 16, 2020
1 parent e6c6e45 commit e903b6c
Show file tree
Hide file tree
Showing 26 changed files with 331 additions and 8 deletions.
146 changes: 143 additions & 3 deletions third_party/blink/renderer/core/html/link_web_bundle.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,163 @@

#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 {

// 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() = 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() {
// 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 {
return kOther;
}

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
KURL LinkWebBundle::ParseResourceUrl(const AtomicString& str) {
Expand Down
23 changes: 21 additions & 2 deletions third_party/blink/renderer/core/html/link_web_bundle.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,50 @@
#ifndef 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/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"

namespace blink {

class WebBundleLoader;

// LinkWebBundle is used in the Subresource loading with Web Bundles feature.
// See crbug.com/1082020 for details.
// 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:
explicit LinkWebBundle(HTMLLinkElement* owner);
~LinkWebBundle() override = default;
~LinkWebBundle() override;
void Trace(Visitor* visitor) const override;

void NotifyLoaded();

// LinkResource overrides:
void Process() override;
LinkResourceType GetType() const override;
bool HasLoaded() const 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
// WebBundles specification requires, this returns invalid empty KURL as an
// error.
// See
// https://wicg.github.io/webpackage/draft-yasskin-wpack-bundled-exchanges.html#name-parsing-the-index-section
static KURL ParseResourceUrl(const AtomicString& str);

Member<WebBundleLoader> bundle_loader_;
};

} // namespace blink
Expand Down
1 change: 1 addition & 0 deletions third_party/blink/renderer/platform/loader/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ blink_platform_sources("loader") {
"fetch/source_keyed_cached_metadata_handler.h",
"fetch/stale_revalidation_resource_client.cc",
"fetch/stale_revalidation_resource_client.h",
"fetch/subresource_web_bundle.h",
"fetch/text_resource_decoder_options.cc",
"fetch/text_resource_decoder_options.h",
"fetch/trust_token_params_conversion.cc",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "base/metrics/histogram_macros.h"
#include "base/time/time.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/mime_util/mime_util.h"
#include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
Expand Down Expand Up @@ -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_timing_info.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/mhtml/archive_resource.h"
#include "third_party/blink/renderer/platform/mhtml/mhtml_archive.h"
Expand Down Expand Up @@ -1260,6 +1262,15 @@ std::unique_ptr<WebURLLoader> ResourceFetcher::CreateURLLoader(
const ResourceLoaderOptions& options) {
DCHECK(!GetProperties().IsDetached());
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_);
}

Expand Down Expand Up @@ -2227,6 +2238,17 @@ FrameOrWorkerScheduler* ResourceFetcher::GetFrameOrWorkerScheduler() {
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 {
visitor->Trace(context_);
visitor->Trace(properties_);
Expand All @@ -2245,6 +2267,7 @@ void ResourceFetcher::Trace(Visitor* visitor) const {
visitor->Trace(matched_preloads_);
visitor->Trace(resource_timing_info_map_);
visitor->Trace(blob_registry_remote_);
visitor->Trace(subresource_web_bundles_);
}

// static
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class Resource;
class ResourceError;
class ResourceLoadObserver;
class ResourceTimingInfo;
class SubresourceWebBundle;
class WebURLLoader;
struct ResourceFetcherInit;
struct ResourceLoaderOptions;
Expand Down Expand Up @@ -282,6 +283,9 @@ class PLATFORM_EXPORT ResourceFetcher
scheduler_->SetThrottleOptionOverride(throttle_option_override);
}

void AddSubresourceWebBundle(SubresourceWebBundle& subresource_web_bundle);
void RemoveSubresourceWebBundle(SubresourceWebBundle& subresource_web_bundle);

private:
friend class ResourceCacheValidationSuppressor;
enum class StopFetchingTarget {
Expand Down Expand Up @@ -437,6 +441,8 @@ class PLATFORM_EXPORT ResourceFetcher
HeapMojoWrapperMode::kWithoutContextObserver>
blob_registry_remote_;

HeapHashSet<Member<SubresourceWebBundle>> subresource_web_bundles_;

// This is not in the bit field below because we want to use AutoReset.
bool is_in_request_resource_ = false;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// 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_
2 changes: 2 additions & 0 deletions third_party/blink/web_tests/external/wpt/lint.ignore
Original file line number Diff line number Diff line change
Expand Up @@ -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: *.bmp
TRAILING WHITESPACE, INDENT TABS, CR AT EOL: *.sxg
TRAILING WHITESPACE, INDENT TABS, CR AT EOL: *.wbn

## .gitignore
W3C-TEST.ORG: .gitignore
Expand Down Expand Up @@ -706,6 +707,7 @@ WEB-PLATFORM.TEST:signed-exchange/resources/generate-test-sxgs.sh
# Web Bundle files have hard-coded URLs
WEB-PLATFORM.TEST:web-bundle/resources/generate-test-wbns.sh
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:
# https://github.com/web-platform-tests/wpt/issues/16455
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const result = 'resource1 from network';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const result = 'resource2 from network';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const result = 'resource3 from network';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const result = 'resource4 from network';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const result = 'resource1 from dynamic1.wbn';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const result = 'resource2 from dynamic1.wbn';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const result = 'resource3 from dynamic1.wbn';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const result = 'resource4 from dynamic1.wbn';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const result = 'resource1 from dynamic2.wbn';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const result = 'resource2 from dynamic2.wbn';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const result = 'resource3 from dynamic2.wbn';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const result = 'resource4 from dynamic2.wbn';

0 comments on commit e903b6c

Please sign in to comment.