diff options
author | clamy <clamy@chromium.org> | 2015-10-27 09:20:49 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-10-27 16:22:04 +0000 |
commit | 2a7a25b565fd4b702bb12ce40f16284d965a11ad (patch) | |
tree | 6a35f7fe47cd36f1616e0cae3254d699624bc04d /content | |
parent | 349ad1fff5eed0f938acb47396ca64dd93277ebe (diff) | |
download | chromium_src-2a7a25b565fd4b702bb12ce40f16284d965a11ad.zip chromium_src-2a7a25b565fd4b702bb12ce40f16284d965a11ad.tar.gz chromium_src-2a7a25b565fd4b702bb12ce40f16284d965a11ad.tar.bz2 |
PlzNavigate: Make ServiceWorker work with PlzNavigate.
This CL makes the ServiceWorker architecture work with PlzNavigate enabled.
This is done by allowing the browser to pre-create a ServiceWorkerProviderHost
during navigations if needed. If the navigation is successful, the renderer
chosen to commit the navigation will create a matching
ServiceWorkerNetworkProvider. If no ServiceWorkerProviderHost was pre-created,
the renderer creates a ServiceWorkerNetworkProvider in the traditional way.
This is a continuation of https://codereview.chromium.org/1294243004/ by
fdegans@ following his departure from the team.
BUG=440463
Review URL: https://codereview.chromium.org/1399363004
Cr-Commit-Position: refs/heads/master@{#356310}
Diffstat (limited to 'content')
38 files changed, 736 insertions, 92 deletions
diff --git a/content/browser/frame_host/navigation_handle_impl.cc b/content/browser/frame_host/navigation_handle_impl.cc index 1c53047..2e30d1e 100644 --- a/content/browser/frame_host/navigation_handle_impl.cc +++ b/content/browser/frame_host/navigation_handle_impl.cc @@ -4,12 +4,19 @@ #include "content/browser/frame_host/navigation_handle_impl.h" +#include "base/command_line.h" #include "content/browser/frame_host/frame_tree_node.h" #include "content/browser/frame_host/navigator.h" #include "content/browser/frame_host/navigator_delegate.h" +#include "content/browser/service_worker/service_worker_context_wrapper.h" +#include "content/browser/service_worker/service_worker_navigation_handle.h" +#include "content/public/browser/browser_context.h" #include "content/public/browser/content_browser_client.h" +#include "content/public/browser/storage_partition.h" #include "content/public/common/content_client.h" +#include "content/public/common/content_switches.h" #include "net/url_request/redirect_info.h" +#include "third_party/WebKit/public/web/WebSandboxFlags.h" namespace content { @@ -45,6 +52,29 @@ NavigationHandleImpl::NavigationHandleImpl(const GURL& url, is_transferring_(false), frame_tree_node_(frame_tree_node), next_index_(0) { + // PlzNavigate + // Initialize the ServiceWorkerNavigationHandle if it can be created for this + // frame. + bool can_create_service_worker = + (frame_tree_node_->current_replication_state().sandbox_flags & + blink::WebSandboxFlags::Origin) != blink::WebSandboxFlags::Origin; + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableBrowserSideNavigation) && + can_create_service_worker) { + BrowserContext* browser_context = + frame_tree_node_->navigator()->GetController()->GetBrowserContext(); + // TODO(clamy): Picking the partition based on the URL is incorrect. + // See crbug.com/513539 + StoragePartition* partition = + BrowserContext::GetStoragePartitionForSite(browser_context, url_); + DCHECK(partition); + ServiceWorkerContextWrapper* service_worker_context = + static_cast<ServiceWorkerContextWrapper*>( + partition->GetServiceWorkerContext()); + service_worker_handle_.reset( + new ServiceWorkerNavigationHandle(service_worker_context)); + } + GetDelegate()->DidStartNavigation(this); } diff --git a/content/browser/frame_host/navigation_handle_impl.h b/content/browser/frame_host/navigation_handle_impl.h index 59a5f65..6f46707 100644 --- a/content/browser/frame_host/navigation_handle_impl.h +++ b/content/browser/frame_host/navigation_handle_impl.h @@ -19,6 +19,7 @@ namespace content { class NavigatorDelegate; +class ServiceWorkerNavigationHandle; struct NavigationRequestInfo; // This class keeps track of a single navigation. It is created upon receipt of @@ -104,6 +105,11 @@ class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle { is_transferring_ = is_transferring; } + // PlzNavigate + ServiceWorkerNavigationHandle* service_worker_handle() const { + return service_worker_handle_.get(); + } + typedef base::Callback<void(NavigationThrottle::ThrottleCheckResult)> ThrottleChecksFinishedCallback; @@ -194,6 +200,11 @@ class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle { // This callback will be run when all throttle checks have been performed. ThrottleChecksFinishedCallback complete_callback_; + // PlzNavigate + // Manages the lifetime of a pre-created ServiceWorkerProviderHost until a + // corresponding ServiceWorkerNetworkProvider is created in the renderer. + scoped_ptr<ServiceWorkerNavigationHandle> service_worker_handle_; + DISALLOW_COPY_AND_ASSIGN(NavigationHandleImpl); }; diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc index 171b1b5..a6ba970 100644 --- a/content/browser/frame_host/navigation_request.cc +++ b/content/browser/frame_host/navigation_request.cc @@ -11,6 +11,7 @@ #include "content/browser/frame_host/navigation_request_info.h" #include "content/browser/frame_host/navigator.h" #include "content/browser/loader/navigation_url_loader.h" +#include "content/browser/service_worker/service_worker_navigation_handle.h" #include "content/browser/site_instance_impl.h" #include "content/common/resource_request_body.h" #include "content/public/browser/navigation_controller.h" @@ -19,6 +20,7 @@ #include "net/base/load_flags.h" #include "net/http/http_request_headers.h" #include "net/url_request/redirect_info.h" +#include "third_party/WebKit/public/web/WebSandboxFlags.h" namespace content { @@ -252,6 +254,17 @@ void NavigationRequest::OnResponseStarted( scoped_ptr<StreamHandle> body) { DCHECK(state_ == STARTED); state_ = RESPONSE_STARTED; + + // Update the service worker params of the request params. + request_params_.should_create_service_worker = + (frame_tree_node_->current_replication_state().sandbox_flags & + blink::WebSandboxFlags::Origin) != blink::WebSandboxFlags::Origin; + if (navigation_handle_->service_worker_handle()) { + request_params_.service_worker_provider_id = + navigation_handle_->service_worker_handle() + ->service_worker_provider_host_id(); + } + frame_tree_node_->navigator()->CommitNavigation(frame_tree_node_, response.get(), body.Pass()); } @@ -282,7 +295,7 @@ void NavigationRequest::OnStartChecksComplete( loader_ = NavigationURLLoader::Create( frame_tree_node_->navigator()->GetController()->GetBrowserContext(), - info_.Pass(), this); + info_.Pass(), navigation_handle_->service_worker_handle(), this); } void NavigationRequest::OnRedirectChecksComplete( diff --git a/content/browser/frame_host/navigation_request.h b/content/browser/frame_host/navigation_request.h index 57218e7..294d086 100644 --- a/content/browser/frame_host/navigation_request.h +++ b/content/browser/frame_host/navigation_request.h @@ -171,9 +171,11 @@ class CONTENT_EXPORT NavigationRequest : public NavigationURLLoaderDelegate { // redirects. // Note: |common_params_| and |begin_params_| are not const as they can be // modified during redirects. + // Note: |request_params_| is not const because service_worker_provider_id + // and should_create_service_worker will be set in OnResponseStarted. CommonNavigationParams common_params_; BeginNavigationParams begin_params_; - const RequestNavigationParams request_params_; + RequestNavigationParams request_params_; const bool browser_initiated_; NavigationState state_; diff --git a/content/browser/frame_host/navigation_request_info.cc b/content/browser/frame_host/navigation_request_info.cc index 42fa7d27..de061de 100644 --- a/content/browser/frame_host/navigation_request_info.cc +++ b/content/browser/frame_host/navigation_request_info.cc @@ -21,7 +21,6 @@ NavigationRequestInfo::NavigationRequestInfo( is_main_frame(is_main_frame), parent_is_main_frame(parent_is_main_frame), frame_tree_node_id(frame_tree_node_id), - service_worker_provider_id(kInvalidServiceWorkerProviderId), request_body(request_body) {} NavigationRequestInfo::~NavigationRequestInfo() {} diff --git a/content/browser/frame_host/navigation_request_info.h b/content/browser/frame_host/navigation_request_info.h index fc10074..f63db77 100644 --- a/content/browser/frame_host/navigation_request_info.h +++ b/content/browser/frame_host/navigation_request_info.h @@ -42,7 +42,6 @@ struct CONTENT_EXPORT NavigationRequestInfo { const bool parent_is_main_frame; const int frame_tree_node_id; - int service_worker_provider_id; scoped_refptr<ResourceRequestBody> request_body; }; diff --git a/content/browser/loader/navigation_url_loader.cc b/content/browser/loader/navigation_url_loader.cc index c1513dc..0da9a25 100644 --- a/content/browser/loader/navigation_url_loader.cc +++ b/content/browser/loader/navigation_url_loader.cc @@ -15,13 +15,14 @@ static NavigationURLLoaderFactory* g_factory = nullptr; scoped_ptr<NavigationURLLoader> NavigationURLLoader::Create( BrowserContext* browser_context, scoped_ptr<NavigationRequestInfo> request_info, + ServiceWorkerNavigationHandle* service_worker_handle, NavigationURLLoaderDelegate* delegate) { if (g_factory) { return g_factory->CreateLoader(browser_context, request_info.Pass(), - delegate); + service_worker_handle, delegate); } return scoped_ptr<NavigationURLLoader>(new NavigationURLLoaderImpl( - browser_context, request_info.Pass(), delegate)); + browser_context, request_info.Pass(), service_worker_handle, delegate)); } void NavigationURLLoader::SetFactoryForTesting( diff --git a/content/browser/loader/navigation_url_loader.h b/content/browser/loader/navigation_url_loader.h index 89553f6..d3d5866 100644 --- a/content/browser/loader/navigation_url_loader.h +++ b/content/browser/loader/navigation_url_loader.h @@ -15,6 +15,7 @@ namespace content { class BrowserContext; class NavigationURLLoaderDelegate; class NavigationURLLoaderFactory; +class ServiceWorkerNavigationHandle; struct CommonNavigationParams; struct NavigationRequestInfo; @@ -35,6 +36,7 @@ class CONTENT_EXPORT NavigationURLLoader { static scoped_ptr<NavigationURLLoader> Create( BrowserContext* browser_context, scoped_ptr<NavigationRequestInfo> request_info, + ServiceWorkerNavigationHandle* service_worker_handle, NavigationURLLoaderDelegate* delegate); // For testing purposes; sets the factory for use in testing. diff --git a/content/browser/loader/navigation_url_loader_factory.h b/content/browser/loader/navigation_url_loader_factory.h index 770644e..a2fd371 100644 --- a/content/browser/loader/navigation_url_loader_factory.h +++ b/content/browser/loader/navigation_url_loader_factory.h @@ -18,6 +18,7 @@ class NavigationURLLoaderFactory { virtual scoped_ptr<NavigationURLLoader> CreateLoader( BrowserContext* browser_context, scoped_ptr<NavigationRequestInfo> request_info, + ServiceWorkerNavigationHandle* service_worker_handle, NavigationURLLoaderDelegate* delegate) = 0; protected: diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc index 7cbd911..2cae9a6 100644 --- a/content/browser/loader/navigation_url_loader_impl.cc +++ b/content/browser/loader/navigation_url_loader_impl.cc @@ -9,6 +9,7 @@ #include "content/browser/frame_host/navigation_request_info.h" #include "content/browser/loader/navigation_url_loader_delegate.h" #include "content/browser/loader/navigation_url_loader_impl_core.h" +#include "content/browser/service_worker/service_worker_navigation_handle.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/stream_handle.h" @@ -18,17 +19,19 @@ namespace content { NavigationURLLoaderImpl::NavigationURLLoaderImpl( BrowserContext* browser_context, scoped_ptr<NavigationRequestInfo> request_info, + ServiceWorkerNavigationHandle* service_worker_handle, NavigationURLLoaderDelegate* delegate) - : delegate_(delegate), - weak_factory_(this) { + : delegate_(delegate), weak_factory_(this) { DCHECK_CURRENTLY_ON(BrowserThread::UI); core_ = new NavigationURLLoaderImplCore(weak_factory_.GetWeakPtr()); + ServiceWorkerNavigationHandleCore* service_worker_handle_core = + service_worker_handle ? service_worker_handle->core() : nullptr; BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::Bind(&NavigationURLLoaderImplCore::Start, base::Unretained(core_), browser_context->GetResourceContext(), - base::Passed(&request_info))); + service_worker_handle_core, base::Passed(&request_info))); } NavigationURLLoaderImpl::~NavigationURLLoaderImpl() { diff --git a/content/browser/loader/navigation_url_loader_impl.h b/content/browser/loader/navigation_url_loader_impl.h index 6a88fc8..5c7fcd0 100644 --- a/content/browser/loader/navigation_url_loader_impl.h +++ b/content/browser/loader/navigation_url_loader_impl.h @@ -19,6 +19,7 @@ struct RedirectInfo; namespace content { class NavigationURLLoaderImplCore; +class ServiceWorkerNavigationHandle; class StreamHandle; struct ResourceResponse; @@ -27,6 +28,7 @@ class NavigationURLLoaderImpl : public NavigationURLLoader { // The caller is responsible for ensuring that |delegate| outlives the loader. NavigationURLLoaderImpl(BrowserContext* browser_context, scoped_ptr<NavigationRequestInfo> request_info, + ServiceWorkerNavigationHandle* service_worker_handle, NavigationURLLoaderDelegate* delegate); ~NavigationURLLoaderImpl() override; diff --git a/content/browser/loader/navigation_url_loader_impl_core.cc b/content/browser/loader/navigation_url_loader_impl_core.cc index 7fe6951..f7c1dde 100644 --- a/content/browser/loader/navigation_url_loader_impl_core.cc +++ b/content/browser/loader/navigation_url_loader_impl_core.cc @@ -10,6 +10,7 @@ #include "content/browser/frame_host/navigation_request_info.h" #include "content/browser/loader/navigation_resource_handler.h" #include "content/browser/loader/resource_dispatcher_host_impl.h" +#include "content/browser/service_worker/service_worker_navigation_handle_core.h" #include "content/common/navigation_params.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/stream_handle.h" @@ -37,6 +38,7 @@ NavigationURLLoaderImplCore::~NavigationURLLoaderImplCore() { void NavigationURLLoaderImplCore::Start( ResourceContext* resource_context, + ServiceWorkerNavigationHandleCore* service_worker_handle_core, scoped_ptr<NavigationRequestInfo> request_info) { DCHECK_CURRENTLY_ON(BrowserThread::IO); @@ -46,7 +48,7 @@ void NavigationURLLoaderImplCore::Start( base::TimeTicks::Now())); ResourceDispatcherHostImpl::Get()->BeginNavigationRequest( - resource_context, *request_info, this); + resource_context, *request_info, this, service_worker_handle_core); } void NavigationURLLoaderImplCore::FollowRedirect() { @@ -56,7 +58,6 @@ void NavigationURLLoaderImplCore::FollowRedirect() { resource_handler_->FollowRedirect(); } - void NavigationURLLoaderImplCore::NotifyRequestRedirected( const net::RedirectInfo& redirect_info, ResourceResponse* response) { diff --git a/content/browser/loader/navigation_url_loader_impl_core.h b/content/browser/loader/navigation_url_loader_impl_core.h index 8a93469..9016ba6 100644 --- a/content/browser/loader/navigation_url_loader_impl_core.h +++ b/content/browser/loader/navigation_url_loader_impl_core.h @@ -23,6 +23,7 @@ class NavigationResourceHandler; class ResourceContext; class ResourceHandler; class ResourceRequestBody; +class ServiceWorkerNavigationHandleCore; class StreamHandle; struct ResourceResponse; @@ -40,6 +41,7 @@ class NavigationURLLoaderImplCore { // Starts the request. void Start(ResourceContext* resource_context, + ServiceWorkerNavigationHandleCore* service_worker_handle_core, scoped_ptr<NavigationRequestInfo> request_info); // Follows the current pending redirect. diff --git a/content/browser/loader/navigation_url_loader_unittest.cc b/content/browser/loader/navigation_url_loader_unittest.cc index 5c4c7fd..418046e 100644 --- a/content/browser/loader/navigation_url_loader_unittest.cc +++ b/content/browser/loader/navigation_url_loader_unittest.cc @@ -188,7 +188,7 @@ class NavigationURLLoaderTest : public testing::Test { -1, scoped_refptr<ResourceRequestBody>())); return NavigationURLLoader::Create(browser_context_.get(), - request_info.Pass(), delegate); + request_info.Pass(), nullptr, delegate); } // Helper function for fetching the body of a URL to a string. diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc index efae657..f342602 100644 --- a/content/browser/loader/resource_dispatcher_host_impl.cc +++ b/content/browser/loader/resource_dispatcher_host_impl.cc @@ -1969,7 +1969,8 @@ void ResourceDispatcherHostImpl::FinishedWithResourcesForRequest( void ResourceDispatcherHostImpl::BeginNavigationRequest( ResourceContext* resource_context, const NavigationRequestInfo& info, - NavigationURLLoaderImplCore* loader) { + NavigationURLLoaderImplCore* loader, + ServiceWorkerNavigationHandleCore* service_worker_handle_core) { // PlzNavigate: BeginNavigationRequest currently should only be used for the // browser-side navigations project. CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch( @@ -2034,10 +2035,11 @@ void ResourceDispatcherHostImpl::BeginNavigationRequest( new_request->SetLoadFlags(load_flags); + storage::BlobStorageContext* blob_context = GetBlobStorageContext( + GetChromeBlobStorageContextForResourceContext(resource_context)); + // Resolve elements from request_body and prepare upload data. if (info.request_body.get()) { - storage::BlobStorageContext* blob_context = GetBlobStorageContext( - GetChromeBlobStorageContextForResourceContext(resource_context)); AttachRequestBodyBlobDataHandles( info.request_body.get(), blob_context); @@ -2094,15 +2096,19 @@ void ResourceDispatcherHostImpl::BeginNavigationRequest( if (new_request->url().SchemeIs(url::kBlobScheme)) { // Hang on to a reference to ensure the blob is not released prior // to the job being started. - ChromeBlobStorageContext* blob_context = - GetChromeBlobStorageContextForResourceContext(resource_context); storage::BlobProtocolHandler::SetRequestedBlobDataHandle( new_request.get(), - blob_context->context()->GetBlobDataFromPublicURL(new_request->url())); + blob_context->GetBlobDataFromPublicURL(new_request->url())); } - // TODO(davidben): Attach ServiceWorkerRequestHandler. - // TODO(michaeln): Help out with this and that. + RequestContextFrameType frame_type = + info.is_main_frame ? REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL + : REQUEST_CONTEXT_FRAME_TYPE_NESTED; + ServiceWorkerRequestHandler::InitializeForNavigation( + new_request.get(), service_worker_handle_core, blob_context, + info.begin_params.skip_service_worker, resource_type, + info.begin_params.request_context_type, frame_type, info.request_body); + // TODO(davidben): Attach AppCacheInterceptor. scoped_ptr<ResourceHandler> handler(new NavigationResourceHandler( diff --git a/content/browser/loader/resource_dispatcher_host_impl.h b/content/browser/loader/resource_dispatcher_host_impl.h index 7772917..d575c10 100644 --- a/content/browser/loader/resource_dispatcher_host_impl.h +++ b/content/browser/loader/resource_dispatcher_host_impl.h @@ -67,6 +67,7 @@ class ResourceMessageDelegate; class ResourceMessageFilter; class ResourceRequestInfoImpl; class SaveFileManager; +class ServiceWorkerNavigationHandleCore; class WebContentsImpl; struct CommonNavigationParams; struct DownloadSaveInfo; @@ -273,9 +274,11 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl // PlzNavigate: Begins a request for NavigationURLLoader. |loader| is the // loader to attach to the leaf resource handler. - void BeginNavigationRequest(ResourceContext* resource_context, - const NavigationRequestInfo& info, - NavigationURLLoaderImplCore* loader); + void BeginNavigationRequest( + ResourceContext* resource_context, + const NavigationRequestInfo& info, + NavigationURLLoaderImplCore* loader, + ServiceWorkerNavigationHandleCore* service_worker_handle_core); private: friend class ResourceDispatcherHostTest; diff --git a/content/browser/service_worker/service_worker_context_core.cc b/content/browser/service_worker/service_worker_context_core.cc index 45f0a2d..ec97d01 100644 --- a/content/browser/service_worker/service_worker_context_core.cc +++ b/content/browser/service_worker/service_worker_context_core.cc @@ -517,6 +517,33 @@ ServiceWorkerVersion* ServiceWorkerContextCore::GetLiveVersion( return (it != live_versions_.end()) ? it->second : NULL; } +// PlzNavigate +void ServiceWorkerContextCore::AddNavigationHandleCore( + int service_worker_provider_id, + ServiceWorkerNavigationHandleCore* handle) { + auto result = navigation_handle_cores_map_.insert( + std::pair<int, ServiceWorkerNavigationHandleCore*>( + service_worker_provider_id, handle)); + DCHECK(result.second) + << "Inserting a duplicate ServiceWorkerNavigationHandleCore"; +} + +// PlzNavigate +void ServiceWorkerContextCore::RemoveNavigationHandleCore( + int service_worker_provider_id) { + navigation_handle_cores_map_.erase(service_worker_provider_id); +} + +// PlzNavigate +ServiceWorkerNavigationHandleCore* +ServiceWorkerContextCore::GetNavigationHandleCore( + int service_worker_provider_id) { + auto result = navigation_handle_cores_map_.find(service_worker_provider_id); + if (result == navigation_handle_cores_map_.end()) + return nullptr; + return result->second; +} + void ServiceWorkerContextCore::AddLiveVersion(ServiceWorkerVersion* version) { // TODO(horo): If we will see crashes here, we have to find the root cause of // the version ID conflict. Otherwise change CHECK to DCHECK. diff --git a/content/browser/service_worker/service_worker_context_core.h b/content/browser/service_worker/service_worker_context_core.h index 99b986c..53a354d 100644 --- a/content/browser/service_worker/service_worker_context_core.h +++ b/content/browser/service_worker/service_worker_context_core.h @@ -42,6 +42,7 @@ class ServiceWorkerContextWrapper; class ServiceWorkerDatabaseTaskManager; class ServiceWorkerHandle; class ServiceWorkerJobCoordinator; +class ServiceWorkerNavigationHandleCore; class ServiceWorkerProviderHost; class ServiceWorkerRegistration; class ServiceWorkerStorage; @@ -223,6 +224,15 @@ class CONTENT_EXPORT ServiceWorkerContextCore return live_versions_; } + // PlzNavigate + // Methods to manage the map keeping track of all + // ServiceWorkerNavigationHandleCores registered for ongoing navigations. + void AddNavigationHandleCore(int service_worker_provider_id, + ServiceWorkerNavigationHandleCore* handle); + void RemoveNavigationHandleCore(int service_worker_provider_id); + ServiceWorkerNavigationHandleCore* GetNavigationHandleCore( + int service_worker_provider_id); + std::vector<ServiceWorkerRegistrationInfo> GetAllLiveRegistrationInfo(); std::vector<ServiceWorkerVersionInfo> GetAllLiveVersionInfo(); @@ -298,6 +308,12 @@ class CONTENT_EXPORT ServiceWorkerContextCore std::map<int64, ServiceWorkerRegistration*> live_registrations_; std::map<int64, ServiceWorkerVersion*> live_versions_; std::map<int64, scoped_refptr<ServiceWorkerVersion>> protected_versions_; + + // PlzNavigate + // Map of ServiceWorkerNavigationHandleCores used for navigation requests. + std::map<int, ServiceWorkerNavigationHandleCore*> + navigation_handle_cores_map_; + int next_handle_id_; int next_registration_handle_id_; // Set in RegisterServiceWorker(), cleared in ClearAllServiceWorkersForTest(). diff --git a/content/browser/service_worker/service_worker_context_wrapper.h b/content/browser/service_worker/service_worker_context_wrapper.h index 81463a0..0e1a83c 100644 --- a/content/browser/service_worker/service_worker_context_wrapper.h +++ b/content/browser/service_worker/service_worker_context_wrapper.h @@ -168,6 +168,7 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper friend class EmbeddedWorkerBrowserTest; friend class ServiceWorkerDispatcherHost; friend class ServiceWorkerInternalsUI; + friend class ServiceWorkerNavigationHandleCore; friend class ServiceWorkerProcessManager; friend class ServiceWorkerRequestHandler; friend class ServiceWorkerVersionBrowserTest; diff --git a/content/browser/service_worker/service_worker_dispatcher_host.cc b/content/browser/service_worker/service_worker_dispatcher_host.cc index a042183..62e5a78 100644 --- a/content/browser/service_worker/service_worker_dispatcher_host.cc +++ b/content/browser/service_worker/service_worker_dispatcher_host.cc @@ -4,6 +4,7 @@ #include "content/browser/service_worker/service_worker_dispatcher_host.h" +#include "base/command_line.h" #include "base/logging.h" #include "base/profiler/scoped_tracker.h" #include "base/strings/utf_string_conversions.h" @@ -15,6 +16,7 @@ #include "content/browser/service_worker/service_worker_context_core.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" #include "content/browser/service_worker/service_worker_handle.h" +#include "content/browser/service_worker/service_worker_navigation_handle_core.h" #include "content/browser/service_worker/service_worker_registration.h" #include "content/browser/service_worker/service_worker_registration_handle.h" #include "content/common/service_worker/embedded_worker_messages.h" @@ -23,6 +25,7 @@ #include "content/common/service_worker/service_worker_utils.h" #include "content/public/browser/content_browser_client.h" #include "content/public/common/content_client.h" +#include "content/public/common/content_switches.h" #include "content/public/common/origin_util.h" #include "ipc/ipc_message_macros.h" #include "net/base/net_util.h" @@ -733,10 +736,36 @@ void ServiceWorkerDispatcherHost::OnProviderCreated( bad_message::SWDH_PROVIDER_CREATED_NO_HOST); return; } - scoped_ptr<ServiceWorkerProviderHost> provider_host( - new ServiceWorkerProviderHost(render_process_id_, route_id, provider_id, - provider_type, GetContext()->AsWeakPtr(), - this)); + + scoped_ptr<ServiceWorkerProviderHost> provider_host; + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableBrowserSideNavigation) && + ServiceWorkerUtils::IsBrowserAssignedProviderId(provider_id)) { + // PlzNavigate + // Retrieve the provider host previously created for navigation requests. + ServiceWorkerNavigationHandleCore* navigation_handle_core = + GetContext()->GetNavigationHandleCore(provider_id); + if (navigation_handle_core != nullptr) + provider_host = navigation_handle_core->RetrievePreCreatedHost(); + if (provider_host == nullptr) { + bad_message::ReceivedBadMessage( + this, bad_message::SWDH_PROVIDER_CREATED_NO_HOST); + return; + } + DCHECK_EQ(SERVICE_WORKER_PROVIDER_FOR_WINDOW, provider_type); + provider_host->CompleteNavigationInitialized(render_process_id_, route_id, + this); + } else { + if (ServiceWorkerUtils::IsBrowserAssignedProviderId(provider_id)) { + bad_message::ReceivedBadMessage( + this, bad_message::SWDH_PROVIDER_CREATED_NO_HOST); + return; + } + provider_host = + scoped_ptr<ServiceWorkerProviderHost>(new ServiceWorkerProviderHost( + render_process_id_, route_id, provider_id, provider_type, + GetContext()->AsWeakPtr(), this)); + } GetContext()->AddProviderHost(provider_host.Pass()); } diff --git a/content/browser/service_worker/service_worker_navigation_handle.cc b/content/browser/service_worker/service_worker_navigation_handle.cc new file mode 100644 index 0000000..2bc87a22 --- /dev/null +++ b/content/browser/service_worker/service_worker_navigation_handle.cc @@ -0,0 +1,35 @@ +// Copyright 2015 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 "content/browser/service_worker/service_worker_navigation_handle.h" + +#include "base/bind.h" +#include "content/browser/service_worker/service_worker_navigation_handle_core.h" +#include "content/common/service_worker/service_worker_types.h" +#include "content/public/browser/browser_thread.h" + +namespace content { + +ServiceWorkerNavigationHandle::ServiceWorkerNavigationHandle( + ServiceWorkerContextWrapper* context_wrapper) + : service_worker_provider_host_id_(kInvalidServiceWorkerProviderId), + weak_factory_(this) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + core_ = new ServiceWorkerNavigationHandleCore(weak_factory_.GetWeakPtr(), + context_wrapper); +} + +ServiceWorkerNavigationHandle::~ServiceWorkerNavigationHandle() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + // Delete the ServiceWorkerNavigationHandleCore on the IO thread. + BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, core_); +} + +void ServiceWorkerNavigationHandle::DidCreateServiceWorkerProviderHost( + int service_worker_provider_host_id) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + service_worker_provider_host_id_ = service_worker_provider_host_id; +} + +} // namespace content diff --git a/content/browser/service_worker/service_worker_navigation_handle.h b/content/browser/service_worker/service_worker_navigation_handle.h new file mode 100644 index 0000000..c5c6938 --- /dev/null +++ b/content/browser/service_worker/service_worker_navigation_handle.h @@ -0,0 +1,78 @@ +// Copyright 2015 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 CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_NAVIGATION_HANDLE_H_ +#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_NAVIGATION_HANDLE_H_ + +#include "base/macros.h" +#include "base/memory/weak_ptr.h" + +namespace content { + +class ServiceWorkerContextWrapper; +class ServiceWorkerNavigationHandleCore; + +// This class is used to manage the lifetime of ServiceWorkerProviderHosts +// created during navigation. This is a UI thread class, with a pendant class +// on the IO thread, the ServiceWorkerNavigationHandleCore. +// +// The lifetime of the ServiceWorkerNavigationHandle, the +// ServiceWorkerNavigationHandleCore and the ServiceWorkerProviderHost are the +// following : +// 1) We create a ServiceWorkerNavigationHandle on the UI thread with a +// service worker provider id of -1. This also leads to the creation of a +// ServiceWorkerNavigationHandleCore with an id of -1. +// +// 2) When the navigation request is sent to the IO thread, we include a +// pointer to the ServiceWorkerNavigationHandleCore. +// +// 3) If we pre-create a ServiceWorkerProviderHost for this navigation, its +// ownershipped is passed to the ServiceWorkerNavigationHandleCore. The +// ServiceWorkerNavigationHandleCore id is updated. +// +// 4) The ServiceWorkerNavigationHandleCore informs the +// ServiceWorkerNavigationHandle on the UI that the service worker provider +// id was updated. +// +// 5) When the navigation is ready to commit, the NavigationRequest will +// update the RequestNavigationParams based on the id from the +// ServiceWorkerNavigationHandle. +// +// 6) If the commit leads to the creation of a ServiceWorkerNetworkProvider +// in the renderer, a ServiceWorkerHostMsg_ProviderCreated will be received +// in the browser. The ServiceWorkerDispatcherHost will retrieve the +// ServiceWorkerProviderHost from the ServiceWorkerNavigationHandleCore and +// put it in the ServiceWorkerContextCore map of ServiceWorkerProviderHosts. +// +// 7) When the navigation finishes, the ServiceWorkerNavigationHandle is +// destroyed. The destructor of the ServiceWorkerNavigationHandle posts a +// task to destroy the ServiceWorkerNavigationHandleCore on the IO thread. +// This in turn leads to the destruction of an unclaimed +// ServiceWorkerProviderHost. +class ServiceWorkerNavigationHandle { + public: + explicit ServiceWorkerNavigationHandle( + ServiceWorkerContextWrapper* context_wrapper); + ~ServiceWorkerNavigationHandle(); + + int service_worker_provider_host_id() const { + return service_worker_provider_host_id_; + } + ServiceWorkerNavigationHandleCore* core() const { return core_; } + + // Called after a ServiceWorkerProviderHost with id + // |service_worker_provider_host_id| was pre-created for the navigation on the + // IO thread. + void DidCreateServiceWorkerProviderHost(int service_worker_provider_host_id); + + private: + int service_worker_provider_host_id_; + ServiceWorkerNavigationHandleCore* core_; + base::WeakPtrFactory<ServiceWorkerNavigationHandle> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(ServiceWorkerNavigationHandle); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_NAVIGATION_HANDLE_H_ diff --git a/content/browser/service_worker/service_worker_navigation_handle_core.cc b/content/browser/service_worker/service_worker_navigation_handle_core.cc new file mode 100644 index 0000000..f1dc1ee --- /dev/null +++ b/content/browser/service_worker/service_worker_navigation_handle_core.cc @@ -0,0 +1,63 @@ +// Copyright 2015 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 "content/browser/service_worker/service_worker_navigation_handle_core.h" + +#include "base/bind.h" +#include "content/browser/service_worker/service_worker_context_core.h" +#include "content/browser/service_worker/service_worker_context_wrapper.h" +#include "content/browser/service_worker/service_worker_navigation_handle.h" +#include "content/browser/service_worker/service_worker_provider_host.h" +#include "content/common/service_worker/service_worker_types.h" +#include "content/public/browser/browser_thread.h" + +namespace content { + +ServiceWorkerNavigationHandleCore::ServiceWorkerNavigationHandleCore( + base::WeakPtr<ServiceWorkerNavigationHandle> ui_handle, + ServiceWorkerContextWrapper* context_wrapper) + : context_wrapper_(context_wrapper), ui_handle_(ui_handle) { + // The ServiceWorkerNavigationHandleCore is created on the UI thread but + // should only be accessed from the IO thread afterwards. + DCHECK_CURRENTLY_ON(BrowserThread::UI); +} + +ServiceWorkerNavigationHandleCore::~ServiceWorkerNavigationHandleCore() { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + if (precreated_host_.get() && context_wrapper_->context()) { + context_wrapper_->context()->RemoveNavigationHandleCore( + precreated_host_->provider_id()); + } +} + +void ServiceWorkerNavigationHandleCore::DidPreCreateProviderHost( + scoped_ptr<ServiceWorkerProviderHost> precreated_host) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK(precreated_host.get()); + DCHECK(context_wrapper_->context()); + + precreated_host_ = precreated_host.Pass(); + context_wrapper_->context()->AddNavigationHandleCore( + precreated_host_->provider_id(), this); + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind( + &ServiceWorkerNavigationHandle::DidCreateServiceWorkerProviderHost, + ui_handle_, precreated_host_->provider_id())); +} + +scoped_ptr<ServiceWorkerProviderHost> +ServiceWorkerNavigationHandleCore::RetrievePreCreatedHost() { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK(precreated_host_); + // Remove the ServiceWorkerNavigationHandleCore from the list of + // ServiceWorkerNavigationHandleCores since it will no longer hold a + // ServiceWorkerProviderHost. + DCHECK(context_wrapper_->context()); + context_wrapper_->context()->RemoveNavigationHandleCore( + precreated_host_->provider_id()); + return precreated_host_.Pass(); +} + +} // namespace content diff --git a/content/browser/service_worker/service_worker_navigation_handle_core.h b/content/browser/service_worker/service_worker_navigation_handle_core.h new file mode 100644 index 0000000..c1ed9eb --- /dev/null +++ b/content/browser/service_worker/service_worker_navigation_handle_core.h @@ -0,0 +1,57 @@ +// Copyright 2015 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 CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_NAVIGATION_HANDLE_CORE_H_ +#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_NAVIGATION_HANDLE_CORE_H_ + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" + +namespace content { + +class ServiceWorkerContextWrapper; +class ServiceWorkerNavigationHandle; +class ServiceWorkerProviderHost; + +// PlzNavigate +// This class is used to manage the lifetime of ServiceWorkerProviderHosts +// created during navigations. This class is created on the UI thread, but +// should only be accessed from the IO thread afterwards. It is the IO thread +// pendant of ServiceWorkerNavigationHandle. See the +// ServiceWorkerNavigationHandle header for more details about the lifetime of +// both classes. +class ServiceWorkerNavigationHandleCore { + public: + ServiceWorkerNavigationHandleCore( + base::WeakPtr<ServiceWorkerNavigationHandle> ui_handle, + ServiceWorkerContextWrapper* context_wrapper); + ~ServiceWorkerNavigationHandleCore(); + + // Called when a ServiceWorkerProviderHost was pre-created for the navigation + // tracked by this ServiceWorkerNavigationHandleCore. Takes ownership of + // |precreated_host|. + void DidPreCreateProviderHost( + scoped_ptr<ServiceWorkerProviderHost> precreated_host); + + // Called when the renderer created a ServiceWorkerNetworkProvider matching + // |precreated_host_|. This releases ownership of |precreated_host_|. + scoped_ptr<ServiceWorkerProviderHost> RetrievePreCreatedHost(); + + ServiceWorkerContextWrapper* context_wrapper() const { + return context_wrapper_.get(); + } + + private: + scoped_ptr<ServiceWorkerProviderHost> precreated_host_; + scoped_refptr<ServiceWorkerContextWrapper> context_wrapper_; + base::WeakPtr<ServiceWorkerNavigationHandle> ui_handle_; + + DISALLOW_COPY_AND_ASSIGN(ServiceWorkerNavigationHandleCore); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_NAVIGATION_HANDLE_CORE_H_ diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc index a27a2c1..d145d4b 100644 --- a/content/browser/service_worker/service_worker_provider_host.cc +++ b/content/browser/service_worker/service_worker_provider_host.cc @@ -4,6 +4,7 @@ #include "content/browser/service_worker/service_worker_provider_host.h" +#include "base/command_line.h" #include "base/guid.h" #include "base/stl_util.h" #include "base/time/time.h" @@ -27,6 +28,7 @@ #include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/web_contents.h" #include "content/public/common/child_process_host.h" +#include "content/public/common/content_switches.h" namespace content { @@ -57,6 +59,11 @@ ServiceWorkerClientInfo FocusOnUIThread(int render_process_id, render_frame_id); } +// PlzNavigate +// Next ServiceWorkerProviderHost ID for navigations, starts at -2 and keeps +// going down. +int g_next_navigation_provider_id = -2; + } // anonymous namespace ServiceWorkerProviderHost::OneShotGetReadyCallback::OneShotGetReadyCallback( @@ -68,6 +75,19 @@ ServiceWorkerProviderHost::OneShotGetReadyCallback::OneShotGetReadyCallback( ServiceWorkerProviderHost::OneShotGetReadyCallback::~OneShotGetReadyCallback() { } +// static +scoped_ptr<ServiceWorkerProviderHost> +ServiceWorkerProviderHost::PreCreateNavigationHost( + base::WeakPtr<ServiceWorkerContextCore> context) { + CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableBrowserSideNavigation)); + // Generate a new browser-assigned id for the host. + int provider_id = g_next_navigation_provider_id--; + return scoped_ptr<ServiceWorkerProviderHost>(new ServiceWorkerProviderHost( + ChildProcessHost::kInvalidUniqueID, MSG_ROUTING_NONE, provider_id, + SERVICE_WORKER_PROVIDER_FOR_WINDOW, context, nullptr)); +} + ServiceWorkerProviderHost::ServiceWorkerProviderHost( int render_process_id, int route_id, @@ -84,9 +104,14 @@ ServiceWorkerProviderHost::ServiceWorkerProviderHost( context_(context), dispatcher_host_(dispatcher_host), allow_association_(true) { - DCHECK_NE(ChildProcessHost::kInvalidUniqueID, render_process_id_); DCHECK_NE(SERVICE_WORKER_PROVIDER_UNKNOWN, provider_type_); DCHECK_NE(SERVICE_WORKER_PROVIDER_FOR_SANDBOXED_FRAME, provider_type_); + + // PlzNavigate + CHECK_IMPLIES(render_process_id == ChildProcessHost::kInvalidUniqueID, + base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableBrowserSideNavigation)); + if (provider_type_ == SERVICE_WORKER_PROVIDER_FOR_CONTROLLER) { // Actual thread id is set when the service worker context gets started. render_thread_id_ = kInvalidEmbeddedWorkerThreadId; @@ -516,29 +541,28 @@ void ServiceWorkerProviderHost::CompleteCrossSiteTransfer( DCHECK_NE(ChildProcessHost::kInvalidUniqueID, new_process_id); DCHECK_NE(MSG_ROUTING_NONE, new_frame_id); - render_process_id_ = new_process_id; - route_id_ = new_frame_id; render_thread_id_ = kDocumentMainThreadId; provider_id_ = new_provider_id; provider_type_ = new_provider_type; - dispatcher_host_ = new_dispatcher_host; - for (const GURL& pattern : associated_patterns_) - IncreaseProcessReference(pattern); + FinalizeInitialization(new_process_id, new_frame_id, new_dispatcher_host); +} - for (auto& key_registration : matching_registrations_) - IncreaseProcessReference(key_registration.second->pattern()); +// PlzNavigate +void ServiceWorkerProviderHost::CompleteNavigationInitialized( + int process_id, + int frame_routing_id, + ServiceWorkerDispatcherHost* dispatcher_host) { + CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableBrowserSideNavigation)); + DCHECK_EQ(ChildProcessHost::kInvalidUniqueID, render_process_id_); + DCHECK_EQ(SERVICE_WORKER_PROVIDER_FOR_WINDOW, provider_type_); + DCHECK_EQ(kDocumentMainThreadId, render_thread_id_); - if (associated_registration_.get()) { - SendAssociateRegistrationMessage(); - if (dispatcher_host_ && associated_registration_->active_version()) { - Send(new ServiceWorkerMsg_SetControllerServiceWorker( - render_thread_id_, provider_id(), - GetOrCreateServiceWorkerHandle( - associated_registration_->active_version()), - false /* shouldNotifyControllerChange */)); - } - } + DCHECK_NE(ChildProcessHost::kInvalidUniqueID, process_id); + DCHECK_NE(MSG_ROUTING_NONE, frame_routing_id); + + FinalizeInitialization(process_id, frame_routing_id, dispatcher_host); } void ServiceWorkerProviderHost::SendUpdateFoundMessage( @@ -684,4 +708,30 @@ void ServiceWorkerProviderHost::Send(IPC::Message* message) const { dispatcher_host_->Send(message); } +void ServiceWorkerProviderHost::FinalizeInitialization( + int process_id, + int frame_routing_id, + ServiceWorkerDispatcherHost* dispatcher_host) { + render_process_id_ = process_id; + route_id_ = frame_routing_id; + dispatcher_host_ = dispatcher_host; + + for (const GURL& pattern : associated_patterns_) + IncreaseProcessReference(pattern); + + for (auto& key_registration : matching_registrations_) + IncreaseProcessReference(key_registration.second->pattern()); + + if (associated_registration_.get()) { + SendAssociateRegistrationMessage(); + if (dispatcher_host_ && associated_registration_->active_version()) { + Send(new ServiceWorkerMsg_SetControllerServiceWorker( + render_thread_id_, provider_id(), + GetOrCreateServiceWorkerHandle( + associated_registration_->active_version()), + false /* shouldNotifyControllerChange */)); + } + } +} + } // namespace content diff --git a/content/browser/service_worker/service_worker_provider_host.h b/content/browser/service_worker/service_worker_provider_host.h index 70ed349..1ed95fa 100644 --- a/content/browser/service_worker/service_worker_provider_host.h +++ b/content/browser/service_worker/service_worker_provider_host.h @@ -52,6 +52,13 @@ class CONTENT_EXPORT ServiceWorkerProviderHost using GetRegistrationForReadyCallback = base::Callback<void(ServiceWorkerRegistration* reigstration)>; + // PlzNavigate + // Used to pre-create a ServiceWorkerProviderHost for a navigation. The + // ServiceWorkerNetworkProvider will later be created in the renderer, should + // the navigation succeed. + static scoped_ptr<ServiceWorkerProviderHost> PreCreateNavigationHost( + base::WeakPtr<ServiceWorkerContextCore> context); + // When this provider host is for a Service Worker context, |route_id| is // MSG_ROUTING_NONE. When this provider host is for a Document, // |route_id| is the frame ID of the Document. When this provider host is for @@ -202,6 +209,13 @@ class CONTENT_EXPORT ServiceWorkerProviderHost return dispatcher_host_; } + // PlzNavigate + // Completes initialization of provider hosts used for navigation requests. + void CompleteNavigationInitialized( + int process_id, + int frame_routing_id, + ServiceWorkerDispatcherHost* dispatcher_host); + // Sends event messages to the renderer. Events for the worker are queued up // until the worker thread id is known via SetReadyToSendMessagesToWorker(). void SendUpdateFoundMessage( @@ -289,6 +303,11 @@ class CONTENT_EXPORT ServiceWorkerProviderHost bool IsReadyToSendMessages() const; void Send(IPC::Message* message) const; + // Finalizes cross-site transfers and navigation-initalized hosts. + void FinalizeInitialization(int process_id, + int frame_routing_id, + ServiceWorkerDispatcherHost* dispatcher_host); + std::string client_uuid_; int render_process_id_; int route_id_; diff --git a/content/browser/service_worker/service_worker_request_handler.cc b/content/browser/service_worker/service_worker_request_handler.cc index 6d7d04b..27f3dea 100644 --- a/content/browser/service_worker/service_worker_request_handler.cc +++ b/content/browser/service_worker/service_worker_request_handler.cc @@ -6,8 +6,10 @@ #include <string> +#include "base/command_line.h" #include "content/browser/service_worker/service_worker_context_core.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" +#include "content/browser/service_worker/service_worker_navigation_handle_core.h" #include "content/browser/service_worker/service_worker_provider_host.h" #include "content/browser/service_worker/service_worker_registration.h" #include "content/browser/service_worker/service_worker_url_request_job.h" @@ -15,7 +17,10 @@ #include "content/common/service_worker/service_worker_types.h" #include "content/common/service_worker/service_worker_utils.h" #include "content/public/browser/resource_context.h" +#include "content/public/common/child_process_host.h" +#include "content/public/common/content_switches.h" #include "content/public/common/origin_util.h" +#include "ipc/ipc_message.h" #include "net/base/net_util.h" #include "net/url_request/url_request.h" #include "net/url_request/url_request_interceptor.h" @@ -49,8 +54,92 @@ class ServiceWorkerRequestInterceptor DISALLOW_COPY_AND_ASSIGN(ServiceWorkerRequestInterceptor); }; +void FinalizeHandlerInitialization( + net::URLRequest* request, + ServiceWorkerProviderHost* provider_host, + storage::BlobStorageContext* blob_storage_context, + bool skip_service_worker, + FetchRequestMode request_mode, + FetchCredentialsMode credentials_mode, + FetchRedirectMode redirect_mode, + ResourceType resource_type, + RequestContextType request_context_type, + RequestContextFrameType frame_type, + scoped_refptr<ResourceRequestBody> body) { + if (skip_service_worker) { + // TODO(horo): Does this work properly for PlzNavigate? + if (ServiceWorkerUtils::IsMainResourceType(resource_type)) { + provider_host->SetDocumentUrl(net::SimplifyUrlForRequest(request->url())); + provider_host->SetTopmostFrameUrl(request->first_party_for_cookies()); + // A page load with skip_service_worker should be triggered by + // shift-reload, so retain all live matching registrations. + provider_host->AddAllMatchingRegistrations(); + } + return; + } + + scoped_ptr<ServiceWorkerRequestHandler> handler( + provider_host->CreateRequestHandler( + request_mode, credentials_mode, redirect_mode, resource_type, + request_context_type, frame_type, blob_storage_context->AsWeakPtr(), + body)); + if (!handler) + return; + + request->SetUserData(&kUserDataKey, handler.release()); +} + } // namespace +// PlzNavigate +void ServiceWorkerRequestHandler::InitializeForNavigation( + net::URLRequest* request, + ServiceWorkerNavigationHandleCore* navigation_handle_core, + storage::BlobStorageContext* blob_storage_context, + bool skip_service_worker, + ResourceType resource_type, + RequestContextType request_context_type, + RequestContextFrameType frame_type, + scoped_refptr<ResourceRequestBody> body) { + CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableBrowserSideNavigation)); + + // Only create a handler when there is a ServiceWorkerNavigationHandlerCore + // to take ownership of a pre-created SeviceWorkerProviderHost. + if (!navigation_handle_core) + return; + + // Create the handler even for insecure HTTP since it's used in the + // case of redirect to HTTPS. + if (!request->url().SchemeIsHTTPOrHTTPS() && + !OriginCanAccessServiceWorkers(request->url())) { + return; + } + + if (!navigation_handle_core->context_wrapper() || + !navigation_handle_core->context_wrapper()->context()) { + return; + } + + // Initialize the SWProviderHost. + scoped_ptr<ServiceWorkerProviderHost> provider_host = + ServiceWorkerProviderHost::PreCreateNavigationHost( + navigation_handle_core->context_wrapper()->context()->AsWeakPtr()); + + FinalizeHandlerInitialization( + request, provider_host.get(), blob_storage_context, skip_service_worker, + FETCH_REQUEST_MODE_SAME_ORIGIN, FETCH_CREDENTIALS_MODE_INCLUDE, + FetchRedirectMode::MANUAL_MODE, resource_type, request_context_type, + frame_type, body); + + // Transfer ownership to the ServiceWorkerNavigationHandleCore. + // In the case of a successful navigation, the SWProviderHost will be + // transferred to its "final" destination in the OnProviderCreated handler. If + // the navigation fails, it will be destroyed along with the + // ServiceWorkerNavigationHandleCore. + navigation_handle_core->DidPreCreateProviderHost(provider_host.Pass()); +} + void ServiceWorkerRequestHandler::InitializeHandler( net::URLRequest* request, ServiceWorkerContextWrapper* context_wrapper, @@ -82,26 +171,10 @@ void ServiceWorkerRequestHandler::InitializeHandler( if (!provider_host || !provider_host->IsContextAlive()) return; - if (skip_service_worker) { - if (ServiceWorkerUtils::IsMainResourceType(resource_type)) { - provider_host->SetDocumentUrl(net::SimplifyUrlForRequest(request->url())); - provider_host->SetTopmostFrameUrl(request->first_party_for_cookies()); - // A page load with skip_service_worker should be triggered by - // shift-reload, so retain all live matching registrations. - provider_host->AddAllMatchingRegistrations(); - } - return; - } - - scoped_ptr<ServiceWorkerRequestHandler> handler( - provider_host->CreateRequestHandler( - request_mode, credentials_mode, redirect_mode, resource_type, - request_context_type, frame_type, blob_storage_context->AsWeakPtr(), - body)); - if (!handler) - return; - - request->SetUserData(&kUserDataKey, handler.release()); + FinalizeHandlerInitialization(request, provider_host, blob_storage_context, + skip_service_worker, request_mode, + credentials_mode, redirect_mode, resource_type, + request_context_type, frame_type, body); } ServiceWorkerRequestHandler* ServiceWorkerRequestHandler::GetHandler( @@ -128,30 +201,33 @@ bool ServiceWorkerRequestHandler::IsControlledByServiceWorker( void ServiceWorkerRequestHandler::PrepareForCrossSiteTransfer( int old_process_id) { + CHECK(!base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableBrowserSideNavigation)); if (!provider_host_ || !context_) return; old_process_id_ = old_process_id; old_provider_id_ = provider_host_->provider_id(); - host_for_cross_site_transfer_ = - context_->TransferProviderHostOut(old_process_id, - provider_host_->provider_id()); + host_for_cross_site_transfer_ = context_->TransferProviderHostOut( + old_process_id, provider_host_->provider_id()); DCHECK_EQ(provider_host_.get(), host_for_cross_site_transfer_.get()); } void ServiceWorkerRequestHandler::CompleteCrossSiteTransfer( int new_process_id, int new_provider_id) { + CHECK(!base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableBrowserSideNavigation)); if (!host_for_cross_site_transfer_.get() || !context_) return; DCHECK_EQ(provider_host_.get(), host_for_cross_site_transfer_.get()); - context_->TransferProviderHostIn( - new_process_id, - new_provider_id, - host_for_cross_site_transfer_.Pass()); + context_->TransferProviderHostIn(new_process_id, new_provider_id, + host_for_cross_site_transfer_.Pass()); DCHECK_EQ(provider_host_->provider_id(), new_provider_id); } void ServiceWorkerRequestHandler::MaybeCompleteCrossSiteTransferInOldProcess( int old_process_id) { + CHECK(!base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableBrowserSideNavigation)); if (!host_for_cross_site_transfer_.get() || !context_ || old_process_id_ != old_process_id) { return; diff --git a/content/browser/service_worker/service_worker_request_handler.h b/content/browser/service_worker/service_worker_request_handler.h index 2c14eb1..3d170c0 100644 --- a/content/browser/service_worker/service_worker_request_handler.h +++ b/content/browser/service_worker/service_worker_request_handler.h @@ -33,6 +33,7 @@ class ResourceContext; class ResourceRequestBody; class ServiceWorkerContextCore; class ServiceWorkerContextWrapper; +class ServiceWorkerNavigationHandleCore; class ServiceWorkerProviderHost; struct ResourceResponseInfo; @@ -41,6 +42,19 @@ struct ResourceResponseInfo; class CONTENT_EXPORT ServiceWorkerRequestHandler : public base::SupportsUserData::Data { public: + // PlzNavigate + // Attaches a newly created handler if the given |request| needs to be handled + // by ServiceWorker. + static void InitializeForNavigation( + net::URLRequest* request, + ServiceWorkerNavigationHandleCore* navigation_handle_core, + storage::BlobStorageContext* blob_storage_context, + bool skip_service_worker, + ResourceType resource_type, + RequestContextType request_context_type, + RequestContextFrameType frame_type, + scoped_refptr<ResourceRequestBody> body); + // Attaches a newly created handler if the given |request| needs to // be handled by ServiceWorker. // TODO(kinuko): While utilizing UserData to attach data to URLRequest diff --git a/content/child/service_worker/service_worker_network_provider.cc b/content/child/service_worker/service_worker_network_provider.cc index 1dcf75e..cb0225c 100644 --- a/content/child/service_worker/service_worker_network_provider.cc +++ b/content/child/service_worker/service_worker_network_provider.cc @@ -5,9 +5,13 @@ #include "content/child/service_worker/service_worker_network_provider.h" #include "base/atomic_sequence_num.h" +#include "base/command_line.h" #include "content/child/child_thread_impl.h" #include "content/child/service_worker/service_worker_provider_context.h" +#include "content/common/navigation_params.h" #include "content/common/service_worker/service_worker_messages.h" +#include "content/common/service_worker/service_worker_utils.h" +#include "content/public/common/content_switches.h" namespace content { @@ -44,10 +48,66 @@ ServiceWorkerNetworkProvider* ServiceWorkerNetworkProvider::FromDocumentState( datasource_userdata->GetUserData(&kUserDataKey)); } +// static +scoped_ptr<ServiceWorkerNetworkProvider> +ServiceWorkerNetworkProvider::CreateForNavigation( + int route_id, + const RequestNavigationParams& request_params, + blink::WebSandboxFlags sandbox_flags, + bool content_initiated) { + bool browser_side_navigation = + base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableBrowserSideNavigation); + bool should_create_provider_for_window = false; + int service_worker_provider_id = kInvalidServiceWorkerProviderId; + scoped_ptr<ServiceWorkerNetworkProvider> network_provider; + + // Determine if a ServiceWorkerNetworkProvider should be created and properly + // initialized for the navigation. A default ServiceWorkerNetworkProvider + // will always be created since it is expected in a certain number of places, + // however it will have an invalid id. + // PlzNavigate: |service_worker_provider_id| can be sent by the browser, if + // it already created the SeviceWorkerProviderHost. + if (browser_side_navigation && !content_initiated) { + should_create_provider_for_window = + request_params.should_create_service_worker; + service_worker_provider_id = request_params.service_worker_provider_id; + DCHECK(ServiceWorkerUtils::IsBrowserAssignedProviderId( + service_worker_provider_id) || + service_worker_provider_id == kInvalidServiceWorkerProviderId); + } else { + should_create_provider_for_window = + (sandbox_flags & blink::WebSandboxFlags::Origin) != + blink::WebSandboxFlags::Origin; + } + + // Now create the ServiceWorkerNetworkProvider (with invalid id if needed). + if (should_create_provider_for_window) { + if (service_worker_provider_id == kInvalidServiceWorkerProviderId) { + network_provider = scoped_ptr<ServiceWorkerNetworkProvider>( + new ServiceWorkerNetworkProvider(route_id, + SERVICE_WORKER_PROVIDER_FOR_WINDOW)); + } else { + CHECK(browser_side_navigation); + DCHECK(ServiceWorkerUtils::IsBrowserAssignedProviderId( + service_worker_provider_id)); + network_provider = scoped_ptr<ServiceWorkerNetworkProvider>( + new ServiceWorkerNetworkProvider(route_id, + SERVICE_WORKER_PROVIDER_FOR_WINDOW, + service_worker_provider_id)); + } + } else { + network_provider = scoped_ptr<ServiceWorkerNetworkProvider>( + new ServiceWorkerNetworkProvider()); + } + return network_provider.Pass(); +} + ServiceWorkerNetworkProvider::ServiceWorkerNetworkProvider( int route_id, - ServiceWorkerProviderType provider_type) - : provider_id_(GenerateProviderIdForType(provider_type)) { + ServiceWorkerProviderType provider_type, + int browser_provider_id) + : provider_id_(browser_provider_id) { if (provider_id_ == kInvalidServiceWorkerProviderId) return; context_ = new ServiceWorkerProviderContext(provider_id_, provider_type); @@ -57,6 +117,16 @@ ServiceWorkerNetworkProvider::ServiceWorkerNetworkProvider( provider_id_, route_id, provider_type)); } +ServiceWorkerNetworkProvider::ServiceWorkerNetworkProvider( + int route_id, + ServiceWorkerProviderType provider_type) + : ServiceWorkerNetworkProvider(route_id, + provider_type, + GenerateProviderIdForType(provider_type)) {} + +ServiceWorkerNetworkProvider::ServiceWorkerNetworkProvider() + : provider_id_(kInvalidServiceWorkerProviderId) {} + ServiceWorkerNetworkProvider::~ServiceWorkerNetworkProvider() { if (provider_id_ == kInvalidServiceWorkerProviderId) return; diff --git a/content/child/service_worker/service_worker_network_provider.h b/content/child/service_worker/service_worker_network_provider.h index ec1bdce..c34adf4 100644 --- a/content/child/service_worker/service_worker_network_provider.h +++ b/content/child/service_worker/service_worker_network_provider.h @@ -11,10 +11,12 @@ #include "base/supports_user_data.h" #include "content/common/content_export.h" #include "content/common/service_worker/service_worker_types.h" +#include "third_party/WebKit/public/web/WebSandboxFlags.h" namespace content { class ServiceWorkerProviderContext; +struct RequestNavigationParams; // A unique provider_id is generated for each instance. // Instantiated prior to the main resource load being started and remains @@ -37,7 +39,19 @@ class CONTENT_EXPORT ServiceWorkerNetworkProvider static ServiceWorkerNetworkProvider* FromDocumentState( base::SupportsUserData* document_state); + static scoped_ptr<ServiceWorkerNetworkProvider> CreateForNavigation( + int route_id, + const RequestNavigationParams& request_params, + blink::WebSandboxFlags sandbox_flags, + bool content_initiated); + + // PlzNavigate + // The |browser_provider_id| is initialized by the browser for navigations. + ServiceWorkerNetworkProvider(int route_id, + ServiceWorkerProviderType type, + int browser_provider_id); ServiceWorkerNetworkProvider(int route_id, ServiceWorkerProviderType type); + ServiceWorkerNetworkProvider(); ~ServiceWorkerNetworkProvider() override; int provider_id() const { return provider_id_; } diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h index 4af27d3..0e02874 100644 --- a/content/common/frame_messages.h +++ b/content/common/frame_messages.h @@ -312,6 +312,7 @@ IPC_STRUCT_TRAITS_BEGIN(content::RequestNavigationParams) IPC_STRUCT_TRAITS_MEMBER(current_history_list_offset) IPC_STRUCT_TRAITS_MEMBER(current_history_list_length) IPC_STRUCT_TRAITS_MEMBER(should_clear_history_list) + IPC_STRUCT_TRAITS_MEMBER(should_create_service_worker) IPC_STRUCT_TRAITS_MEMBER(service_worker_provider_id) IPC_STRUCT_TRAITS_END() diff --git a/content/common/navigation_params.cc b/content/common/navigation_params.cc index dfaefb1..63e6a11 100644 --- a/content/common/navigation_params.cc +++ b/content/common/navigation_params.cc @@ -126,6 +126,7 @@ RequestNavigationParams::RequestNavigationParams() current_history_list_offset(-1), current_history_list_length(0), should_clear_history_list(false), + should_create_service_worker(false), service_worker_provider_id(kInvalidServiceWorkerProviderId) {} RequestNavigationParams::RequestNavigationParams( @@ -159,6 +160,7 @@ RequestNavigationParams::RequestNavigationParams( current_history_list_offset(current_history_list_offset), current_history_list_length(current_history_list_length), should_clear_history_list(should_clear_history_list), + should_create_service_worker(false), service_worker_provider_id(kInvalidServiceWorkerProviderId) {} RequestNavigationParams::~RequestNavigationParams() { diff --git a/content/common/navigation_params.h b/content/common/navigation_params.h index 8093623..cf3d89a 100644 --- a/content/common/navigation_params.h +++ b/content/common/navigation_params.h @@ -285,10 +285,14 @@ struct CONTENT_EXPORT RequestNavigationParams { bool should_clear_history_list; // PlzNavigate - // The ServiceWorkerProviderHost ID used for navigations. - // Set to kInvalidServiceWorkerProviderId for sandboxed frames and sync loads. - // This parameter is not used in the current navigation architecture, where it - // will always be equal to kInvalidServiceWorkerProviderId. + // Whether a ServiceWorkerProviderHost should be created for the window. + bool should_create_service_worker; + + // PlzNavigate + // The ServiceWorkerProviderHost ID used for navigations, if it was already + // created by the browser. Set to kInvalidServiceWorkerProviderId otherwise. + // This parameter is not used in the current navigation architecture, where + // it will always be equal to kInvalidServiceWorkerProviderId. int service_worker_provider_id; }; diff --git a/content/common/service_worker/service_worker_utils.h b/content/common/service_worker/service_worker_utils.h index 1f74735..8538b5e 100644 --- a/content/common/service_worker/service_worker_utils.h +++ b/content/common/service_worker/service_worker_utils.h @@ -8,6 +8,7 @@ #include "base/macros.h" #include "content/common/content_export.h" #include "content/common/service_worker/service_worker_status_code.h" +#include "content/common/service_worker/service_worker_types.h" #include "content/public/common/resource_type.h" #include "url/gurl.h" @@ -38,6 +39,12 @@ class ServiceWorkerUtils { static bool ContainsDisallowedCharacter(const GURL& scope, const GURL& script_url, std::string* error_message); + + // PlzNavigate + // Returns true if the |provider_id| was assigned by the browser process. + static bool IsBrowserAssignedProviderId(int provider_id) { + return provider_id < kInvalidServiceWorkerProviderId; + } }; class CONTENT_EXPORT LongestScopeMatcher { diff --git a/content/content_browser.gypi b/content/content_browser.gypi index b645c11..e956edd 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi @@ -1383,6 +1383,10 @@ 'browser/service_worker/service_worker_job_coordinator.h', 'browser/service_worker/service_worker_metrics.cc', 'browser/service_worker/service_worker_metrics.h', + 'browser/service_worker/service_worker_navigation_handle.cc', + 'browser/service_worker/service_worker_navigation_handle.h', + 'browser/service_worker/service_worker_navigation_handle_core.cc', + 'browser/service_worker/service_worker_navigation_handle_core.h', 'browser/service_worker/service_worker_process_manager.cc', 'browser/service_worker/service_worker_process_manager.h', 'browser/service_worker/service_worker_provider_host.cc', diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 3cb0fb9..8489199 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc @@ -2648,20 +2648,18 @@ void RenderFrameImpl::didCreateDataSource(blink::WebLocalFrame* frame, // Create the serviceworker's per-document network observing object if it // does not exist (When navigation happens within a page, the provider already // exists). - if (!ServiceWorkerNetworkProvider::FromDocumentState( - DocumentState::FromDataSource(datasource))) { - ServiceWorkerProviderType provider_type = - SERVICE_WORKER_PROVIDER_FOR_WINDOW; - if ((frame->effectiveSandboxFlags() & blink::WebSandboxFlags::Origin) == - blink::WebSandboxFlags::Origin) { - provider_type = SERVICE_WORKER_PROVIDER_FOR_SANDBOXED_FRAME; - } - scoped_ptr<ServiceWorkerNetworkProvider> network_provider( - new ServiceWorkerNetworkProvider(routing_id_, provider_type)); - ServiceWorkerNetworkProvider::AttachToDocumentState( - DocumentState::FromDataSource(datasource), - network_provider.Pass()); - } + if (ServiceWorkerNetworkProvider::FromDocumentState( + DocumentState::FromDataSource(datasource))) + return; + + NavigationStateImpl* navigation_state = static_cast<NavigationStateImpl*>( + DocumentState::FromDataSource(datasource)->navigation_state()); + + ServiceWorkerNetworkProvider::AttachToDocumentState( + DocumentState::FromDataSource(datasource), + ServiceWorkerNetworkProvider::CreateForNavigation( + routing_id_, navigation_state->request_params(), + frame->effectiveSandboxFlags(), content_initiated)); } void RenderFrameImpl::didStartProvisionalLoad(blink::WebLocalFrame* frame, @@ -3420,12 +3418,14 @@ void RenderFrameImpl::willSendRequest( ServiceWorkerNetworkProvider* provider = ServiceWorkerNetworkProvider::FromDocumentState( DocumentState::FromDataSource(frame->provisionalDataSource())); + DCHECK(provider); provider_id = provider->provider_id(); } } else if (frame->dataSource()) { ServiceWorkerNetworkProvider* provider = ServiceWorkerNetworkProvider::FromDocumentState( DocumentState::FromDataSource(frame->dataSource())); + DCHECK(provider); provider_id = provider->provider_id(); // Explicitly set the SkipServiceWorker flag here if the renderer process // hasn't received SetControllerServiceWorker message. diff --git a/content/test/test_navigation_url_loader_factory.cc b/content/test/test_navigation_url_loader_factory.cc index f106a02..29eddd1 100644 --- a/content/test/test_navigation_url_loader_factory.cc +++ b/content/test/test_navigation_url_loader_factory.cc @@ -20,6 +20,7 @@ TestNavigationURLLoaderFactory::~TestNavigationURLLoaderFactory() { scoped_ptr<NavigationURLLoader> TestNavigationURLLoaderFactory::CreateLoader( BrowserContext* browser_context, scoped_ptr<NavigationRequestInfo> request_info, + ServiceWorkerNavigationHandle* service_worker_handle, NavigationURLLoaderDelegate* delegate) { return scoped_ptr<NavigationURLLoader>(new TestNavigationURLLoader( request_info.Pass(), delegate)); diff --git a/content/test/test_navigation_url_loader_factory.h b/content/test/test_navigation_url_loader_factory.h index a91c416..a3bfe2f 100644 --- a/content/test/test_navigation_url_loader_factory.h +++ b/content/test/test_navigation_url_loader_factory.h @@ -27,6 +27,7 @@ class TestNavigationURLLoaderFactory : public NavigationURLLoaderFactory { scoped_ptr<NavigationURLLoader> CreateLoader( BrowserContext* browser_context, scoped_ptr<NavigationRequestInfo> request_info, + ServiceWorkerNavigationHandle* service_worker_handle, NavigationURLLoaderDelegate* delegate) override; private: |