Add conversions for EmbedObject, Figcaption and Figure
[chromium-blink-merge.git] / google_apis / drive / base_requests.cc
blobfe058fe863df173ab5d73573476a8c505f79dbdf
1 // Copyright (c) 2012 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.
5 #include "google_apis/drive/base_requests.h"
7 #include "base/json/json_reader.h"
8 #include "base/location.h"
9 #include "base/sequenced_task_runner.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/task_runner_util.h"
13 #include "base/values.h"
14 #include "google_apis/drive/request_sender.h"
15 #include "google_apis/drive/task_util.h"
16 #include "net/base/io_buffer.h"
17 #include "net/base/load_flags.h"
18 #include "net/base/net_errors.h"
19 #include "net/http/http_byte_range.h"
20 #include "net/http/http_response_headers.h"
21 #include "net/http/http_util.h"
22 #include "net/url_request/url_fetcher.h"
23 #include "net/url_request/url_request_status.h"
25 using net::URLFetcher;
27 namespace {
29 // Template for optional OAuth2 authorization HTTP header.
30 const char kAuthorizationHeaderFormat[] = "Authorization: Bearer %s";
31 // Template for GData API version HTTP header.
32 const char kGDataVersionHeader[] = "GData-Version: 3.0";
34 // Maximum number of attempts for re-authentication per request.
35 const int kMaxReAuthenticateAttemptsPerRequest = 1;
37 // Template for initiate upload of both GData WAPI and Drive API v2.
38 const char kUploadContentType[] = "X-Upload-Content-Type: ";
39 const char kUploadContentLength[] = "X-Upload-Content-Length: ";
40 const char kUploadResponseLocation[] = "location";
42 // Template for upload data range of both GData WAPI and Drive API v2.
43 const char kUploadContentRange[] = "Content-Range: bytes ";
44 const char kUploadResponseRange[] = "range";
46 // Parses JSON passed in |json| on |blocking_task_runner|. Runs |callback| on
47 // the calling thread when finished with either success or failure.
48 // The callback must not be null.
49 void ParseJsonOnBlockingPool(
50 base::TaskRunner* blocking_task_runner,
51 const std::string& json,
52 const base::Callback<void(scoped_ptr<base::Value> value)>& callback) {
53 base::PostTaskAndReplyWithResult(
54 blocking_task_runner,
55 FROM_HERE,
56 base::Bind(&google_apis::ParseJson, json),
57 callback);
60 // Returns response headers as a string. Returns a warning message if
61 // |url_fetcher| does not contain a valid response. Used only for debugging.
62 std::string GetResponseHeadersAsString(const URLFetcher* url_fetcher) {
63 // net::HttpResponseHeaders::raw_headers(), as the name implies, stores
64 // all headers in their raw format, i.e each header is null-terminated.
65 // So logging raw_headers() only shows the first header, which is probably
66 // the status line. GetNormalizedHeaders, on the other hand, will show all
67 // the headers, one per line, which is probably what we want.
68 std::string headers;
69 // Check that response code indicates response headers are valid (i.e. not
70 // malformed) before we retrieve the headers.
71 if (url_fetcher->GetResponseCode() == URLFetcher::RESPONSE_CODE_INVALID) {
72 headers.assign("Response headers are malformed!!");
73 } else {
74 url_fetcher->GetResponseHeaders()->GetNormalizedHeaders(&headers);
76 return headers;
79 bool IsSuccessfulResponseCode(int response_code) {
80 return 200 <= response_code && response_code <= 299;
83 } // namespace
85 namespace google_apis {
87 scoped_ptr<base::Value> ParseJson(const std::string& json) {
88 int error_code = -1;
89 std::string error_message;
90 scoped_ptr<base::Value> value(base::JSONReader::ReadAndReturnError(
91 json, base::JSON_PARSE_RFC, &error_code, &error_message));
93 if (!value.get()) {
94 std::string trimmed_json;
95 if (json.size() < 80) {
96 trimmed_json = json;
97 } else {
98 // Take the first 50 and the last 10 bytes.
99 trimmed_json = base::StringPrintf(
100 "%s [%s bytes] %s",
101 json.substr(0, 50).c_str(),
102 base::Uint64ToString(json.size() - 60).c_str(),
103 json.substr(json.size() - 10).c_str());
105 LOG(WARNING) << "Error while parsing entry response: " << error_message
106 << ", code: " << error_code << ", json:\n" << trimmed_json;
108 return value.Pass();
111 //=========================== ResponseWriter ==================================
112 ResponseWriter::ResponseWriter(base::SequencedTaskRunner* file_task_runner,
113 const base::FilePath& file_path,
114 const GetContentCallback& get_content_callback)
115 : get_content_callback_(get_content_callback),
116 weak_ptr_factory_(this) {
117 if (!file_path.empty()) {
118 file_writer_.reset(
119 new net::URLFetcherFileWriter(file_task_runner, file_path));
123 ResponseWriter::~ResponseWriter() {
126 void ResponseWriter::DisownFile() {
127 DCHECK(file_writer_);
128 file_writer_->DisownFile();
131 int ResponseWriter::Initialize(const net::CompletionCallback& callback) {
132 if (file_writer_)
133 return file_writer_->Initialize(callback);
135 data_.clear();
136 return net::OK;
139 int ResponseWriter::Write(net::IOBuffer* buffer,
140 int num_bytes,
141 const net::CompletionCallback& callback) {
142 if (!get_content_callback_.is_null()) {
143 get_content_callback_.Run(
144 HTTP_SUCCESS,
145 make_scoped_ptr(new std::string(buffer->data(), num_bytes)));
148 if (file_writer_) {
149 const int result = file_writer_->Write(
150 buffer, num_bytes,
151 base::Bind(&ResponseWriter::DidWrite,
152 weak_ptr_factory_.GetWeakPtr(),
153 make_scoped_refptr(buffer), callback));
154 if (result != net::ERR_IO_PENDING)
155 DidWrite(buffer, net::CompletionCallback(), result);
156 return result;
159 data_.append(buffer->data(), num_bytes);
160 return num_bytes;
163 int ResponseWriter::Finish(const net::CompletionCallback& callback) {
164 if (file_writer_)
165 return file_writer_->Finish(callback);
167 return net::OK;
170 void ResponseWriter::DidWrite(scoped_refptr<net::IOBuffer> buffer,
171 const net::CompletionCallback& callback,
172 int result) {
173 if (result > 0) {
174 // Even if file_writer_ is used, append the data to |data_|, so that it can
175 // be used to get error information in case of server side errors.
176 // The size limit is to avoid consuming too much redundant memory.
177 const size_t kMaxStringSize = 1024*1024;
178 if (data_.size() < kMaxStringSize) {
179 data_.append(buffer->data(), std::min(static_cast<size_t>(result),
180 kMaxStringSize - data_.size()));
184 if (!callback.is_null())
185 callback.Run(result);
188 //============================ UrlFetchRequestBase ===========================
190 UrlFetchRequestBase::UrlFetchRequestBase(RequestSender* sender)
191 : re_authenticate_count_(0),
192 response_writer_(NULL),
193 sender_(sender),
194 error_code_(GDATA_OTHER_ERROR),
195 weak_ptr_factory_(this) {
198 UrlFetchRequestBase::~UrlFetchRequestBase() {}
200 void UrlFetchRequestBase::Start(const std::string& access_token,
201 const std::string& custom_user_agent,
202 const ReAuthenticateCallback& callback) {
203 DCHECK(CalledOnValidThread());
204 DCHECK(!access_token.empty());
205 DCHECK(!callback.is_null());
206 DCHECK(re_authenticate_callback_.is_null());
208 re_authenticate_callback_ = callback;
210 GURL url = GetURL();
211 if (url.is_empty()) {
212 // Error is found on generating the url. Send the error message to the
213 // callback, and then return immediately without trying to connect
214 // to the server.
215 RunCallbackOnPrematureFailure(GDATA_OTHER_ERROR);
216 return;
218 DVLOG(1) << "URL: " << url.spec();
220 URLFetcher::RequestType request_type = GetRequestType();
221 url_fetcher_.reset(URLFetcher::Create(url, request_type, this));
222 url_fetcher_->SetRequestContext(sender_->url_request_context_getter());
223 // Always set flags to neither send nor save cookies.
224 url_fetcher_->SetLoadFlags(
225 net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES |
226 net::LOAD_DISABLE_CACHE);
228 base::FilePath output_file_path;
229 GetContentCallback get_content_callback;
230 GetOutputFilePath(&output_file_path, &get_content_callback);
231 if (!get_content_callback.is_null())
232 get_content_callback = CreateRelayCallback(get_content_callback);
233 response_writer_ = new ResponseWriter(blocking_task_runner(),
234 output_file_path,
235 get_content_callback);
236 url_fetcher_->SaveResponseWithWriter(
237 scoped_ptr<net::URLFetcherResponseWriter>(response_writer_));
239 // Add request headers.
240 // Note that SetExtraRequestHeaders clears the current headers and sets it
241 // to the passed-in headers, so calling it for each header will result in
242 // only the last header being set in request headers.
243 if (!custom_user_agent.empty())
244 url_fetcher_->AddExtraRequestHeader("User-Agent: " + custom_user_agent);
245 url_fetcher_->AddExtraRequestHeader(kGDataVersionHeader);
246 url_fetcher_->AddExtraRequestHeader(
247 base::StringPrintf(kAuthorizationHeaderFormat, access_token.data()));
248 std::vector<std::string> headers = GetExtraRequestHeaders();
249 for (size_t i = 0; i < headers.size(); ++i) {
250 url_fetcher_->AddExtraRequestHeader(headers[i]);
251 DVLOG(1) << "Extra header: " << headers[i];
254 // Set upload data if available.
255 std::string upload_content_type;
256 std::string upload_content;
257 if (GetContentData(&upload_content_type, &upload_content)) {
258 url_fetcher_->SetUploadData(upload_content_type, upload_content);
259 } else {
260 base::FilePath local_file_path;
261 int64 range_offset = 0;
262 int64 range_length = 0;
263 if (GetContentFile(&local_file_path, &range_offset, &range_length,
264 &upload_content_type)) {
265 url_fetcher_->SetUploadFilePath(
266 upload_content_type,
267 local_file_path,
268 range_offset,
269 range_length,
270 blocking_task_runner());
271 } else {
272 // Even if there is no content data, UrlFetcher requires to set empty
273 // upload data string for POST, PUT and PATCH methods, explicitly.
274 // It is because that most requests of those methods have non-empty
275 // body, and UrlFetcher checks whether it is actually not forgotten.
276 if (request_type == URLFetcher::POST ||
277 request_type == URLFetcher::PUT ||
278 request_type == URLFetcher::PATCH) {
279 // Set empty upload content-type and upload content, so that
280 // the request will have no "Content-type: " header and no content.
281 url_fetcher_->SetUploadData(std::string(), std::string());
286 url_fetcher_->Start();
289 URLFetcher::RequestType UrlFetchRequestBase::GetRequestType() const {
290 return URLFetcher::GET;
293 std::vector<std::string> UrlFetchRequestBase::GetExtraRequestHeaders() const {
294 return std::vector<std::string>();
297 bool UrlFetchRequestBase::GetContentData(std::string* upload_content_type,
298 std::string* upload_content) {
299 return false;
302 bool UrlFetchRequestBase::GetContentFile(base::FilePath* local_file_path,
303 int64* range_offset,
304 int64* range_length,
305 std::string* upload_content_type) {
306 return false;
309 void UrlFetchRequestBase::GetOutputFilePath(
310 base::FilePath* local_file_path,
311 GetContentCallback* get_content_callback) {
314 void UrlFetchRequestBase::Cancel() {
315 response_writer_ = NULL;
316 url_fetcher_.reset(NULL);
317 RunCallbackOnPrematureFailure(GDATA_CANCELLED);
318 sender_->RequestFinished(this);
321 GDataErrorCode UrlFetchRequestBase::GetErrorCode() {
322 return error_code_;
325 bool UrlFetchRequestBase::CalledOnValidThread() {
326 return thread_checker_.CalledOnValidThread();
329 base::SequencedTaskRunner* UrlFetchRequestBase::blocking_task_runner() const {
330 return sender_->blocking_task_runner();
333 void UrlFetchRequestBase::OnProcessURLFetchResultsComplete() {
334 sender_->RequestFinished(this);
337 void UrlFetchRequestBase::OnURLFetchComplete(const URLFetcher* source) {
338 DVLOG(1) << "Response headers:\n" << GetResponseHeadersAsString(source);
340 // Determine error code.
341 error_code_ = static_cast<GDataErrorCode>(source->GetResponseCode());
342 if (!source->GetStatus().is_success()) {
343 switch (source->GetStatus().error()) {
344 case net::ERR_NETWORK_CHANGED:
345 error_code_ = GDATA_NO_CONNECTION;
346 break;
347 default:
348 error_code_ = GDATA_OTHER_ERROR;
352 // The server may return detailed error status in JSON.
353 // See https://developers.google.com/drive/handle-errors
354 if (!IsSuccessfulResponseCode(error_code_)) {
355 DVLOG(1) << response_writer_->data();
357 const char kErrorKey[] = "error";
358 const char kErrorErrorsKey[] = "errors";
359 const char kErrorReasonKey[] = "reason";
360 const char kErrorMessageKey[] = "message";
361 const char kErrorReasonRateLimitExceeded[] = "rateLimitExceeded";
362 const char kErrorReasonUserRateLimitExceeded[] = "userRateLimitExceeded";
363 const char kErrorReasonQuotaExceeded[] = "quotaExceeded";
365 scoped_ptr<base::Value> value(ParseJson(response_writer_->data()));
366 base::DictionaryValue* dictionary = NULL;
367 base::DictionaryValue* error = NULL;
368 if (value &&
369 value->GetAsDictionary(&dictionary) &&
370 dictionary->GetDictionaryWithoutPathExpansion(kErrorKey, &error)) {
371 // Get error message.
372 std::string message;
373 error->GetStringWithoutPathExpansion(kErrorMessageKey, &message);
374 DLOG(ERROR) << "code: " << error_code_ << ", message: " << message;
376 // Override the error code based on the reason of the first error.
377 base::ListValue* errors = NULL;
378 base::DictionaryValue* first_error = NULL;
379 if (error->GetListWithoutPathExpansion(kErrorErrorsKey, &errors) &&
380 errors->GetDictionary(0, &first_error)) {
381 std::string reason;
382 first_error->GetStringWithoutPathExpansion(kErrorReasonKey, &reason);
383 if (reason == kErrorReasonRateLimitExceeded ||
384 reason == kErrorReasonUserRateLimitExceeded)
385 error_code_ = HTTP_SERVICE_UNAVAILABLE;
386 if (reason == kErrorReasonQuotaExceeded)
387 error_code_ = GDATA_NO_SPACE;
392 // Handle authentication failure.
393 if (error_code_ == HTTP_UNAUTHORIZED) {
394 if (++re_authenticate_count_ <= kMaxReAuthenticateAttemptsPerRequest) {
395 // Reset re_authenticate_callback_ so Start() can be called again.
396 ReAuthenticateCallback callback = re_authenticate_callback_;
397 re_authenticate_callback_.Reset();
398 callback.Run(this);
399 return;
402 OnAuthFailed(error_code_);
403 return;
406 // Overridden by each specialization
407 ProcessURLFetchResults(source);
410 void UrlFetchRequestBase::OnAuthFailed(GDataErrorCode code) {
411 RunCallbackOnPrematureFailure(code);
412 sender_->RequestFinished(this);
415 base::WeakPtr<AuthenticatedRequestInterface>
416 UrlFetchRequestBase::GetWeakPtr() {
417 return weak_ptr_factory_.GetWeakPtr();
420 //============================ EntryActionRequest ============================
422 EntryActionRequest::EntryActionRequest(RequestSender* sender,
423 const EntryActionCallback& callback)
424 : UrlFetchRequestBase(sender),
425 callback_(callback) {
426 DCHECK(!callback_.is_null());
429 EntryActionRequest::~EntryActionRequest() {}
431 void EntryActionRequest::ProcessURLFetchResults(const URLFetcher* source) {
432 callback_.Run(GetErrorCode());
433 OnProcessURLFetchResultsComplete();
436 void EntryActionRequest::RunCallbackOnPrematureFailure(GDataErrorCode code) {
437 callback_.Run(code);
440 //========================= InitiateUploadRequestBase ========================
442 InitiateUploadRequestBase::InitiateUploadRequestBase(
443 RequestSender* sender,
444 const InitiateUploadCallback& callback,
445 const std::string& content_type,
446 int64 content_length)
447 : UrlFetchRequestBase(sender),
448 callback_(callback),
449 content_type_(content_type),
450 content_length_(content_length) {
451 DCHECK(!callback_.is_null());
452 DCHECK(!content_type_.empty());
453 DCHECK_GE(content_length_, 0);
456 InitiateUploadRequestBase::~InitiateUploadRequestBase() {}
458 void InitiateUploadRequestBase::ProcessURLFetchResults(
459 const URLFetcher* source) {
460 GDataErrorCode code = GetErrorCode();
462 std::string upload_location;
463 if (code == HTTP_SUCCESS) {
464 // Retrieve value of the first "Location" header.
465 source->GetResponseHeaders()->EnumerateHeader(NULL,
466 kUploadResponseLocation,
467 &upload_location);
470 callback_.Run(code, GURL(upload_location));
471 OnProcessURLFetchResultsComplete();
474 void InitiateUploadRequestBase::RunCallbackOnPrematureFailure(
475 GDataErrorCode code) {
476 callback_.Run(code, GURL());
479 std::vector<std::string>
480 InitiateUploadRequestBase::GetExtraRequestHeaders() const {
481 std::vector<std::string> headers;
482 headers.push_back(kUploadContentType + content_type_);
483 headers.push_back(
484 kUploadContentLength + base::Int64ToString(content_length_));
485 return headers;
488 //============================ UploadRangeResponse =============================
490 UploadRangeResponse::UploadRangeResponse()
491 : code(HTTP_SUCCESS),
492 start_position_received(0),
493 end_position_received(0) {
496 UploadRangeResponse::UploadRangeResponse(GDataErrorCode code,
497 int64 start_position_received,
498 int64 end_position_received)
499 : code(code),
500 start_position_received(start_position_received),
501 end_position_received(end_position_received) {
504 UploadRangeResponse::~UploadRangeResponse() {
507 //========================== UploadRangeRequestBase ==========================
509 UploadRangeRequestBase::UploadRangeRequestBase(RequestSender* sender,
510 const GURL& upload_url)
511 : UrlFetchRequestBase(sender),
512 upload_url_(upload_url),
513 weak_ptr_factory_(this) {
516 UploadRangeRequestBase::~UploadRangeRequestBase() {}
518 GURL UploadRangeRequestBase::GetURL() const {
519 // This is very tricky to get json from this request. To do that, &alt=json
520 // has to be appended not here but in InitiateUploadRequestBase::GetURL().
521 return upload_url_;
524 URLFetcher::RequestType UploadRangeRequestBase::GetRequestType() const {
525 return URLFetcher::PUT;
528 void UploadRangeRequestBase::ProcessURLFetchResults(
529 const URLFetcher* source) {
530 GDataErrorCode code = GetErrorCode();
531 net::HttpResponseHeaders* hdrs = source->GetResponseHeaders();
533 if (code == HTTP_RESUME_INCOMPLETE) {
534 // Retrieve value of the first "Range" header.
535 // The Range header is appeared only if there is at least one received
536 // byte. So, initialize the positions by 0 so that the [0,0) will be
537 // returned via the |callback_| for empty data case.
538 int64 start_position_received = 0;
539 int64 end_position_received = 0;
540 std::string range_received;
541 hdrs->EnumerateHeader(NULL, kUploadResponseRange, &range_received);
542 if (!range_received.empty()) { // Parse the range header.
543 std::vector<net::HttpByteRange> ranges;
544 if (net::HttpUtil::ParseRangeHeader(range_received, &ranges) &&
545 !ranges.empty() ) {
546 // We only care about the first start-end pair in the range.
548 // Range header represents the range inclusively, while we are treating
549 // ranges exclusively (i.e., end_position_received should be one passed
550 // the last valid index). So "+ 1" is added.
551 start_position_received = ranges[0].first_byte_position();
552 end_position_received = ranges[0].last_byte_position() + 1;
555 // The Range header has the received data range, so the start position
556 // should be always 0.
557 DCHECK_EQ(start_position_received, 0);
559 OnRangeRequestComplete(UploadRangeResponse(code,
560 start_position_received,
561 end_position_received),
562 scoped_ptr<base::Value>());
564 OnProcessURLFetchResultsComplete();
565 } else if (code == HTTP_CREATED || code == HTTP_SUCCESS) {
566 // The upload is successfully done. Parse the response which should be
567 // the entry's metadata.
568 ParseJsonOnBlockingPool(blocking_task_runner(),
569 response_writer()->data(),
570 base::Bind(&UploadRangeRequestBase::OnDataParsed,
571 weak_ptr_factory_.GetWeakPtr(),
572 code));
573 } else {
574 // Failed to upload. Run callbacks to notify the error.
575 OnRangeRequestComplete(
576 UploadRangeResponse(code, -1, -1), scoped_ptr<base::Value>());
577 OnProcessURLFetchResultsComplete();
581 void UploadRangeRequestBase::OnDataParsed(GDataErrorCode code,
582 scoped_ptr<base::Value> value) {
583 DCHECK(CalledOnValidThread());
584 DCHECK(code == HTTP_CREATED || code == HTTP_SUCCESS);
586 OnRangeRequestComplete(UploadRangeResponse(code, -1, -1), value.Pass());
587 OnProcessURLFetchResultsComplete();
590 void UploadRangeRequestBase::RunCallbackOnPrematureFailure(
591 GDataErrorCode code) {
592 OnRangeRequestComplete(
593 UploadRangeResponse(code, 0, 0), scoped_ptr<base::Value>());
596 //========================== ResumeUploadRequestBase =========================
598 ResumeUploadRequestBase::ResumeUploadRequestBase(
599 RequestSender* sender,
600 const GURL& upload_location,
601 int64 start_position,
602 int64 end_position,
603 int64 content_length,
604 const std::string& content_type,
605 const base::FilePath& local_file_path)
606 : UploadRangeRequestBase(sender, upload_location),
607 start_position_(start_position),
608 end_position_(end_position),
609 content_length_(content_length),
610 content_type_(content_type),
611 local_file_path_(local_file_path) {
612 DCHECK_LE(start_position_, end_position_);
615 ResumeUploadRequestBase::~ResumeUploadRequestBase() {}
617 std::vector<std::string>
618 ResumeUploadRequestBase::GetExtraRequestHeaders() const {
619 if (content_length_ == 0) {
620 // For uploading an empty document, just PUT an empty content.
621 DCHECK_EQ(start_position_, 0);
622 DCHECK_EQ(end_position_, 0);
623 return std::vector<std::string>();
626 // The header looks like
627 // Content-Range: bytes <start_position>-<end_position>/<content_length>
628 // for example:
629 // Content-Range: bytes 7864320-8388607/13851821
630 // The header takes inclusive range, so we adjust by "end_position - 1".
631 DCHECK_GE(start_position_, 0);
632 DCHECK_GT(end_position_, 0);
633 DCHECK_GE(content_length_, 0);
635 std::vector<std::string> headers;
636 headers.push_back(
637 std::string(kUploadContentRange) +
638 base::Int64ToString(start_position_) + "-" +
639 base::Int64ToString(end_position_ - 1) + "/" +
640 base::Int64ToString(content_length_));
641 return headers;
644 bool ResumeUploadRequestBase::GetContentFile(
645 base::FilePath* local_file_path,
646 int64* range_offset,
647 int64* range_length,
648 std::string* upload_content_type) {
649 if (start_position_ == end_position_) {
650 // No content data.
651 return false;
654 *local_file_path = local_file_path_;
655 *range_offset = start_position_;
656 *range_length = end_position_ - start_position_;
657 *upload_content_type = content_type_;
658 return true;
661 //======================== GetUploadStatusRequestBase ========================
663 GetUploadStatusRequestBase::GetUploadStatusRequestBase(RequestSender* sender,
664 const GURL& upload_url,
665 int64 content_length)
666 : UploadRangeRequestBase(sender, upload_url),
667 content_length_(content_length) {}
669 GetUploadStatusRequestBase::~GetUploadStatusRequestBase() {}
671 std::vector<std::string>
672 GetUploadStatusRequestBase::GetExtraRequestHeaders() const {
673 // The header looks like
674 // Content-Range: bytes */<content_length>
675 // for example:
676 // Content-Range: bytes */13851821
677 DCHECK_GE(content_length_, 0);
679 std::vector<std::string> headers;
680 headers.push_back(
681 std::string(kUploadContentRange) + "*/" +
682 base::Int64ToString(content_length_));
683 return headers;
686 //============================ DownloadFileRequestBase =========================
688 DownloadFileRequestBase::DownloadFileRequestBase(
689 RequestSender* sender,
690 const DownloadActionCallback& download_action_callback,
691 const GetContentCallback& get_content_callback,
692 const ProgressCallback& progress_callback,
693 const GURL& download_url,
694 const base::FilePath& output_file_path)
695 : UrlFetchRequestBase(sender),
696 download_action_callback_(download_action_callback),
697 get_content_callback_(get_content_callback),
698 progress_callback_(progress_callback),
699 download_url_(download_url),
700 output_file_path_(output_file_path) {
701 DCHECK(!download_action_callback_.is_null());
702 DCHECK(!output_file_path_.empty());
703 // get_content_callback may be null.
706 DownloadFileRequestBase::~DownloadFileRequestBase() {}
708 // Overridden from UrlFetchRequestBase.
709 GURL DownloadFileRequestBase::GetURL() const {
710 return download_url_;
713 void DownloadFileRequestBase::GetOutputFilePath(
714 base::FilePath* local_file_path,
715 GetContentCallback* get_content_callback) {
716 // Configure so that the downloaded content is saved to |output_file_path_|.
717 *local_file_path = output_file_path_;
718 *get_content_callback = get_content_callback_;
721 void DownloadFileRequestBase::OnURLFetchDownloadProgress(
722 const URLFetcher* source,
723 int64 current,
724 int64 total) {
725 if (!progress_callback_.is_null())
726 progress_callback_.Run(current, total);
729 void DownloadFileRequestBase::ProcessURLFetchResults(const URLFetcher* source) {
730 GDataErrorCode code = GetErrorCode();
732 // Take over the ownership of the the downloaded temp file.
733 base::FilePath temp_file;
734 if (code == HTTP_SUCCESS) {
735 response_writer()->DisownFile();
736 temp_file = output_file_path_;
739 download_action_callback_.Run(code, temp_file);
740 OnProcessURLFetchResultsComplete();
743 void DownloadFileRequestBase::RunCallbackOnPrematureFailure(
744 GDataErrorCode code) {
745 download_action_callback_.Run(code, base::FilePath());
748 } // namespace google_apis