blob: e16454558e0ec9cc46862b3110a811dcf3bfca6f [file] [log] [blame]
// Copyright 2013 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_provider_host.h"
#include "base/stl_util.h"
#include "content/browser/message_port_message_filter.h"
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_context_request_handler.h"
#include "content/browser/service_worker/service_worker_controllee_request_handler.h"
#include "content/browser/service_worker/service_worker_dispatcher_host.h"
#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_utils.h"
#include "content/browser/service_worker/service_worker_version.h"
#include "content/common/resource_request_body.h"
#include "content/common/service_worker/service_worker_messages.h"
#include "content/common/service_worker/service_worker_types.h"
namespace content {
static const int kDocumentMainThreadId = 0;
ServiceWorkerProviderHost::ServiceWorkerProviderHost(
int process_id, int provider_id,
base::WeakPtr<ServiceWorkerContextCore> context,
ServiceWorkerDispatcherHost* dispatcher_host)
: process_id_(process_id),
provider_id_(provider_id),
context_(context),
dispatcher_host_(dispatcher_host),
allow_association_(true) {
}
ServiceWorkerProviderHost::~ServiceWorkerProviderHost() {
// Clear docurl so the deferred activation of a waiting worker
// won't associate the new version with a provider being destroyed.
document_url_ = GURL();
if (controlling_version_.get())
controlling_version_->RemoveControllee(this);
if (associated_registration_.get()) {
DecreaseProcessReference(associated_registration_->pattern());
associated_registration_->RemoveListener(this);
}
for (std::vector<GURL>::iterator it = associated_patterns_.begin();
it != associated_patterns_.end(); ++it) {
DecreaseProcessReference(*it);
}
}
void ServiceWorkerProviderHost::OnRegistrationFailed(
ServiceWorkerRegistration* registration) {
DCHECK_EQ(associated_registration_.get(), registration);
DisassociateRegistration();
}
void ServiceWorkerProviderHost::SetDocumentUrl(const GURL& url) {
DCHECK(!url.has_ref());
document_url_ = url;
}
void ServiceWorkerProviderHost::SetTopmostFrameUrl(const GURL& url) {
topmost_frame_url_ = url;
}
void ServiceWorkerProviderHost::SetControllerVersionAttribute(
ServiceWorkerVersion* version) {
if (version == controlling_version_.get())
return;
scoped_refptr<ServiceWorkerVersion> previous_version = controlling_version_;
controlling_version_ = version;
if (version)
version->AddControllee(this);
if (previous_version.get())
previous_version->RemoveControllee(this);
if (!dispatcher_host_)
return; // Could be NULL in some tests.
dispatcher_host_->Send(new ServiceWorkerMsg_SetControllerServiceWorker(
kDocumentMainThreadId, provider_id(), CreateHandleAndPass(version)));
}
bool ServiceWorkerProviderHost::SetHostedVersionId(int64 version_id) {
if (!context_)
return true; // System is shutting down.
if (active_version())
return false; // Unexpected bad message.
ServiceWorkerVersion* live_version = context_->GetLiveVersion(version_id);
if (!live_version)
return true; // Was deleted before it got started.
ServiceWorkerVersionInfo info = live_version->GetInfo();
if (info.running_status != ServiceWorkerVersion::STARTING ||
info.process_id != process_id_) {
// If we aren't trying to start this version in our process
// something is amiss.
return false;
}
running_hosted_version_ = live_version;
return true;
}
void ServiceWorkerProviderHost::AssociateRegistration(
ServiceWorkerRegistration* registration) {
DCHECK(CanAssociateRegistration(registration));
if (associated_registration_.get())
DecreaseProcessReference(associated_registration_->pattern());
IncreaseProcessReference(registration->pattern());
if (dispatcher_host_) {
ServiceWorkerRegistrationHandle* handle =
dispatcher_host_->GetOrCreateRegistrationHandle(
provider_id(), registration);
ServiceWorkerVersionAttributes attrs;
attrs.installing = handle->CreateServiceWorkerHandleAndPass(
registration->installing_version());
attrs.waiting = handle->CreateServiceWorkerHandleAndPass(
registration->waiting_version());
attrs.active = handle->CreateServiceWorkerHandleAndPass(
registration->active_version());
dispatcher_host_->Send(new ServiceWorkerMsg_AssociateRegistration(
kDocumentMainThreadId, provider_id(), handle->GetObjectInfo(), attrs));
}
associated_registration_ = registration;
associated_registration_->AddListener(this);
SetControllerVersionAttribute(registration->active_version());
}
void ServiceWorkerProviderHost::DisassociateRegistration() {
if (!associated_registration_.get())
return;
DecreaseProcessReference(associated_registration_->pattern());
associated_registration_->RemoveListener(this);
associated_registration_ = NULL;
SetControllerVersionAttribute(NULL);
if (dispatcher_host_) {
dispatcher_host_->Send(new ServiceWorkerMsg_DisassociateRegistration(
kDocumentMainThreadId, provider_id()));
}
}
scoped_ptr<ServiceWorkerRequestHandler>
ServiceWorkerProviderHost::CreateRequestHandler(
FetchRequestMode request_mode,
FetchCredentialsMode credentials_mode,
ResourceType resource_type,
RequestContextType request_context_type,
RequestContextFrameType frame_type,
base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
scoped_refptr<ResourceRequestBody> body) {
if (IsHostToRunningServiceWorker()) {
return scoped_ptr<ServiceWorkerRequestHandler>(
new ServiceWorkerContextRequestHandler(
context_, AsWeakPtr(), blob_storage_context, resource_type));
}
if (ServiceWorkerUtils::IsMainResourceType(resource_type) ||
controlling_version()) {
return scoped_ptr<ServiceWorkerRequestHandler>(
new ServiceWorkerControlleeRequestHandler(context_,
AsWeakPtr(),
blob_storage_context,
request_mode,
credentials_mode,
resource_type,
request_context_type,
frame_type,
body));
}
return scoped_ptr<ServiceWorkerRequestHandler>();
}
bool ServiceWorkerProviderHost::CanAssociateRegistration(
ServiceWorkerRegistration* registration) {
if (!context_)
return false;
if (running_hosted_version_.get())
return false;
if (!registration || associated_registration_.get() || !allow_association_)
return false;
return true;
}
void ServiceWorkerProviderHost::PostMessage(
const base::string16& message,
const std::vector<int>& sent_message_port_ids) {
if (!dispatcher_host_)
return; // Could be NULL in some tests.
std::vector<int> new_routing_ids;
dispatcher_host_->message_port_message_filter()->
UpdateMessagePortsWithNewRoutes(sent_message_port_ids,
&new_routing_ids);
dispatcher_host_->Send(
new ServiceWorkerMsg_MessageToDocument(
kDocumentMainThreadId, provider_id(),
message,
sent_message_port_ids,
new_routing_ids));
}
void ServiceWorkerProviderHost::AddScopedProcessReferenceToPattern(
const GURL& pattern) {
associated_patterns_.push_back(pattern);
IncreaseProcessReference(pattern);
}
ServiceWorkerObjectInfo ServiceWorkerProviderHost::CreateHandleAndPass(
ServiceWorkerVersion* version) {
ServiceWorkerObjectInfo info;
if (context_ && version) {
scoped_ptr<ServiceWorkerHandle> handle =
ServiceWorkerHandle::Create(context_,
dispatcher_host_,
kDocumentMainThreadId,
provider_id_,
version);
info = handle->GetObjectInfo();
dispatcher_host_->RegisterServiceWorkerHandle(handle.Pass());
}
return info;
}
void ServiceWorkerProviderHost::IncreaseProcessReference(
const GURL& pattern) {
if (context_ && context_->process_manager()) {
context_->process_manager()->AddProcessReferenceToPattern(
pattern, process_id_);
}
}
void ServiceWorkerProviderHost::DecreaseProcessReference(
const GURL& pattern) {
if (context_ && context_->process_manager()) {
context_->process_manager()->RemoveProcessReferenceFromPattern(
pattern, process_id_);
}
}
bool ServiceWorkerProviderHost::IsContextAlive() {
return context_ != NULL;
}
} // namespace content