Chromium Code Reviews| 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) { |
|
harkness
2017/03/29 22:12:33
Maybe add the file_path and received_bytes to this
Peter Beverloo
2017/03/29 22:20:28
We'll need much more information, so I'd like thos
|
| + 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 |