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

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

Issue 1967683003: service worker: Wait for request body blobs to finish construction (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 4 years, 7 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 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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_url_request_job.h" 5 #include "content/browser/service_worker/service_worker_url_request_job.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 #include <stdint.h> 8 #include <stdint.h>
9 9
10 #include <limits> 10 #include <limits>
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
81 case m::REQUEST_JOB_ERROR_STREAM_ABORTED: 81 case m::REQUEST_JOB_ERROR_STREAM_ABORTED:
82 return n::TYPE_SERVICE_WORKER_ERROR_STREAM_ABORTED; 82 return n::TYPE_SERVICE_WORKER_ERROR_STREAM_ABORTED;
83 case m::REQUEST_JOB_ERROR_KILLED: 83 case m::REQUEST_JOB_ERROR_KILLED:
84 return n::TYPE_SERVICE_WORKER_ERROR_KILLED; 84 return n::TYPE_SERVICE_WORKER_ERROR_KILLED;
85 case m::REQUEST_JOB_ERROR_KILLED_WITH_BLOB: 85 case m::REQUEST_JOB_ERROR_KILLED_WITH_BLOB:
86 return n::TYPE_SERVICE_WORKER_ERROR_KILLED_WITH_BLOB; 86 return n::TYPE_SERVICE_WORKER_ERROR_KILLED_WITH_BLOB;
87 case m::REQUEST_JOB_ERROR_KILLED_WITH_STREAM: 87 case m::REQUEST_JOB_ERROR_KILLED_WITH_STREAM:
88 return n::TYPE_SERVICE_WORKER_ERROR_KILLED_WITH_STREAM; 88 return n::TYPE_SERVICE_WORKER_ERROR_KILLED_WITH_STREAM;
89 case m::REQUEST_JOB_ERROR_BAD_DELEGATE: 89 case m::REQUEST_JOB_ERROR_BAD_DELEGATE:
90 return n::TYPE_SERVICE_WORKER_ERROR_BAD_DELEGATE; 90 return n::TYPE_SERVICE_WORKER_ERROR_BAD_DELEGATE;
91 case m::REQUEST_JOB_ERROR_REQUEST_BODY_BLOB_FAILED:
92 return n::TYPE_SERVICE_WORKER_ERROR_REQUEST_BODY_BLOB_FAILED;
91 // We can't log if there's no request; fallthrough. 93 // We can't log if there's no request; fallthrough.
92 case m::REQUEST_JOB_ERROR_NO_REQUEST: 94 case m::REQUEST_JOB_ERROR_NO_REQUEST:
93 // Obsolete types; fallthrough. 95 // Obsolete types; fallthrough.
94 case m::REQUEST_JOB_ERROR_DESTROYED: 96 case m::REQUEST_JOB_ERROR_DESTROYED:
95 case m::REQUEST_JOB_ERROR_DESTROYED_WITH_BLOB: 97 case m::REQUEST_JOB_ERROR_DESTROYED_WITH_BLOB:
96 case m::REQUEST_JOB_ERROR_DESTROYED_WITH_STREAM: 98 case m::REQUEST_JOB_ERROR_DESTROYED_WITH_STREAM:
97 // Invalid type. 99 // Invalid type.
98 case m::NUM_REQUEST_JOB_RESULT_TYPES: 100 case m::NUM_REQUEST_JOB_RESULT_TYPES:
99 NOTREACHED() << result; 101 NOTREACHED() << result;
100 } 102 }
101 NOTREACHED() << result; 103 NOTREACHED() << result;
102 return n::TYPE_FAILED; 104 return n::TYPE_FAILED;
103 } 105 }
104 106
105 } // namespace 107 } // namespace
106 108
109 class ServiceWorkerURLRequestJob::BlobConstructionWaiter {
110 public:
111 explicit BlobConstructionWaiter(ServiceWorkerURLRequestJob* owner)
112 : owner_(owner), weak_factory_(this) {
113 TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker", "BlobConstructionWaiter", this,
114 "URL", owner_->request()->url().spec());
115 owner_->request()->net_log().AddEvent(
116 net::NetLog::
117 TYPE_SERVICE_WORKER_REQUEST_BODY_BLOB_CONSTRUCTION_STARTED);
mmenke 2016/05/16 15:30:02 Would it make sense to use BeginEvent / EndEvent w
falken 2016/05/17 02:03:14 Done.
118 }
119
120 ~BlobConstructionWaiter() {
121 owner_->request()->net_log().AddEvent(
122 net::NetLog::
123 TYPE_SERVICE_WORKER_REQUEST_BODY_BLOB_CONSTRUCTION_FINISHED,
124 net::NetLog::BoolCallback("Success", phase_ == Phase::SUCCESS));
125 TRACE_EVENT_ASYNC_END1("ServiceWorker", "BlobConstructionWaiter", this,
126 "Success", phase_ == Phase::SUCCESS);
127 }
128
129 void RunOnComplete(const base::Callback<void(bool)>& callback) {
130 DCHECK_EQ(static_cast<int>(Phase::INITIAL), static_cast<int>(phase_));
131 phase_ = Phase::WAITING;
132 num_pending_request_body_blobs_ = 0;
133 callback_ = callback;
134
135 for (const ResourceRequestBody::Element& element :
136 *(owner_->body_->elements())) {
137 if (element.type() != ResourceRequestBody::Element::TYPE_BLOB)
138 continue;
139
140 std::unique_ptr<storage::BlobDataHandle> handle =
141 owner_->blob_storage_context_->GetBlobDataFromUUID(
142 element.blob_uuid());
143 if (handle->IsBroken()) {
144 Complete(false);
145 return;
146 }
147 if (handle->IsBeingBuilt()) {
148 ++num_pending_request_body_blobs_;
149 handle->RunOnConstructionComplete(
150 base::Bind(&BlobConstructionWaiter::OneRequestBodyBlobCompleted,
151 weak_factory_.GetWeakPtr()));
152 }
153 }
154
155 if (num_pending_request_body_blobs_ == 0)
156 Complete(true);
157 }
158
159 private:
160 enum class Phase { INITIAL, WAITING, SUCCESS, FAIL };
161
162 void OneRequestBodyBlobCompleted(
163 bool success,
164 storage::IPCBlobCreationCancelCode cancel_code) {
165 DCHECK_GT(num_pending_request_body_blobs_, 0UL);
166
167 if (success)
168 --num_pending_request_body_blobs_;
169 else
170 num_pending_request_body_blobs_ = 0;
171
172 if (num_pending_request_body_blobs_ == 0)
173 Complete(success);
174 }
175
176 void Complete(bool success) {
177 DCHECK_EQ(static_cast<int>(Phase::WAITING), static_cast<int>(phase_));
178 phase_ = success ? Phase::SUCCESS : Phase::FAIL;
179 // Destroys |this|.
180 callback_.Run(success);
181 }
182
183 // Owns and must outlive |this|.
184 ServiceWorkerURLRequestJob* owner_;
185
186 scoped_refptr<ResourceRequestBody> body_;
187 base::Callback<void(bool)> callback_;
188 size_t num_pending_request_body_blobs_ = 0;
189 Phase phase_ = Phase::INITIAL;
190 base::WeakPtrFactory<BlobConstructionWaiter> weak_factory_;
191
192 DISALLOW_COPY_AND_ASSIGN(BlobConstructionWaiter);
193 };
194
107 bool ServiceWorkerURLRequestJob::Delegate::RequestStillValid( 195 bool ServiceWorkerURLRequestJob::Delegate::RequestStillValid(
108 ServiceWorkerMetrics::URLRequestJobResult* result) { 196 ServiceWorkerMetrics::URLRequestJobResult* result) {
109 return true; 197 return true;
110 } 198 }
111 199
112 ServiceWorkerURLRequestJob::ServiceWorkerURLRequestJob( 200 ServiceWorkerURLRequestJob::ServiceWorkerURLRequestJob(
113 net::URLRequest* request, 201 net::URLRequest* request,
114 net::NetworkDelegate* network_delegate, 202 net::NetworkDelegate* network_delegate,
115 const std::string& client_id, 203 const std::string& client_id,
116 base::WeakPtr<storage::BlobStorageContext> blob_storage_context, 204 base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
(...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after
396 void ServiceWorkerURLRequestJob::MaybeStartRequest() { 484 void ServiceWorkerURLRequestJob::MaybeStartRequest() {
397 if (is_started_ && response_type_ != NOT_DETERMINED) { 485 if (is_started_ && response_type_ != NOT_DETERMINED) {
398 // Start asynchronously. 486 // Start asynchronously.
399 base::ThreadTaskRunnerHandle::Get()->PostTask( 487 base::ThreadTaskRunnerHandle::Get()->PostTask(
400 FROM_HERE, base::Bind(&ServiceWorkerURLRequestJob::StartRequest, 488 FROM_HERE, base::Bind(&ServiceWorkerURLRequestJob::StartRequest,
401 weak_factory_.GetWeakPtr())); 489 weak_factory_.GetWeakPtr()));
402 } 490 }
403 } 491 }
404 492
405 void ServiceWorkerURLRequestJob::StartRequest() { 493 void ServiceWorkerURLRequestJob::StartRequest() {
406 if (request()) { 494 request()->net_log().AddEvent(net::NetLog::TYPE_SERVICE_WORKER_START_REQUEST);
407 request()->net_log().AddEvent(
408 net::NetLog::TYPE_SERVICE_WORKER_START_REQUEST);
409 }
410 495
411 switch (response_type_) { 496 switch (response_type_) {
412 case NOT_DETERMINED: 497 case NOT_DETERMINED:
413 NOTREACHED(); 498 NOTREACHED();
414 return; 499 return;
415 500
416 case FALLBACK_TO_NETWORK: 501 case FALLBACK_TO_NETWORK:
417 // Restart the request to create a new job. Our request handler will 502 // Restart the request to create a new job. Our request handler will
418 // return nullptr, and the default job (which will hit network) should be 503 // return nullptr, and the default job (which will hit network) should be
419 // created. 504 // created.
420 NotifyRestartRequired(); 505 NotifyRestartRequired();
421 return; 506 return;
422 507
423 case FORWARD_TO_SERVICE_WORKER: 508 case FORWARD_TO_SERVICE_WORKER:
424 ServiceWorkerMetrics::URLRequestJobResult result = 509 if (HasRequestBody()) {
425 ServiceWorkerMetrics::REQUEST_JOB_ERROR_BAD_DELEGATE; 510 DCHECK(!blob_construction_waiter_);
426 ServiceWorkerVersion* active_worker = 511 blob_construction_waiter_.reset(new BlobConstructionWaiter(this));
427 delegate_->GetServiceWorkerVersion(&result); 512 blob_construction_waiter_->RunOnComplete(
428 if (!active_worker) { 513 base::Bind(&ServiceWorkerURLRequestJob::RequestBodyBlobsCompleted,
429 RecordResult(result); 514 GetWeakPtr()));
430 DeliverErrorResponse();
431 return; 515 return;
432 } 516 }
433 517
434 DCHECK(!fetch_dispatcher_); 518 RequestBodyBlobsCompleted(true);
435 // Send a fetch event to the ServiceWorker associated to the
436 // provider_host.
437 fetch_dispatcher_.reset(new ServiceWorkerFetchDispatcher(
438 CreateFetchRequest(), active_worker, resource_type_,
439 base::Bind(&ServiceWorkerURLRequestJob::DidPrepareFetchEvent,
440 weak_factory_.GetWeakPtr()),
441 base::Bind(&ServiceWorkerURLRequestJob::DidDispatchFetchEvent,
442 weak_factory_.GetWeakPtr())));
443 worker_start_time_ = base::TimeTicks::Now();
444 fetch_dispatcher_->Run();
445 return; 519 return;
446 } 520 }
447 521
448 NOTREACHED(); 522 NOTREACHED();
449 } 523 }
450 524
451 std::unique_ptr<ServiceWorkerFetchRequest> 525 std::unique_ptr<ServiceWorkerFetchRequest>
452 ServiceWorkerURLRequestJob::CreateFetchRequest() { 526 ServiceWorkerURLRequestJob::CreateFetchRequest() {
453 std::string blob_uuid; 527 std::string blob_uuid;
454 uint64_t blob_size = 0; 528 uint64_t blob_size = 0;
455 // The upload data in URLRequest may have been cleared while handing redirect. 529 if (HasRequestBody())
456 if (request_->has_upload())
457 CreateRequestBodyBlob(&blob_uuid, &blob_size); 530 CreateRequestBodyBlob(&blob_uuid, &blob_size);
458 std::unique_ptr<ServiceWorkerFetchRequest> request( 531 std::unique_ptr<ServiceWorkerFetchRequest> request(
459 new ServiceWorkerFetchRequest()); 532 new ServiceWorkerFetchRequest());
460 request->mode = request_mode_; 533 request->mode = request_mode_;
461 request->is_main_resource_load = IsMainResourceLoad(); 534 request->is_main_resource_load = IsMainResourceLoad();
462 request->request_context_type = request_context_type_; 535 request->request_context_type = request_context_type_;
463 request->frame_type = frame_type_; 536 request->frame_type = frame_type_;
464 request->url = request_->url(); 537 request->url = request_->url();
465 request->method = request_->method(); 538 request->method = request_->method();
466 const net::HttpRequestHeaders& headers = request_->extra_request_headers(); 539 const net::HttpRequestHeaders& headers = request_->extra_request_headers();
(...skipping 17 matching lines...) Expand all
484 CHECK( 557 CHECK(
485 request_->referrer_policy() == 558 request_->referrer_policy() ==
486 net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE); 559 net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE);
487 request->referrer = 560 request->referrer =
488 Referrer(GURL(request_->referrer()), blink::WebReferrerPolicyDefault); 561 Referrer(GURL(request_->referrer()), blink::WebReferrerPolicyDefault);
489 } 562 }
490 request->fetch_type = fetch_type_; 563 request->fetch_type = fetch_type_;
491 return request; 564 return request;
492 } 565 }
493 566
494 bool ServiceWorkerURLRequestJob::CreateRequestBodyBlob(std::string* blob_uuid, 567 void ServiceWorkerURLRequestJob::CreateRequestBodyBlob(std::string* blob_uuid,
495 uint64_t* blob_size) { 568 uint64_t* blob_size) {
496 if (!body_.get() || !blob_storage_context_) 569 DCHECK(HasRequestBody());
497 return false;
498
499 // To ensure the blobs stick around until the end of the reading. 570 // To ensure the blobs stick around until the end of the reading.
500 std::vector<std::unique_ptr<storage::BlobDataHandle>> handles; 571 std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
501 std::vector<std::unique_ptr<storage::BlobDataSnapshot>> snapshots; 572 std::vector<std::unique_ptr<storage::BlobDataSnapshot>> snapshots;
502 // TODO(dmurph): Allow blobs to be added below, so that the context can 573 // TODO(dmurph): Allow blobs to be added below, so that the context can
503 // efficiently re-use blob items for the new blob. 574 // efficiently re-use blob items for the new blob.
504 std::vector<const ResourceRequestBody::Element*> resolved_elements; 575 std::vector<const ResourceRequestBody::Element*> resolved_elements;
505 for (const ResourceRequestBody::Element& element : (*body_->elements())) { 576 for (const ResourceRequestBody::Element& element : (*body_->elements())) {
506 if (element.type() != ResourceRequestBody::Element::TYPE_BLOB) { 577 if (element.type() != ResourceRequestBody::Element::TYPE_BLOB) {
507 resolved_elements.push_back(&element); 578 resolved_elements.push_back(&element);
508 continue; 579 continue;
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
553 break; 624 break;
554 default: 625 default:
555 NOTIMPLEMENTED(); 626 NOTIMPLEMENTED();
556 } 627 }
557 } 628 }
558 629
559 request_body_blob_data_handle_ = 630 request_body_blob_data_handle_ =
560 blob_storage_context_->AddFinishedBlob(&blob_builder); 631 blob_storage_context_->AddFinishedBlob(&blob_builder);
561 *blob_uuid = uuid; 632 *blob_uuid = uuid;
562 *blob_size = total_size; 633 *blob_size = total_size;
563 return true;
564 } 634 }
565 635
566 void ServiceWorkerURLRequestJob::DidPrepareFetchEvent() { 636 void ServiceWorkerURLRequestJob::DidPrepareFetchEvent() {
567 worker_ready_time_ = base::TimeTicks::Now(); 637 worker_ready_time_ = base::TimeTicks::Now();
568 load_timing_info_.send_start = worker_ready_time_; 638 load_timing_info_.send_start = worker_ready_time_;
569 } 639 }
570 640
571 void ServiceWorkerURLRequestJob::DidDispatchFetchEvent( 641 void ServiceWorkerURLRequestJob::DidDispatchFetchEvent(
572 ServiceWorkerStatusCode status, 642 ServiceWorkerStatusCode status,
573 ServiceWorkerFetchEventResult fetch_result, 643 ServiceWorkerFetchEventResult fetch_result,
(...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after
854 fall_back_required_, response_url_, 924 fall_back_required_, response_url_,
855 service_worker_response_type_, worker_start_time_, 925 service_worker_response_type_, worker_start_time_,
856 worker_ready_time_, response_is_in_cache_storage_, 926 worker_ready_time_, response_is_in_cache_storage_,
857 response_cache_storage_cache_name_); 927 response_cache_storage_cache_name_);
858 } 928 }
859 929
860 bool ServiceWorkerURLRequestJob::IsMainResourceLoad() const { 930 bool ServiceWorkerURLRequestJob::IsMainResourceLoad() const {
861 return ServiceWorkerUtils::IsMainResourceType(resource_type_); 931 return ServiceWorkerUtils::IsMainResourceType(resource_type_);
862 } 932 }
863 933
934 bool ServiceWorkerURLRequestJob::HasRequestBody() {
935 // URLRequest::has_upload() must be checked since its upload data may have
936 // been cleared while handling a redirect.
937 return request_->has_upload() && body_.get() && blob_storage_context_;
938 }
939
940 void ServiceWorkerURLRequestJob::RequestBodyBlobsCompleted(bool success) {
941 blob_construction_waiter_.reset();
942 if (!success) {
943 RecordResult(
944 ServiceWorkerMetrics::REQUEST_JOB_ERROR_REQUEST_BODY_BLOB_FAILED);
945 // TODO(falken): This and below should probably be NotifyStartError, not
946 // DeliverErrorResponse. But changing it causes
947 // ServiceWorkerURLRequestJobTest.DeletedProviderHostBeforeFetchEvent to
948 // fail.
949 DeliverErrorResponse();
950 return;
951 }
952
953 ServiceWorkerMetrics::URLRequestJobResult result =
954 ServiceWorkerMetrics::REQUEST_JOB_ERROR_BAD_DELEGATE;
955 ServiceWorkerVersion* active_worker =
956 delegate_->GetServiceWorkerVersion(&result);
957 if (!active_worker) {
958 RecordResult(result);
959 DeliverErrorResponse();
960 return;
961 }
962
963 DCHECK(!fetch_dispatcher_);
964 fetch_dispatcher_.reset(new ServiceWorkerFetchDispatcher(
965 CreateFetchRequest(), active_worker, resource_type_,
966 base::Bind(&ServiceWorkerURLRequestJob::DidPrepareFetchEvent,
967 weak_factory_.GetWeakPtr()),
968 base::Bind(&ServiceWorkerURLRequestJob::DidDispatchFetchEvent,
969 weak_factory_.GetWeakPtr())));
970 worker_start_time_ = base::TimeTicks::Now();
971 fetch_dispatcher_->Run();
972 }
973
864 } // namespace content 974 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698