drive_base_requests.cc 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. // Copyright 2021 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "google_apis/drive/drive_base_requests.h"
  5. #include <stddef.h>
  6. #include <algorithm>
  7. #include <memory>
  8. #include <utility>
  9. #include "base/bind.h"
  10. #include "base/files/file_util.h"
  11. #include "base/json/json_reader.h"
  12. #include "base/json/json_writer.h"
  13. #include "base/location.h"
  14. #include "base/strings/string_number_conversions.h"
  15. #include "base/strings/string_piece.h"
  16. #include "base/strings/stringprintf.h"
  17. #include "base/task/sequenced_task_runner.h"
  18. #include "base/task/task_runner_util.h"
  19. #include "base/threading/thread_task_runner_handle.h"
  20. #include "base/values.h"
  21. #include "google_apis/common/request_sender.h"
  22. #include "google_apis/common/task_util.h"
  23. #include "google_apis/common/time_util.h"
  24. #include "google_apis/drive/drive_api_parser.h"
  25. #include "google_apis/drive/request_util.h"
  26. #include "net/base/load_flags.h"
  27. #include "net/base/mime_util.h"
  28. #include "net/http/http_util.h"
  29. #include "services/network/public/cpp/resource_request.h"
  30. #include "services/network/public/mojom/url_response_head.mojom.h"
  31. namespace {
  32. // Template for initiate upload of both GData WAPI and Drive API v2.
  33. const char kUploadContentType[] = "X-Upload-Content-Type: ";
  34. const char kUploadContentLength[] = "X-Upload-Content-Length: ";
  35. const char kUploadResponseLocation[] = "location";
  36. // Template for upload data range of both GData WAPI and Drive API v2.
  37. const char kUploadContentRange[] = "Content-Range: bytes ";
  38. const char kUploadResponseRange[] = "range";
  39. // Mime type of JSON.
  40. const char kJsonMimeType[] = "application/json";
  41. // Mime type of multipart related.
  42. const char kMultipartRelatedMimeTypePrefix[] = "multipart/related; boundary=";
  43. // Mime type of multipart mixed.
  44. const char kMultipartMixedMimeTypePrefix[] = "multipart/mixed; boundary=";
  45. // Header for each item in a multipart message.
  46. const char kMultipartItemHeaderFormat[] = "--%s\nContent-Type: %s\n\n";
  47. // Footer for whole multipart message.
  48. const char kMultipartFooterFormat[] = "--%s--";
  49. // Parses JSON passed in |json| on |blocking_task_runner|. Runs |callback| on
  50. // the calling thread when finished with either success or failure.
  51. // The callback must not be null.
  52. void ParseJsonOnBlockingPool(
  53. base::TaskRunner* blocking_task_runner,
  54. std::string json,
  55. base::OnceCallback<void(std::unique_ptr<base::Value> value)> callback) {
  56. base::PostTaskAndReplyWithResult(
  57. blocking_task_runner, FROM_HERE,
  58. base::BindOnce(&google_apis::ParseJson, std::move(json)),
  59. std::move(callback));
  60. }
  61. // Obtains the multipart body for the metadata string and file contents. If
  62. // predetermined_boundary is empty, the function generates the boundary string.
  63. bool GetMultipartContent(const std::string& predetermined_boundary,
  64. const std::string& metadata_json,
  65. const std::string& content_type,
  66. const base::FilePath& path,
  67. std::string* upload_content_type,
  68. std::string* upload_content_data) {
  69. std::vector<google_apis::ContentTypeAndData> parts(2);
  70. parts[0].type = kJsonMimeType;
  71. parts[0].data = metadata_json;
  72. parts[1].type = content_type;
  73. if (!ReadFileToString(path, &parts[1].data))
  74. return false;
  75. google_apis::ContentTypeAndData output;
  76. GenerateMultipartBody(google_apis::MultipartType::kRelated,
  77. predetermined_boundary, parts, &output, nullptr);
  78. upload_content_type->swap(output.type);
  79. upload_content_data->swap(output.data);
  80. return true;
  81. }
  82. // See https://developers.google.com/drive/handle-errors
  83. google_apis::ApiErrorCode MapDriveReasonToError(google_apis::ApiErrorCode code,
  84. const std::string& reason) {
  85. const char kErrorReasonRateLimitExceeded[] = "rateLimitExceeded";
  86. const char kErrorReasonUserRateLimitExceeded[] = "userRateLimitExceeded";
  87. const char kErrorReasonQuotaExceeded[] = "quotaExceeded";
  88. const char kErrorReasonResponseTooLarge[] = "responseTooLarge";
  89. if (reason == kErrorReasonRateLimitExceeded ||
  90. reason == kErrorReasonUserRateLimitExceeded) {
  91. return google_apis::HTTP_SERVICE_UNAVAILABLE;
  92. }
  93. if (reason == kErrorReasonQuotaExceeded)
  94. return google_apis::DRIVE_NO_SPACE;
  95. if (reason == kErrorReasonResponseTooLarge)
  96. return google_apis::DRIVE_RESPONSE_TOO_LARGE;
  97. return code;
  98. }
  99. } // namespace
  100. namespace google_apis {
  101. void GenerateMultipartBody(MultipartType multipart_type,
  102. const std::string& predetermined_boundary,
  103. const std::vector<ContentTypeAndData>& parts,
  104. ContentTypeAndData* output,
  105. std::vector<uint64_t>* data_offset) {
  106. std::string boundary;
  107. // Generate random boundary.
  108. if (predetermined_boundary.empty()) {
  109. while (true) {
  110. boundary = net::GenerateMimeMultipartBoundary();
  111. bool conflict_with_content = false;
  112. for (auto& part : parts) {
  113. if (part.data.find(boundary, 0) != std::string::npos) {
  114. conflict_with_content = true;
  115. break;
  116. }
  117. }
  118. if (!conflict_with_content)
  119. break;
  120. }
  121. } else {
  122. boundary = predetermined_boundary;
  123. }
  124. switch (multipart_type) {
  125. case MultipartType::kRelated:
  126. output->type = kMultipartRelatedMimeTypePrefix + boundary;
  127. break;
  128. case MultipartType::kMixed:
  129. output->type = kMultipartMixedMimeTypePrefix + boundary;
  130. break;
  131. }
  132. output->data.clear();
  133. if (data_offset)
  134. data_offset->clear();
  135. for (auto& part : parts) {
  136. output->data.append(base::StringPrintf(
  137. kMultipartItemHeaderFormat, boundary.c_str(), part.type.c_str()));
  138. if (data_offset)
  139. data_offset->push_back(output->data.size());
  140. output->data.append(part.data);
  141. output->data.append("\n");
  142. }
  143. output->data.append(
  144. base::StringPrintf(kMultipartFooterFormat, boundary.c_str()));
  145. }
  146. //========================== DriveUrlFetchRequestBase ======================
  147. DriveUrlFetchRequestBase::DriveUrlFetchRequestBase(
  148. RequestSender* sender,
  149. ProgressCallback upload_progress_callback,
  150. ProgressCallback download_progress_callback)
  151. : UrlFetchRequestBase(sender,
  152. upload_progress_callback,
  153. download_progress_callback) {}
  154. DriveUrlFetchRequestBase::~DriveUrlFetchRequestBase() = default;
  155. ApiErrorCode DriveUrlFetchRequestBase::MapReasonToError(
  156. ApiErrorCode code,
  157. const std::string& reason) {
  158. return MapDriveReasonToError(code, reason);
  159. }
  160. bool DriveUrlFetchRequestBase::IsSuccessfulErrorCode(ApiErrorCode error) {
  161. return IsSuccessfulDriveApiErrorCode(error);
  162. }
  163. //============================ EntryActionRequest ============================
  164. EntryActionRequest::EntryActionRequest(RequestSender* sender,
  165. EntryActionCallback callback)
  166. : DriveUrlFetchRequestBase(sender, ProgressCallback(), ProgressCallback()),
  167. callback_(std::move(callback)) {
  168. DCHECK(callback_);
  169. }
  170. EntryActionRequest::~EntryActionRequest() = default;
  171. void EntryActionRequest::ProcessURLFetchResults(
  172. const network::mojom::URLResponseHead* response_head,
  173. base::FilePath response_file,
  174. std::string response_body) {
  175. std::move(callback_).Run(GetErrorCode());
  176. OnProcessURLFetchResultsComplete();
  177. }
  178. void EntryActionRequest::RunCallbackOnPrematureFailure(ApiErrorCode code) {
  179. std::move(callback_).Run(code);
  180. }
  181. //========================= InitiateUploadRequestBase ========================
  182. InitiateUploadRequestBase::InitiateUploadRequestBase(
  183. RequestSender* sender,
  184. InitiateUploadCallback callback,
  185. const std::string& content_type,
  186. int64_t content_length)
  187. : DriveUrlFetchRequestBase(sender, ProgressCallback(), ProgressCallback()),
  188. callback_(std::move(callback)),
  189. content_type_(content_type),
  190. content_length_(content_length) {
  191. DCHECK(!callback_.is_null());
  192. DCHECK(!content_type_.empty());
  193. DCHECK_GE(content_length_, 0);
  194. }
  195. InitiateUploadRequestBase::~InitiateUploadRequestBase() = default;
  196. void InitiateUploadRequestBase::ProcessURLFetchResults(
  197. const network::mojom::URLResponseHead* response_head,
  198. base::FilePath response_file,
  199. std::string response_body) {
  200. std::string upload_location;
  201. if (GetErrorCode() == HTTP_SUCCESS) {
  202. // Retrieve value of the first "Location" header.
  203. response_head->headers->EnumerateHeader(nullptr, kUploadResponseLocation,
  204. &upload_location);
  205. }
  206. std::move(callback_).Run(GetErrorCode(), GURL(upload_location));
  207. OnProcessURLFetchResultsComplete();
  208. }
  209. void InitiateUploadRequestBase::RunCallbackOnPrematureFailure(
  210. ApiErrorCode code) {
  211. std::move(callback_).Run(code, GURL());
  212. }
  213. std::vector<std::string> InitiateUploadRequestBase::GetExtraRequestHeaders()
  214. const {
  215. std::vector<std::string> headers;
  216. headers.push_back(kUploadContentType + content_type_);
  217. headers.push_back(kUploadContentLength +
  218. base::NumberToString(content_length_));
  219. return headers;
  220. }
  221. //============================ UploadRangeResponse =============================
  222. UploadRangeResponse::UploadRangeResponse() = default;
  223. UploadRangeResponse::UploadRangeResponse(ApiErrorCode code,
  224. int64_t start_position_received,
  225. int64_t end_position_received)
  226. : code(code),
  227. start_position_received(start_position_received),
  228. end_position_received(end_position_received) {}
  229. UploadRangeResponse::~UploadRangeResponse() = default;
  230. //========================== UploadRangeRequestBase ==========================
  231. UploadRangeRequestBase::UploadRangeRequestBase(
  232. RequestSender* sender,
  233. const GURL& upload_url,
  234. ProgressCallback progress_callback)
  235. : DriveUrlFetchRequestBase(sender, progress_callback, ProgressCallback()),
  236. upload_url_(upload_url) {}
  237. UploadRangeRequestBase::~UploadRangeRequestBase() = default;
  238. GURL UploadRangeRequestBase::GetURL() const {
  239. // This is very tricky to get json from this request. To do that, &alt=json
  240. // has to be appended not here but in InitiateUploadRequestBase::GetURL().
  241. return upload_url_;
  242. }
  243. std::string UploadRangeRequestBase::GetRequestType() const {
  244. return "PUT";
  245. }
  246. void UploadRangeRequestBase::ProcessURLFetchResults(
  247. const network::mojom::URLResponseHead* response_head,
  248. base::FilePath response_file,
  249. std::string response_body) {
  250. ApiErrorCode code = GetErrorCode();
  251. if (code == HTTP_RESUME_INCOMPLETE) {
  252. // Retrieve value of the first "Range" header.
  253. // The Range header is appeared only if there is at least one received
  254. // byte. So, initialize the positions by 0 so that the [0,0) will be
  255. // returned via the |callback_| for empty data case.
  256. int64_t start_position_received = 0;
  257. int64_t end_position_received = 0;
  258. std::string range_received;
  259. response_head->headers->EnumerateHeader(nullptr, kUploadResponseRange,
  260. &range_received);
  261. if (!range_received.empty()) { // Parse the range header.
  262. std::vector<net::HttpByteRange> ranges;
  263. if (net::HttpUtil::ParseRangeHeader(range_received, &ranges) &&
  264. !ranges.empty()) {
  265. // We only care about the first start-end pair in the range.
  266. //
  267. // Range header represents the range inclusively, while we are treating
  268. // ranges exclusively (i.e., end_position_received should be one passed
  269. // the last valid index). So "+ 1" is added.
  270. start_position_received = ranges[0].first_byte_position();
  271. end_position_received = ranges[0].last_byte_position() + 1;
  272. }
  273. }
  274. // The Range header has the received data range, so the start position
  275. // should be always 0.
  276. DCHECK_EQ(start_position_received, 0);
  277. OnRangeRequestComplete(UploadRangeResponse(code, start_position_received,
  278. end_position_received),
  279. std::unique_ptr<base::Value>());
  280. OnProcessURLFetchResultsComplete();
  281. } else if (code == HTTP_CREATED || code == HTTP_SUCCESS) {
  282. // The upload is successfully done. Parse the response which should be
  283. // the entry's metadata.
  284. ParseJsonOnBlockingPool(
  285. blocking_task_runner(), std::move(response_body),
  286. base::BindOnce(&UploadRangeRequestBase::OnDataParsed,
  287. weak_ptr_factory_.GetWeakPtr(), code));
  288. } else {
  289. // Failed to upload. Run callbacks to notify the error.
  290. OnRangeRequestComplete(UploadRangeResponse(code, -1, -1),
  291. std::unique_ptr<base::Value>());
  292. OnProcessURLFetchResultsComplete();
  293. }
  294. }
  295. void UploadRangeRequestBase::OnDataParsed(ApiErrorCode code,
  296. std::unique_ptr<base::Value> value) {
  297. DCHECK(CalledOnValidThread());
  298. DCHECK(code == HTTP_CREATED || code == HTTP_SUCCESS);
  299. OnRangeRequestComplete(UploadRangeResponse(code, -1, -1), std::move(value));
  300. OnProcessURLFetchResultsComplete();
  301. }
  302. void UploadRangeRequestBase::RunCallbackOnPrematureFailure(ApiErrorCode code) {
  303. OnRangeRequestComplete(UploadRangeResponse(code, 0, 0),
  304. std::unique_ptr<base::Value>());
  305. }
  306. //========================== ResumeUploadRequestBase =========================
  307. ResumeUploadRequestBase::ResumeUploadRequestBase(
  308. RequestSender* sender,
  309. const GURL& upload_location,
  310. int64_t start_position,
  311. int64_t end_position,
  312. int64_t content_length,
  313. const std::string& content_type,
  314. const base::FilePath& local_file_path,
  315. ProgressCallback progress_callback)
  316. : UploadRangeRequestBase(sender, upload_location, progress_callback),
  317. start_position_(start_position),
  318. end_position_(end_position),
  319. content_length_(content_length),
  320. content_type_(content_type),
  321. local_file_path_(local_file_path) {
  322. DCHECK_LE(start_position_, end_position_);
  323. }
  324. ResumeUploadRequestBase::~ResumeUploadRequestBase() = default;
  325. std::vector<std::string> ResumeUploadRequestBase::GetExtraRequestHeaders()
  326. const {
  327. if (content_length_ == 0) {
  328. // For uploading an empty document, just PUT an empty content.
  329. DCHECK_EQ(start_position_, 0);
  330. DCHECK_EQ(end_position_, 0);
  331. return std::vector<std::string>();
  332. }
  333. // The header looks like
  334. // Content-Range: bytes <start_position>-<end_position>/<content_length>
  335. // for example:
  336. // Content-Range: bytes 7864320-8388607/13851821
  337. // The header takes inclusive range, so we adjust by "end_position - 1".
  338. DCHECK_GE(start_position_, 0);
  339. DCHECK_GT(end_position_, 0);
  340. DCHECK_GE(content_length_, 0);
  341. std::vector<std::string> headers;
  342. headers.push_back(std::string(kUploadContentRange) +
  343. base::NumberToString(start_position_) + "-" +
  344. base::NumberToString(end_position_ - 1) + "/" +
  345. base::NumberToString(content_length_));
  346. return headers;
  347. }
  348. bool ResumeUploadRequestBase::GetContentFile(base::FilePath* local_file_path,
  349. int64_t* range_offset,
  350. int64_t* range_length,
  351. std::string* upload_content_type) {
  352. if (start_position_ == end_position_) {
  353. // No content data.
  354. return false;
  355. }
  356. *local_file_path = local_file_path_;
  357. *range_offset = start_position_;
  358. *range_length = end_position_ - start_position_;
  359. *upload_content_type = content_type_;
  360. return true;
  361. }
  362. //======================== GetUploadStatusRequestBase ========================
  363. GetUploadStatusRequestBase::GetUploadStatusRequestBase(RequestSender* sender,
  364. const GURL& upload_url,
  365. int64_t content_length)
  366. : UploadRangeRequestBase(sender, upload_url, ProgressCallback()),
  367. content_length_(content_length) {}
  368. GetUploadStatusRequestBase::~GetUploadStatusRequestBase() = default;
  369. std::vector<std::string> GetUploadStatusRequestBase::GetExtraRequestHeaders()
  370. const {
  371. // The header looks like
  372. // Content-Range: bytes */<content_length>
  373. // for example:
  374. // Content-Range: bytes */13851821
  375. DCHECK_GE(content_length_, 0);
  376. std::vector<std::string> headers;
  377. headers.push_back(std::string(kUploadContentRange) + "*/" +
  378. base::NumberToString(content_length_));
  379. return headers;
  380. }
  381. //========================= MultipartUploadRequestBase ========================
  382. MultipartUploadRequestBase::MultipartUploadRequestBase(
  383. base::SequencedTaskRunner* blocking_task_runner,
  384. const std::string& metadata_json,
  385. const std::string& content_type,
  386. int64_t content_length,
  387. const base::FilePath& local_file_path,
  388. FileResourceCallback callback,
  389. ProgressCallback progress_callback)
  390. : blocking_task_runner_(blocking_task_runner),
  391. metadata_json_(metadata_json),
  392. content_type_(content_type),
  393. local_path_(local_file_path),
  394. callback_(std::move(callback)),
  395. progress_callback_(progress_callback) {
  396. DCHECK(!content_type.empty());
  397. DCHECK_GE(content_length, 0);
  398. DCHECK(!local_file_path.empty());
  399. DCHECK(!callback_.is_null());
  400. }
  401. MultipartUploadRequestBase::~MultipartUploadRequestBase() = default;
  402. std::vector<std::string> MultipartUploadRequestBase::GetExtraRequestHeaders()
  403. const {
  404. return std::vector<std::string>();
  405. }
  406. void MultipartUploadRequestBase::Prepare(PrepareCallback callback) {
  407. // If the request is cancelled, the request instance will be deleted in
  408. // |UrlFetchRequestBase::Cancel| and OnPrepareUploadContent won't be called.
  409. std::string* const upload_content_type = new std::string();
  410. std::string* const upload_content_data = new std::string();
  411. PostTaskAndReplyWithResult(
  412. blocking_task_runner_.get(), FROM_HERE,
  413. base::BindOnce(&GetMultipartContent, boundary_, metadata_json_,
  414. content_type_, local_path_,
  415. base::Unretained(upload_content_type),
  416. base::Unretained(upload_content_data)),
  417. base::BindOnce(&MultipartUploadRequestBase::OnPrepareUploadContent,
  418. weak_ptr_factory_.GetWeakPtr(), std::move(callback),
  419. base::Owned(upload_content_type),
  420. base::Owned(upload_content_data)));
  421. }
  422. void MultipartUploadRequestBase::OnPrepareUploadContent(
  423. PrepareCallback callback,
  424. std::string* upload_content_type,
  425. std::string* upload_content_data,
  426. bool result) {
  427. if (!result) {
  428. std::move(callback).Run(DRIVE_FILE_ERROR);
  429. return;
  430. }
  431. upload_content_type_.swap(*upload_content_type);
  432. upload_content_data_.swap(*upload_content_data);
  433. std::move(callback).Run(HTTP_SUCCESS);
  434. }
  435. void MultipartUploadRequestBase::SetBoundaryForTesting(
  436. const std::string& boundary) {
  437. boundary_ = boundary;
  438. }
  439. bool MultipartUploadRequestBase::GetContentData(
  440. std::string* upload_content_type,
  441. std::string* upload_content_data) {
  442. // TODO(hirono): Pass stream instead of actual data to reduce memory usage.
  443. upload_content_type->swap(upload_content_type_);
  444. upload_content_data->swap(upload_content_data_);
  445. return true;
  446. }
  447. void MultipartUploadRequestBase::NotifyResult(
  448. ApiErrorCode code,
  449. const std::string& body,
  450. base::OnceClosure notify_complete_callback) {
  451. // The upload is successfully done. Parse the response which should be
  452. // the entry's metadata.
  453. if (code == HTTP_CREATED || code == HTTP_SUCCESS) {
  454. ParseJsonOnBlockingPool(
  455. blocking_task_runner_.get(), body,
  456. base::BindOnce(&MultipartUploadRequestBase::OnDataParsed,
  457. weak_ptr_factory_.GetWeakPtr(), code,
  458. std::move(notify_complete_callback)));
  459. } else {
  460. absl::optional<std::string> reason = MapJsonErrorToReason(body);
  461. NotifyError(reason.has_value() ? MapDriveReasonToError(code, reason.value())
  462. : code);
  463. std::move(notify_complete_callback).Run();
  464. }
  465. }
  466. void MultipartUploadRequestBase::NotifyError(ApiErrorCode code) {
  467. std::move(callback_).Run(code, std::unique_ptr<FileResource>());
  468. }
  469. void MultipartUploadRequestBase::NotifyUploadProgress(int64_t current,
  470. int64_t total) {
  471. if (!progress_callback_.is_null())
  472. progress_callback_.Run(current, total);
  473. }
  474. void MultipartUploadRequestBase::OnDataParsed(
  475. ApiErrorCode code,
  476. base::OnceClosure notify_complete_callback,
  477. std::unique_ptr<base::Value> value) {
  478. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  479. if (value)
  480. std::move(callback_).Run(code,
  481. google_apis::FileResource::CreateFrom(*value));
  482. else
  483. NotifyError(PARSE_ERROR);
  484. std::move(notify_complete_callback).Run();
  485. }
  486. //============================ DownloadFileRequestBase =========================
  487. DownloadFileRequestBase::DownloadFileRequestBase(
  488. RequestSender* sender,
  489. DownloadActionCallback download_action_callback,
  490. const GetContentCallback& get_content_callback,
  491. ProgressCallback progress_callback,
  492. const GURL& download_url,
  493. const base::FilePath& output_file_path)
  494. : DriveUrlFetchRequestBase(sender, ProgressCallback(), progress_callback),
  495. download_action_callback_(std::move(download_action_callback)),
  496. get_content_callback_(get_content_callback),
  497. download_url_(download_url),
  498. output_file_path_(output_file_path) {
  499. DCHECK(!download_action_callback_.is_null());
  500. DCHECK(!output_file_path_.empty());
  501. // get_content_callback may be null.
  502. }
  503. DownloadFileRequestBase::~DownloadFileRequestBase() = default;
  504. // Overridden from UrlFetchRequestBase.
  505. GURL DownloadFileRequestBase::GetURL() const {
  506. return download_url_;
  507. }
  508. void DownloadFileRequestBase::GetOutputFilePath(
  509. base::FilePath* local_file_path,
  510. GetContentCallback* get_content_callback) {
  511. // Configure so that the downloaded content is saved to |output_file_path_|.
  512. *local_file_path = output_file_path_;
  513. *get_content_callback = get_content_callback_;
  514. }
  515. void DownloadFileRequestBase::ProcessURLFetchResults(
  516. const network::mojom::URLResponseHead* response_head,
  517. base::FilePath response_file,
  518. std::string response_body) {
  519. std::move(download_action_callback_).Run(GetErrorCode(), response_file);
  520. OnProcessURLFetchResultsComplete();
  521. }
  522. void DownloadFileRequestBase::RunCallbackOnPrematureFailure(ApiErrorCode code) {
  523. std::move(download_action_callback_).Run(code, base::FilePath());
  524. }
  525. } // namespace google_apis