#include "content/browser/service_worker/service_worker_dispatcher_host.h"
-#include "content/browser/service_worker/service_worker_context.h"
-#include "content/common/service_worker_messages.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/browser/service_worker/embedded_worker_registry.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_provider_host.h"
+#include "content/common/service_worker/embedded_worker_messages.h"
+#include "content/common/service_worker/service_worker_messages.h"
#include "ipc/ipc_message_macros.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerError.h"
#include "url/gurl.h"
+using blink::WebServiceWorkerError;
+
+namespace {
+
+const char kDisabledErrorMessage[] =
+ "ServiceWorker is disabled";
+const char kDomainMismatchErrorMessage[] =
+ "Scope and scripts do not have the same origin";
+
+} // namespace
+
namespace content {
ServiceWorkerDispatcherHost::ServiceWorkerDispatcherHost(
- int render_process_id,
- ServiceWorkerContext* context) : context_(context) {}
+ int render_process_id)
+ : render_process_id_(render_process_id) {
+}
-ServiceWorkerDispatcherHost::~ServiceWorkerDispatcherHost() {}
+ServiceWorkerDispatcherHost::~ServiceWorkerDispatcherHost() {
+ if (context_) {
+ context_->RemoveAllProviderHostsForProcess(render_process_id_);
+ context_->embedded_worker_registry()->RemoveChildProcessSender(
+ render_process_id_);
+ }
+}
-bool ServiceWorkerDispatcherHost::OnMessageReceived(const IPC::Message& message,
- bool* message_was_ok) {
- if (IPC_MESSAGE_CLASS(message) != ServiceWorkerMsgStart)
- return false;
+void ServiceWorkerDispatcherHost::Init(
+ ServiceWorkerContextWrapper* context_wrapper) {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&ServiceWorkerDispatcherHost::Init,
+ this, make_scoped_refptr(context_wrapper)));
+ return;
+ }
+ context_ = context_wrapper->context()->AsWeakPtr();
+ context_->embedded_worker_registry()->AddChildProcessSender(
+ render_process_id_, this);
+}
+void ServiceWorkerDispatcherHost::OnDestruct() const {
+ BrowserThread::DeleteOnIOThread::Destruct(this);
+}
+
+bool ServiceWorkerDispatcherHost::OnMessageReceived(
+ const IPC::Message& message,
+ bool* message_was_ok) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP_EX(
ServiceWorkerDispatcherHost, message, *message_was_ok)
OnRegisterServiceWorker)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_UnregisterServiceWorker,
OnUnregisterServiceWorker)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ProviderCreated,
+ OnProviderCreated)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ProviderDestroyed,
+ OnProviderDestroyed)
+ IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerStarted,
+ OnWorkerStarted)
+ IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerStopped,
+ OnWorkerStopped)
+ IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_SendMessageToBrowser,
+ OnSendMessageToBrowser)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
-// TODO(alecflett): Store the service_worker_id keyed by (domain+pattern,
-// script) so we don't always return a new service worker id.
-static int64 NextWorkerId() {
- static int64 service_worker_id = 0;
- return service_worker_id++;
-}
-
void ServiceWorkerDispatcherHost::OnRegisterServiceWorker(
int32 thread_id,
int32 request_id,
- const GURL& scope,
+ const GURL& pattern,
const GURL& script_url) {
- // TODO(alecflett): add a ServiceWorker-specific policy query in
+ if (!context_ || !context_->IsEnabled()) {
+ Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
+ thread_id,
+ request_id,
+ WebServiceWorkerError::DisabledError,
+ base::ASCIIToUTF16(kDisabledErrorMessage)));
+ return;
+ }
+
+ // TODO(alecflett): This check is insufficient for release. Add a
+ // ServiceWorker-specific policy query in
// ChildProcessSecurityImpl. See http://crbug.com/311631.
+ if (pattern.GetOrigin() != script_url.GetOrigin()) {
+ Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
+ thread_id,
+ request_id,
+ WebServiceWorkerError::SecurityError,
+ base::ASCIIToUTF16(kDomainMismatchErrorMessage)));
+ return;
+ }
+
+ context_->RegisterServiceWorker(
+ pattern,
+ script_url,
+ render_process_id_,
+ base::Bind(&ServiceWorkerDispatcherHost::RegistrationComplete,
+ this,
+ thread_id,
+ request_id));
+}
+
+void ServiceWorkerDispatcherHost::OnUnregisterServiceWorker(
+ int32 thread_id,
+ int32 request_id,
+ const GURL& pattern) {
+ // TODO(alecflett): This check is insufficient for release. Add a
+ // ServiceWorker-specific policy query in
+ // ChildProcessSecurityImpl. See http://crbug.com/311631.
+ if (!context_ || !context_->IsEnabled()) {
+ Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
+ thread_id,
+ request_id,
+ blink::WebServiceWorkerError::DisabledError,
+ base::ASCIIToUTF16(kDisabledErrorMessage)));
+ return;
+ }
+
+ context_->UnregisterServiceWorker(
+ pattern,
+ render_process_id_,
+ base::Bind(&ServiceWorkerDispatcherHost::UnregistrationComplete,
+ this,
+ thread_id,
+ request_id));
+}
+
+void ServiceWorkerDispatcherHost::OnProviderCreated(int provider_id) {
+ if (!context_)
+ return;
+ if (context_->GetProviderHost(render_process_id_, provider_id)) {
+ BadMessageReceived();
+ return;
+ }
+ scoped_ptr<ServiceWorkerProviderHost> provider_host(
+ new ServiceWorkerProviderHost(render_process_id_, provider_id));
+ context_->AddProviderHost(provider_host.Pass());
+}
- // TODO(alecflett): Throw an error for origin mismatch, rather than
- // just returning.
- if (scope.GetOrigin() != script_url.GetOrigin())
+void ServiceWorkerDispatcherHost::OnProviderDestroyed(int provider_id) {
+ if (!context_)
return;
+ if (!context_->GetProviderHost(render_process_id_, provider_id)) {
+ BadMessageReceived();
+ return;
+ }
+ context_->RemoveProviderHost(render_process_id_, provider_id);
+}
+
+void ServiceWorkerDispatcherHost::RegistrationComplete(
+ int32 thread_id,
+ int32 request_id,
+ ServiceWorkerStatusCode status,
+ int64 registration_id) {
+ if (status != SERVICE_WORKER_OK) {
+ SendRegistrationError(thread_id, request_id, status);
+ return;
+ }
Send(new ServiceWorkerMsg_ServiceWorkerRegistered(
- thread_id, request_id, NextWorkerId()));
+ thread_id, request_id, registration_id));
}
-void ServiceWorkerDispatcherHost::OnUnregisterServiceWorker(int32 thread_id,
- int32 request_id,
- const GURL& scope) {
- // TODO(alecflett): add a ServiceWorker-specific policy query in
- // ChildProcessSecurityImpl. See http://crbug.com/311631.
+void ServiceWorkerDispatcherHost::OnWorkerStarted(
+ int thread_id, int embedded_worker_id) {
+ if (!context_)
+ return;
+ context_->embedded_worker_registry()->OnWorkerStarted(
+ render_process_id_, thread_id, embedded_worker_id);
+}
+
+void ServiceWorkerDispatcherHost::OnWorkerStopped(int embedded_worker_id) {
+ if (!context_)
+ return;
+ context_->embedded_worker_registry()->OnWorkerStopped(
+ render_process_id_, embedded_worker_id);
+}
+
+void ServiceWorkerDispatcherHost::OnSendMessageToBrowser(
+ int embedded_worker_id,
+ int request_id,
+ const IPC::Message& message) {
+ if (!context_)
+ return;
+ context_->embedded_worker_registry()->OnSendMessageToBrowser(
+ embedded_worker_id, request_id, message);
+}
+
+void ServiceWorkerDispatcherHost::UnregistrationComplete(
+ int32 thread_id,
+ int32 request_id,
+ ServiceWorkerStatusCode status) {
+ if (status != SERVICE_WORKER_OK) {
+ SendRegistrationError(thread_id, request_id, status);
+ return;
+ }
Send(new ServiceWorkerMsg_ServiceWorkerUnregistered(thread_id, request_id));
}
+void ServiceWorkerDispatcherHost::SendRegistrationError(
+ int32 thread_id,
+ int32 request_id,
+ ServiceWorkerStatusCode status) {
+ base::string16 error_message;
+ blink::WebServiceWorkerError::ErrorType error_type;
+ GetServiceWorkerRegistrationStatusResponse(
+ status, &error_type, &error_message);
+ Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
+ thread_id, request_id, error_type, error_message));
+}
+
} // namespace content