File: download_client.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (156 lines) | stat: -rw-r--r-- 6,050 bytes parent folder | download | duplicates (9)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/background_fetch/download_client.h"

#include <memory>
#include <set>
#include <string>
#include <utility>
#include <vector>

#include "base/functional/bind.h"
#include "base/task/sequenced_task_runner.h"
#include "components/background_fetch/background_fetch_delegate_base.h"
#include "components/download/public/background_service/background_download_service.h"
#include "components/download/public/background_service/download_metadata.h"
#include "content/public/browser/background_fetch_response.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "services/network/public/cpp/resource_request_body.h"
#include "url/origin.h"

namespace background_fetch {

namespace {

using BackgroundFetchFailureReason =
    content::BackgroundFetchResult::FailureReason;
BackgroundFetchFailureReason ToBackgroundFetchFailureReason(
    download::Client::FailureReason reason) {
  switch (reason) {
    case download::Client::FailureReason::NETWORK:
      return BackgroundFetchFailureReason::NETWORK;
    case download::Client::FailureReason::UPLOAD_TIMEDOUT:
    case download::Client::FailureReason::TIMEDOUT:
      return BackgroundFetchFailureReason::TIMEDOUT;
    case download::Client::FailureReason::UNKNOWN:
      return BackgroundFetchFailureReason::FETCH_ERROR;
    case download::Client::FailureReason::ABORTED:
    case download::Client::FailureReason::CANCELLED:
      return BackgroundFetchFailureReason::CANCELLED;
  }
}

}  // namespace

DownloadClient::DownloadClient(content::BrowserContext* context)
    : browser_context_(context) {}

DownloadClient::~DownloadClient() = default;

void DownloadClient::OnServiceInitialized(
    bool state_lost,
    const std::vector<download::DownloadMetaData>& downloads) {
  std::set<std::string> outstanding_guids =
      GetDelegate()->TakeOutstandingGuids();
  for (const auto& download : downloads) {
    if (!outstanding_guids.count(download.guid)) {
      // Background Fetch is not aware of this GUID, so it successfully
      // completed but the information is still around.
      continue;
    }

    if (download.completion_info) {
      // The download finished but was not persisted.
      OnDownloadSucceeded(download.guid, *download.completion_info);
      return;
    }

    // The download is active, and will call the appropriate functions.

    if (download.paused) {
      // We need to resurface the notification in a paused state.
      content::BrowserThread::PostBestEffortTask(
          FROM_HERE, base::SequencedTaskRunner::GetCurrentDefault(),
          base::BindOnce(&BackgroundFetchDelegateBase::RestartPausedDownload,
                         GetDelegate()->GetWeakPtr(), download.guid));
    }
  }

  // There is also the case that the Download Service is not aware of the GUID.
  // i.e. there is a guid in |outstanding_guids| not in |downloads|.
  // This can be due to:
  // 1. The browser crashing before the download started.
  // 2. The download failing before persisting the state.
  // 3. The browser was forced to clean-up the the download.
  // In either case the download should be allowed to restart, so there is
  // nothing to do here.
}

void DownloadClient::OnServiceUnavailable() {}

void DownloadClient::OnDownloadStarted(
    const std::string& guid,
    const std::vector<GURL>& url_chain,
    const scoped_refptr<const net::HttpResponseHeaders>& headers) {
  // TODO(crbug.com/40593934): Validate the chain/headers and cancel the
  // download if invalid.
  auto response =
      std::make_unique<content::BackgroundFetchResponse>(url_chain, headers);
  GetDelegate()->OnDownloadStarted(guid, std::move(response));
}

void DownloadClient::OnDownloadUpdated(const std::string& guid,
                                       uint64_t bytes_uploaded,
                                       uint64_t bytes_downloaded) {
  GetDelegate()->OnDownloadUpdated(guid, bytes_uploaded, bytes_downloaded);
}

void DownloadClient::OnDownloadFailed(const std::string& guid,
                                      const download::CompletionInfo& info,
                                      download::Client::FailureReason reason) {
  auto response = std::make_unique<content::BackgroundFetchResponse>(
      info.url_chain, info.response_headers);
  auto result = std::make_unique<content::BackgroundFetchResult>(
      std::move(response), base::Time::Now(),
      ToBackgroundFetchFailureReason(reason));
  GetDelegate()->OnDownloadFailed(guid, std::move(result));
}

void DownloadClient::OnDownloadSucceeded(const std::string& guid,
                                         const download::CompletionInfo& info) {
  if (browser_context_->IsOffTheRecord()) {
    DCHECK(info.blob_handle);
  } else {
    DCHECK(!info.path.empty());
  }

  auto response = std::make_unique<content::BackgroundFetchResponse>(
      info.url_chain, info.response_headers);
  auto result = std::make_unique<content::BackgroundFetchResult>(
      std::move(response), base::Time::Now(), info.path, info.blob_handle,
      info.bytes_downloaded);

  GetDelegate()->OnDownloadSucceeded(guid, std::move(result));
}

bool DownloadClient::CanServiceRemoveDownloadedFile(const std::string& guid,
                                                    bool force_delete) {
  // If |force_delete| is true the file will be removed anyway.
  // TODO(rayankans): Add UMA to see how often this happens.
  return force_delete || GetDelegate()->IsGuidOutstanding(guid);
}

void DownloadClient::GetUploadData(const std::string& guid,
                                   download::GetUploadDataCallback callback) {
  GetDelegate()->GetUploadData(guid, std::move(callback));
}

BackgroundFetchDelegateBase* DownloadClient::GetDelegate() {
  return static_cast<BackgroundFetchDelegateBase*>(
      browser_context_->GetBackgroundFetchDelegate());
}

}  // namespace background_fetch