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.
4
5#include "google_apis/drive/base_requests.h"
6
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"
24
25using net::URLFetcher;
26
27namespace {
28
29// Template for optional OAuth2 authorization HTTP header.
30const char kAuthorizationHeaderFormat[] = "Authorization: Bearer %s";
31// Template for GData API version HTTP header.
32const char kGDataVersionHeader[] = "GData-Version: 3.0";
33
34// Maximum number of attempts for re-authentication per request.
35const int kMaxReAuthenticateAttemptsPerRequest = 1;
36
37// Template for initiate upload of both GData WAPI and Drive API v2.
38const char kUploadContentType[] = "X-Upload-Content-Type: ";
39const char kUploadContentLength[] = "X-Upload-Content-Length: ";
40const char kUploadResponseLocation[] = "location";
41
42// Template for upload data range of both GData WAPI and Drive API v2.
43const char kUploadContentRange[] = "Content-Range: bytes ";
44const char kUploadResponseRange[] = "range";
45
46// Parse JSON string to base::Value object.
47scoped_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));
52
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());
64    }
65    LOG(WARNING) << "Error while parsing entry response: " << error_message
66                 << ", code: " << error_code << ", json:\n" << trimmed_json;
67  }
68  return value.Pass();
69}
70
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.
73std::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);
87  }
88  return headers;
89}
90
91bool IsSuccessfulResponseCode(int response_code) {
92  return 200 <= response_code && response_code <= 299;
93}
94
95}  // namespace
96
97namespace google_apis {
98
99void 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);
107}
108
109//=========================== ResponseWriter ==================================
110ResponseWriter::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));
118  }
119}
120
121ResponseWriter::~ResponseWriter() {
122}
123
124void ResponseWriter::DisownFile() {
125  DCHECK(file_writer_);
126  file_writer_->DisownFile();
127}
128
129int ResponseWriter::Initialize(const net::CompletionCallback& callback) {
130  if (file_writer_)
131    return file_writer_->Initialize(callback);
132
133  data_.clear();
134  return net::OK;
135}
136
137int 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)));
144  }
145
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;
155  }
156
157  data_.append(buffer->data(), num_bytes);
158  return num_bytes;
159}
160
161int ResponseWriter::Finish(const net::CompletionCallback& callback) {
162  if (file_writer_)
163    return file_writer_->Finish(callback);
164
165  return net::OK;
166}
167
168void 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()));
179    }
180  }
181
182  if (!callback.is_null())
183    callback.Run(result);
184}
185
186//============================ UrlFetchRequestBase ===========================
187
188UrlFetchRequestBase::UrlFetchRequestBase(RequestSender* sender)
189    : re_authenticate_count_(0),
190      sender_(sender),
191      error_code_(GDATA_OTHER_ERROR),
192      weak_ptr_factory_(this) {
193}
194
195UrlFetchRequestBase::~UrlFetchRequestBase() {}
196
197void 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());
204
205  re_authenticate_callback_ = callback;
206
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;
214  }
215  DVLOG(1) << "URL: " << url.spec();
216
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);
225
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_));
236
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];
250  }
251
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());
280      }
281    }
282  }
283
284  url_fetcher_->Start();
285}
286
287URLFetcher::RequestType UrlFetchRequestBase::GetRequestType() const {
288  return URLFetcher::GET;
289}
290
291std::vector<std::string> UrlFetchRequestBase::GetExtraRequestHeaders() const {
292  return std::vector<std::string>();
293}
294
295bool UrlFetchRequestBase::GetContentData(std::string* upload_content_type,
296                                         std::string* upload_content) {
297  return false;
298}
299
300bool UrlFetchRequestBase::GetContentFile(base::FilePath* local_file_path,
301                                         int64* range_offset,
302                                         int64* range_length,
303                                         std::string* upload_content_type) {
304  return false;
305}
306
307void UrlFetchRequestBase::GetOutputFilePath(
308    base::FilePath* local_file_path,
309    GetContentCallback* get_content_callback) {
310}
311
312void UrlFetchRequestBase::Cancel() {
313  response_writer_ = NULL;
314  url_fetcher_.reset(NULL);
315  RunCallbackOnPrematureFailure(GDATA_CANCELLED);
316  sender_->RequestFinished(this);
317}
318
319GDataErrorCode UrlFetchRequestBase::GetErrorCode() {
320  return error_code_;
321}
322
323bool UrlFetchRequestBase::CalledOnValidThread() {
324  return thread_checker_.CalledOnValidThread();
325}
326
327base::SequencedTaskRunner* UrlFetchRequestBase::blocking_task_runner() const {
328  return sender_->blocking_task_runner();
329}
330
331void UrlFetchRequestBase::OnProcessURLFetchResultsComplete() {
332  sender_->RequestFinished(this);
333}
334
335void UrlFetchRequestBase::OnURLFetchComplete(const URLFetcher* source) {
336  DVLOG(1) << "Response headers:\n" << GetResponseHeadersAsString(source);
337
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;
347    }
348  }
349
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();
354
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
362    scoped_ptr<base::Value> value(ParseJsonInternal(response_writer_->data()));
363    base::DictionaryValue* dictionary = NULL;
364    base::DictionaryValue* error = NULL;
365    if (value &&
366        value->GetAsDictionary(&dictionary) &&
367        dictionary->GetDictionaryWithoutPathExpansion(kErrorKey, &error)) {
368      // Get error message.
369      std::string message;
370      error->GetStringWithoutPathExpansion(kErrorMessageKey, &message);
371      DLOG(ERROR) << "code: " << error_code_ << ", message: " << message;
372
373      // Override the error code based on the reason of the first error.
374      base::ListValue* errors = NULL;
375      base::DictionaryValue* first_error = NULL;
376      if (error->GetListWithoutPathExpansion(kErrorErrorsKey, &errors) &&
377          errors->GetDictionary(0, &first_error)) {
378        std::string reason;
379        first_error->GetStringWithoutPathExpansion(kErrorReasonKey, &reason);
380        if (reason == kErrorReasonRateLimitExceeded ||
381            reason == kErrorReasonUserRateLimitExceeded)
382          error_code_ = HTTP_SERVICE_UNAVAILABLE;
383      }
384    }
385  }
386
387  // Handle authentication failure.
388  if (error_code_ == HTTP_UNAUTHORIZED) {
389    if (++re_authenticate_count_ <= kMaxReAuthenticateAttemptsPerRequest) {
390      // Reset re_authenticate_callback_ so Start() can be called again.
391      ReAuthenticateCallback callback = re_authenticate_callback_;
392      re_authenticate_callback_.Reset();
393      callback.Run(this);
394      return;
395    }
396
397    OnAuthFailed(error_code_);
398    return;
399  }
400
401  // Overridden by each specialization
402  ProcessURLFetchResults(source);
403}
404
405void UrlFetchRequestBase::OnAuthFailed(GDataErrorCode code) {
406  RunCallbackOnPrematureFailure(code);
407  sender_->RequestFinished(this);
408}
409
410base::WeakPtr<AuthenticatedRequestInterface>
411UrlFetchRequestBase::GetWeakPtr() {
412  return weak_ptr_factory_.GetWeakPtr();
413}
414
415//============================ EntryActionRequest ============================
416
417EntryActionRequest::EntryActionRequest(RequestSender* sender,
418                                       const EntryActionCallback& callback)
419    : UrlFetchRequestBase(sender),
420      callback_(callback) {
421  DCHECK(!callback_.is_null());
422}
423
424EntryActionRequest::~EntryActionRequest() {}
425
426void EntryActionRequest::ProcessURLFetchResults(const URLFetcher* source) {
427  callback_.Run(GetErrorCode());
428  OnProcessURLFetchResultsComplete();
429}
430
431void EntryActionRequest::RunCallbackOnPrematureFailure(GDataErrorCode code) {
432  callback_.Run(code);
433}
434
435//============================== GetDataRequest ==============================
436
437GetDataRequest::GetDataRequest(RequestSender* sender,
438                               const GetDataCallback& callback)
439    : UrlFetchRequestBase(sender),
440      callback_(callback),
441      weak_ptr_factory_(this) {
442  DCHECK(!callback_.is_null());
443}
444
445GetDataRequest::~GetDataRequest() {}
446
447void GetDataRequest::ParseResponse(GDataErrorCode fetch_error_code,
448                                   const std::string& data) {
449  DCHECK(CalledOnValidThread());
450
451  VLOG(1) << "JSON received from " << GetURL().spec() << ": "
452          << data.size() << " bytes";
453  ParseJson(blocking_task_runner(),
454            data,
455            base::Bind(&GetDataRequest::OnDataParsed,
456                       weak_ptr_factory_.GetWeakPtr(),
457                       fetch_error_code));
458}
459
460void GetDataRequest::ProcessURLFetchResults(const URLFetcher* source) {
461  GDataErrorCode fetch_error_code = GetErrorCode();
462
463  switch (fetch_error_code) {
464    case HTTP_SUCCESS:
465    case HTTP_CREATED:
466      ParseResponse(fetch_error_code, response_writer()->data());
467      break;
468    default:
469      RunCallbackOnPrematureFailure(fetch_error_code);
470      OnProcessURLFetchResultsComplete();
471      break;
472  }
473}
474
475void GetDataRequest::RunCallbackOnPrematureFailure(
476    GDataErrorCode fetch_error_code) {
477  callback_.Run(fetch_error_code, scoped_ptr<base::Value>());
478}
479
480void GetDataRequest::OnDataParsed(GDataErrorCode fetch_error_code,
481                                  scoped_ptr<base::Value> value) {
482  DCHECK(CalledOnValidThread());
483
484  if (!value.get())
485    fetch_error_code = GDATA_PARSE_ERROR;
486
487  callback_.Run(fetch_error_code, value.Pass());
488  OnProcessURLFetchResultsComplete();
489}
490
491//========================= InitiateUploadRequestBase ========================
492
493InitiateUploadRequestBase::InitiateUploadRequestBase(
494    RequestSender* sender,
495    const InitiateUploadCallback& callback,
496    const std::string& content_type,
497    int64 content_length)
498    : UrlFetchRequestBase(sender),
499      callback_(callback),
500      content_type_(content_type),
501      content_length_(content_length) {
502  DCHECK(!callback_.is_null());
503  DCHECK(!content_type_.empty());
504  DCHECK_GE(content_length_, 0);
505}
506
507InitiateUploadRequestBase::~InitiateUploadRequestBase() {}
508
509void InitiateUploadRequestBase::ProcessURLFetchResults(
510    const URLFetcher* source) {
511  GDataErrorCode code = GetErrorCode();
512
513  std::string upload_location;
514  if (code == HTTP_SUCCESS) {
515    // Retrieve value of the first "Location" header.
516    source->GetResponseHeaders()->EnumerateHeader(NULL,
517                                                  kUploadResponseLocation,
518                                                  &upload_location);
519  }
520
521  callback_.Run(code, GURL(upload_location));
522  OnProcessURLFetchResultsComplete();
523}
524
525void InitiateUploadRequestBase::RunCallbackOnPrematureFailure(
526    GDataErrorCode code) {
527  callback_.Run(code, GURL());
528}
529
530std::vector<std::string>
531InitiateUploadRequestBase::GetExtraRequestHeaders() const {
532  std::vector<std::string> headers;
533  headers.push_back(kUploadContentType + content_type_);
534  headers.push_back(
535      kUploadContentLength + base::Int64ToString(content_length_));
536  return headers;
537}
538
539//============================ UploadRangeResponse =============================
540
541UploadRangeResponse::UploadRangeResponse()
542    : code(HTTP_SUCCESS),
543      start_position_received(0),
544      end_position_received(0) {
545}
546
547UploadRangeResponse::UploadRangeResponse(GDataErrorCode code,
548                                         int64 start_position_received,
549                                         int64 end_position_received)
550    : code(code),
551      start_position_received(start_position_received),
552      end_position_received(end_position_received) {
553}
554
555UploadRangeResponse::~UploadRangeResponse() {
556}
557
558//========================== UploadRangeRequestBase ==========================
559
560UploadRangeRequestBase::UploadRangeRequestBase(RequestSender* sender,
561                                               const GURL& upload_url)
562    : UrlFetchRequestBase(sender),
563      upload_url_(upload_url),
564      weak_ptr_factory_(this) {
565}
566
567UploadRangeRequestBase::~UploadRangeRequestBase() {}
568
569GURL UploadRangeRequestBase::GetURL() const {
570  // This is very tricky to get json from this request. To do that, &alt=json
571  // has to be appended not here but in InitiateUploadRequestBase::GetURL().
572  return upload_url_;
573}
574
575URLFetcher::RequestType UploadRangeRequestBase::GetRequestType() const {
576  return URLFetcher::PUT;
577}
578
579void UploadRangeRequestBase::ProcessURLFetchResults(
580    const URLFetcher* source) {
581  GDataErrorCode code = GetErrorCode();
582  net::HttpResponseHeaders* hdrs = source->GetResponseHeaders();
583
584  if (code == HTTP_RESUME_INCOMPLETE) {
585    // Retrieve value of the first "Range" header.
586    // The Range header is appeared only if there is at least one received
587    // byte. So, initialize the positions by 0 so that the [0,0) will be
588    // returned via the |callback_| for empty data case.
589    int64 start_position_received = 0;
590    int64 end_position_received = 0;
591    std::string range_received;
592    hdrs->EnumerateHeader(NULL, kUploadResponseRange, &range_received);
593    if (!range_received.empty()) {  // Parse the range header.
594      std::vector<net::HttpByteRange> ranges;
595      if (net::HttpUtil::ParseRangeHeader(range_received, &ranges) &&
596          !ranges.empty() ) {
597        // We only care about the first start-end pair in the range.
598        //
599        // Range header represents the range inclusively, while we are treating
600        // ranges exclusively (i.e., end_position_received should be one passed
601        // the last valid index). So "+ 1" is added.
602        start_position_received = ranges[0].first_byte_position();
603        end_position_received = ranges[0].last_byte_position() + 1;
604      }
605    }
606    // The Range header has the received data range, so the start position
607    // should be always 0.
608    DCHECK_EQ(start_position_received, 0);
609
610    OnRangeRequestComplete(UploadRangeResponse(code,
611                                               start_position_received,
612                                               end_position_received),
613                           scoped_ptr<base::Value>());
614
615    OnProcessURLFetchResultsComplete();
616  } else if (code == HTTP_CREATED || code == HTTP_SUCCESS) {
617    // The upload is successfully done. Parse the response which should be
618    // the entry's metadata.
619    ParseJson(blocking_task_runner(),
620              response_writer()->data(),
621              base::Bind(&UploadRangeRequestBase::OnDataParsed,
622                         weak_ptr_factory_.GetWeakPtr(),
623                         code));
624  } else {
625    // Failed to upload. Run callbacks to notify the error.
626    OnRangeRequestComplete(
627        UploadRangeResponse(code, -1, -1), scoped_ptr<base::Value>());
628    OnProcessURLFetchResultsComplete();
629  }
630}
631
632void UploadRangeRequestBase::OnDataParsed(GDataErrorCode code,
633                                          scoped_ptr<base::Value> value) {
634  DCHECK(CalledOnValidThread());
635  DCHECK(code == HTTP_CREATED || code == HTTP_SUCCESS);
636
637  OnRangeRequestComplete(UploadRangeResponse(code, -1, -1), value.Pass());
638  OnProcessURLFetchResultsComplete();
639}
640
641void UploadRangeRequestBase::RunCallbackOnPrematureFailure(
642    GDataErrorCode code) {
643  OnRangeRequestComplete(
644      UploadRangeResponse(code, 0, 0), scoped_ptr<base::Value>());
645}
646
647//========================== ResumeUploadRequestBase =========================
648
649ResumeUploadRequestBase::ResumeUploadRequestBase(
650    RequestSender* sender,
651    const GURL& upload_location,
652    int64 start_position,
653    int64 end_position,
654    int64 content_length,
655    const std::string& content_type,
656    const base::FilePath& local_file_path)
657    : UploadRangeRequestBase(sender, upload_location),
658      start_position_(start_position),
659      end_position_(end_position),
660      content_length_(content_length),
661      content_type_(content_type),
662      local_file_path_(local_file_path) {
663  DCHECK_LE(start_position_, end_position_);
664}
665
666ResumeUploadRequestBase::~ResumeUploadRequestBase() {}
667
668std::vector<std::string>
669ResumeUploadRequestBase::GetExtraRequestHeaders() const {
670  if (content_length_ == 0) {
671    // For uploading an empty document, just PUT an empty content.
672    DCHECK_EQ(start_position_, 0);
673    DCHECK_EQ(end_position_, 0);
674    return std::vector<std::string>();
675  }
676
677  // The header looks like
678  // Content-Range: bytes <start_position>-<end_position>/<content_length>
679  // for example:
680  // Content-Range: bytes 7864320-8388607/13851821
681  // The header takes inclusive range, so we adjust by "end_position - 1".
682  DCHECK_GE(start_position_, 0);
683  DCHECK_GT(end_position_, 0);
684  DCHECK_GE(content_length_, 0);
685
686  std::vector<std::string> headers;
687  headers.push_back(
688      std::string(kUploadContentRange) +
689      base::Int64ToString(start_position_) + "-" +
690      base::Int64ToString(end_position_ - 1) + "/" +
691      base::Int64ToString(content_length_));
692  return headers;
693}
694
695bool ResumeUploadRequestBase::GetContentFile(
696    base::FilePath* local_file_path,
697    int64* range_offset,
698    int64* range_length,
699    std::string* upload_content_type) {
700  if (start_position_ == end_position_) {
701    // No content data.
702    return false;
703  }
704
705  *local_file_path = local_file_path_;
706  *range_offset = start_position_;
707  *range_length = end_position_ - start_position_;
708  *upload_content_type = content_type_;
709  return true;
710}
711
712//======================== GetUploadStatusRequestBase ========================
713
714GetUploadStatusRequestBase::GetUploadStatusRequestBase(RequestSender* sender,
715                                                       const GURL& upload_url,
716                                                       int64 content_length)
717    : UploadRangeRequestBase(sender, upload_url),
718      content_length_(content_length) {}
719
720GetUploadStatusRequestBase::~GetUploadStatusRequestBase() {}
721
722std::vector<std::string>
723GetUploadStatusRequestBase::GetExtraRequestHeaders() const {
724  // The header looks like
725  // Content-Range: bytes */<content_length>
726  // for example:
727  // Content-Range: bytes */13851821
728  DCHECK_GE(content_length_, 0);
729
730  std::vector<std::string> headers;
731  headers.push_back(
732      std::string(kUploadContentRange) + "*/" +
733      base::Int64ToString(content_length_));
734  return headers;
735}
736
737//============================ DownloadFileRequestBase =========================
738
739DownloadFileRequestBase::DownloadFileRequestBase(
740    RequestSender* sender,
741    const DownloadActionCallback& download_action_callback,
742    const GetContentCallback& get_content_callback,
743    const ProgressCallback& progress_callback,
744    const GURL& download_url,
745    const base::FilePath& output_file_path)
746    : UrlFetchRequestBase(sender),
747      download_action_callback_(download_action_callback),
748      get_content_callback_(get_content_callback),
749      progress_callback_(progress_callback),
750      download_url_(download_url),
751      output_file_path_(output_file_path) {
752  DCHECK(!download_action_callback_.is_null());
753  DCHECK(!output_file_path_.empty());
754  // get_content_callback may be null.
755}
756
757DownloadFileRequestBase::~DownloadFileRequestBase() {}
758
759// Overridden from UrlFetchRequestBase.
760GURL DownloadFileRequestBase::GetURL() const {
761  return download_url_;
762}
763
764void DownloadFileRequestBase::GetOutputFilePath(
765    base::FilePath* local_file_path,
766    GetContentCallback* get_content_callback) {
767  // Configure so that the downloaded content is saved to |output_file_path_|.
768  *local_file_path = output_file_path_;
769  *get_content_callback = get_content_callback_;
770}
771
772void DownloadFileRequestBase::OnURLFetchDownloadProgress(
773    const URLFetcher* source,
774    int64 current,
775    int64 total) {
776  if (!progress_callback_.is_null())
777    progress_callback_.Run(current, total);
778}
779
780void DownloadFileRequestBase::ProcessURLFetchResults(const URLFetcher* source) {
781  GDataErrorCode code = GetErrorCode();
782
783  // Take over the ownership of the the downloaded temp file.
784  base::FilePath temp_file;
785  if (code == HTTP_SUCCESS) {
786    response_writer()->DisownFile();
787    temp_file = output_file_path_;
788  }
789
790  download_action_callback_.Run(code, temp_file);
791  OnProcessURLFetchResultsComplete();
792}
793
794void DownloadFileRequestBase::RunCallbackOnPrematureFailure(
795    GDataErrorCode code) {
796  download_action_callback_.Run(code, base::FilePath());
797}
798
799}  // namespace google_apis
800