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

Side by Side Diff: content/browser/background_fetch/background_fetch_data_manager.cc

Issue 2786783002: Dispatch a bare Service Worker event for a finished Background Fetch (Closed)
Patch Set: Dispatch a bare Service Worker event for a finished Background Fetch Created 3 years, 8 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 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 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/background_fetch/background_fetch_data_manager.h" 5 #include "content/browser/background_fetch/background_fetch_data_manager.h"
6 6
7 #include <algorithm>
7 #include <queue> 8 #include <queue>
8 9
9 #include "base/memory/ptr_util.h" 10 #include "base/memory/ptr_util.h"
10 #include "content/browser/background_fetch/background_fetch_constants.h" 11 #include "content/browser/background_fetch/background_fetch_constants.h"
11 #include "content/browser/background_fetch/background_fetch_context.h" 12 #include "content/browser/background_fetch/background_fetch_context.h"
12 #include "content/browser/background_fetch/background_fetch_job_response_data.h"
13 #include "content/browser/background_fetch/background_fetch_request_info.h" 13 #include "content/browser/background_fetch/background_fetch_request_info.h"
14 #include "content/browser/blob_storage/chrome_blob_storage_context.h" 14 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
15 #include "content/public/browser/blob_handle.h" 15 #include "content/public/browser/blob_handle.h"
16 #include "content/public/browser/browser_context.h" 16 #include "content/public/browser/browser_context.h"
17 #include "content/public/browser/download_interrupt_reasons.h" 17 #include "content/public/browser/download_interrupt_reasons.h"
18 #include "content/public/browser/download_item.h" 18 #include "content/public/browser/download_item.h"
19 19
20 namespace content { 20 namespace content {
21 21
22 // The Registration Data class encapsulates the data stored for a particular 22 // The Registration Data class encapsulates the data stored for a particular
23 // Background Fetch registration. This roughly matches the on-disk format that 23 // Background Fetch registration. This roughly matches the on-disk format that
24 // will be adhered to in the future. 24 // will be adhered to in the future.
25 class BackgroundFetchDataManager::RegistrationData { 25 class BackgroundFetchDataManager::RegistrationData {
26 public: 26 public:
27 RegistrationData(const std::vector<ServiceWorkerFetchRequest>& requests, 27 RegistrationData(const std::vector<ServiceWorkerFetchRequest>& requests,
28 const BackgroundFetchOptions& options) 28 const BackgroundFetchOptions& options)
29 : options_(options) { 29 : options_(options) {
30 int request_index = 0; 30 int request_index = 0;
31 31
32 // Convert the given |requests| to BackgroundFetchRequestInfo objects. 32 // Convert the given |requests| to BackgroundFetchRequestInfo objects.
33 for (const ServiceWorkerFetchRequest& request : requests) 33 for (const ServiceWorkerFetchRequest& request : requests)
34 requests_.emplace(request_index++, request); 34 pending_requests_.emplace(request_index++, request);
35 } 35 }
36 36
37 ~RegistrationData() = default; 37 ~RegistrationData() = default;
38 38
39 // Returns whether there are remaining requests on the request queue. 39 // Returns whether there are remaining requests on the request queue.
40 bool HasPendingRequests() const { return !requests_.empty(); } 40 bool HasPendingRequests() const { return !pending_requests_.empty(); }
41 41
42 // Consumes a request from the queue that is to be fetched. 42 // Consumes a request from the queue that is to be fetched.
43 BackgroundFetchRequestInfo ConsumeRequest() { 43 BackgroundFetchRequestInfo GetPendingRequest() {
44 DCHECK(!requests_.empty()); 44 DCHECK(!pending_requests_.empty());
45 45
46 BackgroundFetchRequestInfo request = requests_.front(); 46 BackgroundFetchRequestInfo request = pending_requests_.front();
47 requests_.pop(); 47 pending_requests_.pop();
48
49 // The |request| is considered to be active now.
50 active_requests_.push_back(request);
48 51
49 return request; 52 return request;
50 } 53 }
51 54
55 // Marks the |request| as having started with the given |download_guid|.
56 // Persistent storage needs to store the association so we can resume fetches
57 // after a browser restart, here we just verify that the |request| is active.
58 void MarkRequestAsStarted(const BackgroundFetchRequestInfo& request,
59 const std::string& download_guid) {
60 const auto iter = std::find_if(
61 active_requests_.begin(), active_requests_.end(),
62 [&request](const BackgroundFetchRequestInfo& active_request) {
63 return active_request.request_index() == request.request_index();
64 });
65
66 // The |request| must have been consumed from this RegistrationData.
67 DCHECK(iter != active_requests_.end());
68 }
69
70 // Marks the |request| as having completed. Verifies that the |request| is
71 // currently active and moves it to the |completed_requests_| vector.
72 void MarkRequestAsComplete(const BackgroundFetchRequestInfo& request) {
73 const auto iter = std::find_if(
74 active_requests_.begin(), active_requests_.end(),
75 [&request](const BackgroundFetchRequestInfo& active_request) {
76 return active_request.request_index() == request.request_index();
77 });
78
79 // The |request| must have been consumed from this RegistrationData.
80 DCHECK(iter != active_requests_.end());
81
82 active_requests_.erase(iter);
83 completed_requests_.push_back(request);
84 }
85
86 // Returns the vector with all completed requests part of this registration.
87 const std::vector<BackgroundFetchRequestInfo>& GetCompletedRequests() const {
88 return completed_requests_;
89 }
90
52 private: 91 private:
53 std::queue<BackgroundFetchRequestInfo> requests_;
54 BackgroundFetchOptions options_; 92 BackgroundFetchOptions options_;
55 93
94 // TODO(peter): BackgroundFetchRequestInfo should be stored in a
95 // unique_ptr, owned by the BackgroundFetchJobController. Right now we
96 // can't do that as we need to hold on to copies here.
97 std::queue<BackgroundFetchRequestInfo> pending_requests_;
98 std::vector<BackgroundFetchRequestInfo> active_requests_;
99
100 // TODO(peter): Right now it's safe for this to be a vector because we only
101 // allow a single parallel request. That stops when we start allowing more.
102 static_assert(kMaximumBackgroundFetchParallelRequests == 1,
103 "RegistrationData::completed_requests_ assumes no parallelism");
104
105 std::vector<BackgroundFetchRequestInfo> completed_requests_;
106
56 DISALLOW_COPY_AND_ASSIGN(RegistrationData); 107 DISALLOW_COPY_AND_ASSIGN(RegistrationData);
57 }; 108 };
58 109
59 BackgroundFetchDataManager::BackgroundFetchDataManager( 110 BackgroundFetchDataManager::BackgroundFetchDataManager(
60 BrowserContext* browser_context) 111 BrowserContext* browser_context)
61 : browser_context_(browser_context), weak_ptr_factory_(this) { 112 : weak_ptr_factory_(this) {
62 DCHECK(browser_context_); 113 DCHECK_CURRENTLY_ON(BrowserThread::UI);
114 DCHECK(browser_context);
115
116 // Store the blob storage context for the given |browser_context|.
117 blob_storage_context_ =
118 make_scoped_refptr(ChromeBlobStorageContext::GetFor(browser_context));
119 DCHECK(blob_storage_context_);
63 } 120 }
64 121
65 BackgroundFetchDataManager::~BackgroundFetchDataManager() = default; 122 BackgroundFetchDataManager::~BackgroundFetchDataManager() = default;
66 123
67 void BackgroundFetchDataManager::CreateRegistration( 124 void BackgroundFetchDataManager::CreateRegistration(
68 const BackgroundFetchRegistrationId& registration_id, 125 const BackgroundFetchRegistrationId& registration_id,
69 const std::vector<ServiceWorkerFetchRequest>& requests, 126 const std::vector<ServiceWorkerFetchRequest>& requests,
70 const BackgroundFetchOptions& options, 127 const BackgroundFetchOptions& options,
71 CreateRegistrationCallback callback) { 128 CreateRegistrationCallback callback) {
72 if (registrations_.find(registration_id) != registrations_.end()) { 129 if (registrations_.find(registration_id) != registrations_.end()) {
73 std::move(callback).Run(blink::mojom::BackgroundFetchError::DUPLICATED_TAG, 130 std::move(callback).Run(blink::mojom::BackgroundFetchError::DUPLICATED_TAG,
74 std::vector<BackgroundFetchRequestInfo>()); 131 std::vector<BackgroundFetchRequestInfo>());
75 return; 132 return;
76 } 133 }
77 134
78 std::unique_ptr<RegistrationData> registration_data = 135 std::unique_ptr<RegistrationData> registration_data =
79 base::MakeUnique<RegistrationData>(requests, options); 136 base::MakeUnique<RegistrationData>(requests, options);
80 137
81 // Create a vector with the initial requests to feed the Job Controller with. 138 // Create a vector with the initial requests to feed the Job Controller with.
82 std::vector<BackgroundFetchRequestInfo> initial_requests; 139 std::vector<BackgroundFetchRequestInfo> initial_requests;
83 for (size_t i = 0; i < kMaximumBackgroundFetchParallelRequests; ++i) { 140 for (size_t i = 0; i < kMaximumBackgroundFetchParallelRequests; ++i) {
84 if (!registration_data->HasPendingRequests()) 141 if (!registration_data->HasPendingRequests())
85 break; 142 break;
86 143
87 initial_requests.push_back(registration_data->ConsumeRequest()); 144 initial_requests.push_back(registration_data->GetPendingRequest());
88 } 145 }
89 146
90 // Store the created |registration_data| so that we can easily access it. 147 // Store the created |registration_data| so that we can easily access it.
91 registrations_.insert( 148 registrations_.insert(
92 std::make_pair(registration_id, std::move(registration_data))); 149 std::make_pair(registration_id, std::move(registration_data)));
93 150
94 // Inform the |callback| of the newly created registration. 151 // Inform the |callback| of the newly created registration.
95 std::move(callback).Run(blink::mojom::BackgroundFetchError::NONE, 152 std::move(callback).Run(blink::mojom::BackgroundFetchError::NONE,
96 std::move(initial_requests)); 153 std::move(initial_requests));
97 } 154 }
98 155
99 void BackgroundFetchDataManager::MarkRequestAsStarted( 156 void BackgroundFetchDataManager::MarkRequestAsStarted(
100 const BackgroundFetchRegistrationId& registration_id, 157 const BackgroundFetchRegistrationId& registration_id,
101 const BackgroundFetchRequestInfo& request, 158 const BackgroundFetchRequestInfo& request,
102 const std::string& download_guid) { 159 const std::string& download_guid) {
103 auto iter = registrations_.find(registration_id); 160 auto iter = registrations_.find(registration_id);
104 DCHECK(iter != registrations_.end()); 161 DCHECK(iter != registrations_.end());
105 162
106 // TODO(peter): Associate the |download_guid| with the |request|. 163 RegistrationData* registration_data = iter->second.get();
164 registration_data->MarkRequestAsStarted(request, download_guid);
107 } 165 }
108 166
109 void BackgroundFetchDataManager::MarkRequestAsCompleteAndGetNextRequest( 167 void BackgroundFetchDataManager::MarkRequestAsCompleteAndGetNextRequest(
110 const BackgroundFetchRegistrationId& registration_id, 168 const BackgroundFetchRegistrationId& registration_id,
111 const BackgroundFetchRequestInfo& request, 169 const BackgroundFetchRequestInfo& request,
112 NextRequestCallback callback) { 170 NextRequestCallback callback) {
113 auto iter = registrations_.find(registration_id); 171 auto iter = registrations_.find(registration_id);
114 DCHECK(iter != registrations_.end()); 172 DCHECK(iter != registrations_.end());
115 173
116 RegistrationData* registration_data = iter->second.get(); 174 RegistrationData* registration_data = iter->second.get();
117 175 registration_data->MarkRequestAsComplete(request);
118 // TODO(peter): Store the |request| with the |registration_data|.
119 176
120 base::Optional<BackgroundFetchRequestInfo> next_request; 177 base::Optional<BackgroundFetchRequestInfo> next_request;
121 if (registration_data->HasPendingRequests()) 178 if (registration_data->HasPendingRequests())
122 next_request = registration_data->ConsumeRequest(); 179 next_request = registration_data->GetPendingRequest();
123 180
124 std::move(callback).Run(next_request); 181 std::move(callback).Run(next_request);
125 } 182 }
126 183
184 void BackgroundFetchDataManager::GetSettledFetchesForRegistration(
185 const BackgroundFetchRegistrationId& registration_id,
186 SettledFetchesCallback callback) {
187 auto iter = registrations_.find(registration_id);
188 DCHECK(iter != registrations_.end());
189
190 RegistrationData* registration_data = iter->second.get();
191 DCHECK(!registration_data->HasPendingRequests());
192
193 const std::vector<BackgroundFetchRequestInfo>& requests =
194 registration_data->GetCompletedRequests();
195
196 std::vector<BackgroundFetchSettledFetch> settled_fetches;
197 settled_fetches.reserve(requests.size());
198
199 std::vector<std::unique_ptr<BlobHandle>> blob_handles;
200
201 for (const auto& request : requests) {
202 BackgroundFetchSettledFetch settled_fetch;
203 settled_fetch.request = request.fetch_request();
204
205 settled_fetch.response.url_list.push_back(request.GetURL());
206 // TODO: settled_fetch.response.status_code
207 // TODO: settled_fetch.response.status_text
208 // TODO: settled_fetch.response.response_type
209 // TODO: settled_fetch.response.headers
210
211 if (request.received_bytes() > 0) {
212 DCHECK(!request.file_path().empty());
213
214 std::unique_ptr<BlobHandle> blob_handle =
215 blob_storage_context_->CreateFileBackedBlob(
216 request.file_path(), 0 /* offset */, request.received_bytes(),
217 base::Time() /* expected_modification_time */);
218
219 // TODO(peter): Appropriately handle !blob_handle
220 if (blob_handle) {
221 settled_fetch.response.blob_uuid = blob_handle->GetUUID();
222 settled_fetch.response.blob_size = request.received_bytes();
223
224 blob_handles.push_back(std::move(blob_handle));
225 }
226 }
227
228 // TODO: settled_fetch.response.error
229 // TODO: settled_fetch.response.response_time
230 // TODO: settled_fetch.response.cors_exposed_header_names
231
232 settled_fetches.push_back(settled_fetch);
233 }
234
235 std::move(callback).Run(blink::mojom::BackgroundFetchError::NONE,
236 std::move(settled_fetches), std::move(blob_handles));
237 }
238
127 void BackgroundFetchDataManager::DeleteRegistration( 239 void BackgroundFetchDataManager::DeleteRegistration(
128 const BackgroundFetchRegistrationId& registration_id, 240 const BackgroundFetchRegistrationId& registration_id,
129 DeleteRegistrationCallback callback) { 241 DeleteRegistrationCallback callback) {
130 auto iter = registrations_.find(registration_id); 242 auto iter = registrations_.find(registration_id);
131 if (iter == registrations_.end()) { 243 if (iter == registrations_.end()) {
132 std::move(callback).Run(blink::mojom::BackgroundFetchError::INVALID_TAG); 244 std::move(callback).Run(blink::mojom::BackgroundFetchError::INVALID_TAG);
133 return; 245 return;
134 } 246 }
135 247
136 registrations_.erase(iter); 248 registrations_.erase(iter);
137 249
138 std::move(callback).Run(blink::mojom::BackgroundFetchError::NONE); 250 std::move(callback).Run(blink::mojom::BackgroundFetchError::NONE);
139 } 251 }
140 252
141 void BackgroundFetchDataManager::WriteJobToStorage(
142 std::unique_ptr<BackgroundFetchJobInfo> job_info,
143 std::vector<std::unique_ptr<BackgroundFetchRequestInfo>> request_infos) {
144 // TODO(harkness): Check for job_guid clash.
145 const std::string job_guid = job_info->guid();
146 job_map_[job_guid] = std::move(job_info);
147
148 // Make an explicit copy of the original requests
149 // TODO(harkness): Replace this with actually writing to storage.
150 std::vector<BackgroundFetchRequestInfo> requests;
151 for (const auto& request_info : request_infos) {
152 requests.emplace_back(*(request_info.get()));
153 }
154 request_map_[job_guid] = std::move(requests);
155
156 // |request_infos| will be destroyed when it leaves scope here.
157 }
158
159 void BackgroundFetchDataManager::WriteRequestToStorage(
160 const std::string& job_guid,
161 BackgroundFetchRequestInfo* request_info) {
162 std::vector<BackgroundFetchRequestInfo>& request_infos =
163 request_map_[job_guid];
164
165 // Copy the updated |request_info| over the in-memory version.
166 for (size_t i = 0; i < request_infos.size(); i++) {
167 if (request_infos[i].guid() == request_info->guid())
168 request_infos[i] = *request_info;
169 }
170 }
171
172 std::unique_ptr<BackgroundFetchRequestInfo>
173 BackgroundFetchDataManager::GetRequestInfo(const std::string& job_guid,
174 size_t request_index) {
175 // Explicitly create a copy. When this is persisted to StorageWorkerStorage,
176 // the request_map_ will not exist.
177 auto iter = request_map_.find(job_guid);
178 DCHECK(iter != request_map_.end());
179 const std::vector<BackgroundFetchRequestInfo>& request_infos = iter->second;
180
181 DCHECK(request_index <= request_infos.size());
182 return base::MakeUnique<BackgroundFetchRequestInfo>(
183 request_infos[request_index]);
184 }
185
186 void BackgroundFetchDataManager::GetJobResponse(
187 const std::string& job_guid,
188 const BackgroundFetchResponseCompleteCallback& callback) {
189 BrowserThread::PostTaskAndReplyWithResult(
190 BrowserThread::UI, FROM_HERE,
191 base::Bind(&ChromeBlobStorageContext::GetFor, browser_context_),
192 base::Bind(&BackgroundFetchDataManager::DidGetBlobStorageContext,
193 weak_ptr_factory_.GetWeakPtr(), job_guid, callback));
194 }
195
196 void BackgroundFetchDataManager::DidGetBlobStorageContext(
197 const std::string& job_guid,
198 const BackgroundFetchResponseCompleteCallback& callback,
199 ChromeBlobStorageContext* blob_context) {
200 DCHECK(blob_context);
201 BackgroundFetchJobInfo* job_info = job_map_[job_guid].get();
202 DCHECK(job_info);
203
204 // Create a BackgroundFetchJobResponseData object which will aggregate
205 // together the response blobs.
206 job_info->set_job_response_data(
207 base::MakeUnique<BackgroundFetchJobResponseData>(job_info->num_requests(),
208 callback));
209 BackgroundFetchJobResponseData* job_response_data =
210 job_info->job_response_data();
211 DCHECK(job_response_data);
212
213 // Iterate over the requests and create blobs for each response.
214 for (size_t request_index = 0; request_index < job_info->num_requests();
215 request_index++) {
216 // TODO(harkness): This will need to be asynchronous.
217 std::unique_ptr<BackgroundFetchRequestInfo> request_info =
218 GetRequestInfo(job_guid, request_index);
219
220 // TODO(harkness): Only create a blob response if the request was
221 // successful. Otherwise create an error response.
222 std::unique_ptr<BlobHandle> blob_handle =
223 blob_context->CreateFileBackedBlob(
224 request_info->file_path(), 0 /* offset */,
225 request_info->received_bytes(),
226 base::Time() /* expected_modification_time */);
227
228 job_response_data->AddResponse(*request_info.get(), std::move(blob_handle));
229 }
230 }
231
232 bool BackgroundFetchDataManager::UpdateRequestState(
233 const std::string& job_guid,
234 const std::string& request_guid,
235 DownloadItem::DownloadState state,
236 DownloadInterruptReason interrupt_reason) {
237 // Find the request and set the state and the interrupt reason.
238 BackgroundFetchJobInfo* job_info = job_map_[job_guid].get();
239 DCHECK(job_info);
240 BackgroundFetchRequestInfo* request =
241 job_info->GetActiveRequest(request_guid);
242 DCHECK(request);
243 request->set_state(state);
244 request->set_interrupt_reason(interrupt_reason);
245
246 // If the request is now finished, remove it from the active requests.
247 switch (state) {
248 case DownloadItem::DownloadState::COMPLETE:
249 case DownloadItem::DownloadState::CANCELLED:
250 WriteRequestToStorage(job_guid, request);
251 job_info->RemoveActiveRequest(request_guid);
252 break;
253 case DownloadItem::DownloadState::IN_PROGRESS:
254 case DownloadItem::DownloadState::INTERRUPTED:
255 case DownloadItem::DownloadState::MAX_DOWNLOAD_STATE:
256 break;
257 }
258
259 // Return a boolean indicating whether there are more requests to be
260 // processed.
261 return job_info->HasRequestsRemaining();
262 }
263
264 void BackgroundFetchDataManager::UpdateRequestStorageState(
265 const std::string& job_guid,
266 const std::string& request_guid,
267 const base::FilePath& file_path,
268 int64_t received_bytes) {
269 BackgroundFetchJobInfo* job_info = job_map_[job_guid].get();
270 DCHECK(job_info);
271 BackgroundFetchRequestInfo* request =
272 job_info->GetActiveRequest(request_guid);
273 DCHECK(request);
274 request->set_file_path(file_path);
275 request->set_received_bytes(received_bytes);
276 }
277
278 const BackgroundFetchRequestInfo&
279 BackgroundFetchDataManager::GetNextBackgroundFetchRequestInfo(
280 const std::string& job_guid) {
281 BackgroundFetchJobInfo* job_info = job_map_[job_guid].get();
282 DCHECK(job_info);
283
284 // TODO(harkness): This needs to be async when it queries real storage.
285 std::unique_ptr<BackgroundFetchRequestInfo> request_info =
286 GetRequestInfo(job_guid, job_info->next_request_index());
287 const std::string request_guid = request_info->guid();
288 job_info->AddActiveRequest(std::move(request_info));
289 return *job_info->GetActiveRequest(request_guid);
290 }
291
292 bool BackgroundFetchDataManager::IsComplete(const std::string& job_guid) const {
293 auto iter = job_map_.find(job_guid);
294 DCHECK(iter != job_map_.end());
295 return iter->second->IsComplete();
296 }
297
298 bool BackgroundFetchDataManager::HasRequestsRemaining(
299 const std::string& job_guid) const {
300 auto iter = job_map_.find(job_guid);
301 DCHECK(iter != job_map_.end());
302 return iter->second->HasRequestsRemaining();
303 }
304
305 void BackgroundFetchDataManager::UpdateRequestDownloadGuid(
306 const std::string& job_guid,
307 const std::string& request_guid,
308 const std::string& download_guid) {
309 BackgroundFetchJobInfo* job_info = job_map_[job_guid].get();
310 DCHECK(job_info);
311 BackgroundFetchRequestInfo* request =
312 job_info->GetActiveRequest(request_guid);
313 DCHECK(request);
314 request->set_download_guid(download_guid);
315 }
316
317 } // namespace content 253 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698