| 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
|
|
|