Home | History | Annotate | Download | only in drive
      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 
     25 using net::URLFetcher;
     26 
     27 namespace {
     28 
     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";
     33 
     34 // Maximum number of attempts for re-authentication per request.
     35 const int kMaxReAuthenticateAttemptsPerRequest = 1;
     36 
     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";
     41 
     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";
     45 
     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);
     58 }
     59 
     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);
     75   }
     76   return headers;
     77 }
     78 
     79 bool IsSuccessfulResponseCode(int response_code) {
     80   return 200 <= response_code && response_code <= 299;
     81 }
     82 
     83 }  // namespace
     84 
     85 namespace google_apis {
     86 
     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));
     92 
     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());
    104     }
    105     LOG(WARNING) << "Error while parsing entry response: " << error_message
    106                  << ", code: " << error_code << ", json:\n" << trimmed_json;
    107   }
    108   return value.Pass();
    109 }
    110 
    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));
    120   }
    121 }
    122 
    123 ResponseWriter::~ResponseWriter() {
    124 }
    125 
    126 void ResponseWriter::DisownFile() {
    127   DCHECK(file_writer_);
    128   file_writer_->DisownFile();
    129 }
    130 
    131 int ResponseWriter::Initialize(const net::CompletionCallback& callback) {
    132   if (file_writer_)
    133     return file_writer_->Initialize(callback);
    134 
    135   data_.clear();
    136   return net::OK;
    137 }
    138 
    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)));
    146   }
    147 
    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;
    157   }
    158 
    159   data_.append(buffer->data(), num_bytes);
    160   return num_bytes;
    161 }
    162 
    163 int ResponseWriter::Finish(const net::CompletionCallback& callback) {
    164   if (file_writer_)
    165     return file_writer_->Finish(callback);
    166 
    167   return net::OK;
    168 }
    169 
    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()));
    181     }
    182   }
    183 
    184   if (!callback.is_null())
    185     callback.Run(result);
    186 }
    187 
    188 //============================ UrlFetchRequestBase ===========================
    189 
    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) {
    196 }
    197 
    198 UrlFetchRequestBase::~UrlFetchRequestBase() {}
    199 
    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());
    207 
    208   re_authenticate_callback_ = callback;
    209 
    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;
    217   }
    218   DVLOG(1) << "URL: " << url.spec();
    219 
    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);
    227 
    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_));
    238 
    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];
    252   }
    253 
    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());
    282       }
    283     }
    284   }
    285 
    286   url_fetcher_->Start();
    287 }
    288 
    289 URLFetcher::RequestType UrlFetchRequestBase::GetRequestType() const {
    290   return URLFetcher::GET;
    291 }
    292 
    293 std::vector<std::string> UrlFetchRequestBase::GetExtraRequestHeaders() const {
    294   return std::vector<std::string>();
    295 }
    296 
    297 bool UrlFetchRequestBase::GetContentData(std::string* upload_content_type,
    298                                          std::string* upload_content) {
    299   return false;
    300 }
    301 
    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;
    307 }
    308 
    309 void UrlFetchRequestBase::GetOutputFilePath(
    310     base::FilePath* local_file_path,
    311     GetContentCallback* get_content_callback) {
    312 }
    313 
    314 void UrlFetchRequestBase::Cancel() {
    315   response_writer_ = NULL;
    316   url_fetcher_.reset(NULL);
    317   RunCallbackOnPrematureFailure(GDATA_CANCELLED);
    318   sender_->RequestFinished(this);
    319 }
    320 
    321 GDataErrorCode UrlFetchRequestBase::GetErrorCode() {
    322   return error_code_;
    323 }
    324 
    325 bool UrlFetchRequestBase::CalledOnValidThread() {
    326   return thread_checker_.CalledOnValidThread();
    327 }
    328 
    329 base::SequencedTaskRunner* UrlFetchRequestBase::blocking_task_runner() const {
    330   return sender_->blocking_task_runner();
    331 }
    332 
    333 void UrlFetchRequestBase::OnProcessURLFetchResultsComplete() {
    334   sender_->RequestFinished(this);
    335 }
    336 
    337 void UrlFetchRequestBase::OnURLFetchComplete(const URLFetcher* source) {
    338   DVLOG(1) << "Response headers:\n" << GetResponseHeadersAsString(source);
    339 
    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;
    349     }
    350   }
    351 
    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();
    356 
    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";
    364 
    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;
    375 
    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;
    388       }
    389     }
    390   }
    391 
    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;
    400     }
    401 
    402     OnAuthFailed(error_code_);
    403     return;
    404   }
    405 
    406   // Overridden by each specialization
    407   ProcessURLFetchResults(source);
    408 }
    409 
    410 void UrlFetchRequestBase::OnAuthFailed(GDataErrorCode code) {
    411   RunCallbackOnPrematureFailure(code);
    412   sender_->RequestFinished(this);
    413 }
    414 
    415 base::WeakPtr<AuthenticatedRequestInterface>
    416 UrlFetchRequestBase::GetWeakPtr() {
    417   return weak_ptr_factory_.GetWeakPtr();
    418 }
    419 
    420 //============================ EntryActionRequest ============================
    421 
    422 EntryActionRequest::EntryActionRequest(RequestSender* sender,
    423                                        const EntryActionCallback& callback)
    424     : UrlFetchRequestBase(sender),
    425       callback_(callback) {
    426   DCHECK(!callback_.is_null());
    427 }
    428 
    429 EntryActionRequest::~EntryActionRequest() {}
    430 
    431 void EntryActionRequest::ProcessURLFetchResults(const URLFetcher* source) {
    432   callback_.Run(GetErrorCode());
    433   OnProcessURLFetchResultsComplete();
    434 }
    435 
    436 void EntryActionRequest::RunCallbackOnPrematureFailure(GDataErrorCode code) {
    437   callback_.Run(code);
    438 }
    439 
    440 //========================= InitiateUploadRequestBase ========================
    441 
    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);
    454 }
    455 
    456 InitiateUploadRequestBase::~InitiateUploadRequestBase() {}
    457 
    458 void InitiateUploadRequestBase::ProcessURLFetchResults(
    459     const URLFetcher* source) {
    460   GDataErrorCode code = GetErrorCode();
    461 
    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);
    468   }
    469 
    470   callback_.Run(code, GURL(upload_location));
    471   OnProcessURLFetchResultsComplete();
    472 }
    473 
    474 void InitiateUploadRequestBase::RunCallbackOnPrematureFailure(
    475     GDataErrorCode code) {
    476   callback_.Run(code, GURL());
    477 }
    478 
    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;
    486 }
    487 
    488 //============================ UploadRangeResponse =============================
    489 
    490 UploadRangeResponse::UploadRangeResponse()
    491     : code(HTTP_SUCCESS),
    492       start_position_received(0),
    493       end_position_received(0) {
    494 }
    495 
    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) {
    502 }
    503 
    504 UploadRangeResponse::~UploadRangeResponse() {
    505 }
    506 
    507 //========================== UploadRangeRequestBase ==========================
    508 
    509 UploadRangeRequestBase::UploadRangeRequestBase(RequestSender* sender,
    510                                                const GURL& upload_url)
    511     : UrlFetchRequestBase(sender),
    512       upload_url_(upload_url),
    513       weak_ptr_factory_(this) {
    514 }
    515 
    516 UploadRangeRequestBase::~UploadRangeRequestBase() {}
    517 
    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_;
    522 }
    523 
    524 URLFetcher::RequestType UploadRangeRequestBase::GetRequestType() const {
    525   return URLFetcher::PUT;
    526 }
    527 
    528 void UploadRangeRequestBase::ProcessURLFetchResults(
    529     const URLFetcher* source) {
    530   GDataErrorCode code = GetErrorCode();
    531   net::HttpResponseHeaders* hdrs = source->GetResponseHeaders();
    532 
    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.
    547         //
    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;
    553       }
    554     }
    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);
    558 
    559     OnRangeRequestComplete(UploadRangeResponse(code,
    560                                                start_position_received,
    561                                                end_position_received),
    562                            scoped_ptr<base::Value>());
    563 
    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();
    578   }
    579 }
    580 
    581 void UploadRangeRequestBase::OnDataParsed(GDataErrorCode code,
    582                                           scoped_ptr<base::Value> value) {
    583   DCHECK(CalledOnValidThread());
    584   DCHECK(code == HTTP_CREATED || code == HTTP_SUCCESS);
    585 
    586   OnRangeRequestComplete(UploadRangeResponse(code, -1, -1), value.Pass());
    587   OnProcessURLFetchResultsComplete();
    588 }
    589 
    590 void UploadRangeRequestBase::RunCallbackOnPrematureFailure(
    591     GDataErrorCode code) {
    592   OnRangeRequestComplete(
    593       UploadRangeResponse(code, 0, 0), scoped_ptr<base::Value>());
    594 }
    595 
    596 //========================== ResumeUploadRequestBase =========================
    597 
    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_);
    613 }
    614 
    615 ResumeUploadRequestBase::~ResumeUploadRequestBase() {}
    616 
    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>();
    624   }
    625 
    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);
    634 
    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;
    642 }
    643 
    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;
    652   }
    653 
    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;
    659 }
    660 
    661 //======================== GetUploadStatusRequestBase ========================
    662 
    663 GetUploadStatusRequestBase::GetUploadStatusRequestBase(RequestSender* sender,
    664                                                        const GURL& upload_url,
    665                                                        int64 content_length)
    666     : UploadRangeRequestBase(sender, upload_url),
    667       content_length_(content_length) {}
    668 
    669 GetUploadStatusRequestBase::~GetUploadStatusRequestBase() {}
    670 
    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);
    678 
    679   std::vector<std::string> headers;
    680   headers.push_back(
    681       std::string(kUploadContentRange) + "*/" +
    682       base::Int64ToString(content_length_));
    683   return headers;
    684 }
    685 
    686 //============================ DownloadFileRequestBase =========================
    687 
    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.
    704 }
    705 
    706 DownloadFileRequestBase::~DownloadFileRequestBase() {}
    707 
    708 // Overridden from UrlFetchRequestBase.
    709 GURL DownloadFileRequestBase::GetURL() const {
    710   return download_url_;
    711 }
    712 
    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_;
    719 }
    720 
    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);
    727 }
    728 
    729 void DownloadFileRequestBase::ProcessURLFetchResults(const URLFetcher* source) {
    730   GDataErrorCode code = GetErrorCode();
    731 
    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_;
    737   }
    738 
    739   download_action_callback_.Run(code, temp_file);
    740   OnProcessURLFetchResultsComplete();
    741 }
    742 
    743 void DownloadFileRequestBase::RunCallbackOnPrematureFailure(
    744     GDataErrorCode code) {
    745   download_action_callback_.Run(code, base::FilePath());
    746 }
    747 
    748 }  // namespace google_apis
    749