Chromium Code Reviews| Index: content/browser/service_worker/service_worker_url_request_job.cc |
| diff --git a/content/browser/service_worker/service_worker_url_request_job.cc b/content/browser/service_worker/service_worker_url_request_job.cc |
| index 37daad262323d988763fe3ea282a44720c8ebb02..8cfc2699cc506385553797675df66f5a1883c936 100644 |
| --- a/content/browser/service_worker/service_worker_url_request_job.cc |
| +++ b/content/browser/service_worker/service_worker_url_request_job.cc |
| @@ -88,6 +88,8 @@ net::NetLog::EventType RequestJobResultToNetEventType( |
| return n::TYPE_SERVICE_WORKER_ERROR_KILLED_WITH_STREAM; |
| case m::REQUEST_JOB_ERROR_BAD_DELEGATE: |
| return n::TYPE_SERVICE_WORKER_ERROR_BAD_DELEGATE; |
| + case m::REQUEST_JOB_ERROR_REQUEST_BODY_BLOB_FAILED: |
| + return n::TYPE_SERVICE_WORKER_ERROR_REQUEST_BODY_BLOB_FAILED; |
| // We can't log if there's no request; fallthrough. |
| case m::REQUEST_JOB_ERROR_NO_REQUEST: |
| // Obsolete types; fallthrough. |
| @@ -403,10 +405,7 @@ void ServiceWorkerURLRequestJob::MaybeStartRequest() { |
| } |
| void ServiceWorkerURLRequestJob::StartRequest() { |
| - if (request()) { |
| - request()->net_log().AddEvent( |
| - net::NetLog::TYPE_SERVICE_WORKER_START_REQUEST); |
| - } |
| + request()->net_log().AddEvent(net::NetLog::TYPE_SERVICE_WORKER_START_REQUEST); |
| switch (response_type_) { |
| case NOT_DETERMINED: |
| @@ -421,33 +420,40 @@ void ServiceWorkerURLRequestJob::StartRequest() { |
| return; |
| case FORWARD_TO_SERVICE_WORKER: |
| - ServiceWorkerMetrics::URLRequestJobResult result = |
| - ServiceWorkerMetrics::REQUEST_JOB_ERROR_BAD_DELEGATE; |
| - ServiceWorkerVersion* active_worker = |
| - delegate_->GetServiceWorkerVersion(&result); |
| - if (!active_worker) { |
| - RecordResult(result); |
| - DeliverErrorResponse(); |
| + if (HasRequestBody()) { |
| + WaitForRequestBobyBlobsToComplete(); |
| return; |
| } |
| - DCHECK(!fetch_dispatcher_); |
| - // Send a fetch event to the ServiceWorker associated to the |
| - // provider_host. |
| - fetch_dispatcher_.reset(new ServiceWorkerFetchDispatcher( |
| - CreateFetchRequest(), active_worker, resource_type_, |
| - base::Bind(&ServiceWorkerURLRequestJob::DidPrepareFetchEvent, |
| - weak_factory_.GetWeakPtr()), |
| - base::Bind(&ServiceWorkerURLRequestJob::DidDispatchFetchEvent, |
| - weak_factory_.GetWeakPtr()))); |
| - worker_start_time_ = base::TimeTicks::Now(); |
| - fetch_dispatcher_->Run(); |
| + DispatchToWorker(); |
| return; |
| } |
| NOTREACHED(); |
| } |
| +void ServiceWorkerURLRequestJob::DispatchToWorker() { |
| + ServiceWorkerMetrics::URLRequestJobResult result = |
| + ServiceWorkerMetrics::REQUEST_JOB_ERROR_BAD_DELEGATE; |
| + ServiceWorkerVersion* active_worker = |
| + delegate_->GetServiceWorkerVersion(&result); |
| + if (!active_worker) { |
| + RecordResult(result); |
| + DeliverErrorResponse(); |
| + return; |
| + } |
| + |
| + DCHECK(!fetch_dispatcher_); |
| + fetch_dispatcher_.reset(new ServiceWorkerFetchDispatcher( |
| + CreateFetchRequest(), active_worker, resource_type_, |
| + base::Bind(&ServiceWorkerURLRequestJob::DidPrepareFetchEvent, |
| + weak_factory_.GetWeakPtr()), |
| + base::Bind(&ServiceWorkerURLRequestJob::DidDispatchFetchEvent, |
| + weak_factory_.GetWeakPtr()))); |
| + worker_start_time_ = base::TimeTicks::Now(); |
| + fetch_dispatcher_->Run(); |
| +} |
| + |
| std::unique_ptr<ServiceWorkerFetchRequest> |
| ServiceWorkerURLRequestJob::CreateFetchRequest() { |
| std::string blob_uuid; |
| @@ -861,4 +867,80 @@ bool ServiceWorkerURLRequestJob::IsMainResourceLoad() const { |
| return ServiceWorkerUtils::IsMainResourceType(resource_type_); |
| } |
| +bool ServiceWorkerURLRequestJob::HasRequestBody() { |
| + // |has_upload| must be checked since it may have been cleared while handling |
| + // a redirect. |
| + return request_->has_upload() && body_.get() && blob_storage_context_; |
| +} |
| + |
| +void ServiceWorkerURLRequestJob::WaitForRequestBobyBlobsToComplete() { |
| + DCHECK(HasRequestBody()); |
| + |
| + num_pending_request_body_blobs_ = 0; |
| + for (const ResourceRequestBody::Element& element : (*body_->elements())) { |
| + if (element.type() == ResourceRequestBody::Element::TYPE_BLOB) |
| + ++num_pending_request_body_blobs_; |
| + } |
| + |
| + if (num_pending_request_body_blobs_ == 0) { |
| + DispatchToWorker(); |
| + return; |
| + } |
| + |
| + TRACE_EVENT_ASYNC_BEGIN1( |
| + "ServiceWorker", |
| + "ServiceWorkerURLRequestJob::WaitForRequestBobyBlobsToComplete", this, |
| + "URL", request()->url().spec()); |
| + request()->net_log().AddEvent( |
| + net::NetLog::TYPE_SERVICE_WORKER_REQUEST_BODY_BLOB_CONSTRUCTION_STARTED); |
| + |
| + for (const ResourceRequestBody::Element& element : (*body_->elements())) { |
| + if (element.type() == ResourceRequestBody::Element::TYPE_BLOB) { |
| + std::unique_ptr<storage::BlobDataHandle> handle = |
|
dmurph
2016/05/11 21:35:58
You can check if the blob is building before calli
falken
2016/05/12 08:49:33
Done. I had considered that but was worried about
|
| + blob_storage_context_->GetBlobDataFromUUID(element.blob_uuid()); |
| + handle->RunOnConstructionComplete( |
| + base::Bind(&ServiceWorkerURLRequestJob::OneRequestBodyBlobCompleted, |
| + GetWeakPtr())); |
| + } |
| + } |
| +} |
| + |
| +void ServiceWorkerURLRequestJob::OneRequestBodyBlobCompleted( |
| + bool success, |
| + storage::IPCBlobCreationCancelCode cancel_code) { |
| + if (num_pending_request_body_blobs_ == 0) { |
| + // We already ran the callback. |
| + return; |
| + } |
| + |
| + if (success) |
| + --num_pending_request_body_blobs_; |
| + else |
| + num_pending_request_body_blobs_ = 0; |
| + |
| + if (num_pending_request_body_blobs_ == 0) |
| + RequestBodyBlobsCompleted(success, cancel_code); |
| +} |
| + |
| +void ServiceWorkerURLRequestJob::RequestBodyBlobsCompleted( |
| + bool success, |
| + storage::IPCBlobCreationCancelCode cancel_code) { |
| + TRACE_EVENT_ASYNC_END2( |
| + "ServiceWorker", |
| + "ServiceWorkerURLRequestJob::WaitForRequestBobyBlobsToComplete", this, |
| + "Success", success, "IPCBlobCreationCancelCode", |
| + static_cast<int>(cancel_code)); |
| + |
| + if (!success) { |
| + RecordResult( |
| + ServiceWorkerMetrics::REQUEST_JOB_ERROR_REQUEST_BODY_BLOB_FAILED); |
| + NotifyStartError(net::URLRequestStatus::FromError(net::ERR_FAILED)); |
| + return; |
| + } |
| + |
| + request()->net_log().AddEvent( |
| + net::NetLog::TYPE_SERVICE_WORKER_REQUEST_BODY_BLOB_CONSTRUCTION_FINISHED); |
| + DispatchToWorker(); |
| +} |
| + |
| } // namespace content |