| 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 b4d60f16581d34766878e12bf532aa8fb0175780..5def082d44ad09db2ad89496d84f98cf182835fb 100644
 | 
| --- a/content/browser/background_fetch/background_fetch_data_manager.cc
 | 
| +++ b/content/browser/background_fetch/background_fetch_data_manager.cc
 | 
| @@ -6,23 +6,27 @@
 | 
|  
 | 
|  #include "base/memory/ptr_util.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/public/browser/blob_handle.h"
 | 
| +#include "content/public/browser/browser_context.h"
 | 
| +#include "content/public/browser/download_interrupt_reasons.h"
 | 
| +#include "content/public/browser/download_item.h"
 | 
|  
 | 
|  namespace content {
 | 
|  
 | 
|  BackgroundFetchDataManager::BackgroundFetchDataManager(
 | 
| -    BackgroundFetchContext* background_fetch_context)
 | 
| -    : background_fetch_context_(background_fetch_context) {
 | 
| -  DCHECK(background_fetch_context_);
 | 
| +    BrowserContext* browser_context)
 | 
| +    : browser_context_(browser_context), weak_ptr_factory_(this) {
 | 
| +  DCHECK(browser_context_);
 | 
|    // TODO(harkness) Read from persistent storage and recreate requests.
 | 
|  }
 | 
|  
 | 
|  BackgroundFetchDataManager::~BackgroundFetchDataManager() = default;
 | 
|  
 | 
| -std::unique_ptr<BackgroundFetchJobData>
 | 
| -BackgroundFetchDataManager::CreateRequest(
 | 
| +void BackgroundFetchDataManager::CreateRequest(
 | 
|      std::unique_ptr<BackgroundFetchJobInfo> job_info,
 | 
| -    BackgroundFetchRequestInfos request_infos) {
 | 
| +    std::vector<std::unique_ptr<BackgroundFetchRequestInfo>> request_infos) {
 | 
|    BackgroundFetchRegistrationId registration_id(
 | 
|        job_info->service_worker_registration_id(), job_info->origin(),
 | 
|        job_info->tag());
 | 
| @@ -34,36 +38,190 @@ BackgroundFetchDataManager::CreateRequest(
 | 
|               << " has already created a batch request with tag "
 | 
|               << job_info->tag();
 | 
|      // TODO(harkness) Figure out how to return errors like this.
 | 
| -    return nullptr;
 | 
| +    return;
 | 
|    }
 | 
|  
 | 
| -  // Add the request to our maps and return a JobData to track the individual
 | 
| -  // files in the request.
 | 
| +  // Add the JobInfo to the in-memory map, and write the individual requests out
 | 
| +  // to storage.
 | 
| +  job_info->set_num_requests(request_infos.size());
 | 
|    const std::string job_guid = job_info->guid();
 | 
|    known_registrations_.insert(std::move(registration_id));
 | 
|    WriteJobToStorage(std::move(job_info), std::move(request_infos));
 | 
| -  // TODO(harkness): Remove data when the job is complete.
 | 
| -
 | 
| -  return base::MakeUnique<BackgroundFetchJobData>(
 | 
| -      ReadRequestsFromStorage(job_guid));
 | 
|  }
 | 
|  
 | 
|  void BackgroundFetchDataManager::WriteJobToStorage(
 | 
|      std::unique_ptr<BackgroundFetchJobInfo> job_info,
 | 
| -    BackgroundFetchRequestInfos request_infos) {
 | 
| -  // TODO(harkness): Replace these maps with actually writing to storage.
 | 
| +    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);
 | 
| -  request_map_[job_guid] = std::move(request_infos);
 | 
| +
 | 
| +  // 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);
 | 
| +
 | 
| +  // |request_infos| will be destroyed when it leaves scope here.
 | 
| +}
 | 
| +
 | 
| +void BackgroundFetchDataManager::WriteRequestToStorage(
 | 
| +    const std::string& job_guid,
 | 
| +    BackgroundFetchRequestInfo* request_info) {
 | 
| +  std::vector<BackgroundFetchRequestInfo>& request_infos =
 | 
| +      request_map_[job_guid];
 | 
| +
 | 
| +  // 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;
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +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]);
 | 
|  }
 | 
|  
 | 
| -// TODO(harkness): This should be changed to read (and cache) small numbers of
 | 
| -// the RequestInfos instead of returning all of them.
 | 
| -BackgroundFetchRequestInfos&
 | 
| -BackgroundFetchDataManager::ReadRequestsFromStorage(
 | 
| +void BackgroundFetchDataManager::GetJobResponse(
 | 
| +    const std::string& job_guid,
 | 
| +    const BackgroundFetchResponseCompleteCallback& callback) {
 | 
| +  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));
 | 
| +
 | 
| +  // 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.
 | 
| +    content::BrowserContext::CreateFileBackedBlob(
 | 
| +        browser_context_, request_info->file_path(), 0 /* offset */,
 | 
| +        request_info->received_bytes(),
 | 
| +        base::Time() /* expected_modification_time */,
 | 
| +        base::Bind(&BackgroundFetchDataManager::DidGetRequestResponse,
 | 
| +                   weak_ptr_factory_.GetWeakPtr(), job_guid, request_index));
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +void BackgroundFetchDataManager::DidGetRequestResponse(
 | 
| +    const std::string& job_guid,
 | 
| +    int request_sequence_number,
 | 
| +    std::unique_ptr<BlobHandle> blob_handle) {
 | 
| +  BackgroundFetchJobInfo* job_info = job_map_[job_guid].get();
 | 
| +  DCHECK(job_info);
 | 
| +
 | 
| +  BackgroundFetchJobResponseData* job_response_data =
 | 
| +      job_info->job_response_data();
 | 
| +  DCHECK(job_response_data);
 | 
| +
 | 
| +  job_response_data->AddResponse(request_sequence_number,
 | 
| +                                 std::move(blob_handle));
 | 
| +}
 | 
| +
 | 
| +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;
 | 
| +  }
 | 
| +
 | 
| +  // Return a boolean indicating whether there are more requests to be
 | 
| +  // processed.
 | 
| +  return job_info->HasRequestsRemaining();
 | 
| +}
 | 
| +
 | 
| +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);
 | 
| +}
 | 
| +
 | 
| +const BackgroundFetchRequestInfo&
 | 
| +BackgroundFetchDataManager::GetNextBackgroundFetchRequestInfo(
 | 
|      const std::string& job_guid) {
 | 
| -  return request_map_[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);
 | 
| +}
 | 
| +
 | 
| +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();
 | 
| +}
 | 
| +
 | 
| +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();
 | 
| +}
 | 
| +
 | 
| +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);
 | 
|  }
 | 
|  
 | 
|  }  // namespace content
 | 
| 
 |