Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / google_apis / drive / base_requests.cc
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 // 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));
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.
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);
87   }
88   return headers;
89 }
90
91 bool IsSuccessfulResponseCode(int response_code) {
92   return 200 <= response_code && response_code <= 299;
93 }
94
95 }  // namespace
96
97 namespace google_apis {
98
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);
107 }
108
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));
118   }
119 }
120
121 ResponseWriter::~ResponseWriter() {
122 }
123
124 void ResponseWriter::DisownFile() {
125   DCHECK(file_writer_);
126   file_writer_->DisownFile();
127 }
128
129 int 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
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)));
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
161 int ResponseWriter::Finish(const net::CompletionCallback& callback) {
162   if (file_writer_)
163     return file_writer_->Finish(callback);
164
165   return net::OK;
166 }
167
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()));
179     }
180   }
181
182   if (!callback.is_null())
183     callback.Run(result);
184 }
185
186 //============================ UrlFetchRequestBase ===========================
187
188 UrlFetchRequestBase::UrlFetchRequestBase(RequestSender* sender)
189     : re_authenticate_count_(0),
190       sender_(sender),
191       error_code_(GDATA_OTHER_ERROR),
192       weak_ptr_factory_(this) {
193 }
194
195 UrlFetchRequestBase::~UrlFetchRequestBase() {}
196
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());
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
287 URLFetcher::RequestType UrlFetchRequestBase::GetRequestType() const {
288   return URLFetcher::GET;
289 }
290
291 std::vector<std::string> UrlFetchRequestBase::GetExtraRequestHeaders() const {
292   return std::vector<std::string>();
293 }
294
295 bool UrlFetchRequestBase::GetContentData(std::string* upload_content_type,
296                                          std::string* upload_content) {
297   return false;
298 }
299
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;
305 }
306
307 void UrlFetchRequestBase::GetOutputFilePath(
308     base::FilePath* local_file_path,
309     GetContentCallback* get_content_callback) {
310 }
311
312 void UrlFetchRequestBase::Cancel() {
313   response_writer_ = NULL;
314   url_fetcher_.reset(NULL);
315   RunCallbackOnPrematureFailure(GDATA_CANCELLED);
316   sender_->RequestFinished(this);
317 }
318
319 GDataErrorCode UrlFetchRequestBase::GetErrorCode() {
320   return error_code_;
321 }
322
323 bool UrlFetchRequestBase::CalledOnValidThread() {
324   return thread_checker_.CalledOnValidThread();
325 }
326
327 base::SequencedTaskRunner* UrlFetchRequestBase::blocking_task_runner() const {
328   return sender_->blocking_task_runner();
329 }
330
331 void UrlFetchRequestBase::OnProcessURLFetchResultsComplete() {
332   sender_->RequestFinished(this);
333 }
334
335 void 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     const char kErrorReasonQuotaExceeded[] = "quotaExceeded";
362
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;
373
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;
386       }
387     }
388   }
389
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;
398     }
399
400     OnAuthFailed(error_code_);
401     return;
402   }
403
404   // Overridden by each specialization
405   ProcessURLFetchResults(source);
406 }
407
408 void UrlFetchRequestBase::OnAuthFailed(GDataErrorCode code) {
409   RunCallbackOnPrematureFailure(code);
410   sender_->RequestFinished(this);
411 }
412
413 base::WeakPtr<AuthenticatedRequestInterface>
414 UrlFetchRequestBase::GetWeakPtr() {
415   return weak_ptr_factory_.GetWeakPtr();
416 }
417
418 //============================ EntryActionRequest ============================
419
420 EntryActionRequest::EntryActionRequest(RequestSender* sender,
421                                        const EntryActionCallback& callback)
422     : UrlFetchRequestBase(sender),
423       callback_(callback) {
424   DCHECK(!callback_.is_null());
425 }
426
427 EntryActionRequest::~EntryActionRequest() {}
428
429 void EntryActionRequest::ProcessURLFetchResults(const URLFetcher* source) {
430   callback_.Run(GetErrorCode());
431   OnProcessURLFetchResultsComplete();
432 }
433
434 void EntryActionRequest::RunCallbackOnPrematureFailure(GDataErrorCode code) {
435   callback_.Run(code);
436 }
437
438 //============================== GetDataRequest ==============================
439
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());
446 }
447
448 GetDataRequest::~GetDataRequest() {}
449
450 void GetDataRequest::ParseResponse(GDataErrorCode fetch_error_code,
451                                    const std::string& data) {
452   DCHECK(CalledOnValidThread());
453
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));
461 }
462
463 void GetDataRequest::ProcessURLFetchResults(const URLFetcher* source) {
464   GDataErrorCode fetch_error_code = GetErrorCode();
465
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;
475   }
476 }
477
478 void GetDataRequest::RunCallbackOnPrematureFailure(
479     GDataErrorCode fetch_error_code) {
480   callback_.Run(fetch_error_code, scoped_ptr<base::Value>());
481 }
482
483 void GetDataRequest::OnDataParsed(GDataErrorCode fetch_error_code,
484                                   scoped_ptr<base::Value> value) {
485   DCHECK(CalledOnValidThread());
486
487   if (!value.get())
488     fetch_error_code = GDATA_PARSE_ERROR;
489
490   callback_.Run(fetch_error_code, value.Pass());
491   OnProcessURLFetchResultsComplete();
492 }
493
494 //========================= InitiateUploadRequestBase ========================
495
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);
508 }
509
510 InitiateUploadRequestBase::~InitiateUploadRequestBase() {}
511
512 void InitiateUploadRequestBase::ProcessURLFetchResults(
513     const URLFetcher* source) {
514   GDataErrorCode code = GetErrorCode();
515
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);
522   }
523
524   callback_.Run(code, GURL(upload_location));
525   OnProcessURLFetchResultsComplete();
526 }
527
528 void InitiateUploadRequestBase::RunCallbackOnPrematureFailure(
529     GDataErrorCode code) {
530   callback_.Run(code, GURL());
531 }
532
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;
540 }
541
542 //============================ UploadRangeResponse =============================
543
544 UploadRangeResponse::UploadRangeResponse()
545     : code(HTTP_SUCCESS),
546       start_position_received(0),
547       end_position_received(0) {
548 }
549
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) {
556 }
557
558 UploadRangeResponse::~UploadRangeResponse() {
559 }
560
561 //========================== UploadRangeRequestBase ==========================
562
563 UploadRangeRequestBase::UploadRangeRequestBase(RequestSender* sender,
564                                                const GURL& upload_url)
565     : UrlFetchRequestBase(sender),
566       upload_url_(upload_url),
567       weak_ptr_factory_(this) {
568 }
569
570 UploadRangeRequestBase::~UploadRangeRequestBase() {}
571
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_;
576 }
577
578 URLFetcher::RequestType UploadRangeRequestBase::GetRequestType() const {
579   return URLFetcher::PUT;
580 }
581
582 void UploadRangeRequestBase::ProcessURLFetchResults(
583     const URLFetcher* source) {
584   GDataErrorCode code = GetErrorCode();
585   net::HttpResponseHeaders* hdrs = source->GetResponseHeaders();
586
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.
601         //
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;
607       }
608     }
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);
612
613     OnRangeRequestComplete(UploadRangeResponse(code,
614                                                start_position_received,
615                                                end_position_received),
616                            scoped_ptr<base::Value>());
617
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();
632   }
633 }
634
635 void UploadRangeRequestBase::OnDataParsed(GDataErrorCode code,
636                                           scoped_ptr<base::Value> value) {
637   DCHECK(CalledOnValidThread());
638   DCHECK(code == HTTP_CREATED || code == HTTP_SUCCESS);
639
640   OnRangeRequestComplete(UploadRangeResponse(code, -1, -1), value.Pass());
641   OnProcessURLFetchResultsComplete();
642 }
643
644 void UploadRangeRequestBase::RunCallbackOnPrematureFailure(
645     GDataErrorCode code) {
646   OnRangeRequestComplete(
647       UploadRangeResponse(code, 0, 0), scoped_ptr<base::Value>());
648 }
649
650 //========================== ResumeUploadRequestBase =========================
651
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_);
667 }
668
669 ResumeUploadRequestBase::~ResumeUploadRequestBase() {}
670
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>();
678   }
679
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);
688
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;
696 }
697
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;
706   }
707
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;
713 }
714
715 //======================== GetUploadStatusRequestBase ========================
716
717 GetUploadStatusRequestBase::GetUploadStatusRequestBase(RequestSender* sender,
718                                                        const GURL& upload_url,
719                                                        int64 content_length)
720     : UploadRangeRequestBase(sender, upload_url),
721       content_length_(content_length) {}
722
723 GetUploadStatusRequestBase::~GetUploadStatusRequestBase() {}
724
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);
732
733   std::vector<std::string> headers;
734   headers.push_back(
735       std::string(kUploadContentRange) + "*/" +
736       base::Int64ToString(content_length_));
737   return headers;
738 }
739
740 //============================ DownloadFileRequestBase =========================
741
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.
758 }
759
760 DownloadFileRequestBase::~DownloadFileRequestBase() {}
761
762 // Overridden from UrlFetchRequestBase.
763 GURL DownloadFileRequestBase::GetURL() const {
764   return download_url_;
765 }
766
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_;
773 }
774
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);
781 }
782
783 void DownloadFileRequestBase::ProcessURLFetchResults(const URLFetcher* source) {
784   GDataErrorCode code = GetErrorCode();
785
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_;
791   }
792
793   download_action_callback_.Run(code, temp_file);
794   OnProcessURLFetchResultsComplete();
795 }
796
797 void DownloadFileRequestBase::RunCallbackOnPrematureFailure(
798     GDataErrorCode code) {
799   download_action_callback_.Run(code, base::FilePath());
800 }
801
802 }  // namespace google_apis