service_worker_dispatcher_host.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "content/browser/service_worker/service_worker_dispatcher_host.h" 6 7#include "base/logging.h" 8#include "base/strings/utf_string_conversions.h" 9#include "content/browser/message_port_message_filter.h" 10#include "content/browser/message_port_service.h" 11#include "content/browser/service_worker/embedded_worker_registry.h" 12#include "content/browser/service_worker/service_worker_context_core.h" 13#include "content/browser/service_worker/service_worker_context_wrapper.h" 14#include "content/browser/service_worker/service_worker_handle.h" 15#include "content/browser/service_worker/service_worker_registration.h" 16#include "content/browser/service_worker/service_worker_utils.h" 17#include "content/common/service_worker/embedded_worker_messages.h" 18#include "content/common/service_worker/service_worker_messages.h" 19#include "ipc/ipc_message_macros.h" 20#include "third_party/WebKit/public/platform/WebServiceWorkerError.h" 21#include "url/gurl.h" 22 23using blink::WebServiceWorkerError; 24 25namespace content { 26 27namespace { 28 29const char kDisabledErrorMessage[] = 30 "ServiceWorker is disabled"; 31const char kDomainMismatchErrorMessage[] = 32 "Scope and scripts do not have the same origin"; 33 34const uint32 kFilteredMessageClasses[] = { 35 ServiceWorkerMsgStart, 36 EmbeddedWorkerMsgStart, 37}; 38 39} // namespace 40 41ServiceWorkerDispatcherHost::ServiceWorkerDispatcherHost( 42 int render_process_id, 43 MessagePortMessageFilter* message_port_message_filter) 44 : BrowserMessageFilter(kFilteredMessageClasses, 45 arraysize(kFilteredMessageClasses)), 46 render_process_id_(render_process_id), 47 message_port_message_filter_(message_port_message_filter), 48 channel_ready_(false) { 49} 50 51ServiceWorkerDispatcherHost::~ServiceWorkerDispatcherHost() { 52 if (GetContext()) { 53 GetContext()->RemoveAllProviderHostsForProcess(render_process_id_); 54 GetContext()->embedded_worker_registry()->RemoveChildProcessSender( 55 render_process_id_); 56 } 57} 58 59void ServiceWorkerDispatcherHost::Init( 60 ServiceWorkerContextWrapper* context_wrapper) { 61 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { 62 BrowserThread::PostTask( 63 BrowserThread::IO, FROM_HERE, 64 base::Bind(&ServiceWorkerDispatcherHost::Init, 65 this, make_scoped_refptr(context_wrapper))); 66 return; 67 } 68 context_wrapper_ = context_wrapper; 69 GetContext()->embedded_worker_registry()->AddChildProcessSender( 70 render_process_id_, this); 71} 72 73void ServiceWorkerDispatcherHost::OnFilterAdded(IPC::Sender* sender) { 74 BrowserMessageFilter::OnFilterAdded(sender); 75 channel_ready_ = true; 76 std::vector<IPC::Message*> messages; 77 pending_messages_.release(&messages); 78 for (size_t i = 0; i < messages.size(); ++i) { 79 BrowserMessageFilter::Send(messages[i]); 80 } 81} 82 83void ServiceWorkerDispatcherHost::OnDestruct() const { 84 BrowserThread::DeleteOnIOThread::Destruct(this); 85} 86 87bool ServiceWorkerDispatcherHost::OnMessageReceived( 88 const IPC::Message& message) { 89 bool handled = true; 90 IPC_BEGIN_MESSAGE_MAP(ServiceWorkerDispatcherHost, message) 91 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_RegisterServiceWorker, 92 OnRegisterServiceWorker) 93 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_UnregisterServiceWorker, 94 OnUnregisterServiceWorker) 95 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ProviderCreated, 96 OnProviderCreated) 97 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ProviderDestroyed, 98 OnProviderDestroyed) 99 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SetVersionId, 100 OnSetHostedVersionId) 101 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToWorker, 102 OnPostMessageToWorker) 103 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerScriptLoaded, 104 OnWorkerScriptLoaded) 105 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerScriptLoadFailed, 106 OnWorkerScriptLoadFailed) 107 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerStarted, 108 OnWorkerStarted) 109 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerStopped, 110 OnWorkerStopped) 111 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_ReportException, 112 OnReportException) 113 IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_ReportConsoleMessage, 114 OnReportConsoleMessage) 115 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_IncrementServiceWorkerRefCount, 116 OnIncrementServiceWorkerRefCount) 117 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_DecrementServiceWorkerRefCount, 118 OnDecrementServiceWorkerRefCount) 119 IPC_MESSAGE_UNHANDLED(handled = false) 120 IPC_END_MESSAGE_MAP() 121 122 if (!handled && GetContext()) { 123 handled = 124 GetContext()->embedded_worker_registry()->OnMessageReceived(message); 125 if (!handled) 126 BadMessageReceived(); 127 } 128 129 return handled; 130} 131 132bool ServiceWorkerDispatcherHost::Send(IPC::Message* message) { 133 if (channel_ready_) { 134 BrowserMessageFilter::Send(message); 135 // Don't bother passing through Send()'s result: it's not reliable. 136 return true; 137 } 138 139 pending_messages_.push_back(message); 140 return true; 141} 142 143void ServiceWorkerDispatcherHost::RegisterServiceWorkerHandle( 144 scoped_ptr<ServiceWorkerHandle> handle) { 145 int handle_id = handle->handle_id(); 146 handles_.AddWithID(handle.release(), handle_id); 147} 148 149void ServiceWorkerDispatcherHost::OnRegisterServiceWorker( 150 int thread_id, 151 int request_id, 152 int provider_id, 153 const GURL& pattern, 154 const GURL& script_url) { 155 if (!GetContext() || !ServiceWorkerUtils::IsFeatureEnabled()) { 156 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError( 157 thread_id, 158 request_id, 159 WebServiceWorkerError::ErrorTypeDisabled, 160 base::ASCIIToUTF16(kDisabledErrorMessage))); 161 return; 162 } 163 164 // TODO(alecflett): This check is insufficient for release. Add a 165 // ServiceWorker-specific policy query in 166 // ChildProcessSecurityImpl. See http://crbug.com/311631. 167 if (pattern.GetOrigin() != script_url.GetOrigin()) { 168 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError( 169 thread_id, 170 request_id, 171 WebServiceWorkerError::ErrorTypeSecurity, 172 base::ASCIIToUTF16(kDomainMismatchErrorMessage))); 173 return; 174 } 175 176 ServiceWorkerProviderHost* provider_host = GetContext()->GetProviderHost( 177 render_process_id_, provider_id); 178 if (!provider_host) { 179 BadMessageReceived(); 180 return; 181 } 182 if (!provider_host->IsContextAlive()) { 183 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError( 184 thread_id, 185 request_id, 186 WebServiceWorkerError::ErrorTypeDisabled, 187 base::ASCIIToUTF16(kDisabledErrorMessage))); 188 return; 189 } 190 191 GetContext()->RegisterServiceWorker( 192 pattern, 193 script_url, 194 render_process_id_, 195 provider_host, 196 base::Bind(&ServiceWorkerDispatcherHost::RegistrationComplete, 197 this, 198 thread_id, 199 request_id)); 200} 201 202void ServiceWorkerDispatcherHost::OnUnregisterServiceWorker( 203 int thread_id, 204 int request_id, 205 int provider_id, 206 const GURL& pattern) { 207 // TODO(alecflett): This check is insufficient for release. Add a 208 // ServiceWorker-specific policy query in 209 // ChildProcessSecurityImpl. See http://crbug.com/311631. 210 if (!GetContext() || !ServiceWorkerUtils::IsFeatureEnabled()) { 211 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError( 212 thread_id, 213 request_id, 214 blink::WebServiceWorkerError::ErrorTypeDisabled, 215 base::ASCIIToUTF16(kDisabledErrorMessage))); 216 return; 217 } 218 219 ServiceWorkerProviderHost* provider_host = GetContext()->GetProviderHost( 220 render_process_id_, provider_id); 221 if (!provider_host) { 222 BadMessageReceived(); 223 return; 224 } 225 if (!provider_host->IsContextAlive()) { 226 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError( 227 thread_id, 228 request_id, 229 blink::WebServiceWorkerError::ErrorTypeDisabled, 230 base::ASCIIToUTF16(kDisabledErrorMessage))); 231 return; 232 } 233 234 GetContext()->UnregisterServiceWorker( 235 pattern, 236 base::Bind(&ServiceWorkerDispatcherHost::UnregistrationComplete, 237 this, 238 thread_id, 239 request_id)); 240} 241 242void ServiceWorkerDispatcherHost::OnPostMessageToWorker( 243 int handle_id, 244 const base::string16& message, 245 const std::vector<int>& sent_message_port_ids) { 246 if (!GetContext() || !ServiceWorkerUtils::IsFeatureEnabled()) 247 return; 248 249 ServiceWorkerHandle* handle = handles_.Lookup(handle_id); 250 if (!handle) { 251 BadMessageReceived(); 252 return; 253 } 254 255 std::vector<int> new_routing_ids; 256 message_port_message_filter_->UpdateMessagePortsWithNewRoutes( 257 sent_message_port_ids, &new_routing_ids); 258 handle->version()->SendMessage( 259 ServiceWorkerMsg_MessageToWorker(message, 260 sent_message_port_ids, 261 new_routing_ids), 262 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback)); 263} 264 265void ServiceWorkerDispatcherHost::OnProviderCreated(int provider_id) { 266 if (!GetContext()) 267 return; 268 if (GetContext()->GetProviderHost(render_process_id_, provider_id)) { 269 BadMessageReceived(); 270 return; 271 } 272 scoped_ptr<ServiceWorkerProviderHost> provider_host( 273 new ServiceWorkerProviderHost( 274 render_process_id_, provider_id, GetContext()->AsWeakPtr(), this)); 275 GetContext()->AddProviderHost(provider_host.Pass()); 276} 277 278void ServiceWorkerDispatcherHost::OnProviderDestroyed(int provider_id) { 279 if (!GetContext()) 280 return; 281 if (!GetContext()->GetProviderHost(render_process_id_, provider_id)) { 282 BadMessageReceived(); 283 return; 284 } 285 GetContext()->RemoveProviderHost(render_process_id_, provider_id); 286} 287 288void ServiceWorkerDispatcherHost::OnSetHostedVersionId( 289 int provider_id, int64 version_id) { 290 if (!GetContext()) 291 return; 292 ServiceWorkerProviderHost* provider_host = 293 GetContext()->GetProviderHost(render_process_id_, provider_id); 294 if (!provider_host) { 295 BadMessageReceived(); 296 return; 297 } 298 if (!provider_host->IsContextAlive()) 299 return; 300 if (!provider_host->SetHostedVersionId(version_id)) 301 BadMessageReceived(); 302} 303 304void ServiceWorkerDispatcherHost::RegistrationComplete( 305 int thread_id, 306 int request_id, 307 ServiceWorkerStatusCode status, 308 int64 registration_id, 309 int64 version_id) { 310 if (!GetContext()) 311 return; 312 313 if (status != SERVICE_WORKER_OK) { 314 SendRegistrationError(thread_id, request_id, status); 315 return; 316 } 317 318 ServiceWorkerVersion* version = GetContext()->GetLiveVersion(version_id); 319 DCHECK(version); 320 DCHECK_EQ(registration_id, version->registration_id()); 321 scoped_ptr<ServiceWorkerHandle> handle = 322 ServiceWorkerHandle::Create(GetContext()->AsWeakPtr(), 323 this, thread_id, version); 324 Send(new ServiceWorkerMsg_ServiceWorkerRegistered( 325 thread_id, request_id, handle->GetObjectInfo())); 326 RegisterServiceWorkerHandle(handle.Pass()); 327} 328 329// TODO(nhiroki): These message handlers that take |embedded_worker_id| as an 330// input should check if the worker refers to the live context. If the context 331// was deleted, handle the messege gracefully (http://crbug.com/371675). 332void ServiceWorkerDispatcherHost::OnWorkerScriptLoaded(int embedded_worker_id) { 333 if (!GetContext()) 334 return; 335 GetContext()->embedded_worker_registry()->OnWorkerScriptLoaded( 336 render_process_id_, embedded_worker_id); 337} 338 339void ServiceWorkerDispatcherHost::OnWorkerScriptLoadFailed( 340 int embedded_worker_id) { 341 if (!GetContext()) 342 return; 343 GetContext()->embedded_worker_registry()->OnWorkerScriptLoadFailed( 344 render_process_id_, embedded_worker_id); 345} 346 347void ServiceWorkerDispatcherHost::OnWorkerStarted( 348 int thread_id, int embedded_worker_id) { 349 if (!GetContext()) 350 return; 351 GetContext()->embedded_worker_registry()->OnWorkerStarted( 352 render_process_id_, thread_id, embedded_worker_id); 353} 354 355void ServiceWorkerDispatcherHost::OnWorkerStopped(int embedded_worker_id) { 356 if (!GetContext()) 357 return; 358 GetContext()->embedded_worker_registry()->OnWorkerStopped( 359 render_process_id_, embedded_worker_id); 360} 361 362void ServiceWorkerDispatcherHost::OnReportException( 363 int embedded_worker_id, 364 const base::string16& error_message, 365 int line_number, 366 int column_number, 367 const GURL& source_url) { 368 if (!GetContext()) 369 return; 370 GetContext()->embedded_worker_registry()->OnReportException( 371 embedded_worker_id, 372 error_message, 373 line_number, 374 column_number, 375 source_url); 376} 377 378void ServiceWorkerDispatcherHost::OnReportConsoleMessage( 379 int embedded_worker_id, 380 const EmbeddedWorkerHostMsg_ReportConsoleMessage_Params& params) { 381 if (!GetContext()) 382 return; 383 GetContext()->embedded_worker_registry()->OnReportConsoleMessage( 384 embedded_worker_id, 385 params.source_identifier, 386 params.message_level, 387 params.message, 388 params.line_number, 389 params.source_url); 390} 391 392void ServiceWorkerDispatcherHost::OnIncrementServiceWorkerRefCount( 393 int handle_id) { 394 ServiceWorkerHandle* handle = handles_.Lookup(handle_id); 395 if (!handle) { 396 BadMessageReceived(); 397 return; 398 } 399 handle->IncrementRefCount(); 400} 401 402void ServiceWorkerDispatcherHost::OnDecrementServiceWorkerRefCount( 403 int handle_id) { 404 ServiceWorkerHandle* handle = handles_.Lookup(handle_id); 405 if (!handle) { 406 BadMessageReceived(); 407 return; 408 } 409 handle->DecrementRefCount(); 410 if (handle->HasNoRefCount()) 411 handles_.Remove(handle_id); 412} 413 414void ServiceWorkerDispatcherHost::UnregistrationComplete( 415 int thread_id, 416 int request_id, 417 ServiceWorkerStatusCode status) { 418 if (status != SERVICE_WORKER_OK) { 419 SendRegistrationError(thread_id, request_id, status); 420 return; 421 } 422 423 Send(new ServiceWorkerMsg_ServiceWorkerUnregistered(thread_id, request_id)); 424} 425 426void ServiceWorkerDispatcherHost::SendRegistrationError( 427 int thread_id, 428 int request_id, 429 ServiceWorkerStatusCode status) { 430 base::string16 error_message; 431 blink::WebServiceWorkerError::ErrorType error_type; 432 GetServiceWorkerRegistrationStatusResponse( 433 status, &error_type, &error_message); 434 Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError( 435 thread_id, request_id, error_type, error_message)); 436} 437 438ServiceWorkerContextCore* ServiceWorkerDispatcherHost::GetContext() { 439 return context_wrapper_->context(); 440} 441 442} // namespace content 443