Commit 26fae311 authored by Wei Lee's avatar Wei Lee Committed by Commit Bot

Supports SharedWorker in SWA

Currently only Worker (DedicatedWorker) works on SWA but not
SharedWorker since it will hit unknown scheme error due to its scheme
(chrome://).

The reason is that currently we don't put an WebUIUrlLoaderFactory when
creating factory bundle in WorkerScriptFetchInitiator so it will try to
fetch scripts with "chrome://" scheme through internet, and causes the
unknown scheme error.

Bug: 980846, 1127464
Test: Chrome camera app (SWA version) can use SharedWorker
Change-Id: Ia57a18d75963fb3395a37d2ed3c70d21e7964282
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2406234
Commit-Queue: Wei Lee <wtlee@chromium.org>
Reviewed-by: default avatarNasko Oskov <nasko@chromium.org>
Reviewed-by: default avatarGiovanni Ortuño Urquidi <ortuno@chromium.org>
Reviewed-by: default avatarMatt Falkenhagen <falken@chromium.org>
Cr-Commit-Position: refs/heads/master@{#810487}
parent f56ca6b5
......@@ -17,6 +17,7 @@
#include "base/test/bind_test_util.h"
#include "base/test/simple_test_tick_clock.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "content/browser/webui/content_web_ui_controller_factory.h"
#include "content/browser/webui/web_ui_impl.h"
#include "content/public/browser/child_process_security_policy.h"
......@@ -33,6 +34,7 @@
#include "content/public/test/test_utils.h"
#include "content/public/test/web_ui_browsertest_util.h"
#include "content/shell/browser/shell.h"
#include "testing/gmock/include/gmock/gmock-matchers.h"
#include "third_party/blink/public/common/input/web_mouse_event.h"
#include "third_party/blink/public/common/input/web_mouse_wheel_event.h"
#include "ui/events/base_event_utils.h"
......@@ -43,6 +45,16 @@ namespace {
using WebUIImplBrowserTest = ContentBrowserTest;
const char kLoadSharedWorkerScript[] = R"(
new Promise((resolve) => {
const sharedWorker = new SharedWorker($1);
sharedWorker.port.onmessage = (event) => {
resolve(event.data === 'pong');
};
sharedWorker.port.postMessage('ping');
});
)";
class TestWebUIMessageHandler : public WebUIMessageHandler {
public:
void RegisterMessages() override {
......@@ -519,4 +531,72 @@ IN_PROC_BROWSER_TEST_F(WebUIRequestSchemesTest,
}
}
class WebUIWorkerTest : public ContentBrowserTest {
public:
WebUIWorkerTest() { WebUIControllerFactory::RegisterFactory(&factory_); }
~WebUIWorkerTest() override {
WebUIControllerFactory::UnregisterFactoryForTesting(&factory_);
}
WebUIWorkerTest(const WebUIWorkerTest&) = delete;
WebUIWorkerTest& operator=(const WebUIWorkerTest&) = delete;
private:
TestWebUIControllerFactory factory_;
};
// TODO(crbug.com/154571): Shared workers are not available on Android.
#if defined(OS_ANDROID)
#define MAYBE_CanCreateWebUISharedWorkerForWebUI \
DISABLED_CanCreateWebUISharedWorkerForWebUI
#define MAYBE_CannotCreateWebUISharedWorkerForNonWebUI \
DISABLED_CannotCreateWebUISharedWorkerForNonWebUI
#else
#define MAYBE_CanCreateWebUISharedWorkerForWebUI \
CanCreateWebUISharedWorkerForWebUI
#define MAYBE_CannotCreateWebUISharedWorkerForNonWebUI \
CannotCreateWebUISharedWorkerForNonWebUI
#endif
// Verify that we can create SharedWorker with scheme "chrome://" under
// WebUI page.
IN_PROC_BROWSER_TEST_F(WebUIWorkerTest, CanCreateWebUISharedWorkerForWebUI) {
const GURL web_ui_url =
GURL(GetWebUIURL("test-host/title2.html?notrustedtypes=true"));
const GURL web_ui_worker_url =
GURL(GetWebUIURL("test-host/web_ui_shared_worker.js"));
auto* web_contents = shell()->web_contents();
ASSERT_TRUE(NavigateToURL(web_contents, web_ui_url));
EXPECT_EQ(true, EvalJs(web_contents,
JsReplace(kLoadSharedWorkerScript,
web_ui_worker_url.spec().c_str()),
EXECUTE_SCRIPT_DEFAULT_OPTIONS, 1 /* world_id */));
}
// Verify that pages with scheme other than "chrome://" cannot create
// SharedWorker with scheme "chrome://".
IN_PROC_BROWSER_TEST_F(WebUIWorkerTest,
CannotCreateWebUISharedWorkerForNonWebUI) {
ASSERT_TRUE(embedded_test_server()->Start());
const GURL non_web_ui_url =
GURL(embedded_test_server()->GetURL("/title1.html?notrustedtypes=true"));
const GURL web_ui_worker_url =
GURL(GetWebUIURL("test-host/web_ui_shared_worker.js"));
auto* web_contents = shell()->web_contents();
ASSERT_TRUE(NavigateToURL(web_contents, non_web_ui_url));
auto result = EvalJs(
web_contents,
JsReplace(kLoadSharedWorkerScript, web_ui_worker_url.spec().c_str()),
EXECUTE_SCRIPT_DEFAULT_OPTIONS, 1 /* world_id */);
std::string expected_failure = R"(a JavaScript error:
Error: Failed to construct 'SharedWorker')";
EXPECT_THAT(result.error, ::testing::StartsWith(expected_failure));
}
} // namespace content
......@@ -502,6 +502,13 @@ void DedicatedWorkerHost::UpdateSubresourceLoaderFactories() {
// Start observing Network Service crash again.
ObserveNetworkServiceCrash(storage_partition_impl);
// If this is a nested worker, there is no creator frame and
// |creator_render_frame_host| will be null.
RenderFrameHostImpl* creator_render_frame_host =
creator_render_frame_host_id_
? RenderFrameHostImpl::FromID(creator_render_frame_host_id_.value())
: nullptr;
// Recreate the default URLLoaderFactory. This doesn't support
// AppCache-specific factory.
std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
......@@ -510,7 +517,7 @@ void DedicatedWorkerHost::UpdateSubresourceLoaderFactories() {
WorkerScriptFetchInitiator::LoaderType::kSubResource,
worker_process_host_->GetID(), storage_partition_impl,
partition_domain, file_url_support_,
/*filesystem_url_support=*/true);
/*filesystem_url_support=*/true, creator_render_frame_host);
bool bypass_redirect_checks = false;
subresource_loader_factories->pending_default_factory() =
......
......@@ -38,6 +38,7 @@
#include "content/public/browser/resource_context.h"
#include "content/public/browser/shared_cors_origin_access_list.h"
#include "content/public/browser/url_loader_throttles.h"
#include "content/public/browser/web_ui_url_loader_factory.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_features.h"
#include "content/public/common/referrer.h"
......@@ -56,11 +57,6 @@
namespace content {
namespace {
} // namespace
// static
void WorkerScriptFetchInitiator::Start(
int worker_process_id,
......@@ -111,11 +107,13 @@ void WorkerScriptFetchInitiator::Start(
std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
factory_bundle_for_browser = CreateFactoryBundle(
LoaderType::kMainResource, worker_process_id, storage_partition,
storage_domain, constructor_uses_file_url, filesystem_url_support);
storage_domain, constructor_uses_file_url, filesystem_url_support,
creator_render_frame_host);
std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
subresource_loader_factories = CreateFactoryBundle(
LoaderType::kSubResource, worker_process_id, storage_partition,
storage_domain, constructor_uses_file_url, filesystem_url_support);
storage_domain, constructor_uses_file_url, filesystem_url_support,
creator_render_frame_host);
// Create a resource request for initiating worker script fetch from the
// browser process.
......@@ -192,7 +190,8 @@ WorkerScriptFetchInitiator::CreateFactoryBundle(
StoragePartitionImpl* storage_partition,
const std::string& storage_domain,
bool file_support,
bool filesystem_url_support) {
bool filesystem_url_support,
RenderFrameHost* creator_render_frame_host) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
ContentBrowserClient::NonNetworkURLLoaderFactoryDeprecatedMap
......@@ -238,6 +237,22 @@ WorkerScriptFetchInitiator::CreateFactoryBundle(
break;
}
// Create WebUI loader for chrome:// workers from WebUI frames.
// TODO(crbug.com/1128243): Enable shared worker on "chrome-untrusted://" as
// well.
if (creator_render_frame_host) {
auto requesting_scheme =
creator_render_frame_host->GetLastCommittedOrigin().scheme();
if (requesting_scheme == kChromeUIScheme &&
creator_render_frame_host->GetWebUI() != nullptr) {
non_network_factories.emplace(
kChromeUIScheme,
CreateWebUIURLLoaderFactory(
creator_render_frame_host, kChromeUIScheme,
/*allowed_webui_hosts=*/base::flat_set<std::string>()));
}
}
auto factory_bundle =
std::make_unique<blink::PendingURLLoaderFactoryBundle>();
for (auto& pair : non_network_uniquely_owned_factories) {
......
......@@ -91,14 +91,16 @@ class CONTENT_EXPORT WorkerScriptFetchInitiator {
// Used for specifying how URLLoaderFactoryBundle is used.
enum class LoaderType { kMainResource, kSubResource };
// Creates a loader factory bundle. Must be called on the UI thread.
// Creates a loader factory bundle. Must be called on the UI thread. For
// nested workers, |creator_render_frame_host| can be null.
static std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
CreateFactoryBundle(LoaderType loader_type,
int worker_process_id,
StoragePartitionImpl* storage_partition,
const std::string& storage_domain,
bool file_support,
bool filesystem_url_support);
bool filesystem_url_support,
RenderFrameHost* creator_render_frame_host);
private:
FRIEND_TEST_ALL_PREFIXES(WorkerScriptFetchInitiatorTest,
......
// 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.
onconnect = (event) => {
const port = event.ports[0];
port.onmessage = (e) => {
if (e.data === 'ping') {
port.postMessage('pong');
}
};
};
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