Chromium Code Reviews| Index: content/browser/service_worker/service_worker_version.cc |
| diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc |
| index a1b225b36b96dd0313f51bddc91256d684cc213f..78e8447be423a64e343f46c47395a5c6f5d387b4 100644 |
| --- a/content/browser/service_worker/service_worker_version.cc |
| +++ b/content/browser/service_worker/service_worker_version.cc |
| @@ -92,6 +92,19 @@ void RunIDMapCallbacks(IDMAP* callbacks, const Params&... params) { |
| callbacks->Clear(); |
| } |
| +template <typename CallbackType, typename... Params> |
| +bool RunIDMapCallback(IDMap<CallbackType, IDMapOwnPointer>* callbacks, |
| + int request_id, |
| + const Params&... params) { |
| + CallbackType* callback = callbacks->Lookup(request_id); |
| + if (!callback) |
| + return false; |
| + |
| + callback->Run(params...); |
| + callbacks->Remove(request_id); |
| + return true; |
| +} |
| + |
| void RunStartWorkerCallback( |
| const StatusCallback& callback, |
| scoped_refptr<ServiceWorkerRegistration> protect, |
| @@ -142,7 +155,7 @@ void RunErrorMessageCallback( |
| void RunErrorCrossOriginConnectCallback( |
| const ServiceWorkerVersion::CrossOriginConnectCallback& callback, |
| ServiceWorkerStatusCode status) { |
| - callback.Run(status, false); |
| + callback.Run(status, false /* accept_connection */); |
| } |
| using WindowOpenedCallback = base::Callback<void(int, int)>; |
| @@ -304,6 +317,7 @@ void OnGetClientsFromUI( |
| } // namespace |
| const int ServiceWorkerVersion::kStartWorkerTimeoutMinutes = 5; |
| +const int ServiceWorkerVersion::kRequestTimeoutMinutes = 5; |
|
kinuko
2015/03/25 04:18:03
I assume we can change this value and merge it if
falken
2015/03/25 06:10:00
Yes that's reasonable. Or just skip pushing onto |
|
| ServiceWorkerVersion::ServiceWorkerVersion( |
| ServiceWorkerRegistration* registration, |
| @@ -536,7 +550,7 @@ void ServiceWorkerVersion::DispatchFetchEvent( |
| prepare_callback.Run(); |
| - int request_id = fetch_callbacks_.Add(new FetchCallback(fetch_callback)); |
| + int request_id = AddRequest(fetch_callback, &fetch_callbacks_, REQUEST_FETCH); |
| ServiceWorkerStatusCode status = embedded_worker_->SendMessage( |
| ServiceWorkerMsg_FetchEvent(request_id, request)); |
| if (status != SERVICE_WORKER_OK) { |
| @@ -566,7 +580,7 @@ void ServiceWorkerVersion::DispatchSyncEvent(const StatusCallback& callback) { |
| return; |
| } |
| - int request_id = sync_callbacks_.Add(new StatusCallback(callback)); |
| + int request_id = AddRequest(callback, &sync_callbacks_, REQUEST_SYNC); |
| ServiceWorkerStatusCode status = embedded_worker_->SendMessage( |
| ServiceWorkerMsg_SyncEvent(request_id)); |
| if (status != SERVICE_WORKER_OK) { |
| @@ -591,8 +605,8 @@ void ServiceWorkerVersion::DispatchNotificationClickEvent( |
| return; |
| } |
| - int request_id = |
| - notification_click_callbacks_.Add(new StatusCallback(callback)); |
| + int request_id = AddRequest(callback, ¬ification_click_callbacks_, |
| + REQUEST_NOTIFICATION_CLICK); |
| ServiceWorkerStatusCode status = embedded_worker_->SendMessage( |
| ServiceWorkerMsg_NotificationClickEvent(request_id, |
| notification_id, |
| @@ -616,7 +630,7 @@ void ServiceWorkerVersion::DispatchPushEvent(const StatusCallback& callback, |
| return; |
| } |
| - int request_id = push_callbacks_.Add(new StatusCallback(callback)); |
| + int request_id = AddRequest(callback, &push_callbacks_, REQUEST_PUSH); |
| ServiceWorkerStatusCode status = embedded_worker_->SendMessage( |
| ServiceWorkerMsg_PushEvent(request_id, data)); |
| if (status != SERVICE_WORKER_OK) { |
| @@ -652,7 +666,8 @@ void ServiceWorkerVersion::DispatchGeofencingEvent( |
| return; |
| } |
| - int request_id = geofencing_callbacks_.Add(new StatusCallback(callback)); |
| + int request_id = |
| + AddRequest(callback, &geofencing_callbacks_, REQUEST_GEOFENCING); |
| ServiceWorkerStatusCode status = |
| embedded_worker_->SendMessage(ServiceWorkerMsg_GeofencingEvent( |
| request_id, event_type, region_id, region)); |
| @@ -683,8 +698,8 @@ void ServiceWorkerVersion::DispatchCrossOriginConnectEvent( |
| return; |
| } |
| - int request_id = cross_origin_connect_callbacks_.Add( |
| - new CrossOriginConnectCallback(callback)); |
| + int request_id = AddRequest(callback, &cross_origin_connect_callbacks_, |
| + REQUEST_CROSS_ORIGIN_CONNECT); |
| ServiceWorkerStatusCode status = embedded_worker_->SendMessage( |
| ServiceWorkerMsg_CrossOriginConnectEvent(request_id, client)); |
| if (status != SERVICE_WORKER_OK) { |
| @@ -780,9 +795,16 @@ void ServiceWorkerVersion::Doom() { |
| void ServiceWorkerVersion::SetDevToolsAttached(bool attached) { |
| embedded_worker()->set_devtools_attached(attached); |
| if (attached) { |
| + // TODO(falken): Canceling the timeouts when debugging could cause |
| + // heisenbugs; we should instead run them as normal show an educational |
| + // message in DevTools when they occur. |
|
kinuko
2015/03/25 04:18:03
Needs a bug?
falken
2015/03/25 06:10:00
Done.
|
| + |
| // Don't record the startup time metric once DevTools is attached. |
| ClearTick(&start_time_); |
| skip_recording_startup_time_ = true; |
| + |
| + // Cancel request timeouts. |
| + SetAllRequestTimes(base::TimeTicks()); |
| return; |
| } |
| if (!start_callbacks_.empty()) { |
| @@ -792,6 +814,9 @@ void ServiceWorkerVersion::SetDevToolsAttached(bool attached) { |
| << running_status(); |
| RestartTick(&start_time_); |
| } |
| + |
| + // Reactivate request timeouts. |
| + SetAllRequestTimes(base::TimeTicks::Now()); |
| } |
| void ServiceWorkerVersion::SetMainScriptHttpResponseInfo( |
| @@ -804,6 +829,13 @@ ServiceWorkerVersion::GetMainScriptHttpResponseInfo() { |
| return main_script_http_info_.get(); |
| } |
| +ServiceWorkerVersion::RequestInfo::RequestInfo(int id, RequestType type) |
| + : id(id), type(type), time(base::TimeTicks::Now()) { |
| +} |
| + |
| +ServiceWorkerVersion::RequestInfo::~RequestInfo() { |
| +} |
| + |
| void ServiceWorkerVersion::OnScriptLoaded() { |
| DCHECK_EQ(STARTING, running_status()); |
| // Activate ping/pong now that JavaScript execution will start. |
| @@ -966,7 +998,7 @@ void ServiceWorkerVersion::DispatchInstallEventAfterStartWorker( |
| DCHECK_EQ(RUNNING, running_status()) |
| << "Worker stopped too soon after it was started."; |
| - int request_id = install_callbacks_.Add(new StatusCallback(callback)); |
| + int request_id = AddRequest(callback, &install_callbacks_, REQUEST_INSTALL); |
| ServiceWorkerStatusCode status = embedded_worker_->SendMessage( |
| ServiceWorkerMsg_InstallEvent(request_id)); |
| if (status != SERVICE_WORKER_OK) { |
| @@ -980,7 +1012,7 @@ void ServiceWorkerVersion::DispatchActivateEventAfterStartWorker( |
| DCHECK_EQ(RUNNING, running_status()) |
| << "Worker stopped too soon after it was started."; |
| - int request_id = activate_callbacks_.Add(new StatusCallback(callback)); |
| + int request_id = AddRequest(callback, &activate_callbacks_, REQUEST_ACTIVATE); |
| ServiceWorkerStatusCode status = |
| embedded_worker_->SendMessage(ServiceWorkerMsg_ActivateEvent(request_id)); |
| if (status != SERVICE_WORKER_OK) { |
| @@ -1541,9 +1573,22 @@ void ServiceWorkerVersion::OnTimeoutTimer() { |
| return; |
| } |
| - // This check occurs after the start_time_ timeout check, since in that case |
| - // the start callbacks should fail with ERROR_TIMEOUT. In the other timeout |
| - // checks, there's nothing more to do as the worker is already stopping. |
| + // Requests have not finished within a certain period. |
| + bool callback_timed_out = false; |
| + while (!requests_.empty()) { |
| + RequestInfo info = requests_.front(); |
| + if (GetTickDuration(info.time) < |
| + base::TimeDelta::FromMinutes(kRequestTimeoutMinutes)) |
| + break; |
| + if (OnRequestTimeout(info)) |
| + callback_timed_out = true; |
| + requests_.pop(); |
| + } |
| + if (callback_timed_out && running_status() != STOPPING) |
| + embedded_worker_->Stop(); |
| + |
| + // For the timeouts below, there are no callbacks to timeout so there is |
| + // nothing more to do if the worker is already stopping. |
| if (running_status() == STOPPING) |
| return; |
| @@ -1681,4 +1726,57 @@ void ServiceWorkerVersion::RemoveCallbackAndStopIfDoomed( |
| } |
| } |
| +template <typename CallbackType> |
| +int ServiceWorkerVersion::AddRequest( |
| + const CallbackType& callback, |
| + IDMap<CallbackType, IDMapOwnPointer>* callback_map, |
| + RequestType request_type) { |
| + int request_id = callback_map->Add(new CallbackType(callback)); |
| + requests_.push(RequestInfo(request_id, request_type)); |
| + return request_id; |
| +} |
| + |
| +bool ServiceWorkerVersion::OnRequestTimeout(const RequestInfo& info) { |
| + switch (info.type) { |
| + case REQUEST_ACTIVATE: |
| + return RunIDMapCallback(&activate_callbacks_, info.id, |
| + SERVICE_WORKER_ERROR_TIMEOUT); |
| + case REQUEST_INSTALL: |
| + return RunIDMapCallback(&install_callbacks_, info.id, |
| + SERVICE_WORKER_ERROR_TIMEOUT); |
| + case REQUEST_FETCH: |
| + return RunIDMapCallback( |
| + &fetch_callbacks_, info.id, SERVICE_WORKER_ERROR_TIMEOUT, |
| + /* The other args are ignored for non-OK status. */ |
| + SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK, ServiceWorkerResponse()); |
| + case REQUEST_SYNC: |
| + return RunIDMapCallback(&sync_callbacks_, info.id, |
| + SERVICE_WORKER_ERROR_TIMEOUT); |
| + case REQUEST_NOTIFICATION_CLICK: |
| + return RunIDMapCallback(¬ification_click_callbacks_, info.id, |
| + SERVICE_WORKER_ERROR_TIMEOUT); |
| + case REQUEST_PUSH: |
| + return RunIDMapCallback(&push_callbacks_, info.id, |
| + SERVICE_WORKER_ERROR_TIMEOUT); |
| + case REQUEST_GEOFENCING: |
| + return RunIDMapCallback(&geofencing_callbacks_, info.id, |
| + SERVICE_WORKER_ERROR_TIMEOUT); |
| + case REQUEST_CROSS_ORIGIN_CONNECT: |
| + return RunIDMapCallback(&cross_origin_connect_callbacks_, info.id, |
| + SERVICE_WORKER_ERROR_TIMEOUT, |
| + false /* accept_connection */); |
| + } |
| +} |
| + |
| +void ServiceWorkerVersion::SetAllRequestTimes(const base::TimeTicks& ticks) { |
| + std::queue<RequestInfo> new_callback_timeouts; |
| + while (!requests_.empty()) { |
| + RequestInfo info = requests_.front(); |
| + info.time = ticks; |
| + new_callback_timeouts.push(info); |
| + requests_.pop(); |
| + } |
| + requests_.swap(new_callback_timeouts); |
| +} |
| + |
| } // namespace content |