Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 "base/memory/ptr_util.h" | 7 #include "base/memory/ptr_util.h" |
| 8 #include "content/browser/background_fetch/background_fetch_context.h" | 8 #include "content/browser/background_fetch/background_fetch_context.h" |
| 9 #include "content/browser/background_fetch/background_fetch_job_response_data.h" | |
| 9 #include "content/browser/background_fetch/background_fetch_request_info.h" | 10 #include "content/browser/background_fetch/background_fetch_request_info.h" |
| 11 #include "content/public/browser/blob_handle.h" | |
| 12 #include "content/public/browser/browser_context.h" | |
| 13 #include "content/public/browser/download_interrupt_reasons.h" | |
| 14 #include "content/public/browser/download_item.h" | |
| 10 | 15 |
| 11 namespace content { | 16 namespace content { |
| 12 | 17 |
| 13 BackgroundFetchDataManager::BackgroundFetchDataManager( | 18 BackgroundFetchDataManager::BackgroundFetchDataManager( |
| 14 BackgroundFetchContext* background_fetch_context) | 19 BrowserContext* browser_context) |
| 15 : background_fetch_context_(background_fetch_context) { | 20 : browser_context_(browser_context), weak_ptr_factory_(this) { |
| 16 DCHECK(background_fetch_context_); | 21 DCHECK(browser_context_); |
| 17 // TODO(harkness) Read from persistent storage and recreate requests. | 22 // TODO(harkness) Read from persistent storage and recreate requests. |
| 18 } | 23 } |
| 19 | 24 |
| 20 BackgroundFetchDataManager::~BackgroundFetchDataManager() = default; | 25 BackgroundFetchDataManager::~BackgroundFetchDataManager() = default; |
| 21 | 26 |
| 22 std::unique_ptr<BackgroundFetchJobData> | 27 void BackgroundFetchDataManager::CreateRequest( |
| 23 BackgroundFetchDataManager::CreateRequest( | |
| 24 std::unique_ptr<BackgroundFetchJobInfo> job_info, | 28 std::unique_ptr<BackgroundFetchJobInfo> job_info, |
| 25 BackgroundFetchRequestInfos request_infos) { | 29 BackgroundFetchRequestInfos request_infos) { |
| 26 JobIdentifier id(job_info->service_worker_registration_id(), job_info->tag()); | 30 JobIdentifier id(job_info->service_worker_registration_id(), job_info->tag()); |
| 27 // Ensure that this is not a duplicate request. | 31 // Ensure that this is not a duplicate request. |
| 28 if (service_worker_tag_map_.find(id) != service_worker_tag_map_.end()) { | 32 if (service_worker_tag_map_.find(id) != service_worker_tag_map_.end()) { |
| 29 DVLOG(1) << "Origin " << job_info->origin() | 33 DVLOG(1) << "Origin " << job_info->origin() |
| 30 << " has already created a batch request with tag " | 34 << " has already created a batch request with tag " |
| 31 << job_info->tag(); | 35 << job_info->tag(); |
| 32 // TODO(harkness) Figure out how to return errors like this. | 36 // TODO(harkness) Figure out how to return errors like this. |
| 33 return nullptr; | 37 return; |
| 34 } | 38 } |
| 35 | 39 |
| 36 // Add the request to our maps and return a JobData to track the individual | 40 // Add the JobInfo to the in-memory map, and write the individual requests out |
| 37 // files in the request. | 41 // to storage. |
| 42 job_info->set_num_requests(request_infos.size()); | |
| 38 const std::string job_guid = job_info->guid(); | 43 const std::string job_guid = job_info->guid(); |
| 39 service_worker_tag_map_[id] = job_guid; | 44 service_worker_tag_map_[id] = job_guid; |
| 40 WriteJobToStorage(std::move(job_info), std::move(request_infos)); | 45 WriteJobToStorage(std::move(job_info), std::move(request_infos)); |
| 41 // TODO(harkness): Remove data when the job is complete. | |
| 42 | |
| 43 return base::MakeUnique<BackgroundFetchJobData>( | |
| 44 ReadRequestsFromStorage(job_guid)); | |
| 45 } | 46 } |
| 46 | 47 |
| 47 void BackgroundFetchDataManager::WriteJobToStorage( | 48 void BackgroundFetchDataManager::WriteJobToStorage( |
| 48 std::unique_ptr<BackgroundFetchJobInfo> job_info, | 49 std::unique_ptr<BackgroundFetchJobInfo> job_info, |
| 49 BackgroundFetchRequestInfos request_infos) { | 50 BackgroundFetchRequestInfos request_infos) { |
| 50 // TODO(harkness): Replace these maps with actually writing to storage. | |
| 51 // TODO(harkness): Check for job_guid clash. | 51 // TODO(harkness): Check for job_guid clash. |
| 52 const std::string job_guid = job_info->guid(); | 52 const std::string job_guid = job_info->guid(); |
| 53 job_map_[job_guid] = std::move(job_info); | 53 job_map_[job_guid] = std::move(job_info); |
| 54 request_map_[job_guid] = std::move(request_infos); | 54 |
| 55 // Make an explicit copy of the original requests | |
| 56 // TODO(harkness): Replace this with actually writing to storage. | |
| 57 std::vector<BackgroundFetchRequestInfo> requests; | |
| 58 for (const auto& request_info : request_infos) { | |
| 59 requests.emplace_back(*(request_info.get())); | |
| 60 } | |
| 61 request_map_[job_guid] = std::move(requests); | |
| 62 | |
| 63 // |request_infos| will be destroyed when it leaves scope here. | |
| 55 } | 64 } |
| 56 | 65 |
| 57 // TODO(harkness): This should be changed to read (and cache) small numbers of | 66 void BackgroundFetchDataManager::WriteRequestToStorage( |
| 58 // the RequestInfos instead of returning all of them. | 67 const std::string& job_guid, |
| 59 BackgroundFetchRequestInfos& | 68 BackgroundFetchRequestInfo* request_info) { |
| 60 BackgroundFetchDataManager::ReadRequestsFromStorage( | 69 std::vector<BackgroundFetchRequestInfo>& request_infos = |
| 70 request_map_[job_guid]; | |
| 71 | |
| 72 // Copy the updated |request_info| over the in-memory version. | |
| 73 for (size_t i = 0; i < request_infos.size(); i++) { | |
| 74 if (request_infos[i].guid() == request_info->guid()) | |
| 75 request_infos[i] = *request_info; | |
| 76 } | |
| 77 } | |
| 78 | |
| 79 std::unique_ptr<BackgroundFetchRequestInfo> | |
| 80 BackgroundFetchDataManager::GetRequestInfo(const std::string& job_guid, | |
| 81 size_t request_index) const { | |
| 82 // Explicitly create a copy. When this is persisted to StorageWorkerStorage, | |
| 83 // the request_map_ will not exist. | |
| 84 auto iter = request_map_.find(job_guid); | |
| 85 DCHECK(iter != request_map_.end()); | |
| 86 const std::vector<BackgroundFetchRequestInfo>& request_infos = iter->second; | |
| 87 | |
| 88 DCHECK(request_index <= request_infos.size()); | |
| 89 BackgroundFetchRequestInfo request_info = | |
| 90 *(request_infos.begin() + request_index); | |
|
Peter Beverloo
2017/03/25 03:38:50
Why wouldn't request_infos[request_index] work?
harkness
2017/03/26 16:13:18
I could do that, but then the method couldn't be c
Peter Beverloo
2017/03/26 22:32:39
This can't be const anyway - conceptually it could
harkness
2017/03/27 07:32:37
Changed.
| |
| 91 return base::MakeUnique<BackgroundFetchRequestInfo>(request_info); | |
| 92 } | |
| 93 | |
| 94 void BackgroundFetchDataManager::GetJobResponse( | |
| 95 const std::string& job_guid, | |
| 96 const BackgroundFetchResponseCompleteCallback& callback) { | |
| 97 BackgroundFetchJobInfo* job_info = job_map_[job_guid].get(); | |
| 98 DCHECK(job_info); | |
| 99 | |
| 100 // Create a BackgroundFetchJobResponseData object which will aggregate | |
| 101 // together the response blobs. | |
| 102 job_info->set_job_response_data( | |
| 103 base::MakeUnique<BackgroundFetchJobResponseData>(job_info->num_requests(), | |
| 104 std::move(callback))); | |
|
Peter Beverloo
2017/03/25 03:38:50
This std::move() doesn't do anything because |call
harkness
2017/03/26 16:13:18
Done.
| |
| 105 | |
| 106 // Iterate over the requests and create blobs for each response. | |
| 107 for (size_t request_index = 0; request_index < job_info->num_requests(); | |
| 108 request_index++) { | |
| 109 // TODO(harkness): This will need to be asynchronous. | |
| 110 std::unique_ptr<BackgroundFetchRequestInfo> request_info = | |
| 111 GetRequestInfo(job_guid, request_index); | |
| 112 | |
| 113 // TODO(harkness): Only create a blob response if the request was | |
| 114 // successful. Otherwise create an error response. | |
| 115 content::BrowserContext::CreateFileBackedBlob( | |
|
Peter Beverloo
2017/03/25 03:38:50
That method only exists to bridge UI thread calls
harkness
2017/03/26 16:13:18
Won't the DataManager need access to the browser c
Peter Beverloo
2017/03/26 22:32:39
We'd give it the ServiceWorkerContextWrapper inste
harkness
2017/03/27 07:32:37
Fair enough.
| |
| 116 browser_context_, request_info->file_path(), 0 /* offset */, | |
| 117 request_info->received_bytes(), | |
| 118 base::Time() /* expected_modification_time */, | |
| 119 base::Bind(&BackgroundFetchDataManager::DidGetRequestResponse, | |
| 120 weak_ptr_factory_.GetWeakPtr(), job_guid, request_index)); | |
| 121 } | |
| 122 } | |
| 123 | |
| 124 void BackgroundFetchDataManager::DidGetRequestResponse( | |
| 125 const std::string& job_guid, | |
| 126 int request_sequence_number, | |
| 127 std::unique_ptr<BlobHandle> blob_handle) { | |
| 128 BackgroundFetchJobInfo* job_info = job_map_[job_guid].get(); | |
| 129 DCHECK(job_info); | |
| 130 | |
| 131 BackgroundFetchJobResponseData* job_response_data = | |
| 132 job_info->job_response_data(); | |
| 133 DCHECK(job_response_data); | |
| 134 | |
| 135 job_response_data->AddResponse(request_sequence_number, | |
| 136 std::move(blob_handle)); | |
| 137 } | |
| 138 | |
| 139 bool BackgroundFetchDataManager::UpdateRequestState( | |
| 140 const std::string& job_guid, | |
| 141 const std::string& request_guid, | |
| 142 DownloadItem::DownloadState state, | |
| 143 DownloadInterruptReason interrupt_reason) { | |
| 144 // Find the request and set the state and the interrupt reason. | |
| 145 BackgroundFetchJobInfo* job_info = job_map_[job_guid].get(); | |
| 146 DCHECK(job_info); | |
|
Peter Beverloo
2017/03/25 03:38:50
This is the sort of error condition that we'll hav
harkness
2017/03/26 16:13:18
The only way I could see this being hit would be i
| |
| 147 BackgroundFetchRequestInfo* request = | |
| 148 job_info->GetActiveRequest(request_guid); | |
| 149 DCHECK(request); | |
| 150 request->set_state(state); | |
| 151 request->set_interrupt_reason(interrupt_reason); | |
| 152 | |
| 153 // If the request is now finished, remove it from the active requests. | |
| 154 switch (state) { | |
| 155 case DownloadItem::DownloadState::COMPLETE: | |
| 156 case DownloadItem::DownloadState::CANCELLED: | |
| 157 WriteRequestToStorage(job_guid, request); | |
| 158 job_info->RemoveActiveRequest(request_guid); | |
| 159 case DownloadItem::DownloadState::IN_PROGRESS: | |
| 160 case DownloadItem::DownloadState::INTERRUPTED: | |
| 161 case DownloadItem::DownloadState::MAX_DOWNLOAD_STATE: | |
| 162 break; | |
| 163 } | |
| 164 | |
| 165 // Return a boolean indicating whether there are more requests to be | |
| 166 // processed. | |
| 167 return job_info->HasRequestsRemaining(); | |
| 168 } | |
| 169 | |
| 170 void BackgroundFetchDataManager::UpdateRequestStorageState( | |
| 171 const std::string& job_guid, | |
| 172 const std::string& request_guid, | |
| 173 const base::FilePath& file_path, | |
| 174 int64_t received_bytes) { | |
| 175 BackgroundFetchJobInfo* job_info = job_map_[job_guid].get(); | |
| 176 DCHECK(job_info); | |
| 177 BackgroundFetchRequestInfo* request = | |
| 178 job_info->GetActiveRequest(request_guid); | |
| 179 DCHECK(request); | |
| 180 request->set_file_path(file_path); | |
| 181 request->set_received_bytes(received_bytes); | |
| 182 } | |
| 183 | |
| 184 const BackgroundFetchRequestInfo& | |
| 185 BackgroundFetchDataManager::GetNextBackgroundFetchRequestInfo( | |
| 61 const std::string& job_guid) { | 186 const std::string& job_guid) { |
| 62 return request_map_[job_guid]; | 187 BackgroundFetchJobInfo* job_info = job_map_[job_guid].get(); |
| 188 DCHECK(job_info); | |
| 189 | |
| 190 // TODO(harkness): This needs to be async when it queries real storage. | |
| 191 std::unique_ptr<BackgroundFetchRequestInfo> request_info = | |
| 192 GetRequestInfo(job_guid, job_info->next_request_index()); | |
| 193 const std::string request_guid = request_info->guid(); | |
| 194 job_info->AddActiveRequest(std::move(request_info)); | |
| 195 return *job_info->GetActiveRequest(request_guid); | |
| 196 } | |
| 197 | |
| 198 bool BackgroundFetchDataManager::IsComplete(const std::string& job_guid) const { | |
| 199 auto iter = job_map_.find(job_guid); | |
| 200 DCHECK(iter != job_map_.end()); | |
| 201 return iter->second->IsComplete(); | |
| 202 } | |
| 203 | |
| 204 bool BackgroundFetchDataManager::HasRequestsRemaining( | |
| 205 const std::string& job_guid) const { | |
| 206 auto iter = job_map_.find(job_guid); | |
| 207 DCHECK(iter != job_map_.end()); | |
| 208 return iter->second->HasRequestsRemaining(); | |
| 209 } | |
| 210 | |
| 211 void BackgroundFetchDataManager::UpdateRequestDownloadGuid( | |
| 212 const std::string& job_guid, | |
| 213 const std::string& request_guid, | |
| 214 const std::string& download_guid) { | |
|
Peter Beverloo
2017/03/25 03:38:50
I'd love to simplify the data model away from GUID
harkness
2017/03/26 16:13:18
I do hate that we have to have the download_guid a
Peter Beverloo
2017/03/26 22:32:39
Good!
harkness
2017/03/27 07:32:38
All the knowledge now on the JobInfo are things th
| |
| 215 BackgroundFetchJobInfo* job_info = job_map_[job_guid].get(); | |
| 216 DCHECK(job_info); | |
| 217 BackgroundFetchRequestInfo* request = | |
| 218 job_info->GetActiveRequest(request_guid); | |
| 219 DCHECK(request); | |
| 220 request->set_download_guid(download_guid); | |
| 63 } | 221 } |
| 64 | 222 |
| 65 } // namespace content | 223 } // namespace content |
| OLD | NEW |