Index: content/browser/background_fetch/background_fetch_data_manager.cc |
diff --git a/content/browser/background_fetch/background_fetch_data_manager.cc b/content/browser/background_fetch/background_fetch_data_manager.cc |
index c47840865c19b44d5aa6883492bbc4c82e44e7f5..100e67d4631bf6cf5817fcab7d9e2a7dc105197f 100644 |
--- a/content/browser/background_fetch/background_fetch_data_manager.cc |
+++ b/content/browser/background_fetch/background_fetch_data_manager.cc |
@@ -4,12 +4,12 @@ |
#include "content/browser/background_fetch/background_fetch_data_manager.h" |
+#include <algorithm> |
#include <queue> |
#include "base/memory/ptr_util.h" |
#include "content/browser/background_fetch/background_fetch_constants.h" |
#include "content/browser/background_fetch/background_fetch_context.h" |
-#include "content/browser/background_fetch/background_fetch_job_response_data.h" |
#include "content/browser/background_fetch/background_fetch_request_info.h" |
#include "content/browser/blob_storage/chrome_blob_storage_context.h" |
#include "content/public/browser/blob_handle.h" |
@@ -31,35 +31,92 @@ class BackgroundFetchDataManager::RegistrationData { |
// Convert the given |requests| to BackgroundFetchRequestInfo objects. |
for (const ServiceWorkerFetchRequest& request : requests) |
- requests_.emplace(request_index++, request); |
+ pending_requests_.emplace(request_index++, request); |
} |
~RegistrationData() = default; |
// Returns whether there are remaining requests on the request queue. |
- bool HasPendingRequests() const { return !requests_.empty(); } |
+ bool HasPendingRequests() const { return !pending_requests_.empty(); } |
// Consumes a request from the queue that is to be fetched. |
- BackgroundFetchRequestInfo ConsumeRequest() { |
- DCHECK(!requests_.empty()); |
+ BackgroundFetchRequestInfo GetPendingRequest() { |
+ DCHECK(!pending_requests_.empty()); |
- BackgroundFetchRequestInfo request = requests_.front(); |
- requests_.pop(); |
+ BackgroundFetchRequestInfo request = pending_requests_.front(); |
+ pending_requests_.pop(); |
+ |
+ // The |request| is considered to be active now. |
+ active_requests_.push_back(request); |
return request; |
} |
+ // Marks the |request| as having started with the given |download_guid|. |
+ // Persistent storage needs to store the association so we can resume fetches |
+ // after a browser restart, here we just verify that the |request| is active. |
+ void MarkRequestAsStarted(const BackgroundFetchRequestInfo& request, |
+ const std::string& download_guid) { |
+ const auto iter = std::find_if( |
+ active_requests_.begin(), active_requests_.end(), |
+ [&request](const BackgroundFetchRequestInfo& active_request) { |
+ return active_request.request_index() == request.request_index(); |
+ }); |
+ |
+ // The |request| must have been consumed from this RegistrationData. |
+ DCHECK(iter != active_requests_.end()); |
+ } |
+ |
+ // Marks the |request| as having completed. Verifies that the |request| is |
+ // currently active and moves it to the |completed_requests_| vector. |
+ void MarkRequestAsComplete(const BackgroundFetchRequestInfo& request) { |
+ const auto iter = std::find_if( |
+ active_requests_.begin(), active_requests_.end(), |
+ [&request](const BackgroundFetchRequestInfo& active_request) { |
+ return active_request.request_index() == request.request_index(); |
+ }); |
+ |
+ // The |request| must have been consumed from this RegistrationData. |
+ DCHECK(iter != active_requests_.end()); |
+ |
+ active_requests_.erase(iter); |
+ completed_requests_.push_back(request); |
+ } |
+ |
+ // Returns the vector with all completed requests part of this registration. |
+ const std::vector<BackgroundFetchRequestInfo>& GetCompletedRequests() const { |
+ return completed_requests_; |
+ } |
+ |
private: |
- std::queue<BackgroundFetchRequestInfo> requests_; |
BackgroundFetchOptions options_; |
+ // TODO(peter): BackgroundFetchRequestInfo should be stored in a |
+ // unique_ptr, owned by the BackgroundFetchJobController. Right now we |
+ // can't do that as we need to hold on to copies here. |
+ std::queue<BackgroundFetchRequestInfo> pending_requests_; |
+ std::vector<BackgroundFetchRequestInfo> active_requests_; |
+ |
+ // TODO(peter): Right now it's safe for this to be a vector because we only |
+ // allow a single parallel request. That stops when we start allowing more. |
+ static_assert(kMaximumBackgroundFetchParallelRequests == 1, |
+ "RegistrationData::completed_requests_ assumes no parallelism"); |
+ |
+ std::vector<BackgroundFetchRequestInfo> completed_requests_; |
+ |
DISALLOW_COPY_AND_ASSIGN(RegistrationData); |
}; |
BackgroundFetchDataManager::BackgroundFetchDataManager( |
BrowserContext* browser_context) |
- : browser_context_(browser_context), weak_ptr_factory_(this) { |
- DCHECK(browser_context_); |
+ : weak_ptr_factory_(this) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ DCHECK(browser_context); |
+ |
+ // Store the blob storage context for the given |browser_context|. |
+ blob_storage_context_ = |
+ make_scoped_refptr(ChromeBlobStorageContext::GetFor(browser_context)); |
+ DCHECK(blob_storage_context_); |
} |
BackgroundFetchDataManager::~BackgroundFetchDataManager() = default; |
@@ -84,7 +141,7 @@ void BackgroundFetchDataManager::CreateRegistration( |
if (!registration_data->HasPendingRequests()) |
break; |
- initial_requests.push_back(registration_data->ConsumeRequest()); |
+ initial_requests.push_back(registration_data->GetPendingRequest()); |
} |
// Store the created |registration_data| so that we can easily access it. |
@@ -103,7 +160,8 @@ void BackgroundFetchDataManager::MarkRequestAsStarted( |
auto iter = registrations_.find(registration_id); |
DCHECK(iter != registrations_.end()); |
- // TODO(peter): Associate the |download_guid| with the |request|. |
+ RegistrationData* registration_data = iter->second.get(); |
+ registration_data->MarkRequestAsStarted(request, download_guid); |
} |
void BackgroundFetchDataManager::MarkRequestAsCompleteAndGetNextRequest( |
@@ -114,204 +172,82 @@ void BackgroundFetchDataManager::MarkRequestAsCompleteAndGetNextRequest( |
DCHECK(iter != registrations_.end()); |
RegistrationData* registration_data = iter->second.get(); |
- |
- // TODO(peter): Store the |request| with the |registration_data|. |
+ registration_data->MarkRequestAsComplete(request); |
base::Optional<BackgroundFetchRequestInfo> next_request; |
if (registration_data->HasPendingRequests()) |
- next_request = registration_data->ConsumeRequest(); |
+ next_request = registration_data->GetPendingRequest(); |
std::move(callback).Run(next_request); |
} |
-void BackgroundFetchDataManager::DeleteRegistration( |
+void BackgroundFetchDataManager::GetSettledFetchesForRegistration( |
const BackgroundFetchRegistrationId& registration_id, |
- DeleteRegistrationCallback callback) { |
+ SettledFetchesCallback callback) { |
auto iter = registrations_.find(registration_id); |
- if (iter == registrations_.end()) { |
- std::move(callback).Run(blink::mojom::BackgroundFetchError::INVALID_TAG); |
- return; |
- } |
+ DCHECK(iter != registrations_.end()); |
- registrations_.erase(iter); |
+ RegistrationData* registration_data = iter->second.get(); |
+ DCHECK(!registration_data->HasPendingRequests()); |
- std::move(callback).Run(blink::mojom::BackgroundFetchError::NONE); |
-} |
+ const std::vector<BackgroundFetchRequestInfo>& requests = |
+ registration_data->GetCompletedRequests(); |
-void BackgroundFetchDataManager::WriteJobToStorage( |
- std::unique_ptr<BackgroundFetchJobInfo> job_info, |
- std::vector<std::unique_ptr<BackgroundFetchRequestInfo>> request_infos) { |
- // TODO(harkness): Check for job_guid clash. |
- const std::string job_guid = job_info->guid(); |
- job_map_[job_guid] = std::move(job_info); |
- |
- // Make an explicit copy of the original requests |
- // TODO(harkness): Replace this with actually writing to storage. |
- std::vector<BackgroundFetchRequestInfo> requests; |
- for (const auto& request_info : request_infos) { |
- requests.emplace_back(*(request_info.get())); |
- } |
- request_map_[job_guid] = std::move(requests); |
+ std::vector<BackgroundFetchSettledFetch> settled_fetches; |
+ settled_fetches.reserve(requests.size()); |
- // |request_infos| will be destroyed when it leaves scope here. |
-} |
+ std::vector<std::unique_ptr<BlobHandle>> blob_handles; |
-void BackgroundFetchDataManager::WriteRequestToStorage( |
- const std::string& job_guid, |
- BackgroundFetchRequestInfo* request_info) { |
- std::vector<BackgroundFetchRequestInfo>& request_infos = |
- request_map_[job_guid]; |
+ for (const auto& request : requests) { |
+ BackgroundFetchSettledFetch settled_fetch; |
+ settled_fetch.request = request.fetch_request(); |
- // Copy the updated |request_info| over the in-memory version. |
- for (size_t i = 0; i < request_infos.size(); i++) { |
- if (request_infos[i].guid() == request_info->guid()) |
- request_infos[i] = *request_info; |
- } |
-} |
+ settled_fetch.response.url_list.push_back(request.GetURL()); |
+ // TODO: settled_fetch.response.status_code |
+ // TODO: settled_fetch.response.status_text |
+ // TODO: settled_fetch.response.response_type |
+ // TODO: settled_fetch.response.headers |
-std::unique_ptr<BackgroundFetchRequestInfo> |
-BackgroundFetchDataManager::GetRequestInfo(const std::string& job_guid, |
- size_t request_index) { |
- // Explicitly create a copy. When this is persisted to StorageWorkerStorage, |
- // the request_map_ will not exist. |
- auto iter = request_map_.find(job_guid); |
- DCHECK(iter != request_map_.end()); |
- const std::vector<BackgroundFetchRequestInfo>& request_infos = iter->second; |
- |
- DCHECK(request_index <= request_infos.size()); |
- return base::MakeUnique<BackgroundFetchRequestInfo>( |
- request_infos[request_index]); |
-} |
+ if (request.received_bytes() > 0) { |
+ DCHECK(!request.file_path().empty()); |
-void BackgroundFetchDataManager::GetJobResponse( |
- const std::string& job_guid, |
- const BackgroundFetchResponseCompleteCallback& callback) { |
- BrowserThread::PostTaskAndReplyWithResult( |
- BrowserThread::UI, FROM_HERE, |
- base::Bind(&ChromeBlobStorageContext::GetFor, browser_context_), |
- base::Bind(&BackgroundFetchDataManager::DidGetBlobStorageContext, |
- weak_ptr_factory_.GetWeakPtr(), job_guid, callback)); |
-} |
+ std::unique_ptr<BlobHandle> blob_handle = |
+ blob_storage_context_->CreateFileBackedBlob( |
+ request.file_path(), 0 /* offset */, request.received_bytes(), |
+ base::Time() /* expected_modification_time */); |
-void BackgroundFetchDataManager::DidGetBlobStorageContext( |
- const std::string& job_guid, |
- const BackgroundFetchResponseCompleteCallback& callback, |
- ChromeBlobStorageContext* blob_context) { |
- DCHECK(blob_context); |
- BackgroundFetchJobInfo* job_info = job_map_[job_guid].get(); |
- DCHECK(job_info); |
- |
- // Create a BackgroundFetchJobResponseData object which will aggregate |
- // together the response blobs. |
- job_info->set_job_response_data( |
- base::MakeUnique<BackgroundFetchJobResponseData>(job_info->num_requests(), |
- callback)); |
- BackgroundFetchJobResponseData* job_response_data = |
- job_info->job_response_data(); |
- DCHECK(job_response_data); |
- |
- // Iterate over the requests and create blobs for each response. |
- for (size_t request_index = 0; request_index < job_info->num_requests(); |
- request_index++) { |
- // TODO(harkness): This will need to be asynchronous. |
- std::unique_ptr<BackgroundFetchRequestInfo> request_info = |
- GetRequestInfo(job_guid, request_index); |
- |
- // TODO(harkness): Only create a blob response if the request was |
- // successful. Otherwise create an error response. |
- std::unique_ptr<BlobHandle> blob_handle = |
- blob_context->CreateFileBackedBlob( |
- request_info->file_path(), 0 /* offset */, |
- request_info->received_bytes(), |
- base::Time() /* expected_modification_time */); |
- |
- job_response_data->AddResponse(*request_info.get(), std::move(blob_handle)); |
- } |
-} |
+ // TODO(peter): Appropriately handle !blob_handle |
+ if (blob_handle) { |
+ settled_fetch.response.blob_uuid = blob_handle->GetUUID(); |
+ settled_fetch.response.blob_size = request.received_bytes(); |
-bool BackgroundFetchDataManager::UpdateRequestState( |
- const std::string& job_guid, |
- const std::string& request_guid, |
- DownloadItem::DownloadState state, |
- DownloadInterruptReason interrupt_reason) { |
- // Find the request and set the state and the interrupt reason. |
- BackgroundFetchJobInfo* job_info = job_map_[job_guid].get(); |
- DCHECK(job_info); |
- BackgroundFetchRequestInfo* request = |
- job_info->GetActiveRequest(request_guid); |
- DCHECK(request); |
- request->set_state(state); |
- request->set_interrupt_reason(interrupt_reason); |
- |
- // If the request is now finished, remove it from the active requests. |
- switch (state) { |
- case DownloadItem::DownloadState::COMPLETE: |
- case DownloadItem::DownloadState::CANCELLED: |
- WriteRequestToStorage(job_guid, request); |
- job_info->RemoveActiveRequest(request_guid); |
- break; |
- case DownloadItem::DownloadState::IN_PROGRESS: |
- case DownloadItem::DownloadState::INTERRUPTED: |
- case DownloadItem::DownloadState::MAX_DOWNLOAD_STATE: |
- break; |
- } |
+ blob_handles.push_back(std::move(blob_handle)); |
+ } |
+ } |
- // Return a boolean indicating whether there are more requests to be |
- // processed. |
- return job_info->HasRequestsRemaining(); |
-} |
+ // TODO: settled_fetch.response.error |
+ // TODO: settled_fetch.response.response_time |
+ // TODO: settled_fetch.response.cors_exposed_header_names |
-void BackgroundFetchDataManager::UpdateRequestStorageState( |
- const std::string& job_guid, |
- const std::string& request_guid, |
- const base::FilePath& file_path, |
- int64_t received_bytes) { |
- BackgroundFetchJobInfo* job_info = job_map_[job_guid].get(); |
- DCHECK(job_info); |
- BackgroundFetchRequestInfo* request = |
- job_info->GetActiveRequest(request_guid); |
- DCHECK(request); |
- request->set_file_path(file_path); |
- request->set_received_bytes(received_bytes); |
-} |
+ settled_fetches.push_back(settled_fetch); |
+ } |
-const BackgroundFetchRequestInfo& |
-BackgroundFetchDataManager::GetNextBackgroundFetchRequestInfo( |
- const std::string& job_guid) { |
- BackgroundFetchJobInfo* job_info = job_map_[job_guid].get(); |
- DCHECK(job_info); |
- |
- // TODO(harkness): This needs to be async when it queries real storage. |
- std::unique_ptr<BackgroundFetchRequestInfo> request_info = |
- GetRequestInfo(job_guid, job_info->next_request_index()); |
- const std::string request_guid = request_info->guid(); |
- job_info->AddActiveRequest(std::move(request_info)); |
- return *job_info->GetActiveRequest(request_guid); |
+ std::move(callback).Run(blink::mojom::BackgroundFetchError::NONE, |
+ std::move(settled_fetches), std::move(blob_handles)); |
} |
-bool BackgroundFetchDataManager::IsComplete(const std::string& job_guid) const { |
- auto iter = job_map_.find(job_guid); |
- DCHECK(iter != job_map_.end()); |
- return iter->second->IsComplete(); |
-} |
+void BackgroundFetchDataManager::DeleteRegistration( |
+ const BackgroundFetchRegistrationId& registration_id, |
+ DeleteRegistrationCallback callback) { |
+ auto iter = registrations_.find(registration_id); |
+ if (iter == registrations_.end()) { |
+ std::move(callback).Run(blink::mojom::BackgroundFetchError::INVALID_TAG); |
+ return; |
+ } |
-bool BackgroundFetchDataManager::HasRequestsRemaining( |
- const std::string& job_guid) const { |
- auto iter = job_map_.find(job_guid); |
- DCHECK(iter != job_map_.end()); |
- return iter->second->HasRequestsRemaining(); |
-} |
+ registrations_.erase(iter); |
-void BackgroundFetchDataManager::UpdateRequestDownloadGuid( |
- const std::string& job_guid, |
- const std::string& request_guid, |
- const std::string& download_guid) { |
- BackgroundFetchJobInfo* job_info = job_map_[job_guid].get(); |
- DCHECK(job_info); |
- BackgroundFetchRequestInfo* request = |
- job_info->GetActiveRequest(request_guid); |
- DCHECK(request); |
- request->set_download_guid(download_guid); |
+ std::move(callback).Run(blink::mojom::BackgroundFetchError::NONE); |
} |
} // namespace content |