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 std::vector<std::unique_ptr<BackgroundFetchRequestInfo>> request_infos) { |
26 BackgroundFetchRegistrationId registration_id( | 30 BackgroundFetchRegistrationId registration_id( |
27 job_info->service_worker_registration_id(), job_info->origin(), | 31 job_info->service_worker_registration_id(), job_info->origin(), |
28 job_info->tag()); | 32 job_info->tag()); |
29 | 33 |
30 // Ensure that this is not a duplicate request. | 34 // Ensure that this is not a duplicate request. |
31 if (known_registrations_.find(registration_id) != | 35 if (known_registrations_.find(registration_id) != |
32 known_registrations_.end()) { | 36 known_registrations_.end()) { |
33 DVLOG(1) << "Origin " << job_info->origin() | 37 DVLOG(1) << "Origin " << job_info->origin() |
34 << " has already created a batch request with tag " | 38 << " has already created a batch request with tag " |
35 << job_info->tag(); | 39 << job_info->tag(); |
36 // TODO(harkness) Figure out how to return errors like this. | 40 // TODO(harkness) Figure out how to return errors like this. |
37 return nullptr; | 41 return; |
38 } | 42 } |
39 | 43 |
40 // Add the request to our maps and return a JobData to track the individual | 44 // Add the JobInfo to the in-memory map, and write the individual requests out |
41 // files in the request. | 45 // to storage. |
| 46 job_info->set_num_requests(request_infos.size()); |
42 const std::string job_guid = job_info->guid(); | 47 const std::string job_guid = job_info->guid(); |
43 known_registrations_.insert(std::move(registration_id)); | 48 known_registrations_.insert(std::move(registration_id)); |
44 WriteJobToStorage(std::move(job_info), std::move(request_infos)); | 49 WriteJobToStorage(std::move(job_info), std::move(request_infos)); |
45 // TODO(harkness): Remove data when the job is complete. | |
46 | |
47 return base::MakeUnique<BackgroundFetchJobData>( | |
48 ReadRequestsFromStorage(job_guid)); | |
49 } | 50 } |
50 | 51 |
51 void BackgroundFetchDataManager::WriteJobToStorage( | 52 void BackgroundFetchDataManager::WriteJobToStorage( |
52 std::unique_ptr<BackgroundFetchJobInfo> job_info, | 53 std::unique_ptr<BackgroundFetchJobInfo> job_info, |
53 BackgroundFetchRequestInfos request_infos) { | 54 std::vector<std::unique_ptr<BackgroundFetchRequestInfo>> request_infos) { |
54 // TODO(harkness): Replace these maps with actually writing to storage. | |
55 // TODO(harkness): Check for job_guid clash. | 55 // TODO(harkness): Check for job_guid clash. |
56 const std::string job_guid = job_info->guid(); | 56 const std::string job_guid = job_info->guid(); |
57 job_map_[job_guid] = std::move(job_info); | 57 job_map_[job_guid] = std::move(job_info); |
58 request_map_[job_guid] = std::move(request_infos); | 58 |
| 59 // Make an explicit copy of the original requests |
| 60 // TODO(harkness): Replace this with actually writing to storage. |
| 61 std::vector<BackgroundFetchRequestInfo> requests; |
| 62 for (const auto& request_info : request_infos) { |
| 63 requests.emplace_back(*(request_info.get())); |
| 64 } |
| 65 request_map_[job_guid] = std::move(requests); |
| 66 |
| 67 // |request_infos| will be destroyed when it leaves scope here. |
59 } | 68 } |
60 | 69 |
61 // TODO(harkness): This should be changed to read (and cache) small numbers of | 70 void BackgroundFetchDataManager::WriteRequestToStorage( |
62 // the RequestInfos instead of returning all of them. | 71 const std::string& job_guid, |
63 BackgroundFetchRequestInfos& | 72 BackgroundFetchRequestInfo* request_info) { |
64 BackgroundFetchDataManager::ReadRequestsFromStorage( | 73 std::vector<BackgroundFetchRequestInfo>& request_infos = |
| 74 request_map_[job_guid]; |
| 75 |
| 76 // Copy the updated |request_info| over the in-memory version. |
| 77 for (size_t i = 0; i < request_infos.size(); i++) { |
| 78 if (request_infos[i].guid() == request_info->guid()) |
| 79 request_infos[i] = *request_info; |
| 80 } |
| 81 } |
| 82 |
| 83 std::unique_ptr<BackgroundFetchRequestInfo> |
| 84 BackgroundFetchDataManager::GetRequestInfo(const std::string& job_guid, |
| 85 size_t request_index) { |
| 86 // Explicitly create a copy. When this is persisted to StorageWorkerStorage, |
| 87 // the request_map_ will not exist. |
| 88 auto iter = request_map_.find(job_guid); |
| 89 DCHECK(iter != request_map_.end()); |
| 90 const std::vector<BackgroundFetchRequestInfo>& request_infos = iter->second; |
| 91 |
| 92 DCHECK(request_index <= request_infos.size()); |
| 93 return base::MakeUnique<BackgroundFetchRequestInfo>( |
| 94 request_infos[request_index]); |
| 95 } |
| 96 |
| 97 void BackgroundFetchDataManager::GetJobResponse( |
| 98 const std::string& job_guid, |
| 99 const BackgroundFetchResponseCompleteCallback& callback) { |
| 100 BackgroundFetchJobInfo* job_info = job_map_[job_guid].get(); |
| 101 DCHECK(job_info); |
| 102 |
| 103 // Create a BackgroundFetchJobResponseData object which will aggregate |
| 104 // together the response blobs. |
| 105 job_info->set_job_response_data( |
| 106 base::MakeUnique<BackgroundFetchJobResponseData>(job_info->num_requests(), |
| 107 callback)); |
| 108 |
| 109 // Iterate over the requests and create blobs for each response. |
| 110 for (size_t request_index = 0; request_index < job_info->num_requests(); |
| 111 request_index++) { |
| 112 // TODO(harkness): This will need to be asynchronous. |
| 113 std::unique_ptr<BackgroundFetchRequestInfo> request_info = |
| 114 GetRequestInfo(job_guid, request_index); |
| 115 |
| 116 // TODO(harkness): Only create a blob response if the request was |
| 117 // successful. Otherwise create an error response. |
| 118 content::BrowserContext::CreateFileBackedBlob( |
| 119 browser_context_, request_info->file_path(), 0 /* offset */, |
| 120 request_info->received_bytes(), |
| 121 base::Time() /* expected_modification_time */, |
| 122 base::Bind(&BackgroundFetchDataManager::DidGetRequestResponse, |
| 123 weak_ptr_factory_.GetWeakPtr(), job_guid, request_index)); |
| 124 } |
| 125 } |
| 126 |
| 127 void BackgroundFetchDataManager::DidGetRequestResponse( |
| 128 const std::string& job_guid, |
| 129 int request_sequence_number, |
| 130 std::unique_ptr<BlobHandle> blob_handle) { |
| 131 BackgroundFetchJobInfo* job_info = job_map_[job_guid].get(); |
| 132 DCHECK(job_info); |
| 133 |
| 134 BackgroundFetchJobResponseData* job_response_data = |
| 135 job_info->job_response_data(); |
| 136 DCHECK(job_response_data); |
| 137 |
| 138 job_response_data->AddResponse(request_sequence_number, |
| 139 std::move(blob_handle)); |
| 140 } |
| 141 |
| 142 bool BackgroundFetchDataManager::UpdateRequestState( |
| 143 const std::string& job_guid, |
| 144 const std::string& request_guid, |
| 145 DownloadItem::DownloadState state, |
| 146 DownloadInterruptReason interrupt_reason) { |
| 147 // Find the request and set the state and the interrupt reason. |
| 148 BackgroundFetchJobInfo* job_info = job_map_[job_guid].get(); |
| 149 DCHECK(job_info); |
| 150 BackgroundFetchRequestInfo* request = |
| 151 job_info->GetActiveRequest(request_guid); |
| 152 DCHECK(request); |
| 153 request->set_state(state); |
| 154 request->set_interrupt_reason(interrupt_reason); |
| 155 |
| 156 // If the request is now finished, remove it from the active requests. |
| 157 switch (state) { |
| 158 case DownloadItem::DownloadState::COMPLETE: |
| 159 case DownloadItem::DownloadState::CANCELLED: |
| 160 WriteRequestToStorage(job_guid, request); |
| 161 job_info->RemoveActiveRequest(request_guid); |
| 162 break; |
| 163 case DownloadItem::DownloadState::IN_PROGRESS: |
| 164 case DownloadItem::DownloadState::INTERRUPTED: |
| 165 case DownloadItem::DownloadState::MAX_DOWNLOAD_STATE: |
| 166 break; |
| 167 } |
| 168 |
| 169 // Return a boolean indicating whether there are more requests to be |
| 170 // processed. |
| 171 return job_info->HasRequestsRemaining(); |
| 172 } |
| 173 |
| 174 void BackgroundFetchDataManager::UpdateRequestStorageState( |
| 175 const std::string& job_guid, |
| 176 const std::string& request_guid, |
| 177 const base::FilePath& file_path, |
| 178 int64_t received_bytes) { |
| 179 BackgroundFetchJobInfo* job_info = job_map_[job_guid].get(); |
| 180 DCHECK(job_info); |
| 181 BackgroundFetchRequestInfo* request = |
| 182 job_info->GetActiveRequest(request_guid); |
| 183 DCHECK(request); |
| 184 request->set_file_path(file_path); |
| 185 request->set_received_bytes(received_bytes); |
| 186 } |
| 187 |
| 188 const BackgroundFetchRequestInfo& |
| 189 BackgroundFetchDataManager::GetNextBackgroundFetchRequestInfo( |
65 const std::string& job_guid) { | 190 const std::string& job_guid) { |
66 return request_map_[job_guid]; | 191 BackgroundFetchJobInfo* job_info = job_map_[job_guid].get(); |
| 192 DCHECK(job_info); |
| 193 |
| 194 // TODO(harkness): This needs to be async when it queries real storage. |
| 195 std::unique_ptr<BackgroundFetchRequestInfo> request_info = |
| 196 GetRequestInfo(job_guid, job_info->next_request_index()); |
| 197 const std::string request_guid = request_info->guid(); |
| 198 job_info->AddActiveRequest(std::move(request_info)); |
| 199 return *job_info->GetActiveRequest(request_guid); |
| 200 } |
| 201 |
| 202 bool BackgroundFetchDataManager::IsComplete(const std::string& job_guid) const { |
| 203 auto iter = job_map_.find(job_guid); |
| 204 DCHECK(iter != job_map_.end()); |
| 205 return iter->second->IsComplete(); |
| 206 } |
| 207 |
| 208 bool BackgroundFetchDataManager::HasRequestsRemaining( |
| 209 const std::string& job_guid) const { |
| 210 auto iter = job_map_.find(job_guid); |
| 211 DCHECK(iter != job_map_.end()); |
| 212 return iter->second->HasRequestsRemaining(); |
| 213 } |
| 214 |
| 215 void BackgroundFetchDataManager::UpdateRequestDownloadGuid( |
| 216 const std::string& job_guid, |
| 217 const std::string& request_guid, |
| 218 const std::string& download_guid) { |
| 219 BackgroundFetchJobInfo* job_info = job_map_[job_guid].get(); |
| 220 DCHECK(job_info); |
| 221 BackgroundFetchRequestInfo* request = |
| 222 job_info->GetActiveRequest(request_guid); |
| 223 DCHECK(request); |
| 224 request->set_download_guid(download_guid); |
67 } | 225 } |
68 | 226 |
69 } // namespace content | 227 } // namespace content |
OLD | NEW |