Commit 0b868ca7 authored by Hiroki Nakagawa's avatar Hiroki Nakagawa Committed by Commit Bot

Worker: Factor out the impl of the 'shadow page' concept into its own class

For code cleanup, this CL factors out the implementation of the 'shadow page'
concept from WebEmbeddedWorkerImpl and WebSharedWorkerImpl into
WorkerShadowPage.

<What's the 'shadow page'?>

The 'shadow page' concept was introduced for providing script loading on
out-of-process workers (i.e., SharedWorker and ServiceWorker). Loading
components are strongly associated with frames, but such the workers don't have
frames. The 'shadow page' provides a virtual frame to them.

Bug: 500856
Change-Id: I0e4cbbbf5ca784ac04b6a50e54689f141e9cb890
Reviewed-on: https://chromium-review.googlesource.com/593527
Commit-Queue: Hiroki Nakagawa <nhiroki@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarMakoto Shimazu <shimazu@chromium.org>
Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Reviewed-by: default avatarMatt Falkenhagen <falken@chromium.org>
Cr-Commit-Position: refs/heads/master@{#491284}
parent 49d1e1f8
......@@ -93,6 +93,8 @@ blink_core_sources("exported") {
"WebViewBase.h",
"WebViewImpl.cpp",
"WebViewImpl.h",
"WorkerShadowPage.cpp",
"WorkerShadowPage.h",
]
jumbo_excluded_sources = [
......
......@@ -36,9 +36,6 @@
#include "core/dom/Document.h"
#include "core/dom/TaskRunnerHelper.h"
#include "core/events/MessageEvent.h"
#include "core/exported/WebDocumentLoaderImpl.h"
#include "core/exported/WebViewImpl.h"
#include "core/frame/WebLocalFrameImpl.h"
#include "core/inspector/ConsoleMessage.h"
#include "core/loader/FrameLoadRequest.h"
#include "core/loader/FrameLoader.h"
......@@ -73,39 +70,20 @@
#include "public/platform/WebWorkerFetchContext.h"
#include "public/platform/modules/serviceworker/WebServiceWorkerNetworkProvider.h"
#include "public/web/WebDevToolsAgent.h"
#include "public/web/WebFrame.h"
#include "public/web/WebSettings.h"
#include "public/web/WebView.h"
#include "public/web/shared_worker_content_settings_proxy.mojom-blink.h"
namespace blink {
// TODO(toyoshim): Share implementation with WebEmbeddedWorkerImpl as much as
// possible.
WebSharedWorkerImpl::WebSharedWorkerImpl(WebSharedWorkerClient* client)
: web_view_(nullptr),
main_frame_(nullptr),
asked_to_terminate_(false),
worker_inspector_proxy_(WorkerInspectorProxy::Create()),
: worker_inspector_proxy_(WorkerInspectorProxy::Create()),
client_(client),
pause_worker_context_on_start_(false),
is_paused_on_start_(false),
creation_address_space_(kWebAddressSpacePublic) {
DCHECK(IsMainThread());
service_manager::mojom::InterfaceProviderPtr provider;
mojo::MakeRequest(&provider);
interface_provider_.Bind(std::move(provider));
}
WebSharedWorkerImpl::~WebSharedWorkerImpl() {
DCHECK(IsMainThread());
DCHECK(web_view_);
// Detach the client before closing the view to avoid getting called back.
main_frame_->SetClient(0);
web_view_->Close();
main_frame_->Close();
}
void WebSharedWorkerImpl::TerminateWorkerThread() {
......@@ -125,35 +103,6 @@ void WebSharedWorkerImpl::TerminateWorkerThread() {
worker_inspector_proxy_->WorkerThreadTerminated();
}
void WebSharedWorkerImpl::InitializeLoader(bool data_saver_enabled) {
DCHECK(IsMainThread());
// Create 'shadow page'. This page is never displayed, it is used to proxy the
// loading requests from the worker context to the rest of WebKit and Chromium
// infrastructure.
DCHECK(!web_view_);
web_view_ = WebViewImpl::Create(nullptr, kWebPageVisibilityStateVisible);
// FIXME: http://crbug.com/363843. This needs to find a better way to
// not create graphics layers.
web_view_->GetSettings()->SetAcceleratedCompositingEnabled(false);
web_view_->GetSettings()->SetDataSaverEnabled(data_saver_enabled);
// FIXME: Settings information should be passed to the Worker process from
// Browser process when the worker is created (similar to
// RenderThread::OnCreateNewView).
main_frame_ = WebLocalFrameImpl::CreateMainFrame(
web_view_, this, nullptr, nullptr, g_empty_atom, WebSandboxFlags::kNone);
main_frame_->SetDevToolsAgentClient(this);
// If we were asked to pause worker context on start and wait for debugger
// then it is the good time to do that.
client_->WorkerReadyForInspection();
if (pause_worker_context_on_start_) {
is_paused_on_start_ = true;
return;
}
LoadShadowPage();
}
std::unique_ptr<WebApplicationCacheHost>
WebSharedWorkerImpl::CreateApplicationCacheHost(
WebApplicationCacheHostClient* appcache_host_client) {
......@@ -161,34 +110,12 @@ WebSharedWorkerImpl::CreateApplicationCacheHost(
return client_->CreateApplicationCacheHost(appcache_host_client);
}
void WebSharedWorkerImpl::LoadShadowPage() {
DCHECK(IsMainThread());
// Construct substitute data source for the 'shadow page'. We only need it
// to have same origin as the worker so the loading checks work correctly.
CString content("");
RefPtr<SharedBuffer> buffer(
SharedBuffer::Create(content.data(), content.length()));
main_frame_->GetFrame()->Loader().Load(FrameLoadRequest(
0, ResourceRequest(url_),
SubstituteData(buffer, "text/html", "UTF-8", NullURL())));
}
void WebSharedWorkerImpl::FrameDetached(WebLocalFrame* frame, DetachType type) {
DCHECK(type == DetachType::kRemove && frame->Parent());
DCHECK(frame->FrameWidget());
frame->Close();
}
void WebSharedWorkerImpl::DidFinishDocumentLoad() {
void WebSharedWorkerImpl::OnShadowPageInitialized() {
DCHECK(IsMainThread());
DCHECK(!loading_document_);
DCHECK(!main_script_loader_);
main_frame_->GetDocumentLoader()->SetServiceWorkerNetworkProvider(
shadow_page_->DocumentLoader()->SetServiceWorkerNetworkProvider(
client_->CreateServiceWorkerNetworkProvider());
main_script_loader_ = WorkerScriptLoader::Create();
loading_document_ = main_frame_->GetFrame()->GetDocument();
WebURLRequest::FetchRequestMode fetch_request_mode =
WebURLRequest::kFetchRequestModeSameOrigin;
......@@ -200,22 +127,17 @@ void WebSharedWorkerImpl::DidFinishDocumentLoad() {
}
main_script_loader_->LoadAsynchronously(
*loading_document_.Get(), url_,
*shadow_page_->GetDocument(), url_,
WebURLRequest::kRequestContextSharedWorker, fetch_request_mode,
fetch_credentials_mode, creation_address_space_,
Bind(&WebSharedWorkerImpl::DidReceiveScriptLoaderResponse,
WTF::Unretained(this)),
Bind(&WebSharedWorkerImpl::OnScriptLoaderFinished,
WTF::Unretained(this)));
// Do nothing here since onScriptLoaderFinished() might have been already
// Do nothing here since OnScriptLoaderFinished() might have been already
// invoked and |this| might have been deleted at this point.
}
service_manager::InterfaceProvider*
WebSharedWorkerImpl::GetInterfaceProvider() {
return &interface_provider_;
}
void WebSharedWorkerImpl::SendProtocolMessage(int session_id,
int call_id,
const WebString& message,
......@@ -228,8 +150,10 @@ void WebSharedWorkerImpl::ResumeStartup() {
DCHECK(IsMainThread());
bool is_paused_on_start = is_paused_on_start_;
is_paused_on_start_ = false;
if (is_paused_on_start)
LoadShadowPage();
if (is_paused_on_start) {
// We'll continue in OnShadowPageInitialized().
shadow_page_->Initialize(url_);
}
}
WebDevToolsAgentClient::WebKitClientMessageLoop*
......@@ -305,19 +229,31 @@ void WebSharedWorkerImpl::StartWorkerContext(
content_settings_info_ =
mojom::blink::SharedWorkerContentSettingsProxyPtrInfo(
std::move(content_settings_handle), 0u);
InitializeLoader(data_saver_enabled);
shadow_page_ = WTF::MakeUnique<WorkerShadowPage>(this);
shadow_page_->GetSettings()->SetDataSaverEnabled(data_saver_enabled);
// If we were asked to pause worker context on start and wait for debugger
// then now is a good time to do that.
client_->WorkerReadyForInspection();
if (pause_worker_context_on_start_) {
is_paused_on_start_ = true;
return;
}
// We'll continue in OnShadowPageInitialized().
shadow_page_->Initialize(url_);
}
void WebSharedWorkerImpl::DidReceiveScriptLoaderResponse() {
DCHECK(IsMainThread());
probe::didReceiveScriptResponse(loading_document_,
probe::didReceiveScriptResponse(shadow_page_->GetDocument(),
main_script_loader_->Identifier());
client_->SelectAppCacheID(main_script_loader_->AppCacheID());
}
void WebSharedWorkerImpl::OnScriptLoaderFinished() {
DCHECK(IsMainThread());
DCHECK(loading_document_);
DCHECK(main_script_loader_);
if (asked_to_terminate_)
return;
......@@ -334,7 +270,8 @@ void WebSharedWorkerImpl::OnScriptLoaderFinished() {
// FIXME: this document's origin is pristine and without any extra privileges
// (e.g. GrantUniversalAccess) that can be overriden in regular documents
// via WebPreference by embedders. (crbug.com/254993)
SecurityOrigin* starter_origin = loading_document_->GetSecurityOrigin();
Document* document = shadow_page_->GetDocument();
SecurityOrigin* starter_origin = document->GetSecurityOrigin();
WorkerClients* worker_clients = WorkerClients::Create();
CoreInitializer::GetInstance().ProvideLocalFileSystemToWorker(
......@@ -349,18 +286,17 @@ void WebSharedWorkerImpl::OnScriptLoaderFinished() {
if (RuntimeEnabledFeatures::OffMainThreadFetchEnabled()) {
std::unique_ptr<WebWorkerFetchContext> web_worker_fetch_context =
client_->CreateWorkerFetchContext(
WebLocalFrameBase::FromFrame(main_frame_->GetFrame())
->GetDocumentLoader()
->GetServiceWorkerNetworkProvider());
shadow_page_->DocumentLoader()->GetServiceWorkerNetworkProvider());
DCHECK(web_worker_fetch_context);
web_worker_fetch_context->SetApplicationCacheHostID(
main_frame_->GetFrame()
->GetDocument()
shadow_page_->GetDocument()
->Fetcher()
->Context()
.ApplicationCacheHostID());
web_worker_fetch_context->SetDataSaverEnabled(
main_frame_->GetFrame()->GetSettings()->GetDataSaverEnabled());
web_worker_fetch_context->SetDataSaverEnabled(shadow_page_->GetDocument()
->GetFrame()
->GetSettings()
->GetDataSaverEnabled());
ProvideWorkerFetchContextToWorker(worker_clients,
std::move(web_worker_fetch_context));
}
......@@ -368,13 +304,14 @@ void WebSharedWorkerImpl::OnScriptLoaderFinished() {
ContentSecurityPolicy* content_security_policy =
main_script_loader_->ReleaseContentSecurityPolicy();
WorkerThreadStartMode start_mode =
worker_inspector_proxy_->WorkerStartMode(loading_document_);
std::unique_ptr<WorkerSettings> worker_settings = WTF::WrapUnique(
new WorkerSettings(main_frame_->GetFrame()->GetSettings()));
worker_inspector_proxy_->WorkerStartMode(document);
std::unique_ptr<WorkerSettings> worker_settings =
WTF::WrapUnique(new WorkerSettings(
shadow_page_->GetDocument()->GetFrame()->GetSettings()));
auto global_scope_creation_params =
WTF::MakeUnique<GlobalScopeCreationParams>(
url_, loading_document_->UserAgent(),
main_script_loader_->SourceText(), nullptr, start_mode,
url_, document->UserAgent(), main_script_loader_->SourceText(),
nullptr, start_mode,
content_security_policy ? content_security_policy->Headers().get()
: nullptr,
main_script_loader_->GetReferrerPolicy(), starter_origin,
......@@ -392,10 +329,8 @@ void WebSharedWorkerImpl::OnScriptLoaderFinished() {
reporting_proxy_ = new SharedWorkerReportingProxy(this, task_runners);
worker_thread_ = WTF::MakeUnique<SharedWorkerThread>(
name_,
ThreadableLoadingContext::Create(*ToDocument(loading_document_.Get())),
*reporting_proxy_);
probe::scriptImported(loading_document_, main_script_loader_->Identifier(),
name_, ThreadableLoadingContext::Create(*document), *reporting_proxy_);
probe::scriptImported(document, main_script_loader_->Identifier(),
main_script_loader_->SourceText());
main_script_loader_.Clear();
......@@ -405,8 +340,8 @@ void WebSharedWorkerImpl::OnScriptLoaderFinished() {
GetWorkerThread()->Start(std::move(global_scope_creation_params),
thread_startup_data, task_runners);
worker_inspector_proxy_->WorkerThreadCreated(ToDocument(loading_document_),
GetWorkerThread(), url_);
worker_inspector_proxy_->WorkerThreadCreated(document, GetWorkerThread(),
url_);
client_->WorkerScriptLoaded();
}
......@@ -421,7 +356,7 @@ void WebSharedWorkerImpl::PauseWorkerContextOnStart() {
void WebSharedWorkerImpl::AttachDevTools(const WebString& host_id,
int session_id) {
WebDevToolsAgent* devtools_agent = main_frame_->DevToolsAgent();
WebDevToolsAgent* devtools_agent = shadow_page_->DevToolsAgent();
if (devtools_agent)
devtools_agent->Attach(host_id, session_id);
}
......@@ -429,14 +364,14 @@ void WebSharedWorkerImpl::AttachDevTools(const WebString& host_id,
void WebSharedWorkerImpl::ReattachDevTools(const WebString& host_id,
int session_id,
const WebString& saved_state) {
WebDevToolsAgent* devtools_agent = main_frame_->DevToolsAgent();
WebDevToolsAgent* devtools_agent = shadow_page_->DevToolsAgent();
if (devtools_agent)
devtools_agent->Reattach(host_id, session_id, saved_state);
ResumeStartup();
}
void WebSharedWorkerImpl::DetachDevTools(int session_id) {
WebDevToolsAgent* devtools_agent = main_frame_->DevToolsAgent();
WebDevToolsAgent* devtools_agent = shadow_page_->DevToolsAgent();
if (devtools_agent)
devtools_agent->Detach(session_id);
}
......@@ -447,7 +382,7 @@ void WebSharedWorkerImpl::DispatchDevToolsMessage(int session_id,
const WebString& message) {
if (asked_to_terminate_)
return;
WebDevToolsAgent* devtools_agent = main_frame_->DevToolsAgent();
WebDevToolsAgent* devtools_agent = shadow_page_->DevToolsAgent();
if (devtools_agent) {
devtools_agent->DispatchOnInspectorBackend(session_id, call_id, method,
message);
......
......@@ -35,17 +35,15 @@
#include <memory>
#include "core/CoreExport.h"
#include "core/dom/ExecutionContext.h"
#include "core/exported/WorkerShadowPage.h"
#include "core/workers/SharedWorkerReportingProxy.h"
#include "core/workers/WorkerClients.h"
#include "core/workers/WorkerThread.h"
#include "platform/WebTaskRunner.h"
#include "platform/wtf/RefPtr.h"
#include "public/platform/Platform.h"
#include "public/platform/WebAddressSpace.h"
#include "public/platform/WebContentSecurityPolicy.h"
#include "public/web/WebDevToolsAgentClient.h"
#include "public/web/WebFrameClient.h"
#include "public/web/WebSharedWorkerClient.h"
#include "public/web/shared_worker_content_settings_proxy.mojom-blink.h"
......@@ -53,12 +51,10 @@ namespace blink {
class WebApplicationCacheHost;
class WebApplicationCacheHostClient;
class WebLocalFrameBase;
class WebServiceWorkerNetworkProvider;
class WebSharedWorkerClient;
class WebString;
class WebURL;
class WebView;
class WorkerInspectorProxy;
class WorkerScriptLoader;
......@@ -66,19 +62,15 @@ class WorkerScriptLoader;
// implementation. This is basically accessed on the main thread, but some
// methods must be called from a worker thread. Such methods are suffixed with
// *OnWorkerThread or have header comments.
class CORE_EXPORT WebSharedWorkerImpl final
: public WebFrameClient,
public WebSharedWorker,
NON_EXPORTED_BASE(public WebDevToolsAgentClient) {
class CORE_EXPORT WebSharedWorkerImpl final : public WebSharedWorker,
public WorkerShadowPage::Client {
public:
explicit WebSharedWorkerImpl(WebSharedWorkerClient*);
// WebFrameClient methods to support resource loading thru the 'shadow page'.
// WorkerShadowPage::Client overrides.
std::unique_ptr<WebApplicationCacheHost> CreateApplicationCacheHost(
WebApplicationCacheHostClient*) override;
void FrameDetached(WebLocalFrame*, DetachType) override;
void DidFinishDocumentLoad() override;
service_manager::InterfaceProvider* GetInterfaceProvider() override;
void OnShadowPageInitialized() override;
// WebDevToolsAgentClient overrides.
void SendProtocolMessage(int session_id,
......@@ -112,13 +104,6 @@ class CORE_EXPORT WebSharedWorkerImpl final
const WebString& method,
const WebString& message) override;
std::unique_ptr<blink::WebURLLoader> CreateURLLoader(
const WebURLRequest& request,
SingleThreadTaskRunner* task_runner) override {
// TODO(yhirano): Stop using Platform::CreateURLLoader() here.
return Platform::Current()->CreateURLLoader(request, task_runner);
}
// Callback methods for SharedWorkerReportingProxy.
void CountFeature(WebFeature);
void PostMessageToPageInspector(int session_id, const String& message);
......@@ -133,22 +118,12 @@ class CORE_EXPORT WebSharedWorkerImpl final
// Shuts down the worker thread.
void TerminateWorkerThread();
// Creates the shadow loader used for worker network requests.
void InitializeLoader(bool data_saver_enabled);
void LoadShadowPage();
void DidReceiveScriptLoaderResponse();
void OnScriptLoaderFinished();
void ConnectTaskOnWorkerThread(std::unique_ptr<WebMessagePortChannel>);
// 'shadow page' - created to proxy loading requests from the worker.
// Will be accessed by worker thread when posting tasks.
Persistent<ExecutionContext> loading_document_;
Persistent<ThreadableLoadingContext> loading_context_;
WebView* web_view_;
Persistent<WebLocalFrameBase> main_frame_;
bool asked_to_terminate_;
std::unique_ptr<WorkerShadowPage> shadow_page_;
std::unique_ptr<WebServiceWorkerNetworkProvider> network_provider_;
......@@ -156,13 +131,13 @@ class CORE_EXPORT WebSharedWorkerImpl final
Persistent<SharedWorkerReportingProxy> reporting_proxy_;
std::unique_ptr<WorkerThread> worker_thread_;
service_manager::InterfaceProvider interface_provider_;
mojom::blink::SharedWorkerContentSettingsProxyPtrInfo content_settings_info_;
WebSharedWorkerClient* client_;
bool pause_worker_context_on_start_;
bool is_paused_on_start_;
bool asked_to_terminate_ = false;
bool pause_worker_context_on_start_ = false;
bool is_paused_on_start_ = false;
// Kept around only while main script loading is ongoing.
RefPtr<WorkerScriptLoader> main_script_loader_;
......
// Copyright 2017 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 "core/exported/WorkerShadowPage.h"
#include "core/exported/WebViewImpl.h"
#include "core/frame/csp/ContentSecurityPolicy.h"
#include "public/platform/Platform.h"
#include "public/web/WebSettings.h"
namespace blink {
WorkerShadowPage::WorkerShadowPage(Client* client)
: web_view_(WebViewImpl::Create(nullptr, kWebPageVisibilityStateVisible)),
main_frame_(WebLocalFrameImpl::CreateMainFrame(web_view_,
this,
nullptr,
nullptr,
g_empty_atom,
WebSandboxFlags::kNone)),
client_(client) {
DCHECK(IsMainThread());
// TODO(http://crbug.com/363843): This needs to find a better way to
// not create graphics layers.
web_view_->GetSettings()->SetAcceleratedCompositingEnabled(false);
main_frame_->SetDevToolsAgentClient(client_);
// Create an empty InterfaceProvider because WebFrameClient subclasses are
// required to do it even if it's not used.
// See https://chromium-review.googlesource.com/c/576370
service_manager::mojom::InterfaceProviderPtr provider;
mojo::MakeRequest(&provider);
interface_provider_.Bind(std::move(provider));
}
WorkerShadowPage::~WorkerShadowPage() {
DCHECK(IsMainThread());
// Detach the client before closing the view to avoid getting called back.
main_frame_->SetClient(nullptr);
web_view_->Close();
main_frame_->Close();
}
void WorkerShadowPage::Initialize(const KURL& script_url) {
DCHECK(IsMainThread());
AdvanceState(State::kInitializing);
// Construct substitute data source. We only need it to have same origin as
// the worker so the loading checks work correctly.
CString content("");
RefPtr<SharedBuffer> buffer(
SharedBuffer::Create(content.data(), content.length()));
main_frame_->GetFrame()->Loader().Load(
FrameLoadRequest(0, ResourceRequest(script_url), SubstituteData(buffer)));
}
void WorkerShadowPage::SetContentSecurityPolicyAndReferrerPolicy(
ContentSecurityPolicyResponseHeaders csp_headers,
String referrer_policy) {
DCHECK(IsMainThread());
Document* document = main_frame_->GetFrame()->GetDocument();
ContentSecurityPolicy* content_security_policy =
ContentSecurityPolicy::Create();
content_security_policy->SetOverrideURLForSelf(document->Url());
content_security_policy->DidReceiveHeaders(csp_headers);
document->InitContentSecurityPolicy(content_security_policy);
if (!referrer_policy.IsNull())
document->ParseAndSetReferrerPolicy(referrer_policy);
}
void WorkerShadowPage::DidFinishDocumentLoad() {
DCHECK(IsMainThread());
AdvanceState(State::kInitialized);
client_->OnShadowPageInitialized();
}
std::unique_ptr<WebApplicationCacheHost>
WorkerShadowPage::CreateApplicationCacheHost(
WebApplicationCacheHostClient* appcache_host_client) {
DCHECK(IsMainThread());
return client_->CreateApplicationCacheHost(appcache_host_client);
}
void WorkerShadowPage::FrameDetached(WebLocalFrame* frame, DetachType type) {
DCHECK(IsMainThread());
DCHECK(type == DetachType::kRemove && frame->Parent());
DCHECK(frame->FrameWidget());
frame->Close();
}
service_manager::InterfaceProvider* WorkerShadowPage::GetInterfaceProvider() {
DCHECK(IsMainThread());
return &interface_provider_;
}
std::unique_ptr<blink::WebURLLoader> WorkerShadowPage::CreateURLLoader(
const WebURLRequest& request,
SingleThreadTaskRunner* task_runner) {
DCHECK(IsMainThread());
// TODO(yhirano): Stop using Platform::CreateURLLoader() here.
return Platform::Current()->CreateURLLoader(request, task_runner);
}
bool WorkerShadowPage::WasInitialized() const {
return state_ == State::kInitialized;
}
void WorkerShadowPage::AdvanceState(State new_state) {
switch (new_state) {
case State::kUninitialized:
NOTREACHED();
return;
case State::kInitializing:
DCHECK_EQ(State::kUninitialized, state_);
state_ = new_state;
return;
case State::kInitialized:
DCHECK_EQ(State::kInitializing, state_);
state_ = new_state;
return;
}
}
} // namespace blink
// Copyright 2017 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 WorkerShadowPage_h
#define WorkerShadowPage_h
#include "core/frame/WebLocalFrameImpl.h"
#include "platform/network/ContentSecurityPolicyResponseHeaders.h"
#include "public/web/WebDevToolsAgentClient.h"
#include "public/web/WebDocumentLoader.h"
#include "public/web/WebFrameClient.h"
#include "public/web/WebView.h"
#include "services/service_manager/public/cpp/interface_provider.h"
namespace blink {
class WebApplicationCacheHost;
class WebApplicationCacheHostClient;
class WebSettings;
// WorkerShadowPage implements the 'shadow page' concept.
//
// Loading components are strongly associated with frames, but out-of-process
// workers (i.e., SharedWorker and ServiceWorker) don't have frames. To enable
// loading on such workers, this class provides a virtual frame (a.k.a, shadow
// page) to them.
//
// WorkerShadowPage lives on the main thread.
//
// TODO(nhiroki): Move this into core/workers once all dependencies on
// core/exported are gone (now depending on core/exported/WebViewImpl.h in
// *.cpp).
// TODO(kinuko): Make this go away (https://crbug.com/538751).
class CORE_EXPORT WorkerShadowPage : public WebFrameClient {
public:
class CORE_EXPORT Client : NON_EXPORTED_BASE(public WebDevToolsAgentClient) {
public:
virtual ~Client() {}
// Called when the shadow page is requested to create an application cache
// host.
virtual std::unique_ptr<WebApplicationCacheHost> CreateApplicationCacheHost(
WebApplicationCacheHostClient*) = 0;
// Called when Initialize() is completed.
virtual void OnShadowPageInitialized() = 0;
};
explicit WorkerShadowPage(Client*);
~WorkerShadowPage() override;
// Calls Client::OnShadowPageInitialized() when complete.
void Initialize(const KURL& script_url);
void SetContentSecurityPolicyAndReferrerPolicy(
ContentSecurityPolicyResponseHeaders csp_headers,
String referrer_policy);
// WebFrameClient overrides.
std::unique_ptr<WebApplicationCacheHost> CreateApplicationCacheHost(
WebApplicationCacheHostClient*) override;
void FrameDetached(WebLocalFrame*, DetachType) override;
void DidFinishDocumentLoad() override;
service_manager::InterfaceProvider* GetInterfaceProvider() override;
std::unique_ptr<blink::WebURLLoader> CreateURLLoader(
const WebURLRequest&,
SingleThreadTaskRunner*) override;
Document* GetDocument() { return main_frame_->GetFrame()->GetDocument(); }
WebSettings* GetSettings() { return web_view_->GetSettings(); }
WebDocumentLoader* DocumentLoader() {
return main_frame_->GetDocumentLoader();
}
WebDevToolsAgent* DevToolsAgent() { return main_frame_->DevToolsAgent(); }
bool WasInitialized() const;
private:
enum class State { kUninitialized, kInitializing, kInitialized };
void AdvanceState(State);
WebView* web_view_;
Persistent<WebLocalFrameImpl> main_frame_;
Client* client_;
service_manager::InterfaceProvider interface_provider_;
State state_ = State::kUninitialized;
};
} // namespace blink
#endif // WorkerShadowPage_h
......@@ -35,16 +35,12 @@
#include "core/dom/Document.h"
#include "core/dom/SecurityContext.h"
#include "core/dom/TaskRunnerHelper.h"
#include "core/exported/WebDocumentLoaderImpl.h"
#include "core/exported/WebViewImpl.h"
#include "core/frame/WebLocalFrameImpl.h"
#include "core/frame/csp/ContentSecurityPolicy.h"
#include "core/inspector/ConsoleMessage.h"
#include "core/loader/FrameLoadRequest.h"
#include "core/loader/ThreadableLoadingContext.h"
#include "core/loader/WorkerFetchContext.h"
#include "core/probe/CoreProbes.h"
#include "core/workers/GlobalScopeCreationParams.h"
#include "core/workers/ParentFrameTaskRunners.h"
#include "core/workers/WorkerBackingThreadStartupData.h"
#include "core/workers/WorkerContentSettingsClient.h"
......@@ -78,7 +74,6 @@
#include "public/web/WebConsoleMessage.h"
#include "public/web/WebDevToolsAgent.h"
#include "public/web/WebSettings.h"
#include "public/web/WebView.h"
#include "public/web/modules/serviceworker/WebServiceWorkerContextClient.h"
namespace blink {
......@@ -101,10 +96,6 @@ WebEmbeddedWorkerImpl::WebEmbeddedWorkerImpl(
: worker_context_client_(std::move(client)),
content_settings_client_(std::move(content_settings_client)),
worker_inspector_proxy_(WorkerInspectorProxy::Create()),
web_view_(nullptr),
main_frame_(nullptr),
loading_shadow_page_(false),
asked_to_terminate_(false),
pause_after_download_state_(kDontPauseAfterDownload),
waiting_for_debugger_state_(kNotWaitingForDebugger) {
if (RuntimeEnabledFeatures::ServiceWorkerScriptStreamingEnabled() &&
......@@ -113,27 +104,16 @@ WebEmbeddedWorkerImpl::WebEmbeddedWorkerImpl(
WTF::MakeUnique<ServiceWorkerInstalledScriptsManager>(
std::move(installed_scripts_manager));
}
service_manager::mojom::InterfaceProviderPtr provider;
mojo::MakeRequest(&provider);
interface_provider_.Bind(std::move(provider));
}
WebEmbeddedWorkerImpl::~WebEmbeddedWorkerImpl() {
// TerminateWorkerContext() must be called before the destructor.
DCHECK(asked_to_terminate_);
DCHECK(web_view_);
// Detach the client before closing the view to avoid getting called back.
main_frame_->SetClient(0);
if (worker_global_scope_proxy_) {
worker_global_scope_proxy_->Detach();
worker_global_scope_proxy_.Clear();
}
web_view_->Close();
main_frame_->Close();
}
void WebEmbeddedWorkerImpl::StartWorkerContext(
......@@ -161,14 +141,31 @@ void WebEmbeddedWorkerImpl::StartWorkerContext(
if (data.pause_after_download_mode ==
WebEmbeddedWorkerStartData::kPauseAfterDownload)
pause_after_download_state_ = kDoPauseAfterDownload;
PrepareShadowPageForLoader();
shadow_page_ = WTF::MakeUnique<WorkerShadowPage>(this);
WebSettings* settings = shadow_page_->GetSettings();
settings->SetDataSaverEnabled(worker_start_data_.data_saver_enabled);
// Currently we block all mixed-content requests from a ServiceWorker.
settings->SetStrictMixedContentChecking(true);
settings->SetAllowRunningOfInsecureContent(false);
// If we were asked to wait for debugger then now is a good time to do that.
worker_context_client_->WorkerReadyForInspection();
if (worker_start_data_.wait_for_debugger_mode ==
WebEmbeddedWorkerStartData::kWaitForDebugger) {
waiting_for_debugger_state_ = kWaitingForDebugger;
return;
}
shadow_page_->Initialize(worker_start_data_.script_url);
}
void WebEmbeddedWorkerImpl::TerminateWorkerContext() {
if (asked_to_terminate_)
return;
asked_to_terminate_ = true;
if (loading_shadow_page_) {
if (!shadow_page_->WasInitialized()) {
// This deletes 'this'.
worker_context_client_->WorkerContextFailedToStart();
return;
......@@ -204,7 +201,7 @@ void WebEmbeddedWorkerImpl::ResumeAfterDownload() {
void WebEmbeddedWorkerImpl::AttachDevTools(const WebString& host_id,
int session_id) {
WebDevToolsAgent* devtools_agent = main_frame_->DevToolsAgent();
WebDevToolsAgent* devtools_agent = shadow_page_->DevToolsAgent();
if (devtools_agent)
devtools_agent->Attach(host_id, session_id);
}
......@@ -212,14 +209,14 @@ void WebEmbeddedWorkerImpl::AttachDevTools(const WebString& host_id,
void WebEmbeddedWorkerImpl::ReattachDevTools(const WebString& host_id,
int session_id,
const WebString& saved_state) {
WebDevToolsAgent* devtools_agent = main_frame_->DevToolsAgent();
WebDevToolsAgent* devtools_agent = shadow_page_->DevToolsAgent();
if (devtools_agent)
devtools_agent->Reattach(host_id, session_id, saved_state);
ResumeStartup();
}
void WebEmbeddedWorkerImpl::DetachDevTools(int session_id) {
WebDevToolsAgent* devtools_agent = main_frame_->DevToolsAgent();
WebDevToolsAgent* devtools_agent = shadow_page_->DevToolsAgent();
if (devtools_agent)
devtools_agent->Detach(session_id);
}
......@@ -230,7 +227,7 @@ void WebEmbeddedWorkerImpl::DispatchDevToolsMessage(int session_id,
const WebString& message) {
if (asked_to_terminate_)
return;
WebDevToolsAgent* devtools_agent = main_frame_->DevToolsAgent();
WebDevToolsAgent* devtools_agent = shadow_page_->DevToolsAgent();
if (devtools_agent) {
devtools_agent->DispatchOnInspectorBackend(session_id, call_id, method,
message);
......@@ -258,11 +255,10 @@ void WebEmbeddedWorkerImpl::AddMessageToConsole(
return;
}
main_frame_->GetFrame()->GetDocument()->AddConsoleMessage(
ConsoleMessage::Create(
kOtherMessageSource, web_core_message_level, message.text,
SourceLocation::Create(message.url, message.line_number,
message.column_number, nullptr)));
shadow_page_->GetDocument()->AddConsoleMessage(ConsoleMessage::Create(
kOtherMessageSource, web_core_message_level, message.text,
SourceLocation::Create(message.url, message.line_number,
message.column_number, nullptr)));
}
void WebEmbeddedWorkerImpl::PostMessageToPageInspector(int session_id,
......@@ -274,78 +270,22 @@ void WebEmbeddedWorkerImpl::SetContentSecurityPolicyAndReferrerPolicy(
ContentSecurityPolicyResponseHeaders csp_headers,
String referrer_policy,
WaitableEvent* event) {
Document* document = main_frame_->GetFrame()->GetDocument();
ContentSecurityPolicy* content_security_policy =
ContentSecurityPolicy::Create();
content_security_policy->SetOverrideURLForSelf(document->Url());
content_security_policy->DidReceiveHeaders(csp_headers);
document->InitContentSecurityPolicy(content_security_policy);
if (!referrer_policy.IsNull())
document->ParseAndSetReferrerPolicy(referrer_policy);
shadow_page_->SetContentSecurityPolicyAndReferrerPolicy(
std::move(csp_headers), std::move(referrer_policy));
event->Signal();
}
void WebEmbeddedWorkerImpl::PrepareShadowPageForLoader() {
// Create 'shadow page', which is never displayed and is used mainly to
// provide a context for loading on the main thread.
//
// FIXME: This does mostly same as WebSharedWorkerImpl::initializeLoader.
// This code, and probably most of the code in this class should be shared
// with SharedWorker.
DCHECK(!web_view_);
web_view_ = WebViewImpl::Create(nullptr, kWebPageVisibilityStateVisible);
WebSettings* settings = web_view_->GetSettings();
// FIXME: http://crbug.com/363843. This needs to find a better way to
// not create graphics layers.
settings->SetAcceleratedCompositingEnabled(false);
// Currently we block all mixed-content requests from a ServiceWorker.
// FIXME: When we support FetchEvent.default(), we should relax this
// restriction.
settings->SetStrictMixedContentChecking(true);
settings->SetAllowRunningOfInsecureContent(false);
settings->SetDataSaverEnabled(worker_start_data_.data_saver_enabled);
main_frame_ = WebLocalFrameImpl::CreateMainFrame(
web_view_, this, nullptr, nullptr, g_empty_atom, WebSandboxFlags::kNone);
main_frame_->SetDevToolsAgentClient(this);
// If we were asked to wait for debugger then it is the good time to do that.
worker_context_client_->WorkerReadyForInspection();
if (worker_start_data_.wait_for_debugger_mode ==
WebEmbeddedWorkerStartData::kWaitForDebugger) {
waiting_for_debugger_state_ = kWaitingForDebugger;
return;
}
LoadShadowPage();
std::unique_ptr<WebApplicationCacheHost>
WebEmbeddedWorkerImpl::CreateApplicationCacheHost(
WebApplicationCacheHostClient*) {
return nullptr;
}
void WebEmbeddedWorkerImpl::LoadShadowPage() {
// Construct substitute data source for the 'shadow page'. We only need it
// to have same origin as the worker so the loading checks work correctly.
CString content("");
RefPtr<SharedBuffer> buffer(
SharedBuffer::Create(content.data(), content.length()));
loading_shadow_page_ = true;
main_frame_->GetFrame()->Loader().Load(
FrameLoadRequest(0, ResourceRequest(worker_start_data_.script_url),
SubstituteData(buffer)));
}
void WebEmbeddedWorkerImpl::FrameDetached(WebLocalFrame* frame,
DetachType type) {
DCHECK(type == DetachType::kRemove && frame->Parent());
DCHECK(frame->FrameWidget());
frame->Close();
}
void WebEmbeddedWorkerImpl::OnShadowPageInitialized() {
DCHECK(!asked_to_terminate_);
void WebEmbeddedWorkerImpl::DidFinishDocumentLoad() {
DCHECK(!main_script_loader_);
DCHECK(main_frame_);
DCHECK(worker_context_client_);
DCHECK(loading_shadow_page_);
DCHECK(!asked_to_terminate_);
loading_shadow_page_ = false;
main_frame_->GetDocumentLoader()->SetServiceWorkerNetworkProvider(
shadow_page_->DocumentLoader()->SetServiceWorkerNetworkProvider(
worker_context_client_->CreateServiceWorkerNetworkProvider());
// Kickstart the worker before loading the script when the script has been
......@@ -359,9 +299,10 @@ void WebEmbeddedWorkerImpl::DidFinishDocumentLoad() {
return;
}
DCHECK(!main_script_loader_);
main_script_loader_ = WorkerScriptLoader::Create();
main_script_loader_->LoadAsynchronously(
*main_frame_->GetFrame()->GetDocument(), worker_start_data_.script_url,
*shadow_page_->GetDocument(), worker_start_data_.script_url,
WebURLRequest::kRequestContextServiceWorker,
WebURLRequest::kFetchRequestModeSameOrigin,
WebURLRequest::kFetchCredentialsModeSameOrigin,
......@@ -372,11 +313,6 @@ void WebEmbeddedWorkerImpl::DidFinishDocumentLoad() {
// invoked and |this| might have been deleted at this point.
}
service_manager::InterfaceProvider*
WebEmbeddedWorkerImpl::GetInterfaceProvider() {
return &interface_provider_;
}
void WebEmbeddedWorkerImpl::SendProtocolMessage(int session_id,
int call_id,
const WebString& message,
......@@ -389,7 +325,7 @@ void WebEmbeddedWorkerImpl::ResumeStartup() {
bool was_waiting = (waiting_for_debugger_state_ == kWaitingForDebugger);
waiting_for_debugger_state_ = kNotWaitingForDebugger;
if (was_waiting)
LoadShadowPage();
shadow_page_->Initialize(worker_start_data_.script_url);
}
WebDevToolsAgentClient::WebKitClientMessageLoop*
......@@ -436,7 +372,7 @@ void WebEmbeddedWorkerImpl::StartWorkerThread() {
DCHECK_EQ(pause_after_download_state_, kDontPauseAfterDownload);
DCHECK(!asked_to_terminate_);
Document* document = main_frame_->GetFrame()->GetDocument();
Document* document = shadow_page_->GetDocument();
// FIXME: this document's origin is pristine and without any extra privileges.
// (crbug.com/254993)
......@@ -458,8 +394,10 @@ void WebEmbeddedWorkerImpl::StartWorkerThread() {
std::unique_ptr<WebWorkerFetchContext> web_worker_fetch_context =
worker_context_client_->CreateServiceWorkerFetchContext();
DCHECK(web_worker_fetch_context);
web_worker_fetch_context->SetDataSaverEnabled(
document->GetFrame()->GetSettings()->GetDataSaverEnabled());
web_worker_fetch_context->SetDataSaverEnabled(shadow_page_->GetDocument()
->GetFrame()
->GetSettings()
->GetDataSaverEnabled());
ProvideWorkerFetchContextToWorker(worker_clients,
std::move(web_worker_fetch_context));
}
......@@ -467,7 +405,7 @@ void WebEmbeddedWorkerImpl::StartWorkerThread() {
WorkerThreadStartMode start_mode =
worker_inspector_proxy_->WorkerStartMode(document);
std::unique_ptr<WorkerSettings> worker_settings =
WTF::WrapUnique(new WorkerSettings(document->GetSettings()));
WTF::MakeUnique<WorkerSettings>(document->GetSettings());
std::unique_ptr<GlobalScopeCreationParams> global_scope_creation_params;
// |main_script_loader_| isn't created if the InstalledScriptsManager had the
......
......@@ -32,35 +32,30 @@
#define WebEmbeddedWorkerImpl_h
#include <memory>
#include "core/frame/csp/ContentSecurityPolicy.h"
#include "core/exported/WorkerShadowPage.h"
#include "core/workers/GlobalScopeCreationParams.h"
#include "core/workers/WorkerClients.h"
#include "modules/ModulesExport.h"
#include "platform/WebTaskRunner.h"
#include "platform/heap/Handle.h"
#include "public/platform/Platform.h"
#include "public/platform/WebContentSecurityPolicy.h"
#include "public/web/WebDevToolsAgentClient.h"
#include "public/web/WebEmbeddedWorker.h"
#include "public/web/WebEmbeddedWorkerStartData.h"
#include "public/web/WebFrameClient.h"
#include "services/service_manager/public/cpp/interface_provider.h"
namespace blink {
class ThreadableLoadingContext;
class ServiceWorkerGlobalScopeProxy;
class ServiceWorkerInstalledScriptsManager;
class WaitableEvent;
class WebLocalFrameBase;
class WebView;
class WorkerInspectorProxy;
class WorkerScriptLoader;
class WorkerThread;
class MODULES_EXPORT WebEmbeddedWorkerImpl final
: public WebEmbeddedWorker,
public WebFrameClient,
NON_EXPORTED_BASE(public WebDevToolsAgentClient) {
public WorkerShadowPage::Client {
WTF_MAKE_NONCOPYABLE(WebEmbeddedWorkerImpl);
public:
......@@ -96,22 +91,13 @@ class MODULES_EXPORT WebEmbeddedWorkerImpl final
ContentSecurityPolicyResponseHeaders,
WTF::String referrer_policy,
WaitableEvent*);
std::unique_ptr<blink::WebURLLoader> CreateURLLoader(
const WebURLRequest& request,
SingleThreadTaskRunner* task_runner) override {
// TODO(yhirano): Stop using Platform::CreateURLLoader() here.
return Platform::Current()->CreateURLLoader(request, task_runner);
}
private:
void PrepareShadowPageForLoader();
void LoadShadowPage();
// WebFrameClient overrides.
void FrameDetached(WebLocalFrame*, DetachType) override;
void DidFinishDocumentLoad() override;
service_manager::InterfaceProvider* GetInterfaceProvider() override;
// WorkerShadowPage::Client overrides.
std::unique_ptr<WebApplicationCacheHost> CreateApplicationCacheHost(
WebApplicationCacheHostClient*) override;
void OnShadowPageInitialized() override;
private:
// WebDevToolsAgentClient overrides.
void SendProtocolMessage(int session_id,
int call_id,
......@@ -128,17 +114,12 @@ class MODULES_EXPORT WebEmbeddedWorkerImpl final
std::unique_ptr<WebServiceWorkerContextClient> worker_context_client_;
// This is valid until the worker thread is created. After the worker thread
// is created, this is passed to the worker thread.
// These are valid until StartWorkerThread() is called. After the worker
// thread is created, these are passed to the worker thread.
std::unique_ptr<ServiceWorkerInstalledScriptsManager>
installed_scripts_manager_;
// This is kept until startWorkerContext is called, and then passed on
// to WorkerContext.
std::unique_ptr<WebContentSettingsClient> content_settings_client_;
service_manager::InterfaceProvider interface_provider_;
// Kept around only while main script loading is ongoing.
RefPtr<WorkerScriptLoader> main_script_loader_;
......@@ -146,17 +127,9 @@ class MODULES_EXPORT WebEmbeddedWorkerImpl final
Persistent<ServiceWorkerGlobalScopeProxy> worker_global_scope_proxy_;
Persistent<WorkerInspectorProxy> worker_inspector_proxy_;
// 'shadow page' - created to proxy loading requests from the worker.
// Both WebView and WebFrame objects are close()'ed (where they're
// deref'ed) when this EmbeddedWorkerImpl is destructed, therefore they
// are guaranteed to exist while this object is around.
WebView* web_view_;
Persistent<WebLocalFrameBase> main_frame_;
Persistent<ThreadableLoadingContext> loading_context_;
std::unique_ptr<WorkerShadowPage> shadow_page_;
bool loading_shadow_page_;
bool asked_to_terminate_;
bool asked_to_terminate_ = false;
enum WaitingForDebuggerState { kWaitingForDebugger, kNotWaitingForDebugger };
......
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