Index: content/browser/service_worker/service_worker_provider_host.cc |
diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc |
index 34be8dd0c8f7916e44abfbc074dc82f235056dd3..7e9f223e1510e1f532647545da50c3992a40c0d2 100644 |
--- a/content/browser/service_worker/service_worker_provider_host.cc |
+++ b/content/browser/service_worker/service_worker_provider_host.cc |
@@ -19,6 +19,7 @@ |
#include "content/browser/service_worker/service_worker_handle.h" |
#include "content/browser/service_worker/service_worker_registration_handle.h" |
#include "content/browser/service_worker/service_worker_version.h" |
+#include "content/browser/url_loader_factory_getter.h" |
#include "content/common/resource_request_body_impl.h" |
#include "content/common/service_worker/service_worker_messages.h" |
#include "content/common/service_worker/service_worker_types.h" |
@@ -31,15 +32,19 @@ |
#include "content/public/common/origin_util.h" |
#include "mojo/public/cpp/bindings/strong_associated_binding.h" |
#include "net/base/url_util.h" |
+#include "storage/browser/blob/blob_storage_context.h" |
namespace content { |
namespace { |
-// PlzNavigate |
-// Next ServiceWorkerProviderHost ID for navigations, starts at -2 and keeps |
-// going down. |
-int g_next_navigation_provider_id = -2; |
+// Provider host for navigation with PlzNavigate or service worker's context is |
+// created on the browser side. This function provides the next |
+// ServiceWorkerProviderHost ID for them, starts at -2 and keeps going down. |
+int NextBrowserProvidedProviderId() { |
+ static int g_next_browser_provided_provider_id = -2; |
+ return g_next_browser_provided_provider_id--; |
+} |
// A request handler derivative used to handle navigation requests when |
// skip_service_worker flag is set. It tracks the document URL and sets the url |
@@ -59,10 +64,9 @@ class ServiceWorkerURLTrackingRequestHandler |
~ServiceWorkerURLTrackingRequestHandler() override {} |
// Called via custom URLRequestJobFactory. |
- net::URLRequestJob* MaybeCreateJob( |
- net::URLRequest* request, |
- net::NetworkDelegate* /* network_delegate */, |
- ResourceContext* /* resource_context */) override { |
+ net::URLRequestJob* MaybeCreateJob(net::URLRequest* request, |
+ net::NetworkDelegate*, |
+ ResourceContext*) override { |
// |provider_host_| may have been deleted when the request is resumed. |
if (!provider_host_) |
return nullptr; |
@@ -96,6 +100,152 @@ void RemoveProviderHost(base::WeakPtr<ServiceWorkerContextCore> context, |
context->RemoveProviderHost(process_id, provider_id); |
} |
+// Used by a Service Worker for script loading (only during installation, |
+// eventually). For now this is just a proxy loader for the network loader. |
+// TODO(kinuko): Implement this. Hook up the existing code in |
+// ServiceWorkerContextRequestHandler. |
+class ScriptURLLoader : public mojom::URLLoader, public mojom::URLLoaderClient { |
+ public: |
+ ScriptURLLoader( |
+ int32_t routing_id, |
+ int32_t request_id, |
+ uint32_t options, |
+ const ResourceRequest& url_request, |
+ mojom::URLLoaderClientPtr client, |
+ base::WeakPtr<ServiceWorkerContextCore> context, |
+ base::WeakPtr<ServiceWorkerProviderHost> provider_host, |
+ base::WeakPtr<storage::BlobStorageContext> blob_storage_context, |
+ scoped_refptr<URLLoaderFactoryGetter> loader_factory_getter, |
+ const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) |
+ : network_client_binding_(this), |
+ forwarding_client_(std::move(client)), |
+ provider_host_(provider_host) { |
+ mojom::URLLoaderClientPtr network_client; |
+ network_client_binding_.Bind(mojo::MakeRequest(&network_client)); |
+ loader_factory_getter->GetNetworkFactory()->get()->CreateLoaderAndStart( |
+ mojo::MakeRequest(&network_loader_), routing_id, request_id, options, |
+ url_request, std::move(network_client), traffic_annotation); |
+ } |
+ ~ScriptURLLoader() override {} |
+ |
+ // mojom::URLLoader: |
+ void FollowRedirect() override { network_loader_->FollowRedirect(); } |
+ void SetPriority(net::RequestPriority priority, |
+ int32_t intra_priority_value) override { |
+ network_loader_->SetPriority(priority, intra_priority_value); |
+ } |
+ |
+ // mojom::URLLoaderClient for simply proxying network: |
+ void OnReceiveResponse( |
+ const ResourceResponseHead& response_head, |
+ const base::Optional<net::SSLInfo>& ssl_info, |
+ mojom::DownloadedTempFilePtr downloaded_file) override { |
+ if (provider_host_) { |
+ // We don't have complete info here, but fill in what we have now. |
+ // At least we need headers and SSL info. |
+ net::HttpResponseInfo response_info; |
+ response_info.headers = response_head.headers; |
+ if (ssl_info.has_value()) |
+ response_info.ssl_info = *ssl_info; |
+ response_info.was_fetched_via_spdy = response_head.was_fetched_via_spdy; |
+ response_info.was_alpn_negotiated = response_head.was_alpn_negotiated; |
+ response_info.alpn_negotiated_protocol = |
+ response_head.alpn_negotiated_protocol; |
+ response_info.connection_info = response_head.connection_info; |
+ response_info.socket_address = response_head.socket_address; |
+ |
+ DCHECK(provider_host_->IsHostToRunningServiceWorker()); |
+ provider_host_->running_hosted_version()->SetMainScriptHttpResponseInfo( |
+ response_info); |
+ } |
+ forwarding_client_->OnReceiveResponse(response_head, ssl_info, |
+ std::move(downloaded_file)); |
+ } |
+ void OnReceiveRedirect(const net::RedirectInfo& redirect_info, |
+ const ResourceResponseHead& response_head) override { |
+ forwarding_client_->OnReceiveRedirect(redirect_info, response_head); |
+ } |
+ void OnDataDownloaded(int64_t data_len, int64_t encoded_data_len) override { |
+ forwarding_client_->OnDataDownloaded(data_len, encoded_data_len); |
+ } |
+ void OnUploadProgress(int64_t current_position, |
+ int64_t total_size, |
+ OnUploadProgressCallback ack_callback) override { |
+ forwarding_client_->OnUploadProgress(current_position, total_size, |
+ std::move(ack_callback)); |
+ } |
+ void OnReceiveCachedMetadata(const std::vector<uint8_t>& data) override { |
+ forwarding_client_->OnReceiveCachedMetadata(data); |
+ } |
+ void OnTransferSizeUpdated(int32_t transfer_size_diff) override { |
+ forwarding_client_->OnTransferSizeUpdated(transfer_size_diff); |
+ } |
+ void OnStartLoadingResponseBody( |
+ mojo::ScopedDataPipeConsumerHandle body) override { |
+ forwarding_client_->OnStartLoadingResponseBody(std::move(body)); |
+ } |
+ void OnComplete(const ResourceRequestCompletionStatus& status) override { |
+ forwarding_client_->OnComplete(status); |
+ } |
+ |
+ private: |
+ mojom::URLLoaderAssociatedPtr network_loader_; |
+ mojo::Binding<mojom::URLLoaderClient> network_client_binding_; |
+ mojom::URLLoaderClientPtr forwarding_client_; |
+ base::WeakPtr<ServiceWorkerProviderHost> provider_host_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(ScriptURLLoader); |
+}; |
+ |
+// Created per one controller worker for script loading (only during |
+// installation, eventually). This is kept alive while |
+// ServiceWorkerNetworkProvider in the renderer process is alive. |
+// Used only when IsServicificationEnabled is true. |
+class ScriptURLLoaderFactory : public mojom::URLLoaderFactory { |
+ public: |
+ ScriptURLLoaderFactory( |
+ base::WeakPtr<ServiceWorkerContextCore> context, |
+ base::WeakPtr<ServiceWorkerProviderHost> provider_host, |
+ base::WeakPtr<storage::BlobStorageContext> blob_storage_context, |
+ scoped_refptr<URLLoaderFactoryGetter> loader_factory_getter) |
+ : context_(context), |
+ provider_host_(provider_host), |
+ blob_storage_context_(blob_storage_context), |
+ loader_factory_getter_(loader_factory_getter) {} |
+ ~ScriptURLLoaderFactory() override {} |
+ |
+ // mojom::URLLoaderFactory: |
+ void CreateLoaderAndStart(mojom::URLLoaderAssociatedRequest request, |
+ int32_t routing_id, |
+ int32_t request_id, |
+ uint32_t options, |
+ const ResourceRequest& url_request, |
+ mojom::URLLoaderClientPtr client, |
+ const net::MutableNetworkTrafficAnnotationTag& |
+ traffic_annotation) override { |
+ mojo::MakeStrongAssociatedBinding( |
+ base::MakeUnique<ScriptURLLoader>( |
+ routing_id, request_id, options, url_request, std::move(client), |
+ context_, provider_host_, blob_storage_context_, |
+ loader_factory_getter_, traffic_annotation), |
+ std::move(request)); |
+ } |
+ |
+ void SyncLoad(int32_t routing_id, |
+ int32_t request_id, |
+ const ResourceRequest& request, |
+ SyncLoadCallback callback) override { |
+ NOTREACHED(); |
+ } |
+ |
+ private: |
+ base::WeakPtr<ServiceWorkerContextCore> context_; |
+ base::WeakPtr<ServiceWorkerProviderHost> provider_host_; |
+ base::WeakPtr<storage::BlobStorageContext> blob_storage_context_; |
+ scoped_refptr<URLLoaderFactoryGetter> loader_factory_getter_; |
+ DISALLOW_COPY_AND_ASSIGN(ScriptURLLoaderFactory); |
+}; |
+ |
} // anonymous namespace |
ServiceWorkerProviderHost::OneShotGetReadyCallback::OneShotGetReadyCallback( |
@@ -114,18 +264,32 @@ ServiceWorkerProviderHost::PreCreateNavigationHost( |
bool are_ancestors_secure, |
const WebContentsGetter& web_contents_getter) { |
CHECK(IsBrowserSideNavigationEnabled()); |
- // Generate a new browser-assigned id for the host. |
- int provider_id = g_next_navigation_provider_id--; |
auto host = base::WrapUnique(new ServiceWorkerProviderHost( |
ChildProcessHost::kInvalidUniqueID, |
- ServiceWorkerProviderHostInfo(provider_id, MSG_ROUTING_NONE, |
- SERVICE_WORKER_PROVIDER_FOR_WINDOW, |
- are_ancestors_secure), |
+ ServiceWorkerProviderHostInfo( |
+ NextBrowserProvidedProviderId(), MSG_ROUTING_NONE, |
+ SERVICE_WORKER_PROVIDER_FOR_WINDOW, are_ancestors_secure), |
context, nullptr)); |
host->web_contents_getter_ = web_contents_getter; |
return host; |
} |
+// static |
+std::unique_ptr<ServiceWorkerProviderHost> |
+ServiceWorkerProviderHost::PreCreateForController( |
+ ServiceWorkerVersion* version, |
+ base::WeakPtr<ServiceWorkerContextCore> context) { |
+ auto host = base::WrapUnique(new ServiceWorkerProviderHost( |
+ ChildProcessHost::kInvalidUniqueID, |
+ ServiceWorkerProviderHostInfo(NextBrowserProvidedProviderId(), |
+ MSG_ROUTING_NONE, |
+ SERVICE_WORKER_PROVIDER_FOR_CONTROLLER, |
+ true /* is_parent_frame_secure */), |
+ context, nullptr)); |
+ host->SetHostedVersion(version); |
+ return host; |
+} |
+ |
// static |
std::unique_ptr<ServiceWorkerProviderHost> ServiceWorkerProviderHost::Create( |
int process_id, |
@@ -177,20 +341,27 @@ ServiceWorkerProviderHost::ServiceWorkerProviderHost( |
binding_(this) { |
DCHECK_NE(SERVICE_WORKER_PROVIDER_UNKNOWN, info_.type); |
- // PlzNavigate |
- CHECK(render_process_id != ChildProcessHost::kInvalidUniqueID || |
- IsBrowserSideNavigationEnabled()); |
if (info_.type == SERVICE_WORKER_PROVIDER_FOR_CONTROLLER) { |
- // Actual thread id is set when the service worker context gets started. |
+ // Actual |render_process_id| will be set after choosing a process for the |
+ // controller, and |render_thread id| will be set when the service worker |
+ // context gets started. |
+ DCHECK_EQ(ChildProcessHost::kInvalidUniqueID, render_process_id); |
render_thread_id_ = kInvalidEmbeddedWorkerThreadId; |
+ } else { |
+ // PlzNavigate |
+ CHECK(render_process_id != ChildProcessHost::kInvalidUniqueID || |
+ IsBrowserSideNavigationEnabled()); |
} |
+ |
context_->RegisterProviderHostByClientID(client_uuid_, this); |
- // PlzNavigate |
- // |provider_| and |binding_| will be bound on CompleteNavigationInitialized. |
- if (IsBrowserSideNavigationEnabled()) { |
- DCHECK(!info.client_ptr_info.is_valid() && !info.host_request.is_pending()); |
+ // |client_| and |binding_| will be bound on CompleteNavigationInitialized |
+ // (PlzNavigate) or on CompleteStartWorkerPreparation (providers for |
+ // controller). |
+ if (!info_.client_ptr_info.is_valid() && !info_.host_request.is_pending()) { |
+ DCHECK(IsBrowserSideNavigationEnabled() || |
+ info_.type == SERVICE_WORKER_PROVIDER_FOR_CONTROLLER); |
return; |
} |
@@ -327,8 +498,8 @@ void ServiceWorkerProviderHost::SetControllerVersionAttribute( |
void ServiceWorkerProviderHost::SetHostedVersion( |
ServiceWorkerVersion* version) { |
DCHECK(!IsProviderForClient()); |
- DCHECK_EQ(EmbeddedWorkerStatus::STARTING, version->running_status()); |
- DCHECK_EQ(render_process_id_, version->embedded_worker()->process_id()); |
+ DCHECK_EQ(EmbeddedWorkerStatus::STOPPED, version->running_status()); |
+ DCHECK(!running_hosted_version_); |
running_hosted_version_ = version; |
} |
@@ -566,6 +737,7 @@ bool ServiceWorkerProviderHost::GetRegistrationForReady( |
std::unique_ptr<ServiceWorkerProviderHost> |
ServiceWorkerProviderHost::PrepareForCrossSiteTransfer() { |
DCHECK(!IsBrowserSideNavigationEnabled()); |
+ DCHECK(!ServiceWorkerUtils::IsServicificationEnabled()); |
DCHECK_NE(ChildProcessHost::kInvalidUniqueID, render_process_id_); |
DCHECK_NE(MSG_ROUTING_NONE, info_.route_id); |
DCHECK_EQ(kDocumentMainThreadId, render_thread_id_); |
@@ -599,6 +771,7 @@ ServiceWorkerProviderHost::PrepareForCrossSiteTransfer() { |
void ServiceWorkerProviderHost::CompleteCrossSiteTransfer( |
ServiceWorkerProviderHost* provisional_host) { |
DCHECK(!IsBrowserSideNavigationEnabled()); |
+ DCHECK(!ServiceWorkerUtils::IsServicificationEnabled()); |
DCHECK_EQ(ChildProcessHost::kInvalidUniqueID, render_process_id_); |
DCHECK_NE(ChildProcessHost::kInvalidUniqueID, provisional_host->process_id()); |
DCHECK_NE(MSG_ROUTING_NONE, provisional_host->frame_id()); |
@@ -659,6 +832,64 @@ void ServiceWorkerProviderHost::CompleteNavigationInitialized( |
NotifyControllerToAssociatedProvider(); |
} |
+void ServiceWorkerProviderHost::CompleteStartWorkerPreparation( |
+ int process_id, |
+ mojom::ServiceWorkerProviderClientInfoPtr* out_provider_client_info) { |
+ DCHECK(context_); |
+ |
+ DCHECK_EQ(kInvalidEmbeddedWorkerThreadId, render_thread_id_); |
+ DCHECK_EQ(ChildProcessHost::kInvalidUniqueID, render_process_id_); |
+ DCHECK_EQ(SERVICE_WORKER_PROVIDER_FOR_CONTROLLER, provider_type()); |
+ DCHECK(running_hosted_version_); |
+ |
+ DCHECK_NE(ChildProcessHost::kInvalidUniqueID, process_id); |
+ |
+ ServiceWorkerDispatcherHost* dispatcher_host = |
+ context_->GetDispatcherHost(process_id); |
+ DCHECK(dispatcher_host); |
+ render_process_id_ = process_id; |
+ dispatcher_host_ = dispatcher_host; |
+ |
+ // Retrieve the registration associated with |version|. The registration |
+ // must be alive because the version keeps it during starting worker. |
+ ServiceWorkerRegistration* registration = context_->GetLiveRegistration( |
+ running_hosted_version()->registration_id()); |
+ DCHECK(registration); |
+ ServiceWorkerRegistrationObjectInfo info; |
+ ServiceWorkerVersionAttributes attrs; |
+ dispatcher_host->GetRegistrationObjectInfoAndVersionAttributes( |
+ AsWeakPtr(), registration, &info, &attrs); |
+ |
+ // Initialize provider_client_info. |
+ (*out_provider_client_info)->provider_id = provider_id(); |
+ (*out_provider_client_info)->type = provider_type(); |
+ (*out_provider_client_info)->attributes = std::move(attrs); |
+ (*out_provider_client_info)->registration = std::move(info); |
+ (*out_provider_client_info)->is_parent_frame_secure = |
+ is_parent_frame_secure(); |
+ (*out_provider_client_info)->client_request = mojo::MakeRequest(&provider_); |
+ |
+ mojom::URLLoaderFactoryAssociatedPtr loader_factory_ptr; |
+ if (ServiceWorkerUtils::IsServicificationEnabled()) { |
+ mojo::MakeStrongAssociatedBinding( |
+ base::MakeUnique<ScriptURLLoaderFactory>( |
+ context_, AsWeakPtr(), context_->blob_storage_context(), |
+ context_->loader_factory_getter()), |
+ mojo::MakeRequest(&loader_factory_ptr)); |
+ (*out_provider_client_info)->script_loader_factory_ptr_info = |
+ loader_factory_ptr.PassInterface(); |
+ } |
+ |
+ auto* host_ptr_info_ptr = &(*out_provider_client_info)->host_ptr_info; |
+ binding_.Bind(mojo::MakeRequest(host_ptr_info_ptr)); |
+ binding_.set_connection_error_handler( |
+ base::Bind(&RemoveProviderHost, context_, process_id, provider_id())); |
+ |
+ // Set the document URL to the script url in order to allow |
+ // register/unregister/getRegistration on ServiceWorkerGlobalScope. |
+ SetDocumentUrl(running_hosted_version()->script_url()); |
+} |
+ |
void ServiceWorkerProviderHost::SendUpdateFoundMessage( |
int registration_handle_id) { |
if (!dispatcher_host_) |