| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/service_worker/service_worker_version.h" | 5 #include "content/browser/service_worker/service_worker_version.h" |
| 6 | 6 |
| 7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
| 8 #include "base/memory/ref_counted.h" | 8 #include "base/memory/ref_counted.h" |
| 9 #include "base/stl_util.h" | 9 #include "base/stl_util.h" |
| 10 #include "base/strings/string16.h" | 10 #include "base/strings/string16.h" |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 78 // (Note that if all references to the version is dropped the worker | 78 // (Note that if all references to the version is dropped the worker |
| 79 // is also stopped without delay) | 79 // is also stopped without delay) |
| 80 const int64 kStopWorkerDelay = 30; // 30 secs. | 80 const int64 kStopWorkerDelay = 30; // 30 secs. |
| 81 | 81 |
| 82 // Delay for attempting to stop a doomed worker with in-flight requests. | 82 // Delay for attempting to stop a doomed worker with in-flight requests. |
| 83 const int64 kStopDoomedWorkerDelay = 5; // 5 secs. | 83 const int64 kStopDoomedWorkerDelay = 5; // 5 secs. |
| 84 | 84 |
| 85 // Default delay for scheduled update. | 85 // Default delay for scheduled update. |
| 86 const int kUpdateDelaySeconds = 1; | 86 const int kUpdateDelaySeconds = 1; |
| 87 | 87 |
| 88 // Delay between sending pings to the worker. |
| 89 const int kPingIntervalTime = 10; // 10 secs. |
| 90 |
| 91 // Timeout for waiting for a response to a ping. |
| 92 const int kPingTimeoutTime = 30; // 30 secs. |
| 93 |
| 88 const char kClaimClientsStateErrorMesage[] = | 94 const char kClaimClientsStateErrorMesage[] = |
| 89 "Only the active worker can claim clients."; | 95 "Only the active worker can claim clients."; |
| 90 | 96 |
| 91 const char kClaimClientsShutdownErrorMesage[] = | 97 const char kClaimClientsShutdownErrorMesage[] = |
| 92 "Failed to claim clients due to Service Worker system shutdown."; | 98 "Failed to claim clients due to Service Worker system shutdown."; |
| 93 | 99 |
| 94 void RunSoon(const base::Closure& callback) { | 100 void RunSoon(const base::Closure& callback) { |
| 95 if (!callback.is_null()) | 101 if (!callback.is_null()) |
| 96 base::MessageLoop::current()->PostTask(FROM_HERE, callback); | 102 base::MessageLoop::current()->PostTask(FROM_HERE, callback); |
| 97 } | 103 } |
| (...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 290 ServiceWorkerRegistration* registration, | 296 ServiceWorkerRegistration* registration, |
| 291 const GURL& script_url, | 297 const GURL& script_url, |
| 292 int64 version_id, | 298 int64 version_id, |
| 293 base::WeakPtr<ServiceWorkerContextCore> context) | 299 base::WeakPtr<ServiceWorkerContextCore> context) |
| 294 : version_id_(version_id), | 300 : version_id_(version_id), |
| 295 registration_id_(kInvalidServiceWorkerVersionId), | 301 registration_id_(kInvalidServiceWorkerVersionId), |
| 296 script_url_(script_url), | 302 script_url_(script_url), |
| 297 status_(NEW), | 303 status_(NEW), |
| 298 context_(context), | 304 context_(context), |
| 299 script_cache_map_(this, context), | 305 script_cache_map_(this, context), |
| 306 ping_timed_out_(false), |
| 300 is_doomed_(false), | 307 is_doomed_(false), |
| 301 skip_waiting_(false), | 308 skip_waiting_(false), |
| 302 weak_factory_(this) { | 309 weak_factory_(this) { |
| 303 DCHECK(context_); | 310 DCHECK(context_); |
| 304 DCHECK(registration); | 311 DCHECK(registration); |
| 305 if (registration) { | 312 if (registration) { |
| 306 registration_id_ = registration->id(); | 313 registration_id_ = registration->id(); |
| 307 scope_ = registration->pattern(); | 314 scope_ = registration->pattern(); |
| 308 } | 315 } |
| 309 context_->AddLiveVersion(this); | 316 context_->AddLiveVersion(this); |
| (...skipping 474 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 784 void ServiceWorkerVersion::Doom() { | 791 void ServiceWorkerVersion::Doom() { |
| 785 if (is_doomed_) | 792 if (is_doomed_) |
| 786 return; | 793 return; |
| 787 is_doomed_ = true; | 794 is_doomed_ = true; |
| 788 if (!HasControllee()) | 795 if (!HasControllee()) |
| 789 DoomInternal(); | 796 DoomInternal(); |
| 790 } | 797 } |
| 791 | 798 |
| 792 void ServiceWorkerVersion::SetDevToolsAttached(bool attached) { | 799 void ServiceWorkerVersion::SetDevToolsAttached(bool attached) { |
| 793 embedded_worker()->set_devtools_attached(attached); | 800 embedded_worker()->set_devtools_attached(attached); |
| 794 if (!attached && !stop_worker_timer_.IsRunning()) { | 801 if (attached) |
| 795 // If devtools is detached from this version and stop-worker-timer is not | 802 return; |
| 796 // running, try scheduling stop-worker-timer now. | 803 // If devtools is detached try scheduling the timers for stopping the worker |
| 804 // now. |
| 805 if (!stop_worker_timer_.IsRunning()) |
| 797 ScheduleStopWorker(); | 806 ScheduleStopWorker(); |
| 798 } | 807 if (!ping_worker_timer_.IsRunning()) |
| 808 StartPingWorker(); |
| 799 } | 809 } |
| 800 | 810 |
| 801 void ServiceWorkerVersion::SetMainScriptHttpResponseInfo( | 811 void ServiceWorkerVersion::SetMainScriptHttpResponseInfo( |
| 802 const net::HttpResponseInfo& http_info) { | 812 const net::HttpResponseInfo& http_info) { |
| 803 main_script_http_info_.reset(new net::HttpResponseInfo(http_info)); | 813 main_script_http_info_.reset(new net::HttpResponseInfo(http_info)); |
| 804 } | 814 } |
| 805 | 815 |
| 806 const net::HttpResponseInfo* | 816 const net::HttpResponseInfo* |
| 807 ServiceWorkerVersion::GetMainScriptHttpResponseInfo() { | 817 ServiceWorkerVersion::GetMainScriptHttpResponseInfo() { |
| 808 return main_script_http_info_.get(); | 818 return main_script_http_info_.get(); |
| 809 } | 819 } |
| 810 | 820 |
| 821 void ServiceWorkerVersion::OnScriptLoaded() { |
| 822 DCHECK_EQ(STARTING, running_status()); |
| 823 StartPingWorker(); |
| 824 } |
| 825 |
| 811 void ServiceWorkerVersion::OnStarted() { | 826 void ServiceWorkerVersion::OnStarted() { |
| 812 DCHECK_EQ(RUNNING, running_status()); | 827 DCHECK_EQ(RUNNING, running_status()); |
| 813 DCHECK(cache_listener_.get()); | 828 DCHECK(cache_listener_.get()); |
| 814 ScheduleStopWorker(); | 829 ScheduleStopWorker(); |
| 815 | 830 |
| 816 // Fire all start callbacks. | 831 // Fire all start callbacks. |
| 817 scoped_refptr<ServiceWorkerVersion> protect(this); | 832 scoped_refptr<ServiceWorkerVersion> protect(this); |
| 818 RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_OK); | 833 RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_OK); |
| 819 FOR_EACH_OBSERVER(Listener, listeners_, OnWorkerStarted(this)); | 834 FOR_EACH_OBSERVER(Listener, listeners_, OnWorkerStarted(this)); |
| 820 } | 835 } |
| 821 | 836 |
| 822 void ServiceWorkerVersion::OnStopped( | 837 void ServiceWorkerVersion::OnStopped( |
| 823 EmbeddedWorkerInstance::Status old_status) { | 838 EmbeddedWorkerInstance::Status old_status) { |
| 824 DCHECK_EQ(STOPPED, running_status()); | 839 DCHECK_EQ(STOPPED, running_status()); |
| 825 scoped_refptr<ServiceWorkerVersion> protect(this); | 840 scoped_refptr<ServiceWorkerVersion> protect(this); |
| 826 | 841 |
| 827 bool should_restart = !is_doomed() && !start_callbacks_.empty() && | 842 bool should_restart = !is_doomed() && !start_callbacks_.empty() && |
| 828 (old_status != EmbeddedWorkerInstance::STARTING); | 843 (old_status != EmbeddedWorkerInstance::STARTING); |
| 829 | 844 |
| 845 ping_worker_timer_.Stop(); |
| 846 if (ping_timed_out_) |
| 847 should_restart = false; |
| 848 |
| 830 // Fire all stop callbacks. | 849 // Fire all stop callbacks. |
| 831 RunCallbacks(this, &stop_callbacks_, SERVICE_WORKER_OK); | 850 RunCallbacks(this, &stop_callbacks_, SERVICE_WORKER_OK); |
| 832 | 851 |
| 833 if (!should_restart) { | 852 if (!should_restart) { |
| 834 // Let all start callbacks fail. | 853 // Let all start callbacks fail. |
| 835 RunCallbacks(this, &start_callbacks_, | 854 RunCallbacks(this, &start_callbacks_, |
| 836 SERVICE_WORKER_ERROR_START_WORKER_FAILED); | 855 SERVICE_WORKER_ERROR_START_WORKER_FAILED); |
| 837 } | 856 } |
| 838 | 857 |
| 839 // Let all message callbacks fail (this will also fire and clear all | 858 // Let all message callbacks fail (this will also fire and clear all |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 933 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClearCachedMetadata, | 952 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClearCachedMetadata, |
| 934 OnClearCachedMetadata) | 953 OnClearCachedMetadata) |
| 935 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToDocument, | 954 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToDocument, |
| 936 OnPostMessageToDocument) | 955 OnPostMessageToDocument) |
| 937 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FocusClient, | 956 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FocusClient, |
| 938 OnFocusClient) | 957 OnFocusClient) |
| 939 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SkipWaiting, | 958 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SkipWaiting, |
| 940 OnSkipWaiting) | 959 OnSkipWaiting) |
| 941 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClaimClients, | 960 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClaimClients, |
| 942 OnClaimClients) | 961 OnClaimClients) |
| 962 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_Pong, OnPongFromWorker) |
| 943 IPC_MESSAGE_UNHANDLED(handled = false) | 963 IPC_MESSAGE_UNHANDLED(handled = false) |
| 944 IPC_END_MESSAGE_MAP() | 964 IPC_END_MESSAGE_MAP() |
| 945 return handled; | 965 return handled; |
| 946 } | 966 } |
| 947 | 967 |
| 948 void ServiceWorkerVersion::OnStartMessageSent( | 968 void ServiceWorkerVersion::OnStartMessageSent( |
| 949 ServiceWorkerStatusCode status) { | 969 ServiceWorkerStatusCode status) { |
| 950 if (status != SERVICE_WORKER_OK) | 970 if (status != SERVICE_WORKER_OK) |
| 951 RunCallbacks(this, &start_callbacks_, status); | 971 RunCallbacks(this, &start_callbacks_, status); |
| 952 } | 972 } |
| (...skipping 389 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1342 | 1362 |
| 1343 ServiceWorkerRegistration* registration = | 1363 ServiceWorkerRegistration* registration = |
| 1344 context_->GetLiveRegistration(registration_id_); | 1364 context_->GetLiveRegistration(registration_id_); |
| 1345 if (!registration) { | 1365 if (!registration) { |
| 1346 callback.Run(SERVICE_WORKER_ERROR_ABORT); | 1366 callback.Run(SERVICE_WORKER_ERROR_ABORT); |
| 1347 return; | 1367 return; |
| 1348 } | 1368 } |
| 1349 registration->ClaimClients(callback); | 1369 registration->ClaimClients(callback); |
| 1350 } | 1370 } |
| 1351 | 1371 |
| 1372 void ServiceWorkerVersion::OnPongFromWorker() { |
| 1373 if (ping_timed_out_) |
| 1374 return; |
| 1375 SchedulePingWorker(); |
| 1376 } |
| 1377 |
| 1352 void ServiceWorkerVersion::DidClaimClients( | 1378 void ServiceWorkerVersion::DidClaimClients( |
| 1353 int request_id, ServiceWorkerStatusCode status) { | 1379 int request_id, ServiceWorkerStatusCode status) { |
| 1354 if (status == SERVICE_WORKER_ERROR_STATE) { | 1380 if (status == SERVICE_WORKER_ERROR_STATE) { |
| 1355 embedded_worker_->SendMessage(ServiceWorkerMsg_ClaimClientsError( | 1381 embedded_worker_->SendMessage(ServiceWorkerMsg_ClaimClientsError( |
| 1356 request_id, blink::WebServiceWorkerError::ErrorTypeState, | 1382 request_id, blink::WebServiceWorkerError::ErrorTypeState, |
| 1357 base::ASCIIToUTF16(kClaimClientsStateErrorMesage))); | 1383 base::ASCIIToUTF16(kClaimClientsStateErrorMesage))); |
| 1358 return; | 1384 return; |
| 1359 } | 1385 } |
| 1360 if (status == SERVICE_WORKER_ERROR_ABORT) { | 1386 if (status == SERVICE_WORKER_ERROR_ABORT) { |
| 1361 embedded_worker_->SendMessage(ServiceWorkerMsg_ClaimClientsError( | 1387 embedded_worker_->SendMessage(ServiceWorkerMsg_ClaimClientsError( |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1380 | 1406 |
| 1381 // We can get info for a frame that was navigating end ended up with a | 1407 // We can get info for a frame that was navigating end ended up with a |
| 1382 // different URL than expected. In such case, we should make sure to not | 1408 // different URL than expected. In such case, we should make sure to not |
| 1383 // expose cross-origin WindowClient. | 1409 // expose cross-origin WindowClient. |
| 1384 if (info.url.GetOrigin() != script_url_.GetOrigin()) | 1410 if (info.url.GetOrigin() != script_url_.GetOrigin()) |
| 1385 return; | 1411 return; |
| 1386 | 1412 |
| 1387 callback->AddClientInfo(client_id, info); | 1413 callback->AddClientInfo(client_id, info); |
| 1388 } | 1414 } |
| 1389 | 1415 |
| 1416 void ServiceWorkerVersion::PingWorker() { |
| 1417 if (running_status() != STARTING && running_status() != RUNNING) |
| 1418 return; |
| 1419 ServiceWorkerStatusCode status = |
| 1420 embedded_worker_->SendMessage(ServiceWorkerMsg_Ping()); |
| 1421 if (status != SERVICE_WORKER_OK) { |
| 1422 // TODO(falken): Maybe try resending Ping a few times first? |
| 1423 ping_timed_out_ = true; |
| 1424 StopWorkerIfIdle(); |
| 1425 return; |
| 1426 } |
| 1427 ping_worker_timer_.Start(FROM_HERE, |
| 1428 base::TimeDelta::FromSeconds(kPingTimeoutTime), |
| 1429 base::Bind(&ServiceWorkerVersion::OnPingTimeout, |
| 1430 weak_factory_.GetWeakPtr())); |
| 1431 } |
| 1432 |
| 1433 void ServiceWorkerVersion::StartPingWorker() { |
| 1434 ping_timed_out_ = false; |
| 1435 SchedulePingWorker(); |
| 1436 } |
| 1437 |
| 1438 void ServiceWorkerVersion::SchedulePingWorker() { |
| 1439 DCHECK(!ping_timed_out_); |
| 1440 ping_worker_timer_.Stop(); |
| 1441 ping_worker_timer_.Start(FROM_HERE, |
| 1442 base::TimeDelta::FromSeconds(kPingIntervalTime), |
| 1443 base::Bind(&ServiceWorkerVersion::PingWorker, |
| 1444 weak_factory_.GetWeakPtr())); |
| 1445 } |
| 1446 |
| 1447 void ServiceWorkerVersion::OnPingTimeout() { |
| 1448 if (running_status() != STARTING && running_status() != RUNNING) |
| 1449 return; |
| 1450 ping_timed_out_ = true; |
| 1451 // TODO(falken): Show a message to the developer that the SW was stopped due |
| 1452 // to timeout (crbug.com/457968). |
| 1453 StopWorkerIfIdle(); |
| 1454 } |
| 1455 |
| 1390 void ServiceWorkerVersion::ScheduleStopWorker() { | 1456 void ServiceWorkerVersion::ScheduleStopWorker() { |
| 1391 if (running_status() != RUNNING) | 1457 if (running_status() != RUNNING) |
| 1392 return; | 1458 return; |
| 1393 stop_worker_timer_.Stop(); | 1459 stop_worker_timer_.Stop(); |
| 1394 stop_worker_timer_.Start( | 1460 stop_worker_timer_.Start( |
| 1395 FROM_HERE, base::TimeDelta::FromSeconds( | 1461 FROM_HERE, base::TimeDelta::FromSeconds( |
| 1396 is_doomed_ ? kStopDoomedWorkerDelay : kStopWorkerDelay), | 1462 is_doomed_ ? kStopDoomedWorkerDelay : kStopWorkerDelay), |
| 1397 base::Bind(&ServiceWorkerVersion::StopWorkerIfIdle, | 1463 base::Bind(&ServiceWorkerVersion::StopWorkerIfIdle, |
| 1398 weak_factory_.GetWeakPtr())); | 1464 weak_factory_.GetWeakPtr())); |
| 1399 } | 1465 } |
| 1400 | 1466 |
| 1401 void ServiceWorkerVersion::StopWorkerIfIdle() { | 1467 void ServiceWorkerVersion::StopWorkerIfIdle() { |
| 1402 // Reschedule the stop the worker while there're inflight requests. | 1468 if (HasInflightRequests() && !ping_timed_out_) { |
| 1403 // (Note: we'll probably need to revisit this so that we can kill 'bad' SW. | |
| 1404 // See https://github.com/slightlyoff/ServiceWorker/issues/527) | |
| 1405 if (HasInflightRequests()) { | |
| 1406 ScheduleStopWorker(); | 1469 ScheduleStopWorker(); |
| 1407 return; | 1470 return; |
| 1408 } | 1471 } |
| 1409 if (running_status() == STOPPED || running_status() == STOPPING || | 1472 if (running_status() == STOPPED || running_status() == STOPPING || |
| 1410 !stop_callbacks_.empty()) { | 1473 !stop_callbacks_.empty()) { |
| 1411 return; | 1474 return; |
| 1412 } | 1475 } |
| 1476 |
| 1477 // TODO(falken): We may need to handle StopIfIdle failure and |
| 1478 // forcibly fail pending callbacks so no one is stuck waiting |
| 1479 // for the worker. |
| 1413 embedded_worker_->StopIfIdle(); | 1480 embedded_worker_->StopIfIdle(); |
| 1414 } | 1481 } |
| 1415 | 1482 |
| 1416 bool ServiceWorkerVersion::HasInflightRequests() const { | 1483 bool ServiceWorkerVersion::HasInflightRequests() const { |
| 1417 return | 1484 return |
| 1418 !activate_callbacks_.IsEmpty() || | 1485 !activate_callbacks_.IsEmpty() || |
| 1419 !install_callbacks_.IsEmpty() || | 1486 !install_callbacks_.IsEmpty() || |
| 1420 !fetch_callbacks_.IsEmpty() || | 1487 !fetch_callbacks_.IsEmpty() || |
| 1421 !sync_callbacks_.IsEmpty() || | 1488 !sync_callbacks_.IsEmpty() || |
| 1422 !notification_click_callbacks_.IsEmpty() || | 1489 !notification_click_callbacks_.IsEmpty() || |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1444 int request_id) { | 1511 int request_id) { |
| 1445 callbacks->Remove(request_id); | 1512 callbacks->Remove(request_id); |
| 1446 if (is_doomed_) { | 1513 if (is_doomed_) { |
| 1447 // The stop should be already scheduled, but try to stop immediately, in | 1514 // The stop should be already scheduled, but try to stop immediately, in |
| 1448 // order to release worker resources soon. | 1515 // order to release worker resources soon. |
| 1449 StopWorkerIfIdle(); | 1516 StopWorkerIfIdle(); |
| 1450 } | 1517 } |
| 1451 } | 1518 } |
| 1452 | 1519 |
| 1453 } // namespace content | 1520 } // namespace content |
| OLD | NEW |