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

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

Issue 2055053003: [BlobAsync] Disk support for blob storage (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Combined BlobSlice & BlobFlattener files, more comments, a little cleanup. Created 4 years, 4 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>
11 #include <map> 10 #include <map>
12 #include <memory> 11 #include <memory>
13 #include <string> 12 #include <string>
14 #include <utility> 13 #include <utility>
15 #include <vector> 14 #include <vector>
16 15
17 #include "base/bind.h" 16 #include "base/bind.h"
17 #include "base/files/file.h"
18 #include "base/guid.h" 18 #include "base/guid.h"
19 #include "base/location.h" 19 #include "base/location.h"
20 #include "base/single_thread_task_runner.h" 20 #include "base/single_thread_task_runner.h"
21 #include "base/strings/stringprintf.h" 21 #include "base/strings/stringprintf.h"
22 #include "base/task_runner.h"
23 #include "base/task_runner_util.h"
22 #include "base/threading/thread_task_runner_handle.h" 24 #include "base/threading/thread_task_runner_handle.h"
23 #include "base/time/time.h" 25 #include "base/time/time.h"
24 #include "content/browser/resource_context_impl.h" 26 #include "content/browser/resource_context_impl.h"
25 #include "content/browser/service_worker/embedded_worker_instance.h" 27 #include "content/browser/service_worker/embedded_worker_instance.h"
26 #include "content/browser/service_worker/service_worker_fetch_dispatcher.h" 28 #include "content/browser/service_worker/service_worker_fetch_dispatcher.h"
27 #include "content/browser/service_worker/service_worker_provider_host.h" 29 #include "content/browser/service_worker/service_worker_provider_host.h"
28 #include "content/browser/service_worker/service_worker_response_info.h" 30 #include "content/browser/service_worker/service_worker_response_info.h"
29 #include "content/browser/streams/stream.h" 31 #include "content/browser/streams/stream.h"
30 #include "content/browser/streams/stream_context.h" 32 #include "content/browser/streams/stream_context.h"
31 #include "content/browser/streams/stream_registry.h" 33 #include "content/browser/streams/stream_registry.h"
32 #include "content/common/resource_request_body_impl.h" 34 #include "content/common/resource_request_body_impl.h"
33 #include "content/common/service_worker/service_worker_types.h" 35 #include "content/common/service_worker/service_worker_types.h"
34 #include "content/common/service_worker/service_worker_utils.h" 36 #include "content/common/service_worker/service_worker_utils.h"
35 #include "content/public/browser/blob_handle.h" 37 #include "content/public/browser/blob_handle.h"
38 #include "content/public/browser/browser_thread.h"
36 #include "content/public/browser/resource_request_info.h" 39 #include "content/public/browser/resource_request_info.h"
37 #include "content/public/browser/service_worker_context.h" 40 #include "content/public/browser/service_worker_context.h"
38 #include "content/public/common/referrer.h" 41 #include "content/public/common/referrer.h"
39 #include "net/base/net_errors.h" 42 #include "net/base/net_errors.h"
40 #include "net/http/http_request_headers.h" 43 #include "net/http/http_request_headers.h"
41 #include "net/http/http_response_headers.h" 44 #include "net/http/http_response_headers.h"
42 #include "net/http/http_response_info.h" 45 #include "net/http/http_response_info.h"
43 #include "net/http/http_util.h" 46 #include "net/http/http_util.h"
44 #include "net/log/net_log.h" 47 #include "net/log/net_log.h"
45 #include "storage/browser/blob/blob_data_builder.h" 48 #include "storage/browser/blob/blob_data_builder.h"
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
98 case m::REQUEST_JOB_ERROR_DESTROYED_WITH_BLOB: 101 case m::REQUEST_JOB_ERROR_DESTROYED_WITH_BLOB:
99 case m::REQUEST_JOB_ERROR_DESTROYED_WITH_STREAM: 102 case m::REQUEST_JOB_ERROR_DESTROYED_WITH_STREAM:
100 // Invalid type. 103 // Invalid type.
101 case m::NUM_REQUEST_JOB_RESULT_TYPES: 104 case m::NUM_REQUEST_JOB_RESULT_TYPES:
102 NOTREACHED() << result; 105 NOTREACHED() << result;
103 } 106 }
104 NOTREACHED() << result; 107 NOTREACHED() << result;
105 return n::TYPE_FAILED; 108 return n::TYPE_FAILED;
106 } 109 }
107 110
111 bool PopulateUnknownFileLengths(
112 std::vector<ResourceRequestBodyImpl::Element>* elements) {
113 for (ResourceRequestBodyImpl::Element& element : *elements) {
114 if (element.type() == ResourceRequestBodyImpl::Element::TYPE_FILE &&
115 element.length() == ResourceRequestBodyImpl::Element::kUnknownSize) {
116 // Try to open our file.
117 base::File file(element.path(),
118 base::File::FLAG_OPEN | base::File::FLAG_READ);
119 if (file.error_details() != base::File::FILE_OK)
michaeln 2016/08/15 22:44:43 base:: has a nice utility to GetFileInfo given jus
dmurph 2016/08/19 00:18:31 Done.
120 return false;
121
122 base::File::Info file_info;
123 if (!file.GetInfo(&file_info))
124 return false;
125
126 element.SetToFilePathRange(element.path(), element.offset(),
127 file_info.size,
128 element.expected_modification_time());
129 }
130 }
131 return true;
132 }
133
108 } // namespace 134 } // namespace
109 135
110 class ServiceWorkerURLRequestJob::BlobConstructionWaiter { 136 class ServiceWorkerURLRequestJob::BlobFilesWaiter {
michaeln 2016/08/15 22:44:43 Oh, the purpose of this class is now completely di
dmurph 2016/08/19 00:18:31 Done.
111 public: 137 public:
112 explicit BlobConstructionWaiter(ServiceWorkerURLRequestJob* owner) 138 explicit BlobFilesWaiter(ServiceWorkerURLRequestJob* owner)
113 : owner_(owner), weak_factory_(this) { 139 : owner_(owner), weak_factory_(this) {
114 TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker", "BlobConstructionWaiter", this, 140 TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker", "BlobFilesWaiter", this, "URL",
115 "URL", owner_->request()->url().spec()); 141 owner_->request()->url().spec());
116 owner_->request()->net_log().BeginEvent( 142 owner_->request()->net_log().BeginEvent(
117 net::NetLog::TYPE_SERVICE_WORKER_WAITING_FOR_REQUEST_BODY_BLOB); 143 net::NetLog::TYPE_SERVICE_WORKER_WAITING_FOR_REQUEST_BODY_FILES);
118 } 144 }
119 145
120 ~BlobConstructionWaiter() { 146 ~BlobFilesWaiter() {
121 owner_->request()->net_log().EndEvent( 147 owner_->request()->net_log().EndEvent(
122 net::NetLog::TYPE_SERVICE_WORKER_WAITING_FOR_REQUEST_BODY_BLOB, 148 net::NetLog::TYPE_SERVICE_WORKER_WAITING_FOR_REQUEST_BODY_FILES,
123 net::NetLog::BoolCallback("success", phase_ == Phase::SUCCESS)); 149 net::NetLog::BoolCallback("success", phase_ == Phase::SUCCESS));
124 TRACE_EVENT_ASYNC_END1("ServiceWorker", "BlobConstructionWaiter", this, 150 TRACE_EVENT_ASYNC_END1("ServiceWorker", "BlobFilesWaiter", this, "Success",
125 "Success", phase_ == Phase::SUCCESS); 151 phase_ == Phase::SUCCESS);
126 } 152 }
127 153
128 void RunOnComplete(const base::Callback<void(bool)>& callback) { 154 void RunOnComplete(base::TaskRunner* file_runner,
155 const base::Callback<void(bool)>& callback) {
129 DCHECK_EQ(static_cast<int>(Phase::INITIAL), static_cast<int>(phase_)); 156 DCHECK_EQ(static_cast<int>(Phase::INITIAL), static_cast<int>(phase_));
130 phase_ = Phase::WAITING; 157 phase_ = Phase::WAITING;
131 num_pending_request_body_blobs_ = 0; 158 body_ = owner_->body_;
132 callback_ = callback; 159 callback_ = callback;
133 160
134 for (const ResourceRequestBodyImpl::Element& element : 161 bool needs_file_stats = false;
135 *(owner_->body_->elements())) { 162 for (const ResourceRequestBodyImpl::Element& element : *body_->elements()) {
michaeln 2016/08/15 22:44:42 might be good place for const auto&
dmurph 2016/08/19 00:18:32 Done.
136 if (element.type() != ResourceRequestBodyImpl::Element::TYPE_BLOB) 163 if (element.type() == ResourceRequestBodyImpl::Element::TYPE_FILE &&
137 continue; 164 element.length() == ResourceRequestBodyImpl::Element::kUnknownSize) {
138 165 needs_file_stats = true;
139 std::unique_ptr<storage::BlobDataHandle> handle =
140 owner_->blob_storage_context_->GetBlobDataFromUUID(
141 element.blob_uuid());
142 if (handle->IsBroken()) {
143 Complete(false);
144 return;
145 }
146 if (handle->IsBeingBuilt()) {
147 ++num_pending_request_body_blobs_;
148 handle->RunOnConstructionComplete(
149 base::Bind(&BlobConstructionWaiter::OneRequestBodyBlobCompleted,
150 weak_factory_.GetWeakPtr()));
151 } 166 }
152 } 167 }
153 168
154 if (num_pending_request_body_blobs_ == 0) 169 if (!needs_file_stats) {
155 Complete(true); 170 Complete(true);
171 return;
172 }
173
174 PostTaskAndReplyWithResult(
175 file_runner, FROM_HERE,
176 base::Bind(&PopulateUnknownFileLengths, body_->elements_mutable()),
Marijn Kruisselbrink 2016/08/05 23:23:54 Is this safe? body_->elements_mutable() is just a
michaeln 2016/08/15 22:44:43 what he said
dmurph 2016/08/19 00:18:31 Now we protect this by accessing the elements only
177 base::Bind(&ServiceWorkerURLRequestJob::BlobFilesWaiter::Complete,
178 weak_factory_.GetWeakPtr()));
156 } 179 }
157 180
158 private: 181 private:
159 enum class Phase { INITIAL, WAITING, SUCCESS, FAIL }; 182 enum class Phase { INITIAL, WAITING, SUCCESS, FAIL };
160 183
161 void OneRequestBodyBlobCompleted(
162 bool success,
163 storage::IPCBlobCreationCancelCode cancel_code) {
164 DCHECK_GT(num_pending_request_body_blobs_, 0UL);
165
166 if (success)
167 --num_pending_request_body_blobs_;
168 else
169 num_pending_request_body_blobs_ = 0;
170
171 if (num_pending_request_body_blobs_ == 0)
172 Complete(success);
173 }
174
175 void Complete(bool success) { 184 void Complete(bool success) {
176 DCHECK_EQ(static_cast<int>(Phase::WAITING), static_cast<int>(phase_)); 185 DCHECK_EQ(static_cast<int>(Phase::WAITING), static_cast<int>(phase_));
177 phase_ = success ? Phase::SUCCESS : Phase::FAIL; 186 phase_ = success ? Phase::SUCCESS : Phase::FAIL;
178 // Destroys |this|. 187 // Destroys |this|.
179 callback_.Run(success); 188 callback_.Run(success);
180 } 189 }
181 190
182 // Owns and must outlive |this|. 191 // Owns and must outlive |this|.
183 ServiceWorkerURLRequestJob* owner_; 192 ServiceWorkerURLRequestJob* owner_;
184 193
185 scoped_refptr<ResourceRequestBodyImpl> body_; 194 scoped_refptr<ResourceRequestBodyImpl> body_;
186 base::Callback<void(bool)> callback_; 195 base::Callback<void(bool)> callback_;
187 size_t num_pending_request_body_blobs_ = 0;
188 Phase phase_ = Phase::INITIAL; 196 Phase phase_ = Phase::INITIAL;
189 base::WeakPtrFactory<BlobConstructionWaiter> weak_factory_; 197 base::WeakPtrFactory<BlobFilesWaiter> weak_factory_;
190 198
191 DISALLOW_COPY_AND_ASSIGN(BlobConstructionWaiter); 199 DISALLOW_COPY_AND_ASSIGN(BlobFilesWaiter);
192 }; 200 };
193 201
194 bool ServiceWorkerURLRequestJob::Delegate::RequestStillValid( 202 bool ServiceWorkerURLRequestJob::Delegate::RequestStillValid(
195 ServiceWorkerMetrics::URLRequestJobResult* result) { 203 ServiceWorkerMetrics::URLRequestJobResult* result) {
196 return true; 204 return true;
197 } 205 }
198 206
199 ServiceWorkerURLRequestJob::ServiceWorkerURLRequestJob( 207 ServiceWorkerURLRequestJob::ServiceWorkerURLRequestJob(
200 net::URLRequest* request, 208 net::URLRequest* request,
201 net::NetworkDelegate* network_delegate, 209 net::NetworkDelegate* network_delegate,
(...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after
516 FinalizeFallbackToNetwork(); 524 FinalizeFallbackToNetwork();
517 return; 525 return;
518 526
519 case FALLBACK_TO_RENDERER: 527 case FALLBACK_TO_RENDERER:
520 FinalizeFallbackToRenderer(); 528 FinalizeFallbackToRenderer();
521 return; 529 return;
522 530
523 case FORWARD_TO_SERVICE_WORKER: 531 case FORWARD_TO_SERVICE_WORKER:
524 if (HasRequestBody()) { 532 if (HasRequestBody()) {
525 DCHECK(!blob_construction_waiter_); 533 DCHECK(!blob_construction_waiter_);
526 blob_construction_waiter_.reset(new BlobConstructionWaiter(this)); 534 blob_construction_waiter_.reset(new BlobFilesWaiter(this));
527 blob_construction_waiter_->RunOnComplete( 535 blob_construction_waiter_->RunOnComplete(
536 BrowserThread::GetBlockingPool(),
528 base::Bind(&ServiceWorkerURLRequestJob::RequestBodyBlobsCompleted, 537 base::Bind(&ServiceWorkerURLRequestJob::RequestBodyBlobsCompleted,
529 GetWeakPtr())); 538 GetWeakPtr()));
530 return; 539 return;
531 } 540 }
532 541
533 RequestBodyBlobsCompleted(true); 542 RequestBodyBlobsCompleted(true);
534 return; 543 return;
535 } 544 }
536 545
537 NOTREACHED(); 546 NOTREACHED();
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
575 request->referrer = 584 request->referrer =
576 Referrer(GURL(request_->referrer()), blink::WebReferrerPolicyDefault); 585 Referrer(GURL(request_->referrer()), blink::WebReferrerPolicyDefault);
577 } 586 }
578 request->fetch_type = fetch_type_; 587 request->fetch_type = fetch_type_;
579 return request; 588 return request;
580 } 589 }
581 590
582 void ServiceWorkerURLRequestJob::CreateRequestBodyBlob(std::string* blob_uuid, 591 void ServiceWorkerURLRequestJob::CreateRequestBodyBlob(std::string* blob_uuid,
583 uint64_t* blob_size) { 592 uint64_t* blob_size) {
584 DCHECK(HasRequestBody()); 593 DCHECK(HasRequestBody());
585 // To ensure the blobs stick around until the end of the reading. 594 const std::string uuid(base::GenerateGUID());
586 std::vector<std::unique_ptr<storage::BlobDataHandle>> handles; 595 storage::BlobDataBuilder blob_builder(uuid);
michaeln 2016/08/15 22:44:43 you could get rid of the uuid local and a line of
dmurph 2016/08/19 00:18:31 Done.
587 std::vector<std::unique_ptr<storage::BlobDataSnapshot>> snapshots;
588 // TODO(dmurph): Allow blobs to be added below, so that the context can
589 // efficiently re-use blob items for the new blob.
590 std::vector<const ResourceRequestBodyImpl::Element*> resolved_elements;
591 for (const ResourceRequestBodyImpl::Element& element : (*body_->elements())) { 596 for (const ResourceRequestBodyImpl::Element& element : (*body_->elements())) {
592 if (element.type() != ResourceRequestBodyImpl::Element::TYPE_BLOB) { 597 blob_builder.AppendIPCDataElement(element);
593 resolved_elements.push_back(&element);
594 continue;
595 }
596 std::unique_ptr<storage::BlobDataHandle> handle =
597 blob_storage_context_->GetBlobDataFromUUID(element.blob_uuid());
598 std::unique_ptr<storage::BlobDataSnapshot> snapshot =
599 handle->CreateSnapshot();
600 if (snapshot->items().empty())
601 continue;
602 const auto& items = snapshot->items();
603 for (const auto& item : items) {
604 DCHECK_NE(storage::DataElement::TYPE_BLOB, item->type());
605 resolved_elements.push_back(item->data_element_ptr());
606 }
607 handles.push_back(std::move(handle));
608 snapshots.push_back(std::move(snapshot));
609 }
610
611 const std::string uuid(base::GenerateGUID());
612 uint64_t total_size = 0;
613
614 storage::BlobDataBuilder blob_builder(uuid);
615 for (size_t i = 0; i < resolved_elements.size(); ++i) {
616 const ResourceRequestBodyImpl::Element& element = *resolved_elements[i];
617 if (total_size != std::numeric_limits<uint64_t>::max() &&
618 element.length() != std::numeric_limits<uint64_t>::max())
619 total_size += element.length();
620 else
621 total_size = std::numeric_limits<uint64_t>::max();
622 switch (element.type()) {
623 case ResourceRequestBodyImpl::Element::TYPE_BYTES:
624 blob_builder.AppendData(element.bytes(), element.length());
625 break;
626 case ResourceRequestBodyImpl::Element::TYPE_FILE:
627 blob_builder.AppendFile(element.path(), element.offset(),
628 element.length(),
629 element.expected_modification_time());
630 break;
631 case ResourceRequestBodyImpl::Element::TYPE_BLOB:
632 // Blob elements should be resolved beforehand.
633 NOTREACHED();
634 break;
635 case ResourceRequestBodyImpl::Element::TYPE_FILE_FILESYSTEM:
636 blob_builder.AppendFileSystemFile(element.filesystem_url(),
637 element.offset(), element.length(),
638 element.expected_modification_time());
639 break;
640 default:
641 NOTIMPLEMENTED();
642 }
643 } 598 }
644 599
645 request_body_blob_data_handle_ = 600 request_body_blob_data_handle_ =
646 blob_storage_context_->AddFinishedBlob(&blob_builder); 601 blob_storage_context_->AddFinishedBlob(&blob_builder);
647 *blob_uuid = uuid; 602 *blob_uuid = uuid;
648 *blob_size = total_size; 603 *blob_size = request_body_blob_data_handle_->size();
649 } 604 }
650 605
651 void ServiceWorkerURLRequestJob::DidPrepareFetchEvent( 606 void ServiceWorkerURLRequestJob::DidPrepareFetchEvent(
652 scoped_refptr<ServiceWorkerVersion> version) { 607 scoped_refptr<ServiceWorkerVersion> version) {
653 worker_ready_time_ = base::TimeTicks::Now(); 608 worker_ready_time_ = base::TimeTicks::Now();
654 load_timing_info_.send_start = worker_ready_time_; 609 load_timing_info_.send_start = worker_ready_time_;
655 610
656 // Record the time taken for the browser to find and possibly start an active 611 // Record the time taken for the browser to find and possibly start an active
657 // worker to which to dispatch a FetchEvent for a main frame resource request. 612 // worker to which to dispatch a FetchEvent for a main frame resource request.
658 // For context, a FetchEvent can only be dispatched to an ACTIVATED worker 613 // For context, a FetchEvent can only be dispatched to an ACTIVATED worker
(...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after
1038 CreateFetchRequest(), active_worker, resource_type_, request()->net_log(), 993 CreateFetchRequest(), active_worker, resource_type_, request()->net_log(),
1039 base::Bind(&ServiceWorkerURLRequestJob::DidPrepareFetchEvent, 994 base::Bind(&ServiceWorkerURLRequestJob::DidPrepareFetchEvent,
1040 weak_factory_.GetWeakPtr(), active_worker), 995 weak_factory_.GetWeakPtr(), active_worker),
1041 base::Bind(&ServiceWorkerURLRequestJob::DidDispatchFetchEvent, 996 base::Bind(&ServiceWorkerURLRequestJob::DidDispatchFetchEvent,
1042 weak_factory_.GetWeakPtr()))); 997 weak_factory_.GetWeakPtr())));
1043 worker_start_time_ = base::TimeTicks::Now(); 998 worker_start_time_ = base::TimeTicks::Now();
1044 fetch_dispatcher_->Run(); 999 fetch_dispatcher_->Run();
1045 } 1000 }
1046 1001
1047 } // namespace content 1002 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698