Update data reduction bypass UMA to reflect modern usage.
[chromium-blink-merge.git] / google_apis / drive / base_requests.cc
blob0c1a238057efe298b85bb75de878acee98c3b2bc
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 // Parse JSON string to base::Value object.
47 scoped_ptr<base::Value> ParseJsonInternal(const std::string& json) {
48 int error_code = -1;
49 std::string error_message;
50 scoped_ptr<base::Value> value(base::JSONReader::ReadAndReturnError(
51 json, base::JSON_PARSE_RFC, &error_code, &error_message));
53 if (!value.get()) {
54 std::string trimmed_json;
55 if (json.size() < 80) {
56 trimmed_json = json;
57 } else {
58 // Take the first 50 and the last 10 bytes.
59 trimmed_json = base::StringPrintf(
60 "%s [%s bytes] %s",
61 json.substr(0, 50).c_str(),
62 base::Uint64ToString(json.size() - 60).c_str(),
63 json.substr(json.size() - 10).c_str());
65 LOG(WARNING) << "Error while parsing entry response: " << error_message
66 << ", code: " << error_code << ", json:\n" << trimmed_json;
68 return value.Pass();
71 // Returns response headers as a string. Returns a warning message if
72 // |url_fetcher| does not contain a valid response. Used only for debugging.
73 std::string GetResponseHeadersAsString(
74 const URLFetcher* url_fetcher) {
75 // net::HttpResponseHeaders::raw_headers(), as the name implies, stores
76 // all headers in their raw format, i.e each header is null-terminated.
77 // So logging raw_headers() only shows the first header, which is probably
78 // the status line. GetNormalizedHeaders, on the other hand, will show all
79 // the headers, one per line, which is probably what we want.
80 std::string headers;
81 // Check that response code indicates response headers are valid (i.e. not
82 // malformed) before we retrieve the headers.
83 if (url_fetcher->GetResponseCode() == URLFetcher::RESPONSE_CODE_INVALID) {
84 headers.assign("Response headers are malformed!!");
85 } else {
86 url_fetcher->GetResponseHeaders()->GetNormalizedHeaders(&headers);
88 return headers;
91 bool IsSuccessfulResponseCode(int response_code) {
92 return 200 <= response_code && response_code <= 299;
95 } // namespace
97 namespace google_apis {
99 void ParseJson(base::TaskRunner* blocking_task_runner,
100 const std::string& json,
101 const ParseJsonCallback& callback) {
102 base::PostTaskAndReplyWithResult(
103 blocking_task_runner,
104 FROM_HERE,
105 base::Bind(&ParseJsonInternal, json),
106 callback);
109 //=========================== ResponseWriter ==================================
110 ResponseWriter::ResponseWriter(base::SequencedTaskRunner* file_task_runner,
111 const base::FilePath& file_path,
112 const GetContentCallback& get_content_callback)
113 : get_content_callback_(get_content_callback),
114 weak_ptr_factory_(this) {
115 if (!file_path.empty()) {
116 file_writer_.reset(
117 new net::URLFetcherFileWriter(file_task_runner, file_path));
121 ResponseWriter::~ResponseWriter() {
124 void ResponseWriter::DisownFile() {
125 DCHECK(file_writer_);
126 file_writer_->DisownFile();
129 int ResponseWriter::Initialize(const net::CompletionCallback& callback) {
130 if (file_writer_)
131 return file_writer_->Initialize(callback);
133 data_.clear();
134 return net::OK;
137 int ResponseWriter::Write(net::IOBuffer* buffer,
138 int num_bytes,
139 const net::CompletionCallback& callback) {
140 if (!get_content_callback_.is_null()) {
141 get_content_callback_.Run(
142 HTTP_SUCCESS,
143 make_scoped_ptr(new std::string(buffer->data(), num_bytes)));
146 if (file_writer_) {
147 const int result = file_writer_->Write(
148 buffer, num_bytes,
149 base::Bind(&ResponseWriter::DidWrite,
150 weak_ptr_factory_.GetWeakPtr(),
151 make_scoped_refptr(buffer), callback));
152 if (result != net::ERR_IO_PENDING)
153 DidWrite(buffer, net::CompletionCallback(), result);
154 return result;
157 data_.append(buffer->data(), num_bytes);
158 return num_bytes;
161 int ResponseWriter::Finish(const net::CompletionCallback& callback) {
162 if (file_writer_)
163 return file_writer_->Finish(callback);
165 return net::OK;
168 void ResponseWriter::DidWrite(scoped_refptr<net::IOBuffer> buffer,
169 const net::CompletionCallback& callback,
170 int result) {
171 if (result > 0) {
172 // Even if file_writer_ is used, append the data to |data_|, so that it can
173 // be used to get error information in case of server side errors.
174 // The size limit is to avoid consuming too much redundant memory.
175 const size_t kMaxStringSize = 1024*1024;
176 if (data_.size() < kMaxStringSize) {
177 data_.append(buffer->data(), std::min(static_cast<size_t>(result),
178 kMaxStringSize - data_.size()));
182 if (!callback.is_null())
183 callback.Run(result);
186 //============================ UrlFetchRequestBase ===========================
188 UrlFetchRequestBase::UrlFetchRequestBase(RequestSender* sender)
189 : re_authenticate_count_(0),
190 sender_(sender),
191 error_code_(GDATA_OTHER_ERROR),
192 weak_ptr_factory_(this) {
195 UrlFetchRequestBase::~UrlFetchRequestBase() {}
197 void UrlFetchRequestBase::Start(const std::string& access_token,
198 const std::string& custom_user_agent,
199 const ReAuthenticateCallback& callback) {
200 DCHECK(CalledOnValidThread());
201 DCHECK(!access_token.empty());
202 DCHECK(!callback.is_null());
203 DCHECK(re_authenticate_callback_.is_null());
205 re_authenticate_callback_ = callback;
207 GURL url = GetURL();
208 if (url.is_empty()) {
209 // Error is found on generating the url. Send the error message to the
210 // callback, and then return immediately without trying to connect
211 // to the server.
212 RunCallbackOnPrematureFailure(GDATA_OTHER_ERROR);
213 return;
215 DVLOG(1) << "URL: " << url.spec();
217 URLFetcher::RequestType request_type = GetRequestType();
218 url_fetcher_.reset(
219 URLFetcher::Create(url, request_type, this));
220 url_fetcher_->SetRequestContext(sender_->url_request_context_getter());
221 // Always set flags to neither send nor save cookies.
222 url_fetcher_->SetLoadFlags(
223 net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES |
224 net::LOAD_DISABLE_CACHE);
226 base::FilePath output_file_path;
227 GetContentCallback get_content_callback;
228 GetOutputFilePath(&output_file_path, &get_content_callback);
229 if (!get_content_callback.is_null())
230 get_content_callback = CreateRelayCallback(get_content_callback);
231 response_writer_ = new ResponseWriter(blocking_task_runner(),
232 output_file_path,
233 get_content_callback);
234 url_fetcher_->SaveResponseWithWriter(
235 scoped_ptr<net::URLFetcherResponseWriter>(response_writer_));
237 // Add request headers.
238 // Note that SetExtraRequestHeaders clears the current headers and sets it
239 // to the passed-in headers, so calling it for each header will result in
240 // only the last header being set in request headers.
241 if (!custom_user_agent.empty())
242 url_fetcher_->AddExtraRequestHeader("User-Agent: " + custom_user_agent);
243 url_fetcher_->AddExtraRequestHeader(kGDataVersionHeader);
244 url_fetcher_->AddExtraRequestHeader(
245 base::StringPrintf(kAuthorizationHeaderFormat, access_token.data()));
246 std::vector<std::string> headers = GetExtraRequestHeaders();
247 for (size_t i = 0; i < headers.size(); ++i) {
248 url_fetcher_->AddExtraRequestHeader(headers[i]);
249 DVLOG(1) << "Extra header: " << headers[i];
252 // Set upload data if available.
253 std::string upload_content_type;
254 std::string upload_content;
255 if (GetContentData(&upload_content_type, &upload_content)) {
256 url_fetcher_->SetUploadData(upload_content_type, upload_content);
257 } else {
258 base::FilePath local_file_path;
259 int64 range_offset = 0;
260 int64 range_length = 0;
261 if (GetContentFile(&local_file_path, &range_offset, &range_length,
262 &upload_content_type)) {
263 url_fetcher_->SetUploadFilePath(
264 upload_content_type,
265 local_file_path,
266 range_offset,
267 range_length,
268 blocking_task_runner());
269 } else {
270 // Even if there is no content data, UrlFetcher requires to set empty
271 // upload data string for POST, PUT and PATCH methods, explicitly.
272 // It is because that most requests of those methods have non-empty
273 // body, and UrlFetcher checks whether it is actually not forgotten.
274 if (request_type == URLFetcher::POST ||
275 request_type == URLFetcher::PUT ||
276 request_type == URLFetcher::PATCH) {
277 // Set empty upload content-type and upload content, so that
278 // the request will have no "Content-type: " header and no content.
279 url_fetcher_->SetUploadData(std::string(), std::string());
284 url_fetcher_->Start();
287 URLFetcher::RequestType UrlFetchRequestBase::GetRequestType() const {
288 return URLFetcher::GET;
291 std::vector<std::string> UrlFetchRequestBase::GetExtraRequestHeaders() const {
292 return std::vector<std::string>();
295 bool UrlFetchRequestBase::GetContentData(std::string* upload_content_type,
296 std::string* upload_content) {
297 return false;
300 bool UrlFetchRequestBase::GetContentFile(base::FilePath* local_file_path,
301 int64* range_offset,
302 int64* range_length,
303 std::string* upload_content_type) {
304 return false;
307 void UrlFetchRequestBase::GetOutputFilePath(
308 base::FilePath* local_file_path,
309 GetContentCallback* get_content_callback) {
312 void UrlFetchRequestBase::Cancel() {
313 response_writer_ = NULL;
314 url_fetcher_.reset(NULL);
315 RunCallbackOnPrematureFailure(GDATA_CANCELLED);
316 sender_->RequestFinished(this);
319 GDataErrorCode UrlFetchRequestBase::GetErrorCode() {
320 return error_code_;
323 bool UrlFetchRequestBase::CalledOnValidThread() {
324 return thread_checker_.CalledOnValidThread();
327 base::SequencedTaskRunner* UrlFetchRequestBase::blocking_task_runner() const {
328 return sender_->blocking_task_runner();
331 void UrlFetchRequestBase::OnProcessURLFetchResultsComplete() {
332 sender_->RequestFinished(this);
335 void UrlFetchRequestBase::OnURLFetchComplete(const URLFetcher* source) {
336 DVLOG(1) << "Response headers:\n" << GetResponseHeadersAsString(source);
338 // Determine error code.
339 error_code_ = static_cast<GDataErrorCode>(source->GetResponseCode());
340 if (!source->GetStatus().is_success()) {
341 switch (source->GetStatus().error()) {
342 case net::ERR_NETWORK_CHANGED:
343 error_code_ = GDATA_NO_CONNECTION;
344 break;
345 default:
346 error_code_ = GDATA_OTHER_ERROR;
350 // The server may return detailed error status in JSON.
351 // See https://developers.google.com/drive/handle-errors
352 if (!IsSuccessfulResponseCode(error_code_)) {
353 DVLOG(1) << response_writer_->data();
355 const char kErrorKey[] = "error";
356 const char kErrorErrorsKey[] = "errors";
357 const char kErrorReasonKey[] = "reason";
358 const char kErrorMessageKey[] = "message";
359 const char kErrorReasonRateLimitExceeded[] = "rateLimitExceeded";
360 const char kErrorReasonUserRateLimitExceeded[] = "userRateLimitExceeded";
361 const char kErrorReasonQuotaExceeded[] = "quotaExceeded";
363 scoped_ptr<base::Value> value(ParseJsonInternal(response_writer_->data()));
364 base::DictionaryValue* dictionary = NULL;
365 base::DictionaryValue* error = NULL;
366 if (value &&
367 value->GetAsDictionary(&dictionary) &&
368 dictionary->GetDictionaryWithoutPathExpansion(kErrorKey, &error)) {
369 // Get error message.
370 std::string message;
371 error->GetStringWithoutPathExpansion(kErrorMessageKey, &message);
372 DLOG(ERROR) << "code: " << error_code_ << ", message: " << message;
374 // Override the error code based on the reason of the first error.
375 base::ListValue* errors = NULL;
376 base::DictionaryValue* first_error = NULL;
377 if (error->GetListWithoutPathExpansion(kErrorErrorsKey, &errors) &&
378 errors->GetDictionary(0, &first_error)) {
379 std::string reason;
380 first_error->GetStringWithoutPathExpansion(kErrorReasonKey, &reason);
381 if (reason == kErrorReasonRateLimitExceeded ||
382 reason == kErrorReasonUserRateLimitExceeded)
383 error_code_ = HTTP_SERVICE_UNAVAILABLE;
384 if (reason == kErrorReasonQuotaExceeded)
385 error_code_ = GDATA_NO_SPACE;
390 // Handle authentication failure.
391 if (error_code_ == HTTP_UNAUTHORIZED) {
392 if (++re_authenticate_count_ <= kMaxReAuthenticateAttemptsPerRequest) {
393 // Reset re_authenticate_callback_ so Start() can be called again.
394 ReAuthenticateCallback callback = re_authenticate_callback_;
395 re_authenticate_callback_.Reset();
396 callback.Run(this);
397 return;
400 OnAuthFailed(error_code_);
401 return;
404 // Overridden by each specialization
405 ProcessURLFetchResults(source);
408 void UrlFetchRequestBase::OnAuthFailed(GDataErrorCode code) {
409 RunCallbackOnPrematureFailure(code);
410 sender_->RequestFinished(this);
413 base::WeakPtr<AuthenticatedRequestInterface>
414 UrlFetchRequestBase::GetWeakPtr() {
415 return weak_ptr_factory_.GetWeakPtr();
418 //============================ EntryActionRequest ============================
420 EntryActionRequest::EntryActionRequest(RequestSender* sender,
421 const EntryActionCallback& callback)
422 : UrlFetchRequestBase(sender),
423 callback_(callback) {
424 DCHECK(!callback_.is_null());
427 EntryActionRequest::~EntryActionRequest() {}
429 void EntryActionRequest::ProcessURLFetchResults(const URLFetcher* source) {
430 callback_.Run(GetErrorCode());
431 OnProcessURLFetchResultsComplete();
434 void EntryActionRequest::RunCallbackOnPrematureFailure(GDataErrorCode code) {
435 callback_.Run(code);
438 //============================== GetDataRequest ==============================
440 GetDataRequest::GetDataRequest(RequestSender* sender,
441 const GetDataCallback& callback)
442 : UrlFetchRequestBase(sender),
443 callback_(callback),
444 weak_ptr_factory_(this) {
445 DCHECK(!callback_.is_null());
448 GetDataRequest::~GetDataRequest() {}
450 void GetDataRequest::ParseResponse(GDataErrorCode fetch_error_code,
451 const std::string& data) {
452 DCHECK(CalledOnValidThread());
454 VLOG(1) << "JSON received from " << GetURL().spec() << ": "
455 << data.size() << " bytes";
456 ParseJson(blocking_task_runner(),
457 data,
458 base::Bind(&GetDataRequest::OnDataParsed,
459 weak_ptr_factory_.GetWeakPtr(),
460 fetch_error_code));
463 void GetDataRequest::ProcessURLFetchResults(const URLFetcher* source) {
464 GDataErrorCode fetch_error_code = GetErrorCode();
466 switch (fetch_error_code) {
467 case HTTP_SUCCESS:
468 case HTTP_CREATED:
469 ParseResponse(fetch_error_code, response_writer()->data());
470 break;
471 default:
472 RunCallbackOnPrematureFailure(fetch_error_code);
473 OnProcessURLFetchResultsComplete();
474 break;
478 void GetDataRequest::RunCallbackOnPrematureFailure(
479 GDataErrorCode fetch_error_code) {
480 callback_.Run(fetch_error_code, scoped_ptr<base::Value>());
483 void GetDataRequest::OnDataParsed(GDataErrorCode fetch_error_code,
484 scoped_ptr<base::Value> value) {
485 DCHECK(CalledOnValidThread());
487 if (!value.get())
488 fetch_error_code = GDATA_PARSE_ERROR;
490 callback_.Run(fetch_error_code, value.Pass());
491 OnProcessURLFetchResultsComplete();
494 //========================= InitiateUploadRequestBase ========================
496 InitiateUploadRequestBase::InitiateUploadRequestBase(
497 RequestSender* sender,
498 const InitiateUploadCallback& callback,
499 const std::string& content_type,
500 int64 content_length)
501 : UrlFetchRequestBase(sender),
502 callback_(callback),
503 content_type_(content_type),
504 content_length_(content_length) {
505 DCHECK(!callback_.is_null());
506 DCHECK(!content_type_.empty());
507 DCHECK_GE(content_length_, 0);
510 InitiateUploadRequestBase::~InitiateUploadRequestBase() {}
512 void InitiateUploadRequestBase::ProcessURLFetchResults(
513 const URLFetcher* source) {
514 GDataErrorCode code = GetErrorCode();
516 std::string upload_location;
517 if (code == HTTP_SUCCESS) {
518 // Retrieve value of the first "Location" header.
519 source->GetResponseHeaders()->EnumerateHeader(NULL,
520 kUploadResponseLocation,
521 &upload_location);
524 callback_.Run(code, GURL(upload_location));
525 OnProcessURLFetchResultsComplete();
528 void InitiateUploadRequestBase::RunCallbackOnPrematureFailure(
529 GDataErrorCode code) {
530 callback_.Run(code, GURL());
533 std::vector<std::string>
534 InitiateUploadRequestBase::GetExtraRequestHeaders() const {
535 std::vector<std::string> headers;
536 headers.push_back(kUploadContentType + content_type_);
537 headers.push_back(
538 kUploadContentLength + base::Int64ToString(content_length_));
539 return headers;
542 //============================ UploadRangeResponse =============================
544 UploadRangeResponse::UploadRangeResponse()
545 : code(HTTP_SUCCESS),
546 start_position_received(0),
547 end_position_received(0) {
550 UploadRangeResponse::UploadRangeResponse(GDataErrorCode code,
551 int64 start_position_received,
552 int64 end_position_received)
553 : code(code),
554 start_position_received(start_position_received),
555 end_position_received(end_position_received) {
558 UploadRangeResponse::~UploadRangeResponse() {
561 //========================== UploadRangeRequestBase ==========================
563 UploadRangeRequestBase::UploadRangeRequestBase(RequestSender* sender,
564 const GURL& upload_url)
565 : UrlFetchRequestBase(sender),
566 upload_url_(upload_url),
567 weak_ptr_factory_(this) {
570 UploadRangeRequestBase::~UploadRangeRequestBase() {}
572 GURL UploadRangeRequestBase::GetURL() const {
573 // This is very tricky to get json from this request. To do that, &alt=json
574 // has to be appended not here but in InitiateUploadRequestBase::GetURL().
575 return upload_url_;
578 URLFetcher::RequestType UploadRangeRequestBase::GetRequestType() const {
579 return URLFetcher::PUT;
582 void UploadRangeRequestBase::ProcessURLFetchResults(
583 const URLFetcher* source) {
584 GDataErrorCode code = GetErrorCode();
585 net::HttpResponseHeaders* hdrs = source->GetResponseHeaders();
587 if (code == HTTP_RESUME_INCOMPLETE) {
588 // Retrieve value of the first "Range" header.
589 // The Range header is appeared only if there is at least one received
590 // byte. So, initialize the positions by 0 so that the [0,0) will be
591 // returned via the |callback_| for empty data case.
592 int64 start_position_received = 0;
593 int64 end_position_received = 0;
594 std::string range_received;
595 hdrs->EnumerateHeader(NULL, kUploadResponseRange, &range_received);
596 if (!range_received.empty()) { // Parse the range header.
597 std::vector<net::HttpByteRange> ranges;
598 if (net::HttpUtil::ParseRangeHeader(range_received, &ranges) &&
599 !ranges.empty() ) {
600 // We only care about the first start-end pair in the range.
602 // Range header represents the range inclusively, while we are treating
603 // ranges exclusively (i.e., end_position_received should be one passed
604 // the last valid index). So "+ 1" is added.
605 start_position_received = ranges[0].first_byte_position();
606 end_position_received = ranges[0].last_byte_position() + 1;
609 // The Range header has the received data range, so the start position
610 // should be always 0.
611 DCHECK_EQ(start_position_received, 0);
613 OnRangeRequestComplete(UploadRangeResponse(code,
614 start_position_received,
615 end_position_received),
616 scoped_ptr<base::Value>());
618 OnProcessURLFetchResultsComplete();
619 } else if (code == HTTP_CREATED || code == HTTP_SUCCESS) {
620 // The upload is successfully done. Parse the response which should be
621 // the entry's metadata.
622 ParseJson(blocking_task_runner(),
623 response_writer()->data(),
624 base::Bind(&UploadRangeRequestBase::OnDataParsed,
625 weak_ptr_factory_.GetWeakPtr(),
626 code));
627 } else {
628 // Failed to upload. Run callbacks to notify the error.
629 OnRangeRequestComplete(
630 UploadRangeResponse(code, -1, -1), scoped_ptr<base::Value>());
631 OnProcessURLFetchResultsComplete();
635 void UploadRangeRequestBase::OnDataParsed(GDataErrorCode code,
636 scoped_ptr<base::Value> value) {
637 DCHECK(CalledOnValidThread());
638 DCHECK(code == HTTP_CREATED || code == HTTP_SUCCESS);
640 OnRangeRequestComplete(UploadRangeResponse(code, -1, -1), value.Pass());
641 OnProcessURLFetchResultsComplete();
644 void UploadRangeRequestBase::RunCallbackOnPrematureFailure(
645 GDataErrorCode code) {
646 OnRangeRequestComplete(
647 UploadRangeResponse(code, 0, 0), scoped_ptr<base::Value>());
650 //========================== ResumeUploadRequestBase =========================
652 ResumeUploadRequestBase::ResumeUploadRequestBase(
653 RequestSender* sender,
654 const GURL& upload_location,
655 int64 start_position,
656 int64 end_position,
657 int64 content_length,
658 const std::string& content_type,
659 const base::FilePath& local_file_path)
660 : UploadRangeRequestBase(sender, upload_location),
661 start_position_(start_position),
662 end_position_(end_position),
663 content_length_(content_length),
664 content_type_(content_type),
665 local_file_path_(local_file_path) {
666 DCHECK_LE(start_position_, end_position_);
669 ResumeUploadRequestBase::~ResumeUploadRequestBase() {}
671 std::vector<std::string>
672 ResumeUploadRequestBase::GetExtraRequestHeaders() const {
673 if (content_length_ == 0) {
674 // For uploading an empty document, just PUT an empty content.
675 DCHECK_EQ(start_position_, 0);
676 DCHECK_EQ(end_position_, 0);
677 return std::vector<std::string>();
680 // The header looks like
681 // Content-Range: bytes <start_position>-<end_position>/<content_length>
682 // for example:
683 // Content-Range: bytes 7864320-8388607/13851821
684 // The header takes inclusive range, so we adjust by "end_position - 1".
685 DCHECK_GE(start_position_, 0);
686 DCHECK_GT(end_position_, 0);
687 DCHECK_GE(content_length_, 0);
689 std::vector<std::string> headers;
690 headers.push_back(
691 std::string(kUploadContentRange) +
692 base::Int64ToString(start_position_) + "-" +
693 base::Int64ToString(end_position_ - 1) + "/" +
694 base::Int64ToString(content_length_));
695 return headers;
698 bool ResumeUploadRequestBase::GetContentFile(
699 base::FilePath* local_file_path,
700 int64* range_offset,
701 int64* range_length,
702 std::string* upload_content_type) {
703 if (start_position_ == end_position_) {
704 // No content data.
705 return false;
708 *local_file_path = local_file_path_;
709 *range_offset = start_position_;
710 *range_length = end_position_ - start_position_;
711 *upload_content_type = content_type_;
712 return true;
715 //======================== GetUploadStatusRequestBase ========================
717 GetUploadStatusRequestBase::GetUploadStatusRequestBase(RequestSender* sender,
718 const GURL& upload_url,
719 int64 content_length)
720 : UploadRangeRequestBase(sender, upload_url),
721 content_length_(content_length) {}
723 GetUploadStatusRequestBase::~GetUploadStatusRequestBase() {}
725 std::vector<std::string>
726 GetUploadStatusRequestBase::GetExtraRequestHeaders() const {
727 // The header looks like
728 // Content-Range: bytes */<content_length>
729 // for example:
730 // Content-Range: bytes */13851821
731 DCHECK_GE(content_length_, 0);
733 std::vector<std::string> headers;
734 headers.push_back(
735 std::string(kUploadContentRange) + "*/" +
736 base::Int64ToString(content_length_));
737 return headers;
740 //============================ DownloadFileRequestBase =========================
742 DownloadFileRequestBase::DownloadFileRequestBase(
743 RequestSender* sender,
744 const DownloadActionCallback& download_action_callback,
745 const GetContentCallback& get_content_callback,
746 const ProgressCallback& progress_callback,
747 const GURL& download_url,
748 const base::FilePath& output_file_path)
749 : UrlFetchRequestBase(sender),
750 download_action_callback_(download_action_callback),
751 get_content_callback_(get_content_callback),
752 progress_callback_(progress_callback),
753 download_url_(download_url),
754 output_file_path_(output_file_path) {
755 DCHECK(!download_action_callback_.is_null());
756 DCHECK(!output_file_path_.empty());
757 // get_content_callback may be null.
760 DownloadFileRequestBase::~DownloadFileRequestBase() {}
762 // Overridden from UrlFetchRequestBase.
763 GURL DownloadFileRequestBase::GetURL() const {
764 return download_url_;
767 void DownloadFileRequestBase::GetOutputFilePath(
768 base::FilePath* local_file_path,
769 GetContentCallback* get_content_callback) {
770 // Configure so that the downloaded content is saved to |output_file_path_|.
771 *local_file_path = output_file_path_;
772 *get_content_callback = get_content_callback_;
775 void DownloadFileRequestBase::OnURLFetchDownloadProgress(
776 const URLFetcher* source,
777 int64 current,
778 int64 total) {
779 if (!progress_callback_.is_null())
780 progress_callback_.Run(current, total);
783 void DownloadFileRequestBase::ProcessURLFetchResults(const URLFetcher* source) {
784 GDataErrorCode code = GetErrorCode();
786 // Take over the ownership of the the downloaded temp file.
787 base::FilePath temp_file;
788 if (code == HTTP_SUCCESS) {
789 response_writer()->DisownFile();
790 temp_file = output_file_path_;
793 download_action_callback_.Run(code, temp_file);
794 OnProcessURLFetchResultsComplete();
797 void DownloadFileRequestBase::RunCallbackOnPrematureFailure(
798 GDataErrorCode code) {
799 download_action_callback_.Run(code, base::FilePath());
802 } // namespace google_apis