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

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: rebase? 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 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
77 // (Note that if all references to the version is dropped the worker 77 // (Note that if all references to the version is dropped the worker
78 // is also stopped without delay) 78 // is also stopped without delay)
79 const int64 kStopWorkerDelay = 30; // 30 secs. 79 const int64 kStopWorkerDelay = 30; // 30 secs.
80 80
81 // Delay for attempting to stop a doomed worker with in-flight requests. 81 // Delay for attempting to stop a doomed worker with in-flight requests.
82 const int64 kStopDoomedWorkerDelay = 5; // 5 secs. 82 const int64 kStopDoomedWorkerDelay = 5; // 5 secs.
83 83
84 // Default delay for scheduled update. 84 // Default delay for scheduled update.
85 const int kUpdateDelaySeconds = 1; 85 const int kUpdateDelaySeconds = 1;
86 86
87 // Delay between sending pings to the worker.
88 const int kPingIntervalTime = 10; // 10 secs.
89
90 // Timeout for waiting for a response to a ping.
91 const int kPingTimeoutTime = 30; // 30 secs.
92
87 const char kClaimClientsStateErrorMesage[] = 93 const char kClaimClientsStateErrorMesage[] =
88 "Only the active worker can claim clients."; 94 "Only the active worker can claim clients.";
89 95
90 const char kClaimClientsShutdownErrorMesage[] = 96 const char kClaimClientsShutdownErrorMesage[] =
91 "Failed to claim clients due to Service Worker system shutdown."; 97 "Failed to claim clients due to Service Worker system shutdown.";
92 98
93 void RunSoon(const base::Closure& callback) { 99 void RunSoon(const base::Closure& callback) {
94 if (!callback.is_null()) 100 if (!callback.is_null())
95 base::MessageLoop::current()->PostTask(FROM_HERE, callback); 101 base::MessageLoop::current()->PostTask(FROM_HERE, callback);
96 } 102 }
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after
272 ServiceWorkerRegistration* registration, 278 ServiceWorkerRegistration* registration,
273 const GURL& script_url, 279 const GURL& script_url,
274 int64 version_id, 280 int64 version_id,
275 base::WeakPtr<ServiceWorkerContextCore> context) 281 base::WeakPtr<ServiceWorkerContextCore> context)
276 : version_id_(version_id), 282 : version_id_(version_id),
277 registration_id_(kInvalidServiceWorkerVersionId), 283 registration_id_(kInvalidServiceWorkerVersionId),
278 script_url_(script_url), 284 script_url_(script_url),
279 status_(NEW), 285 status_(NEW),
280 context_(context), 286 context_(context),
281 script_cache_map_(this, context), 287 script_cache_map_(this, context),
288 ping_timed_out_(false),
282 is_doomed_(false), 289 is_doomed_(false),
283 skip_waiting_(false), 290 skip_waiting_(false),
284 weak_factory_(this) { 291 weak_factory_(this) {
285 DCHECK(context_); 292 DCHECK(context_);
286 DCHECK(registration); 293 DCHECK(registration);
287 if (registration) { 294 if (registration) {
288 registration_id_ = registration->id(); 295 registration_id_ = registration->id();
289 scope_ = registration->pattern(); 296 scope_ = registration->pattern();
290 } 297 }
291 context_->AddLiveVersion(this); 298 context_->AddLiveVersion(this);
(...skipping 488 matching lines...) Expand 10 before | Expand all | Expand 10 after
780 void ServiceWorkerVersion::Doom() { 787 void ServiceWorkerVersion::Doom() {
781 if (is_doomed_) 788 if (is_doomed_)
782 return; 789 return;
783 is_doomed_ = true; 790 is_doomed_ = true;
784 if (!HasControllee()) 791 if (!HasControllee())
785 DoomInternal(); 792 DoomInternal();
786 } 793 }
787 794
788 void ServiceWorkerVersion::SetDevToolsAttached(bool attached) { 795 void ServiceWorkerVersion::SetDevToolsAttached(bool attached) {
789 embedded_worker()->set_devtools_attached(attached); 796 embedded_worker()->set_devtools_attached(attached);
790 if (!attached && !stop_worker_timer_.IsRunning()) { 797 if (attached)
791 // If devtools is detached from this version and stop-worker-timer is not 798 return;
792 // running, try scheduling stop-worker-timer now. 799 // If devtools is detached try scheduling the timers for stopping the worker
800 // now.
801 if (!stop_worker_timer_.IsRunning())
793 ScheduleStopWorker(); 802 ScheduleStopWorker();
794 } 803 if (!ping_worker_timer_.IsRunning())
804 SchedulePingWorker();
795 } 805 }
796 806
797 void ServiceWorkerVersion::SetMainScriptHttpResponseInfo( 807 void ServiceWorkerVersion::SetMainScriptHttpResponseInfo(
798 const net::HttpResponseInfo& http_info) { 808 const net::HttpResponseInfo& http_info) {
799 main_script_http_info_.reset(new net::HttpResponseInfo(http_info)); 809 main_script_http_info_.reset(new net::HttpResponseInfo(http_info));
800 } 810 }
801 811
802 const net::HttpResponseInfo* 812 const net::HttpResponseInfo*
803 ServiceWorkerVersion::GetMainScriptHttpResponseInfo() { 813 ServiceWorkerVersion::GetMainScriptHttpResponseInfo() {
804 return main_script_http_info_.get(); 814 return main_script_http_info_.get();
805 } 815 }
806 816
817 void ServiceWorkerVersion::OnScriptLoaded() {
818 DCHECK_EQ(STARTING, running_status());
819 SchedulePingWorker();
michaeln 2015/02/11 01:02:21 Would it make sense to only turn the ping monitor
falken 2015/02/11 16:10:24 That's a good thing to think about. In practice, p
820 }
821
807 void ServiceWorkerVersion::OnStarted() { 822 void ServiceWorkerVersion::OnStarted() {
808 DCHECK_EQ(RUNNING, running_status()); 823 DCHECK_EQ(RUNNING, running_status());
809 DCHECK(cache_listener_.get()); 824 DCHECK(cache_listener_.get());
810 ScheduleStopWorker(); 825 ScheduleStopWorker();
811 826
812 // Fire all start callbacks. 827 // Fire all start callbacks.
813 scoped_refptr<ServiceWorkerVersion> protect(this); 828 scoped_refptr<ServiceWorkerVersion> protect(this);
814 RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_OK); 829 RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_OK);
815 FOR_EACH_OBSERVER(Listener, listeners_, OnWorkerStarted(this)); 830 FOR_EACH_OBSERVER(Listener, listeners_, OnWorkerStarted(this));
816 } 831 }
817 832
818 void ServiceWorkerVersion::OnStopped( 833 void ServiceWorkerVersion::OnStopped(
819 EmbeddedWorkerInstance::Status old_status) { 834 EmbeddedWorkerInstance::Status old_status) {
820 DCHECK_EQ(STOPPED, running_status()); 835 DCHECK_EQ(STOPPED, running_status());
821 scoped_refptr<ServiceWorkerVersion> protect(this); 836 scoped_refptr<ServiceWorkerVersion> protect(this);
822 837
823 bool should_restart = !is_doomed() && !start_callbacks_.empty() && 838 bool should_restart = !is_doomed() && !start_callbacks_.empty() &&
824 (old_status != EmbeddedWorkerInstance::STARTING); 839 (old_status != EmbeddedWorkerInstance::STARTING);
825 840
841 ping_worker_timer_.Stop();
842 if (ping_timed_out_)
843 should_restart = false;
844
826 // Fire all stop callbacks. 845 // Fire all stop callbacks.
827 RunCallbacks(this, &stop_callbacks_, SERVICE_WORKER_OK); 846 RunCallbacks(this, &stop_callbacks_, SERVICE_WORKER_OK);
828 847
829 if (!should_restart) { 848 if (!should_restart) {
830 // Let all start callbacks fail. 849 // Let all start callbacks fail.
831 RunCallbacks(this, &start_callbacks_, 850 RunCallbacks(this, &start_callbacks_,
832 SERVICE_WORKER_ERROR_START_WORKER_FAILED); 851 SERVICE_WORKER_ERROR_START_WORKER_FAILED);
833 } 852 }
834 853
835 // Let all message callbacks fail (this will also fire and clear all 854 // Let all message callbacks fail (this will also fire and clear all
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
925 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_OpenWindow, 944 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_OpenWindow,
926 OnOpenWindow) 945 OnOpenWindow)
927 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToDocument, 946 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToDocument,
928 OnPostMessageToDocument) 947 OnPostMessageToDocument)
929 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FocusClient, 948 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FocusClient,
930 OnFocusClient) 949 OnFocusClient)
931 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SkipWaiting, 950 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SkipWaiting,
932 OnSkipWaiting) 951 OnSkipWaiting)
933 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClaimClients, 952 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClaimClients,
934 OnClaimClients) 953 OnClaimClients)
954 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_Pong, OnPongFromWorker)
935 IPC_MESSAGE_UNHANDLED(handled = false) 955 IPC_MESSAGE_UNHANDLED(handled = false)
936 IPC_END_MESSAGE_MAP() 956 IPC_END_MESSAGE_MAP()
937 return handled; 957 return handled;
938 } 958 }
939 959
940 void ServiceWorkerVersion::OnStartMessageSent( 960 void ServiceWorkerVersion::OnStartMessageSent(
941 ServiceWorkerStatusCode status) { 961 ServiceWorkerStatusCode status) {
942 if (status != SERVICE_WORKER_OK) 962 if (status != SERVICE_WORKER_OK)
943 RunCallbacks(this, &start_callbacks_, status); 963 RunCallbacks(this, &start_callbacks_, status);
944 } 964 }
(...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after
1315 1335
1316 ServiceWorkerRegistration* registration = 1336 ServiceWorkerRegistration* registration =
1317 context_->GetLiveRegistration(registration_id_); 1337 context_->GetLiveRegistration(registration_id_);
1318 if (!registration) { 1338 if (!registration) {
1319 callback.Run(SERVICE_WORKER_ERROR_ABORT); 1339 callback.Run(SERVICE_WORKER_ERROR_ABORT);
1320 return; 1340 return;
1321 } 1341 }
1322 registration->ClaimClients(callback); 1342 registration->ClaimClients(callback);
1323 } 1343 }
1324 1344
1345 void ServiceWorkerVersion::OnPongFromWorker() {
1346 ping_worker_timer_.Stop();
1347 SchedulePingWorker();
1348 }
1349
1325 void ServiceWorkerVersion::DidClaimClients( 1350 void ServiceWorkerVersion::DidClaimClients(
1326 int request_id, ServiceWorkerStatusCode status) { 1351 int request_id, ServiceWorkerStatusCode status) {
1327 if (status == SERVICE_WORKER_ERROR_STATE) { 1352 if (status == SERVICE_WORKER_ERROR_STATE) {
1328 embedded_worker_->SendMessage(ServiceWorkerMsg_ClaimClientsError( 1353 embedded_worker_->SendMessage(ServiceWorkerMsg_ClaimClientsError(
1329 request_id, blink::WebServiceWorkerError::ErrorTypeState, 1354 request_id, blink::WebServiceWorkerError::ErrorTypeState,
1330 base::ASCIIToUTF16(kClaimClientsStateErrorMesage))); 1355 base::ASCIIToUTF16(kClaimClientsStateErrorMesage)));
1331 return; 1356 return;
1332 } 1357 }
1333 if (status == SERVICE_WORKER_ERROR_ABORT) { 1358 if (status == SERVICE_WORKER_ERROR_ABORT) {
1334 embedded_worker_->SendMessage(ServiceWorkerMsg_ClaimClientsError( 1359 embedded_worker_->SendMessage(ServiceWorkerMsg_ClaimClientsError(
(...skipping 18 matching lines...) Expand all
1353 1378
1354 // We can get info for a frame that was navigating end ended up with a 1379 // We can get info for a frame that was navigating end ended up with a
1355 // different URL than expected. In such case, we should make sure to not 1380 // different URL than expected. In such case, we should make sure to not
1356 // expose cross-origin WindowClient. 1381 // expose cross-origin WindowClient.
1357 if (info.url.GetOrigin() != script_url_.GetOrigin()) 1382 if (info.url.GetOrigin() != script_url_.GetOrigin())
1358 return; 1383 return;
1359 1384
1360 callback->AddClientInfo(client_id, info); 1385 callback->AddClientInfo(client_id, info);
1361 } 1386 }
1362 1387
1388 void ServiceWorkerVersion::PingWorker() {
1389 if (running_status() != STARTING && running_status() != RUNNING)
1390 return;
1391 ServiceWorkerStatusCode status =
1392 embedded_worker_->SendMessage(ServiceWorkerMsg_Ping());
1393 if (status != SERVICE_WORKER_OK) {
1394 OnPingTimeout();
1395 return;
1396 }
1397 ping_worker_timer_.Start(FROM_HERE,
1398 base::TimeDelta::FromSeconds(kPingTimeoutTime),
1399 base::Bind(&ServiceWorkerVersion::OnPingTimeout,
1400 weak_factory_.GetWeakPtr()));
1401 }
1402
1403 void ServiceWorkerVersion::SchedulePingWorker() {
1404 DCHECK(!ping_worker_timer_.IsRunning());
1405 ping_timed_out_ = false;
1406 ping_worker_timer_.Start(FROM_HERE,
1407 base::TimeDelta::FromSeconds(kPingIntervalTime),
1408 base::Bind(&ServiceWorkerVersion::PingWorker,
1409 weak_factory_.GetWeakPtr()));
1410 }
1411
1412 void ServiceWorkerVersion::OnPingTimeout() {
1413 if (running_status() != STARTING && running_status() != RUNNING)
1414 return;
1415 ping_timed_out_ = true;
1416 StopWorkerIfIdle();
kinuko 2015/02/10 09:15:52 In this case we should probably show some error or
falken 2015/02/11 16:10:24 Yes I agree. I don't know a good place we'd show t
1417 }
1418
1363 void ServiceWorkerVersion::ScheduleStopWorker() { 1419 void ServiceWorkerVersion::ScheduleStopWorker() {
1364 if (running_status() != RUNNING) 1420 if (running_status() != RUNNING)
1365 return; 1421 return;
1366 stop_worker_timer_.Stop(); 1422 stop_worker_timer_.Stop();
1367 stop_worker_timer_.Start( 1423 stop_worker_timer_.Start(
1368 FROM_HERE, base::TimeDelta::FromSeconds( 1424 FROM_HERE, base::TimeDelta::FromSeconds(
1369 is_doomed_ ? kStopDoomedWorkerDelay : kStopWorkerDelay), 1425 is_doomed_ ? kStopDoomedWorkerDelay : kStopWorkerDelay),
1370 base::Bind(&ServiceWorkerVersion::StopWorkerIfIdle, 1426 base::Bind(&ServiceWorkerVersion::StopWorkerIfIdle,
1371 weak_factory_.GetWeakPtr())); 1427 weak_factory_.GetWeakPtr()));
1372 } 1428 }
1373 1429
1374 void ServiceWorkerVersion::StopWorkerIfIdle() { 1430 void ServiceWorkerVersion::StopWorkerIfIdle() {
1375 // Reschedule the stop the worker while there're inflight requests. 1431 if (HasInflightRequests() && !ping_timed_out_) {
1376 // (Note: we'll probably need to revisit this so that we can kill 'bad' SW.
1377 // See https://github.com/slightlyoff/ServiceWorker/issues/527)
1378 if (HasInflightRequests()) {
1379 ScheduleStopWorker(); 1432 ScheduleStopWorker();
1380 return; 1433 return;
1381 } 1434 }
1382 if (running_status() == STOPPED || running_status() == STOPPING || 1435 if (running_status() == STOPPED || running_status() == STOPPING ||
1383 !stop_callbacks_.empty()) { 1436 !stop_callbacks_.empty()) {
1384 return; 1437 return;
1385 } 1438 }
1386 embedded_worker_->StopIfIdle(); 1439 embedded_worker_->StopIfIdle();
1387 } 1440 }
1388 1441
(...skipping 28 matching lines...) Expand all
1417 int request_id) { 1470 int request_id) {
1418 callbacks->Remove(request_id); 1471 callbacks->Remove(request_id);
1419 if (is_doomed_) { 1472 if (is_doomed_) {
1420 // The stop should be already scheduled, but try to stop immediately, in 1473 // The stop should be already scheduled, but try to stop immediately, in
1421 // order to release worker resources soon. 1474 // order to release worker resources soon.
1422 StopWorkerIfIdle(); 1475 StopWorkerIfIdle();
1423 } 1476 }
1424 } 1477 }
1425 1478
1426 } // namespace content 1479 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698