-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce <script>-based API for subresource loading with Web Bundles. See the design doc [1] for the motivation of switching from <link>-based API to <script>-based API. The explainer [2] was already updated to use <script>-based API. This feature is guarded by `SubresourceWebBundles` flag. We eventually drop the <link rel=webbundle> support and remove the <link>-based API code once we can confirm <script>-based API can be used as a replacement of <link>-based API. This CL should be considered as the first step to switch to <script>-based API. There are still gaps between <link>-based API and <script>-based API, which will be addressed later [3]. This CL intentionally adds a very minimum test for <script>-based API because there are already WPT tests for <script type=webbundle>. They all have been marked as [ SKIP ] in TestExpectations until now. Now some of them are passing after this CL. We'll make the remaining tests pass in follow-up CLs, and also add tests which are specific to <script>-based API as necessary. These efforts should be tracked by crbug.com/1245166. [1]: https://docs.google.com/document/d/1q_SodTcLuwya4cXt1gIRaVrkiaBfwWyPvkY1fqRKkgM/edit?usp=sharing&resourcekey=0-dqrFOGVCYsg8WRZ4RFgwuw [2]: https://github.com/WICG/webpackage/blob/main/explainers/subresource-loading.md [3]: WICG/webpackage#670 Bug: 1245166 Change-Id: I5109b6e692baf10fd1d8a31a31d93176d4dc4ad2 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3128843 Commit-Queue: Hayato Ito <[email protected]> Reviewed-by: Tsuyoshi Horo <[email protected]> Reviewed-by: Kunihiko Sakamoto <[email protected]> Reviewed-by: Hiroshige Hayashizaki <[email protected]> Reviewed-by: Kouhei Ueno <[email protected]> Cr-Commit-Position: refs/heads/main@{#933346} NOKEYCHECK=True GitOrigin-RevId: e1adbaeb278ee2ca83bc94a593cdc24dc660cda4
- Loading branch information
1 parent
c95496f
commit cee97f8
Showing
21 changed files
with
772 additions
and
12 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
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
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
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
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
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
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
185 changes: 185 additions & 0 deletions
185
blink/renderer/core/loader/web_bundle/script_web_bundle.cc
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,185 @@ | ||
// Copyright 2021 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. | ||
|
||
#include "third_party/blink/renderer/core/loader/web_bundle/script_web_bundle.h" | ||
|
||
#include "third_party/blink/renderer/core/dom/document.h" | ||
#include "third_party/blink/renderer/core/html/cross_origin_attribute.h" | ||
#include "third_party/blink/renderer/core/html/html_script_element.h" | ||
#include "third_party/blink/renderer/core/loader/web_bundle/script_web_bundle_rule.h" | ||
#include "third_party/blink/renderer/core/loader/web_bundle/web_bundle_loader.h" | ||
#include "third_party/blink/renderer/platform/bindings/microtask.h" | ||
#include "third_party/blink/renderer/platform/loader/cors/cors.h" | ||
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h" | ||
#include "third_party/blink/renderer/platform/loader/fetch/subresource_web_bundle_list.h" | ||
#include "third_party/blink/renderer/platform/weborigin/kurl.h" | ||
#include "third_party/blink/renderer/platform/wtf/casting.h" | ||
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h" | ||
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" | ||
|
||
namespace blink { | ||
|
||
// MicroTask which is used to release a webbundle resource. | ||
class ScriptWebBundle::ReleaseResourceTask { | ||
public: | ||
explicit ReleaseResourceTask(ScriptWebBundle& script_web_bundle) | ||
: script_web_bundle_(&script_web_bundle) {} | ||
|
||
void Run() { | ||
if (script_web_bundle_->WillBeReleased()) { | ||
script_web_bundle_->ReleaseBundleLoaderAndUnregister(); | ||
} | ||
} | ||
|
||
private: | ||
Persistent<ScriptWebBundle> script_web_bundle_; | ||
}; | ||
|
||
ScriptWebBundle* ScriptWebBundle::CreateOrReuseInline( | ||
Document& element_document, | ||
const String& source_text) { | ||
auto rule = | ||
ScriptWebBundleRule::ParseJson(source_text, element_document.BaseURL()); | ||
if (!rule) | ||
return nullptr; | ||
|
||
ResourceFetcher* resource_fetcher = element_document.Fetcher(); | ||
if (!resource_fetcher) | ||
return nullptr; | ||
SubresourceWebBundleList* active_bundles = | ||
resource_fetcher->GetOrCreateSubresourceWebBundleList(); | ||
|
||
if (SubresourceWebBundle* found = | ||
active_bundles->FindSubresourceWebBundleWhichWillBeReleased( | ||
rule->source_url())) { | ||
// Re-use the ScriptWebBundle if it has the same bundle URL and is being | ||
// released. | ||
DCHECK(found->IsScriptWebBundle()); | ||
ScriptWebBundle* reused_script_web_bundle = To<ScriptWebBundle>(found); | ||
DCHECK_EQ(reused_script_web_bundle->element_document_, element_document); | ||
reused_script_web_bundle->SetRule(std::move(*rule)); | ||
reused_script_web_bundle->CancelRelease(); | ||
return reused_script_web_bundle; | ||
} | ||
return MakeGarbageCollected<ScriptWebBundle>(element_document, *rule); | ||
} | ||
|
||
ScriptWebBundle::ScriptWebBundle(Document& element_document, | ||
const ScriptWebBundleRule& rule) | ||
: element_document_(&element_document), rule_(rule) { | ||
CreateBundleLoaderAndRegister(); | ||
} | ||
|
||
void ScriptWebBundle::Trace(Visitor* visitor) const { | ||
visitor->Trace(element_document_); | ||
visitor->Trace(bundle_loader_); | ||
SubresourceWebBundle::Trace(visitor); | ||
} | ||
|
||
bool ScriptWebBundle::CanHandleRequest(const KURL& url) const { | ||
if (WillBeReleased()) | ||
return false; | ||
if (!url.IsValid()) | ||
return false; | ||
if (!rule_.ResourcesOrScopesMatch(url)) | ||
return false; | ||
if (url.Protocol() == "urn" || url.Protocol() == "uuid-in-package") | ||
return true; | ||
DCHECK(bundle_loader_); | ||
if (!bundle_loader_->GetSecurityOrigin()->IsSameOriginWith( | ||
SecurityOrigin::Create(url).get())) { | ||
OnWebBundleError(url.ElidedString() + " cannot be loaded from WebBundle " + | ||
bundle_loader_->url().ElidedString() + | ||
": bundled resource must be same origin with the bundle."); | ||
return false; | ||
} | ||
|
||
if (!url.GetString().StartsWith(bundle_loader_->url().BaseAsString())) { | ||
OnWebBundleError( | ||
url.ElidedString() + " cannot be loaded from WebBundle " + | ||
bundle_loader_->url().ElidedString() + | ||
": bundled resource path must contain the bundle's path as a prefix."); | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
const KURL& ScriptWebBundle::GetBundleUrl() const { | ||
return rule_.source_url(); | ||
} | ||
const base::UnguessableToken& ScriptWebBundle::WebBundleToken() const { | ||
return bundle_loader_->WebBundleToken(); | ||
} | ||
String ScriptWebBundle::GetCacheIdentifier() const { | ||
DCHECK(bundle_loader_); | ||
return bundle_loader_->url().GetString(); | ||
} | ||
|
||
// TODO(crbug.com/1245166): Implement these. | ||
void ScriptWebBundle::OnWebBundleError(const String& message) const {} | ||
void ScriptWebBundle::NotifyLoaded() {} | ||
|
||
bool ScriptWebBundle::IsScriptWebBundle() const { | ||
return true; | ||
} | ||
|
||
bool ScriptWebBundle::WillBeReleased() const { | ||
return will_be_released_; | ||
} | ||
|
||
void ScriptWebBundle::CreateBundleLoaderAndRegister() { | ||
DCHECK(!bundle_loader_); | ||
DCHECK(element_document_); | ||
bundle_loader_ = MakeGarbageCollected<WebBundleLoader>( | ||
*this, *element_document_, rule_.source_url(), | ||
// TODO(crbug.com/1245166): Set a cross origin attribute value from the | ||
// rule. | ||
kCrossOriginAttributeNotSet); | ||
ResourceFetcher* resource_fetcher = element_document_->Fetcher(); | ||
if (!resource_fetcher) | ||
return; | ||
SubresourceWebBundleList* active_bundles = | ||
resource_fetcher->GetOrCreateSubresourceWebBundleList(); | ||
active_bundles->Add(*this); | ||
} | ||
|
||
void ScriptWebBundle::ReleaseBundleLoaderAndUnregister() { | ||
if (bundle_loader_) { | ||
// Clear receivers explicitly here, instead of waiting for Blink GC. | ||
bundle_loader_->ClearReceivers(); | ||
bundle_loader_ = nullptr; | ||
} | ||
// element_document_ might not be alive. | ||
if (!element_document_) | ||
return; | ||
ResourceFetcher* resource_fetcher = element_document_->Fetcher(); | ||
if (!resource_fetcher) | ||
return; | ||
SubresourceWebBundleList* active_bundles = | ||
resource_fetcher->GetOrCreateSubresourceWebBundleList(); | ||
active_bundles->Remove(*this); | ||
} | ||
|
||
void ScriptWebBundle::WillReleaseBundleLoaderAndUnregister() { | ||
// We don't release webbundle resources synchronously here. Instead, enqueue a | ||
// microtask which will release webbundle resources later. | ||
|
||
// The motivation is that we want to update a mapping rule dynamically without | ||
// releasing webbundle resources. | ||
// | ||
// For example, if we remove <script type=webbundle>, and then add another | ||
// <script type=webbundle> with the same bundle URL, but with a new mapping | ||
// rule, within the same microtask scope, the new one can re-use the webbundle | ||
// resources, instead of releasing them. In other words, we don't fetch the | ||
// same bundle twice. | ||
// | ||
// Tentative spec: | ||
// https://docs.google.com/document/d/1GEJ3wTERGEeTG_4J0QtAwaNXhPTza0tedd00A7vPVsw/edit#heading=h.y88lpjmx2ndn | ||
will_be_released_ = true; | ||
auto task = std::make_unique<ReleaseResourceTask>(*this); | ||
Microtask::EnqueueMicrotask( | ||
WTF::Bind(&ReleaseResourceTask::Run, std::move(task))); | ||
} | ||
|
||
} // namespace blink |
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,76 @@ | ||
// Copyright 2021 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_CORE_LOADER_WEB_BUNDLE_SCRIPT_WEB_BUNDLE_H_ | ||
#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_WEB_BUNDLE_SCRIPT_WEB_BUNDLE_H_ | ||
|
||
#include "third_party/blink/renderer/core/core_export.h" | ||
#include "third_party/blink/renderer/core/loader/web_bundle/script_web_bundle_rule.h" | ||
#include "third_party/blink/renderer/platform/heap/garbage_collected.h" | ||
#include "third_party/blink/renderer/platform/heap/handle.h" | ||
#include "third_party/blink/renderer/platform/heap/persistent.h" | ||
#include "third_party/blink/renderer/platform/loader/fetch/subresource_web_bundle.h" | ||
#include "third_party/blink/renderer/platform/wtf/casting.h" | ||
|
||
namespace WTF { | ||
class String; | ||
} | ||
|
||
namespace blink { | ||
|
||
class Document; | ||
class KURL; | ||
class WebBundleLoader; | ||
|
||
// ScriptLoader creates this for a script whose type is "webbundle". | ||
// | ||
// https://github.com/WICG/webpackage/blob/main/explainers/subresource-loading.md#script-based-api | ||
class CORE_EXPORT ScriptWebBundle final | ||
: public GarbageCollected<ScriptWebBundle>, | ||
public SubresourceWebBundle { | ||
public: | ||
static ScriptWebBundle* CreateOrReuseInline(Document& element_document, | ||
const String& inline_text); | ||
|
||
ScriptWebBundle(Document& element_document, const ScriptWebBundleRule& rule); | ||
|
||
void Trace(Visitor* visitor) const override; | ||
|
||
// SubresourceWebBundle overrides: | ||
bool CanHandleRequest(const KURL& url) const override; | ||
String GetCacheIdentifier() const override; | ||
const KURL& GetBundleUrl() const override; | ||
const base::UnguessableToken& WebBundleToken() const override; | ||
void NotifyLoaded() override; | ||
void OnWebBundleError(const String& message) const override; | ||
bool IsScriptWebBundle() const override; | ||
bool WillBeReleased() const override; | ||
|
||
void CreateBundleLoaderAndRegister(); | ||
void ReleaseBundleLoaderAndUnregister(); | ||
|
||
void WillReleaseBundleLoaderAndUnregister(); | ||
void CancelRelease() { will_be_released_ = false; } | ||
|
||
void SetRule(ScriptWebBundleRule rule) { rule_ = std::move(rule); } | ||
|
||
class ReleaseResourceTask; | ||
|
||
private: | ||
bool will_be_released_ = false; | ||
WeakMember<Document> element_document_; | ||
ScriptWebBundleRule rule_; | ||
Member<WebBundleLoader> bundle_loader_; | ||
}; | ||
|
||
template <> | ||
struct DowncastTraits<ScriptWebBundle> { | ||
static bool AllowFrom(const SubresourceWebBundle& subresource_web_bundle) { | ||
return subresource_web_bundle.IsScriptWebBundle(); | ||
} | ||
}; | ||
|
||
} // namespace blink | ||
|
||
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_WEB_BUNDLE_SCRIPT_WEB_BUNDLE_H_ |
Oops, something went wrong.