Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: content/browser/service_worker/service_worker_version.cc

Issue 912753002: Stop Service Workers that execute JavaScript for too long. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rethink Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « content/browser/service_worker/service_worker_version.h ('k') | content/common/service_worker/service_worker_messages.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698