#include "content/child/service_worker/service_worker_dispatcher.h"
#include "base/lazy_instance.h"
+#include "base/stl_util.h"
#include "base/threading/thread_local.h"
+#include "content/child/child_thread.h"
+#include "content/child/service_worker/service_worker_handle_reference.h"
+#include "content/child/service_worker/service_worker_provider_context.h"
#include "content/child/service_worker/web_service_worker_impl.h"
#include "content/child/thread_safe_sender.h"
+#include "content/child/webmessageportchannel_impl.h"
#include "content/common/service_worker/service_worker_messages.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerProviderClient.h"
#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
using blink::WebServiceWorkerError;
OnUnregistered)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerRegistrationError,
OnRegistrationError)
+ IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerStateChanged,
+ OnServiceWorkerStateChanged)
+ IPC_MESSAGE_HANDLER(ServiceWorkerMsg_SetCurrentServiceWorker,
+ OnSetCurrentServiceWorker)
+ IPC_MESSAGE_HANDLER(ServiceWorkerMsg_MessageToDocument,
+ OnPostMessage)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
DCHECK(handled) << "Unhandled message:" << msg.type();
}
void ServiceWorkerDispatcher::RegisterServiceWorker(
+ int provider_id,
const GURL& pattern,
const GURL& script_url,
WebServiceWorkerProvider::WebServiceWorkerCallbacks* callbacks) {
DCHECK(callbacks);
int request_id = pending_callbacks_.Add(callbacks);
thread_safe_sender_->Send(new ServiceWorkerHostMsg_RegisterServiceWorker(
- CurrentWorkerId(), request_id, pattern, script_url));
+ CurrentWorkerId(), request_id, provider_id, pattern, script_url));
}
void ServiceWorkerDispatcher::UnregisterServiceWorker(
+ int provider_id,
const GURL& pattern,
WebServiceWorkerProvider::WebServiceWorkerCallbacks* callbacks) {
DCHECK(callbacks);
int request_id = pending_callbacks_.Add(callbacks);
thread_safe_sender_->Send(new ServiceWorkerHostMsg_UnregisterServiceWorker(
- CurrentWorkerId(), request_id, pattern));
+ CurrentWorkerId(), request_id, provider_id, pattern));
+}
+
+void ServiceWorkerDispatcher::AddProviderContext(
+ ServiceWorkerProviderContext* provider_context) {
+ DCHECK(provider_context);
+ int provider_id = provider_context->provider_id();
+ DCHECK(!ContainsKey(provider_contexts_, provider_id));
+ provider_contexts_[provider_id] = provider_context;
+}
+
+void ServiceWorkerDispatcher::RemoveProviderContext(
+ ServiceWorkerProviderContext* provider_context) {
+ DCHECK(provider_context);
+ DCHECK(ContainsKey(provider_contexts_, provider_context->provider_id()));
+ provider_contexts_.erase(provider_context->provider_id());
+ worker_to_provider_.erase(provider_context->current_handle_id());
}
void ServiceWorkerDispatcher::AddScriptClient(
DCHECK(client);
DCHECK(!ContainsKey(script_clients_, provider_id));
script_clients_[provider_id] = client;
- thread_safe_sender_->Send(new ServiceWorkerHostMsg_AddScriptClient(
- CurrentWorkerId(), provider_id));
}
void ServiceWorkerDispatcher::RemoveScriptClient(int provider_id) {
// This could be possibly called multiple times to ensure termination.
- if (ContainsKey(script_clients_, provider_id)) {
+ if (ContainsKey(script_clients_, provider_id))
script_clients_.erase(provider_id);
- thread_safe_sender_->Send(new ServiceWorkerHostMsg_RemoveScriptClient(
- CurrentWorkerId(), provider_id));
- }
}
-ServiceWorkerDispatcher* ServiceWorkerDispatcher::ThreadSpecificInstance(
+ServiceWorkerDispatcher*
+ServiceWorkerDispatcher::GetOrCreateThreadSpecificInstance(
ThreadSafeSender* thread_safe_sender) {
if (g_dispatcher_tls.Pointer()->Get() == kHasBeenDeleted) {
NOTREACHED() << "Re-instantiating TLS ServiceWorkerDispatcher.";
return dispatcher;
}
-void ServiceWorkerDispatcher::OnRegistered(int32 thread_id,
- int32 request_id,
- int64 registration_id) {
+ServiceWorkerDispatcher* ServiceWorkerDispatcher::GetThreadSpecificInstance() {
+ if (g_dispatcher_tls.Pointer()->Get() == kHasBeenDeleted)
+ return NULL;
+ return g_dispatcher_tls.Pointer()->Get();
+}
+
+void ServiceWorkerDispatcher::OnWorkerRunLoopStopped() {
+ delete this;
+}
+
+void ServiceWorkerDispatcher::OnRegistered(
+ int thread_id,
+ int request_id,
+ const ServiceWorkerObjectInfo& info) {
WebServiceWorkerProvider::WebServiceWorkerCallbacks* callbacks =
pending_callbacks_.Lookup(request_id);
DCHECK(callbacks);
if (!callbacks)
return;
- // the browser has to generate the registration_id so the same
+ // The browser has to generate the registration_id so the same
// worker can be called from different renderer contexts. However,
// the impl object doesn't have to be the same instance across calls
// unless we require the DOM objects to be identical when there's a
// duplicate registration. So for now we mint a new object each
// time.
+ //
+ // WebServiceWorkerImpl's ctor internally calls AddServiceWorker.
scoped_ptr<WebServiceWorkerImpl> worker(
- new WebServiceWorkerImpl(registration_id, thread_safe_sender_));
+ new WebServiceWorkerImpl(info, thread_safe_sender_));
callbacks->onSuccess(worker.release());
pending_callbacks_.Remove(request_id);
}
void ServiceWorkerDispatcher::OnUnregistered(
- int32 thread_id,
- int32 request_id) {
+ int thread_id,
+ int request_id) {
WebServiceWorkerProvider::WebServiceWorkerCallbacks* callbacks =
pending_callbacks_.Lookup(request_id);
DCHECK(callbacks);
}
void ServiceWorkerDispatcher::OnRegistrationError(
- int32 thread_id,
- int32 request_id,
+ int thread_id,
+ int request_id,
WebServiceWorkerError::ErrorType error_type,
const base::string16& message) {
WebServiceWorkerProvider::WebServiceWorkerCallbacks* callbacks =
pending_callbacks_.Remove(request_id);
}
-void ServiceWorkerDispatcher::OnWorkerRunLoopStopped() { delete this; }
+void ServiceWorkerDispatcher::OnServiceWorkerStateChanged(
+ int thread_id,
+ int handle_id,
+ blink::WebServiceWorkerState state) {
+ WorkerObjectMap::iterator worker = service_workers_.find(handle_id);
+ if (worker != service_workers_.end())
+ worker->second->OnStateChanged(state);
+
+ WorkerToProviderMap::iterator provider = worker_to_provider_.find(handle_id);
+ if (provider != worker_to_provider_.end())
+ provider->second->OnServiceWorkerStateChanged(handle_id, state);
+}
+
+void ServiceWorkerDispatcher::OnSetCurrentServiceWorker(
+ int thread_id,
+ int provider_id,
+ const ServiceWorkerObjectInfo& info) {
+ ProviderContextMap::iterator provider = provider_contexts_.find(provider_id);
+ if (provider != provider_contexts_.end()) {
+ provider->second->OnSetCurrentServiceWorker(provider_id, info);
+ worker_to_provider_[info.handle_id] = provider->second;
+ }
+
+ ScriptClientMap::iterator found = script_clients_.find(provider_id);
+ if (found != script_clients_.end()) {
+ // Populate the .current field with the new worker object.
+ scoped_ptr<ServiceWorkerHandleReference> handle_ref(
+ ServiceWorkerHandleReference::Create(info, thread_safe_sender_));
+ found->second->setCurrentServiceWorker(
+ new WebServiceWorkerImpl(handle_ref.Pass(), thread_safe_sender_));
+ }
+}
+
+void ServiceWorkerDispatcher::OnPostMessage(
+ int thread_id,
+ int provider_id,
+ const base::string16& message,
+ const std::vector<int>& sent_message_port_ids,
+ const std::vector<int>& new_routing_ids) {
+ // Make sure we're on the main document thread. (That must be the only
+ // thread we get this message)
+ DCHECK(ChildThread::current());
+
+ ScriptClientMap::iterator found = script_clients_.find(provider_id);
+ if (found == script_clients_.end()) {
+ // For now we do no queueing for messages sent to nonexistent / unattached
+ // client.
+ return;
+ }
+
+ std::vector<WebMessagePortChannelImpl*> ports;
+ if (!sent_message_port_ids.empty()) {
+ ports.resize(sent_message_port_ids.size());
+ for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
+ ports[i] = new WebMessagePortChannelImpl(
+ new_routing_ids[i], sent_message_port_ids[i],
+ base::MessageLoopProxy::current());
+ }
+ }
+
+ found->second->dispatchMessageEvent(message, ports);
+}
+
+void ServiceWorkerDispatcher::AddServiceWorker(
+ int handle_id, WebServiceWorkerImpl* worker) {
+ DCHECK(!ContainsKey(service_workers_, handle_id));
+ service_workers_[handle_id] = worker;
+}
+
+void ServiceWorkerDispatcher::RemoveServiceWorker(int handle_id) {
+ DCHECK(ContainsKey(service_workers_, handle_id));
+ service_workers_.erase(handle_id);
+}
} // namespace content