Commit 96e7e0b0 authored by Matt Falkenhagen's avatar Matt Falkenhagen Committed by Commit Bot

service worker: Refactoring in controllee request handler for main resource.

There was very similar code, make it the same function.

This patch tries to maintain the same behavior as previous to minimize
changes.

Detailed changelog:
  - Move |need_to_update|. The point of this upfront was to choose whether
    to "unblock" association on early return. In the need_to_update case,
    we know we call an async function, so didn't want to unblock.
    It's easier to always to unblock upfront, and block before the async
    functions. RAII would improve this, but avoided that to minimize the
    diff.
  - Remove |status| from TRACE when it's already guaranteed to be kOk.
  - Previously we avoided calling AssociateRegistration until after
    trying to make the active worker transition ACTIVATING -> ACTIVATED.
    There shouldn't be a need for that: once there's an active worker,
    the provider host should "use" the registration. But to minimize the
    diff, I've maintained this old behavior. When the callback fires,
    we unassociate there if something failed.

Change-Id: I0d8a9bea5f516a42002ecb7e236a8f1e9eced678
Reviewed-on: https://chromium-review.googlesource.com/1143092
Commit-Queue: Matt Falkenhagen <falken@chromium.org>
Reviewed-by: default avatarMakoto Shimazu <shimazu@chromium.org>
Reviewed-by: default avatarKenichi Ishibashi <bashi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#577464}
parent d7aad75c
...@@ -321,6 +321,8 @@ void ServiceWorkerControlleeRequestHandler::PrepareForMainResource( ...@@ -321,6 +321,8 @@ void ServiceWorkerControlleeRequestHandler::PrepareForMainResource(
// Also prevent a registration from claiming this host while it's not // Also prevent a registration from claiming this host while it's not
// yet execution ready. // yet execution ready.
// TODO(falken): Make an RAII helper instead of all these explcit allow and
// disallow calls.
provider_host_->SetAllowAssociation(false); provider_host_->SetAllowAssociation(false);
stripped_url_ = net::SimplifyUrlForRequest(url); stripped_url_ = net::SimplifyUrlForRequest(url);
...@@ -339,11 +341,9 @@ void ServiceWorkerControlleeRequestHandler:: ...@@ -339,11 +341,9 @@ void ServiceWorkerControlleeRequestHandler::
if (JobWasCanceled()) if (JobWasCanceled())
return; return;
const bool need_to_update = !force_update_started_ && registration && if (provider_host_)
context_->force_update_on_page_load();
if (provider_host_ && !need_to_update)
provider_host_->SetAllowAssociation(true); provider_host_->SetAllowAssociation(true);
if (status != blink::ServiceWorkerStatusCode::kOk) { if (status != blink::ServiceWorkerStatusCode::kOk) {
url_job_->FallbackToNetwork(); url_job_->FallbackToNetwork();
TRACE_EVENT_ASYNC_END1( TRACE_EVENT_ASYNC_END1(
...@@ -376,11 +376,10 @@ void ServiceWorkerControlleeRequestHandler:: ...@@ -376,11 +376,10 @@ void ServiceWorkerControlleeRequestHandler::
registration->pattern(), provider_host_->topmost_frame_url(), registration->pattern(), provider_host_->topmost_frame_url(),
resource_context_, provider_host_->web_contents_getter())) { resource_context_, provider_host_->web_contents_getter())) {
url_job_->FallbackToNetwork(); url_job_->FallbackToNetwork();
TRACE_EVENT_ASYNC_END2( TRACE_EVENT_ASYNC_END1(
"ServiceWorker", "ServiceWorker",
"ServiceWorkerControlleeRequestHandler::PrepareForMainResource", "ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
url_job_.get(), "Status", blink::ServiceWorkerStatusToString(status), url_job_.get(), "Info", "ServiceWorker is blocked");
"Info", "ServiceWorker is blocked");
return; return;
} }
...@@ -395,8 +394,11 @@ void ServiceWorkerControlleeRequestHandler:: ...@@ -395,8 +394,11 @@ void ServiceWorkerControlleeRequestHandler::
return; return;
} }
const bool need_to_update = !force_update_started_ && registration &&
context_->force_update_on_page_load();
if (need_to_update) { if (need_to_update) {
force_update_started_ = true; force_update_started_ = true;
provider_host_->SetAllowAssociation(false);
context_->UpdateServiceWorker( context_->UpdateServiceWorker(
registration.get(), true /* force_bypass_cache */, registration.get(), true /* force_bypass_cache */,
true /* skip_script_comparison */, true /* skip_script_comparison */,
...@@ -413,43 +415,112 @@ void ServiceWorkerControlleeRequestHandler:: ...@@ -413,43 +415,112 @@ void ServiceWorkerControlleeRequestHandler::
scoped_refptr<ServiceWorkerVersion> active_version = scoped_refptr<ServiceWorkerVersion> active_version =
registration->active_version(); registration->active_version();
if (!active_version) {
// Although there is no active version, a registration exists, so associate
// it, so it can be used for .ready.
// TODO(falken): There's no need to associate the registration just for
// .ready. Change this to AddMatchingRegistration instead, and call it
// unconditionally if there is a |provider_host_|.
provider_host_->AssociateRegistration(registration.get(),
false /* notify_controllerchange */);
url_job_->FallbackToNetwork();
TRACE_EVENT_ASYNC_END1(
"ServiceWorker",
"ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
url_job_.get(), "Info",
"No active version, so falling back to network");
return;
}
// TODO(falken): Change these to DCHECK if it holds.
CHECK(active_version->status() == ServiceWorkerVersion::ACTIVATING ||
active_version->status() == ServiceWorkerVersion::ACTIVATED);
// Wait until it's activated before firing fetch events. // Wait until it's activated before firing fetch events.
if (active_version.get() && if (active_version->status() == ServiceWorkerVersion::ACTIVATING) {
active_version->status() == ServiceWorkerVersion::ACTIVATING) {
provider_host_->SetAllowAssociation(false); provider_host_->SetAllowAssociation(false);
active_version->RegisterStatusChangeCallback(base::BindOnce( registration->active_version()->RegisterStatusChangeCallback(base::BindOnce(
&self::OnVersionStatusChanged, weak_factory_.GetWeakPtr(), registration, &ServiceWorkerControlleeRequestHandler::
active_version)); ContinueWithInScopeMainResourceRequest,
TRACE_EVENT_ASYNC_END2( weak_factory_.GetWeakPtr(), registration, active_version));
TRACE_EVENT_ASYNC_END1(
"ServiceWorker", "ServiceWorker",
"ServiceWorkerControlleeRequestHandler::PrepareForMainResource", "ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
url_job_.get(), "Status", blink::ServiceWorkerStatusToString(status), url_job_.get(), "Info", "Wait until finished SW activation");
"Info", "Wait until finished SW activation");
return; return;
} }
// TODO(falken): Factor out the rest of this function and ContinueWithInScopeMainResourceRequest(std::move(registration),
// OnVersionStatusChanged into the same function. std::move(active_version));
}
// A registration exists, so associate it. Note that the controller is only void ServiceWorkerControlleeRequestHandler::
// set if there's an active version. If there's no active version, we should ContinueWithInScopeMainResourceRequest(
// still associate so the provider host can use .ready. scoped_refptr<ServiceWorkerRegistration> registration,
provider_host_->AssociateRegistration(registration.get(), scoped_refptr<ServiceWorkerVersion> active_version) {
false /* notify_controllerchange */); if (provider_host_)
provider_host_->SetAllowAssociation(true);
if (!active_version.get() || // The job may have been canceled before this was invoked. In that
active_version->status() != ServiceWorkerVersion::ACTIVATED) { // case, |url_job_| can't be used, so return.
if (JobWasCanceled()) {
TRACE_EVENT_ASYNC_END1(
"ServiceWorker",
"ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
url_job_.get(), "Info", "The job was canceled");
return;
}
if (!provider_host_) {
url_job_->FallbackToNetwork();
TRACE_EVENT_ASYNC_END1(
"ServiceWorker",
"ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
url_job_.get(), "Info",
"The provider host is gone, so falling back to network");
return;
}
if (active_version->status() != ServiceWorkerVersion::ACTIVATED) {
// TODO(falken): Clean this up and clarify in what cases we come here. I
// guess it's:
// - strange system error cases where promoting from ACTIVATING to ACTIVATED
// failed (shouldn't happen)
// - something calling Doom(), etc, making the active_version REDUNDANT
// - a version called skipWaiting() during activation so the expected
// version is no longer the active one (shouldn't happen: skipWaiting()
// waits for the active version to finish activating).
// In most cases, it sounds like falling back to network would not be right,
// since it's still in-scope. We probably should do:
// 1) If the provider host has an active version that is ACTIVATED, just
// use that, even if it wasn't the expected one.
// 2) If the provider host has an active version that is not ACTIVATED,
// just fail the load. The correct thing is probably to re-try
// activating that version, but there's a risk of an infinite loop of
// retries.
// 3) If the provider host does not have an active version, just fail the
// load.
url_job_->FallbackToNetwork(); url_job_->FallbackToNetwork();
TRACE_EVENT_ASYNC_END2( TRACE_EVENT_ASYNC_END2(
"ServiceWorker", "ServiceWorker",
"ServiceWorkerControlleeRequestHandler::PrepareForMainResource", "ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
url_job_.get(), "Status", blink::ServiceWorkerStatusToString(status), url_job_.get(), "Info",
"Info", "The expected active version is not ACTIVATED, so falling back to "
"ServiceWorkerVersion is not available, so falling back to network"); "network",
"Status",
ServiceWorkerVersion::VersionStatusToString(active_version->status()));
return; return;
} }
provider_host_->AssociateRegistration(registration.get(),
false /* notify_controllerchange */);
// TODO(falken): Change these to DCHECK if it holds, or else figure out
// how this happens.
CHECK_EQ(active_version, registration->active_version());
CHECK_EQ(active_version, provider_host_->controller());
DCHECK_NE(active_version->fetch_handler_existence(), DCHECK_NE(active_version->fetch_handler_existence(),
ServiceWorkerVersion::FetchHandlerExistence::UNKNOWN); ServiceWorkerVersion::FetchHandlerExistence::UNKNOWN);
ServiceWorkerMetrics::CountControlledPageLoad( ServiceWorkerMetrics::CountControlledPageLoad(
...@@ -461,47 +532,14 @@ void ServiceWorkerControlleeRequestHandler:: ...@@ -461,47 +532,14 @@ void ServiceWorkerControlleeRequestHandler::
} }
bool is_forwarded = bool is_forwarded =
MaybeForwardToServiceWorker(url_job_.get(), active_version.get()); MaybeForwardToServiceWorker(url_job_.get(), active_version.get());
TRACE_EVENT_ASYNC_END1(
TRACE_EVENT_ASYNC_END2(
"ServiceWorker", "ServiceWorker",
"ServiceWorkerControlleeRequestHandler::PrepareForMainResource", "ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
url_job_.get(), "Status", blink::ServiceWorkerStatusToString(status), url_job_.get(), "Info",
"Info",
(is_forwarded) ? "Forwarded to the ServiceWorker" (is_forwarded) ? "Forwarded to the ServiceWorker"
: "Skipped the ServiceWorker which has no fetch handler"); : "Skipped the ServiceWorker which has no fetch handler");
} }
void ServiceWorkerControlleeRequestHandler::OnVersionStatusChanged(
scoped_refptr<ServiceWorkerRegistration> registration,
scoped_refptr<ServiceWorkerVersion> version) {
// The job may have been canceled before this was invoked.
if (JobWasCanceled())
return;
if (provider_host_)
provider_host_->SetAllowAssociation(true);
if (version != registration->active_version() ||
version->status() != ServiceWorkerVersion::ACTIVATED ||
!provider_host_) {
url_job_->FallbackToNetwork();
return;
}
DCHECK_NE(version->fetch_handler_existence(),
ServiceWorkerVersion::FetchHandlerExistence::UNKNOWN);
ServiceWorkerMetrics::CountControlledPageLoad(
version->site_for_uma(), stripped_url_, is_main_frame_load_);
provider_host_->AssociateRegistration(registration.get(),
false /* notify_controllerchange */);
if (blink::ServiceWorkerUtils::IsServicificationEnabled() &&
IsResourceTypeFrame(resource_type_)) {
provider_host_->AddServiceWorkerToUpdate(version);
}
MaybeForwardToServiceWorker(url_job_.get(), version.get());
}
void ServiceWorkerControlleeRequestHandler::DidUpdateRegistration( void ServiceWorkerControlleeRequestHandler::DidUpdateRegistration(
const scoped_refptr<ServiceWorkerRegistration>& original_registration, const scoped_refptr<ServiceWorkerRegistration>& original_registration,
blink::ServiceWorkerStatusCode status, blink::ServiceWorkerStatusCode status,
......
...@@ -96,7 +96,7 @@ class CONTENT_EXPORT ServiceWorkerControlleeRequestHandler ...@@ -96,7 +96,7 @@ class CONTENT_EXPORT ServiceWorkerControlleeRequestHandler
void DidLookupRegistrationForMainResource( void DidLookupRegistrationForMainResource(
blink::ServiceWorkerStatusCode status, blink::ServiceWorkerStatusCode status,
scoped_refptr<ServiceWorkerRegistration> registration); scoped_refptr<ServiceWorkerRegistration> registration);
void OnVersionStatusChanged( void ContinueWithInScopeMainResourceRequest(
scoped_refptr<ServiceWorkerRegistration> registration, scoped_refptr<ServiceWorkerRegistration> registration,
scoped_refptr<ServiceWorkerVersion> version); scoped_refptr<ServiceWorkerVersion> version);
......
...@@ -139,6 +139,11 @@ class ServiceWorkerControlleeRequestHandlerTest : public testing::Test { ...@@ -139,6 +139,11 @@ class ServiceWorkerControlleeRequestHandlerTest : public testing::Test {
ServiceWorkerContextCore* context() const { return helper_->context(); } ServiceWorkerContextCore* context() const { return helper_->context(); }
void SetProviderHostIsSecure(ServiceWorkerProviderHost* host,
bool is_secure) {
host->info_->is_parent_frame_secure = is_secure;
}
protected: protected:
TestBrowserThreadBundle browser_thread_bundle_; TestBrowserThreadBundle browser_thread_bundle_;
std::unique_ptr<EmbeddedWorkerTestHelper> helper_; std::unique_ptr<EmbeddedWorkerTestHelper> helper_;
...@@ -197,6 +202,34 @@ TEST_F(ServiceWorkerControlleeRequestHandlerTest, DisallowServiceWorker) { ...@@ -197,6 +202,34 @@ TEST_F(ServiceWorkerControlleeRequestHandlerTest, DisallowServiceWorker) {
SetBrowserClientForTesting(old_browser_client); SetBrowserClientForTesting(old_browser_client);
} }
TEST_F(ServiceWorkerControlleeRequestHandlerTest, InsecureContext) {
// Store an activated worker.
version_->set_fetch_handler_existence(
ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
registration_->SetActiveVersion(version_);
context()->storage()->StoreRegistration(registration_.get(), version_.get(),
base::DoNothing());
base::RunLoop().RunUntilIdle();
SetProviderHostIsSecure(provider_host_.get(), false);
// Conduct a main resource load.
ServiceWorkerRequestTestResources test_resources(
this, GURL("https://host/scope/doc"), RESOURCE_TYPE_MAIN_FRAME);
ServiceWorkerURLRequestJob* sw_job = test_resources.MaybeCreateJob();
EXPECT_FALSE(sw_job->ShouldFallbackToNetwork());
EXPECT_FALSE(sw_job->ShouldForwardToServiceWorker());
EXPECT_FALSE(version_->HasControllee());
base::RunLoop().RunUntilIdle();
// Verify we did not use the worker.
EXPECT_TRUE(sw_job->ShouldFallbackToNetwork());
EXPECT_FALSE(sw_job->ShouldForwardToServiceWorker());
EXPECT_FALSE(version_->HasControllee());
}
TEST_F(ServiceWorkerControlleeRequestHandlerTest, ActivateWaitingVersion) { TEST_F(ServiceWorkerControlleeRequestHandlerTest, ActivateWaitingVersion) {
// Store a registration that is installed but not activated yet. // Store a registration that is installed but not activated yet.
version_->set_fetch_handler_existence( version_->set_fetch_handler_existence(
......
...@@ -467,6 +467,8 @@ class CONTENT_EXPORT ServiceWorkerProviderHost ...@@ -467,6 +467,8 @@ class CONTENT_EXPORT ServiceWorkerProviderHost
friend class ServiceWorkerProviderHostTest; friend class ServiceWorkerProviderHostTest;
friend class ServiceWorkerWriteToCacheJobTest; friend class ServiceWorkerWriteToCacheJobTest;
friend class ServiceWorkerContextRequestHandlerTest; friend class ServiceWorkerContextRequestHandlerTest;
friend class service_worker_controllee_request_handler_unittest::
ServiceWorkerControlleeRequestHandlerTest;
friend class service_worker_object_host_unittest::ServiceWorkerObjectHostTest; friend class service_worker_object_host_unittest::ServiceWorkerObjectHostTest;
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerWriteToCacheJobTest, Update_SameScript); FRIEND_TEST_ALL_PREFIXES(ServiceWorkerWriteToCacheJobTest, Update_SameScript);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerWriteToCacheJobTest, FRIEND_TEST_ALL_PREFIXES(ServiceWorkerWriteToCacheJobTest,
......
...@@ -113,25 +113,6 @@ void ClearTick(base::TimeTicks* time) { ...@@ -113,25 +113,6 @@ void ClearTick(base::TimeTicks* time) {
*time = base::TimeTicks(); *time = base::TimeTicks();
} }
std::string VersionStatusToString(ServiceWorkerVersion::Status status) {
switch (status) {
case ServiceWorkerVersion::NEW:
return "new";
case ServiceWorkerVersion::INSTALLING:
return "installing";
case ServiceWorkerVersion::INSTALLED:
return "installed";
case ServiceWorkerVersion::ACTIVATING:
return "activating";
case ServiceWorkerVersion::ACTIVATED:
return "activated";
case ServiceWorkerVersion::REDUNDANT:
return "redundant";
}
NOTREACHED() << status;
return std::string();
}
const int kInvalidTraceId = -1; const int kInvalidTraceId = -1;
int NextTraceId() { int NextTraceId() {
...@@ -1347,6 +1328,7 @@ void ServiceWorkerVersion::CountFeature(blink::mojom::WebFeature feature) { ...@@ -1347,6 +1328,7 @@ void ServiceWorkerVersion::CountFeature(blink::mojom::WebFeature feature) {
provider_host_by_uuid.second->CountFeature(feature); provider_host_by_uuid.second->CountFeature(feature);
} }
// static
bool ServiceWorkerVersion::IsInstalled(ServiceWorkerVersion::Status status) { bool ServiceWorkerVersion::IsInstalled(ServiceWorkerVersion::Status status) {
switch (status) { switch (status) {
case ServiceWorkerVersion::NEW: case ServiceWorkerVersion::NEW:
...@@ -1362,6 +1344,27 @@ bool ServiceWorkerVersion::IsInstalled(ServiceWorkerVersion::Status status) { ...@@ -1362,6 +1344,27 @@ bool ServiceWorkerVersion::IsInstalled(ServiceWorkerVersion::Status status) {
return false; return false;
} }
// static
std::string ServiceWorkerVersion::VersionStatusToString(
ServiceWorkerVersion::Status status) {
switch (status) {
case ServiceWorkerVersion::NEW:
return "new";
case ServiceWorkerVersion::INSTALLING:
return "installing";
case ServiceWorkerVersion::INSTALLED:
return "installed";
case ServiceWorkerVersion::ACTIVATING:
return "activating";
case ServiceWorkerVersion::ACTIVATED:
return "activated";
case ServiceWorkerVersion::REDUNDANT:
return "redundant";
}
NOTREACHED() << status;
return std::string();
}
void ServiceWorkerVersion::IncrementPendingUpdateHintCount() { void ServiceWorkerVersion::IncrementPendingUpdateHintCount() {
DCHECK(blink::ServiceWorkerUtils::IsServicificationEnabled()); DCHECK(blink::ServiceWorkerUtils::IsServicificationEnabled());
pending_update_hint_count_++; pending_update_hint_count_++;
......
...@@ -484,6 +484,7 @@ class CONTENT_EXPORT ServiceWorkerVersion ...@@ -484,6 +484,7 @@ class CONTENT_EXPORT ServiceWorkerVersion
} }
static bool IsInstalled(ServiceWorkerVersion::Status status); static bool IsInstalled(ServiceWorkerVersion::Status status);
static std::string VersionStatusToString(ServiceWorkerVersion::Status status);
// For scheduling Soft Update after main resource requests. We schedule // For scheduling Soft Update after main resource requests. We schedule
// a Soft Update to happen "soon" after each main resource request, attempting // a Soft Update to happen "soon" after each main resource request, attempting
......
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