1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "google_apis/drive/base_requests.h"
7 #include "base/json/json_reader.h"
8 #include "base/location.h"
9 #include "base/sequenced_task_runner.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/task_runner_util.h"
13 #include "base/values.h"
14 #include "google_apis/drive/request_sender.h"
15 #include "google_apis/drive/task_util.h"
16 #include "net/base/io_buffer.h"
17 #include "net/base/load_flags.h"
18 #include "net/base/net_errors.h"
19 #include "net/http/http_byte_range.h"
20 #include "net/http/http_response_headers.h"
21 #include "net/http/http_util.h"
22 #include "net/url_request/url_fetcher.h"
23 #include "net/url_request/url_request_status.h"
25 using net::URLFetcher
;
29 // Template for optional OAuth2 authorization HTTP header.
30 const char kAuthorizationHeaderFormat
[] = "Authorization: Bearer %s";
31 // Template for GData API version HTTP header.
32 const char kGDataVersionHeader
[] = "GData-Version: 3.0";
34 // Maximum number of attempts for re-authentication per request.
35 const int kMaxReAuthenticateAttemptsPerRequest
= 1;
37 // Template for initiate upload of both GData WAPI and Drive API v2.
38 const char kUploadContentType
[] = "X-Upload-Content-Type: ";
39 const char kUploadContentLength
[] = "X-Upload-Content-Length: ";
40 const char kUploadResponseLocation
[] = "location";
42 // Template for upload data range of both GData WAPI and Drive API v2.
43 const char kUploadContentRange
[] = "Content-Range: bytes ";
44 const char kUploadResponseRange
[] = "range";
46 // Parse JSON string to base::Value object.
47 scoped_ptr
<base::Value
> ParseJsonInternal(const std::string
& json
) {
49 std::string error_message
;
50 scoped_ptr
<base::Value
> value(base::JSONReader::ReadAndReturnError(
51 json
, base::JSON_PARSE_RFC
, &error_code
, &error_message
));
54 std::string trimmed_json
;
55 if (json
.size() < 80) {
58 // Take the first 50 and the last 10 bytes.
59 trimmed_json
= base::StringPrintf(
61 json
.substr(0, 50).c_str(),
62 base::Uint64ToString(json
.size() - 60).c_str(),
63 json
.substr(json
.size() - 10).c_str());
65 LOG(WARNING
) << "Error while parsing entry response: " << error_message
66 << ", code: " << error_code
<< ", json:\n" << trimmed_json
;
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.
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!!");
86 url_fetcher
->GetResponseHeaders()->GetNormalizedHeaders(&headers
);
91 bool IsSuccessfulResponseCode(int response_code
) {
92 return 200 <= response_code
&& response_code
<= 299;
97 namespace google_apis
{
99 void ParseJson(base::TaskRunner
* blocking_task_runner
,
100 const std::string
& json
,
101 const ParseJsonCallback
& callback
) {
102 base::PostTaskAndReplyWithResult(
103 blocking_task_runner
,
105 base::Bind(&ParseJsonInternal
, json
),
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()) {
117 new net::URLFetcherFileWriter(file_task_runner
, file_path
));
121 ResponseWriter::~ResponseWriter() {
124 void ResponseWriter::DisownFile() {
125 DCHECK(file_writer_
);
126 file_writer_
->DisownFile();
129 int ResponseWriter::Initialize(const net::CompletionCallback
& callback
) {
131 return file_writer_
->Initialize(callback
);
137 int ResponseWriter::Write(net::IOBuffer
* buffer
,
139 const net::CompletionCallback
& callback
) {
140 if (!get_content_callback_
.is_null()) {
141 get_content_callback_
.Run(
143 make_scoped_ptr(new std::string(buffer
->data(), num_bytes
)));
147 const int result
= file_writer_
->Write(
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
);
157 data_
.append(buffer
->data(), num_bytes
);
161 int ResponseWriter::Finish(const net::CompletionCallback
& callback
) {
163 return file_writer_
->Finish(callback
);
168 void ResponseWriter::DidWrite(scoped_refptr
<net::IOBuffer
> buffer
,
169 const net::CompletionCallback
& callback
,
172 // Even if file_writer_ is used, append the data to |data_|, so that it can
173 // be used to get error information in case of server side errors.
174 // The size limit is to avoid consuming too much redundant memory.
175 const size_t kMaxStringSize
= 1024*1024;
176 if (data_
.size() < kMaxStringSize
) {
177 data_
.append(buffer
->data(), std::min(static_cast<size_t>(result
),
178 kMaxStringSize
- data_
.size()));
182 if (!callback
.is_null())
183 callback
.Run(result
);
186 //============================ UrlFetchRequestBase ===========================
188 UrlFetchRequestBase::UrlFetchRequestBase(RequestSender
* sender
)
189 : re_authenticate_count_(0),
191 error_code_(GDATA_OTHER_ERROR
),
192 weak_ptr_factory_(this) {
195 UrlFetchRequestBase::~UrlFetchRequestBase() {}
197 void UrlFetchRequestBase::Start(const std::string
& access_token
,
198 const std::string
& custom_user_agent
,
199 const ReAuthenticateCallback
& callback
) {
200 DCHECK(CalledOnValidThread());
201 DCHECK(!access_token
.empty());
202 DCHECK(!callback
.is_null());
203 DCHECK(re_authenticate_callback_
.is_null());
205 re_authenticate_callback_
= callback
;
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
212 RunCallbackOnPrematureFailure(GDATA_OTHER_ERROR
);
215 DVLOG(1) << "URL: " << url
.spec();
217 URLFetcher::RequestType request_type
= GetRequestType();
219 URLFetcher::Create(url
, request_type
, this));
220 url_fetcher_
->SetRequestContext(sender_
->url_request_context_getter());
221 // Always set flags to neither send nor save cookies.
222 url_fetcher_
->SetLoadFlags(
223 net::LOAD_DO_NOT_SEND_COOKIES
| net::LOAD_DO_NOT_SAVE_COOKIES
|
224 net::LOAD_DISABLE_CACHE
);
226 base::FilePath output_file_path
;
227 GetContentCallback get_content_callback
;
228 GetOutputFilePath(&output_file_path
, &get_content_callback
);
229 if (!get_content_callback
.is_null())
230 get_content_callback
= CreateRelayCallback(get_content_callback
);
231 response_writer_
= new ResponseWriter(blocking_task_runner(),
233 get_content_callback
);
234 url_fetcher_
->SaveResponseWithWriter(
235 scoped_ptr
<net::URLFetcherResponseWriter
>(response_writer_
));
237 // Add request headers.
238 // Note that SetExtraRequestHeaders clears the current headers and sets it
239 // to the passed-in headers, so calling it for each header will result in
240 // only the last header being set in request headers.
241 if (!custom_user_agent
.empty())
242 url_fetcher_
->AddExtraRequestHeader("User-Agent: " + custom_user_agent
);
243 url_fetcher_
->AddExtraRequestHeader(kGDataVersionHeader
);
244 url_fetcher_
->AddExtraRequestHeader(
245 base::StringPrintf(kAuthorizationHeaderFormat
, access_token
.data()));
246 std::vector
<std::string
> headers
= GetExtraRequestHeaders();
247 for (size_t i
= 0; i
< headers
.size(); ++i
) {
248 url_fetcher_
->AddExtraRequestHeader(headers
[i
]);
249 DVLOG(1) << "Extra header: " << headers
[i
];
252 // Set upload data if available.
253 std::string upload_content_type
;
254 std::string upload_content
;
255 if (GetContentData(&upload_content_type
, &upload_content
)) {
256 url_fetcher_
->SetUploadData(upload_content_type
, upload_content
);
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(
268 blocking_task_runner());
270 // Even if there is no content data, UrlFetcher requires to set empty
271 // upload data string for POST, PUT and PATCH methods, explicitly.
272 // It is because that most requests of those methods have non-empty
273 // body, and UrlFetcher checks whether it is actually not forgotten.
274 if (request_type
== URLFetcher::POST
||
275 request_type
== URLFetcher::PUT
||
276 request_type
== URLFetcher::PATCH
) {
277 // Set empty upload content-type and upload content, so that
278 // the request will have no "Content-type: " header and no content.
279 url_fetcher_
->SetUploadData(std::string(), std::string());
284 url_fetcher_
->Start();
287 URLFetcher::RequestType
UrlFetchRequestBase::GetRequestType() const {
288 return URLFetcher::GET
;
291 std::vector
<std::string
> UrlFetchRequestBase::GetExtraRequestHeaders() const {
292 return std::vector
<std::string
>();
295 bool UrlFetchRequestBase::GetContentData(std::string
* upload_content_type
,
296 std::string
* upload_content
) {
300 bool UrlFetchRequestBase::GetContentFile(base::FilePath
* local_file_path
,
303 std::string
* upload_content_type
) {
307 void UrlFetchRequestBase::GetOutputFilePath(
308 base::FilePath
* local_file_path
,
309 GetContentCallback
* get_content_callback
) {
312 void UrlFetchRequestBase::Cancel() {
313 response_writer_
= NULL
;
314 url_fetcher_
.reset(NULL
);
315 RunCallbackOnPrematureFailure(GDATA_CANCELLED
);
316 sender_
->RequestFinished(this);
319 GDataErrorCode
UrlFetchRequestBase::GetErrorCode() {
323 bool UrlFetchRequestBase::CalledOnValidThread() {
324 return thread_checker_
.CalledOnValidThread();
327 base::SequencedTaskRunner
* UrlFetchRequestBase::blocking_task_runner() const {
328 return sender_
->blocking_task_runner();
331 void UrlFetchRequestBase::OnProcessURLFetchResultsComplete() {
332 sender_
->RequestFinished(this);
335 void UrlFetchRequestBase::OnURLFetchComplete(const URLFetcher
* source
) {
336 DVLOG(1) << "Response headers:\n" << GetResponseHeadersAsString(source
);
338 // Determine error code.
339 error_code_
= static_cast<GDataErrorCode
>(source
->GetResponseCode());
340 if (!source
->GetStatus().is_success()) {
341 switch (source
->GetStatus().error()) {
342 case net::ERR_NETWORK_CHANGED
:
343 error_code_
= GDATA_NO_CONNECTION
;
346 error_code_
= GDATA_OTHER_ERROR
;
350 // The server may return detailed error status in JSON.
351 // See https://developers.google.com/drive/handle-errors
352 if (!IsSuccessfulResponseCode(error_code_
)) {
353 DVLOG(1) << response_writer_
->data();
355 const char kErrorKey
[] = "error";
356 const char kErrorErrorsKey
[] = "errors";
357 const char kErrorReasonKey
[] = "reason";
358 const char kErrorMessageKey
[] = "message";
359 const char kErrorReasonRateLimitExceeded
[] = "rateLimitExceeded";
360 const char kErrorReasonUserRateLimitExceeded
[] = "userRateLimitExceeded";
361 const char kErrorReasonQuotaExceeded
[] = "quotaExceeded";
363 scoped_ptr
<base::Value
> value(ParseJsonInternal(response_writer_
->data()));
364 base::DictionaryValue
* dictionary
= NULL
;
365 base::DictionaryValue
* error
= NULL
;
367 value
->GetAsDictionary(&dictionary
) &&
368 dictionary
->GetDictionaryWithoutPathExpansion(kErrorKey
, &error
)) {
369 // Get error message.
371 error
->GetStringWithoutPathExpansion(kErrorMessageKey
, &message
);
372 DLOG(ERROR
) << "code: " << error_code_
<< ", message: " << message
;
374 // Override the error code based on the reason of the first error.
375 base::ListValue
* errors
= NULL
;
376 base::DictionaryValue
* first_error
= NULL
;
377 if (error
->GetListWithoutPathExpansion(kErrorErrorsKey
, &errors
) &&
378 errors
->GetDictionary(0, &first_error
)) {
380 first_error
->GetStringWithoutPathExpansion(kErrorReasonKey
, &reason
);
381 if (reason
== kErrorReasonRateLimitExceeded
||
382 reason
== kErrorReasonUserRateLimitExceeded
)
383 error_code_
= HTTP_SERVICE_UNAVAILABLE
;
384 if (reason
== kErrorReasonQuotaExceeded
)
385 error_code_
= GDATA_NO_SPACE
;
390 // Handle authentication failure.
391 if (error_code_
== HTTP_UNAUTHORIZED
) {
392 if (++re_authenticate_count_
<= kMaxReAuthenticateAttemptsPerRequest
) {
393 // Reset re_authenticate_callback_ so Start() can be called again.
394 ReAuthenticateCallback callback
= re_authenticate_callback_
;
395 re_authenticate_callback_
.Reset();
400 OnAuthFailed(error_code_
);
404 // Overridden by each specialization
405 ProcessURLFetchResults(source
);
408 void UrlFetchRequestBase::OnAuthFailed(GDataErrorCode code
) {
409 RunCallbackOnPrematureFailure(code
);
410 sender_
->RequestFinished(this);
413 base::WeakPtr
<AuthenticatedRequestInterface
>
414 UrlFetchRequestBase::GetWeakPtr() {
415 return weak_ptr_factory_
.GetWeakPtr();
418 //============================ EntryActionRequest ============================
420 EntryActionRequest::EntryActionRequest(RequestSender
* sender
,
421 const EntryActionCallback
& callback
)
422 : UrlFetchRequestBase(sender
),
423 callback_(callback
) {
424 DCHECK(!callback_
.is_null());
427 EntryActionRequest::~EntryActionRequest() {}
429 void EntryActionRequest::ProcessURLFetchResults(const URLFetcher
* source
) {
430 callback_
.Run(GetErrorCode());
431 OnProcessURLFetchResultsComplete();
434 void EntryActionRequest::RunCallbackOnPrematureFailure(GDataErrorCode code
) {
438 //============================== GetDataRequest ==============================
440 GetDataRequest::GetDataRequest(RequestSender
* sender
,
441 const GetDataCallback
& callback
)
442 : UrlFetchRequestBase(sender
),
444 weak_ptr_factory_(this) {
445 DCHECK(!callback_
.is_null());
448 GetDataRequest::~GetDataRequest() {}
450 void GetDataRequest::ParseResponse(GDataErrorCode fetch_error_code
,
451 const std::string
& data
) {
452 DCHECK(CalledOnValidThread());
454 VLOG(1) << "JSON received from " << GetURL().spec() << ": "
455 << data
.size() << " bytes";
456 ParseJson(blocking_task_runner(),
458 base::Bind(&GetDataRequest::OnDataParsed
,
459 weak_ptr_factory_
.GetWeakPtr(),
463 void GetDataRequest::ProcessURLFetchResults(const URLFetcher
* source
) {
464 GDataErrorCode fetch_error_code
= GetErrorCode();
466 switch (fetch_error_code
) {
469 ParseResponse(fetch_error_code
, response_writer()->data());
472 RunCallbackOnPrematureFailure(fetch_error_code
);
473 OnProcessURLFetchResultsComplete();
478 void GetDataRequest::RunCallbackOnPrematureFailure(
479 GDataErrorCode fetch_error_code
) {
480 callback_
.Run(fetch_error_code
, scoped_ptr
<base::Value
>());
483 void GetDataRequest::OnDataParsed(GDataErrorCode fetch_error_code
,
484 scoped_ptr
<base::Value
> value
) {
485 DCHECK(CalledOnValidThread());
488 fetch_error_code
= GDATA_PARSE_ERROR
;
490 callback_
.Run(fetch_error_code
, value
.Pass());
491 OnProcessURLFetchResultsComplete();
494 //========================= InitiateUploadRequestBase ========================
496 InitiateUploadRequestBase::InitiateUploadRequestBase(
497 RequestSender
* sender
,
498 const InitiateUploadCallback
& callback
,
499 const std::string
& content_type
,
500 int64 content_length
)
501 : UrlFetchRequestBase(sender
),
503 content_type_(content_type
),
504 content_length_(content_length
) {
505 DCHECK(!callback_
.is_null());
506 DCHECK(!content_type_
.empty());
507 DCHECK_GE(content_length_
, 0);
510 InitiateUploadRequestBase::~InitiateUploadRequestBase() {}
512 void InitiateUploadRequestBase::ProcessURLFetchResults(
513 const URLFetcher
* source
) {
514 GDataErrorCode code
= GetErrorCode();
516 std::string upload_location
;
517 if (code
== HTTP_SUCCESS
) {
518 // Retrieve value of the first "Location" header.
519 source
->GetResponseHeaders()->EnumerateHeader(NULL
,
520 kUploadResponseLocation
,
524 callback_
.Run(code
, GURL(upload_location
));
525 OnProcessURLFetchResultsComplete();
528 void InitiateUploadRequestBase::RunCallbackOnPrematureFailure(
529 GDataErrorCode code
) {
530 callback_
.Run(code
, GURL());
533 std::vector
<std::string
>
534 InitiateUploadRequestBase::GetExtraRequestHeaders() const {
535 std::vector
<std::string
> headers
;
536 headers
.push_back(kUploadContentType
+ content_type_
);
538 kUploadContentLength
+ base::Int64ToString(content_length_
));
542 //============================ UploadRangeResponse =============================
544 UploadRangeResponse::UploadRangeResponse()
545 : code(HTTP_SUCCESS
),
546 start_position_received(0),
547 end_position_received(0) {
550 UploadRangeResponse::UploadRangeResponse(GDataErrorCode code
,
551 int64 start_position_received
,
552 int64 end_position_received
)
554 start_position_received(start_position_received
),
555 end_position_received(end_position_received
) {
558 UploadRangeResponse::~UploadRangeResponse() {
561 //========================== UploadRangeRequestBase ==========================
563 UploadRangeRequestBase::UploadRangeRequestBase(RequestSender
* sender
,
564 const GURL
& upload_url
)
565 : UrlFetchRequestBase(sender
),
566 upload_url_(upload_url
),
567 weak_ptr_factory_(this) {
570 UploadRangeRequestBase::~UploadRangeRequestBase() {}
572 GURL
UploadRangeRequestBase::GetURL() const {
573 // This is very tricky to get json from this request. To do that, &alt=json
574 // has to be appended not here but in InitiateUploadRequestBase::GetURL().
578 URLFetcher::RequestType
UploadRangeRequestBase::GetRequestType() const {
579 return URLFetcher::PUT
;
582 void UploadRangeRequestBase::ProcessURLFetchResults(
583 const URLFetcher
* source
) {
584 GDataErrorCode code
= GetErrorCode();
585 net::HttpResponseHeaders
* hdrs
= source
->GetResponseHeaders();
587 if (code
== HTTP_RESUME_INCOMPLETE
) {
588 // Retrieve value of the first "Range" header.
589 // The Range header is appeared only if there is at least one received
590 // byte. So, initialize the positions by 0 so that the [0,0) will be
591 // returned via the |callback_| for empty data case.
592 int64 start_position_received
= 0;
593 int64 end_position_received
= 0;
594 std::string range_received
;
595 hdrs
->EnumerateHeader(NULL
, kUploadResponseRange
, &range_received
);
596 if (!range_received
.empty()) { // Parse the range header.
597 std::vector
<net::HttpByteRange
> ranges
;
598 if (net::HttpUtil::ParseRangeHeader(range_received
, &ranges
) &&
600 // We only care about the first start-end pair in the range.
602 // Range header represents the range inclusively, while we are treating
603 // ranges exclusively (i.e., end_position_received should be one passed
604 // the last valid index). So "+ 1" is added.
605 start_position_received
= ranges
[0].first_byte_position();
606 end_position_received
= ranges
[0].last_byte_position() + 1;
609 // The Range header has the received data range, so the start position
610 // should be always 0.
611 DCHECK_EQ(start_position_received
, 0);
613 OnRangeRequestComplete(UploadRangeResponse(code
,
614 start_position_received
,
615 end_position_received
),
616 scoped_ptr
<base::Value
>());
618 OnProcessURLFetchResultsComplete();
619 } else if (code
== HTTP_CREATED
|| code
== HTTP_SUCCESS
) {
620 // The upload is successfully done. Parse the response which should be
621 // the entry's metadata.
622 ParseJson(blocking_task_runner(),
623 response_writer()->data(),
624 base::Bind(&UploadRangeRequestBase::OnDataParsed
,
625 weak_ptr_factory_
.GetWeakPtr(),
628 // Failed to upload. Run callbacks to notify the error.
629 OnRangeRequestComplete(
630 UploadRangeResponse(code
, -1, -1), scoped_ptr
<base::Value
>());
631 OnProcessURLFetchResultsComplete();
635 void UploadRangeRequestBase::OnDataParsed(GDataErrorCode code
,
636 scoped_ptr
<base::Value
> value
) {
637 DCHECK(CalledOnValidThread());
638 DCHECK(code
== HTTP_CREATED
|| code
== HTTP_SUCCESS
);
640 OnRangeRequestComplete(UploadRangeResponse(code
, -1, -1), value
.Pass());
641 OnProcessURLFetchResultsComplete();
644 void UploadRangeRequestBase::RunCallbackOnPrematureFailure(
645 GDataErrorCode code
) {
646 OnRangeRequestComplete(
647 UploadRangeResponse(code
, 0, 0), scoped_ptr
<base::Value
>());
650 //========================== ResumeUploadRequestBase =========================
652 ResumeUploadRequestBase::ResumeUploadRequestBase(
653 RequestSender
* sender
,
654 const GURL
& upload_location
,
655 int64 start_position
,
657 int64 content_length
,
658 const std::string
& content_type
,
659 const base::FilePath
& local_file_path
)
660 : UploadRangeRequestBase(sender
, upload_location
),
661 start_position_(start_position
),
662 end_position_(end_position
),
663 content_length_(content_length
),
664 content_type_(content_type
),
665 local_file_path_(local_file_path
) {
666 DCHECK_LE(start_position_
, end_position_
);
669 ResumeUploadRequestBase::~ResumeUploadRequestBase() {}
671 std::vector
<std::string
>
672 ResumeUploadRequestBase::GetExtraRequestHeaders() const {
673 if (content_length_
== 0) {
674 // For uploading an empty document, just PUT an empty content.
675 DCHECK_EQ(start_position_
, 0);
676 DCHECK_EQ(end_position_
, 0);
677 return std::vector
<std::string
>();
680 // The header looks like
681 // Content-Range: bytes <start_position>-<end_position>/<content_length>
683 // Content-Range: bytes 7864320-8388607/13851821
684 // The header takes inclusive range, so we adjust by "end_position - 1".
685 DCHECK_GE(start_position_
, 0);
686 DCHECK_GT(end_position_
, 0);
687 DCHECK_GE(content_length_
, 0);
689 std::vector
<std::string
> headers
;
691 std::string(kUploadContentRange
) +
692 base::Int64ToString(start_position_
) + "-" +
693 base::Int64ToString(end_position_
- 1) + "/" +
694 base::Int64ToString(content_length_
));
698 bool ResumeUploadRequestBase::GetContentFile(
699 base::FilePath
* local_file_path
,
702 std::string
* upload_content_type
) {
703 if (start_position_
== end_position_
) {
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_
;
715 //======================== GetUploadStatusRequestBase ========================
717 GetUploadStatusRequestBase::GetUploadStatusRequestBase(RequestSender
* sender
,
718 const GURL
& upload_url
,
719 int64 content_length
)
720 : UploadRangeRequestBase(sender
, upload_url
),
721 content_length_(content_length
) {}
723 GetUploadStatusRequestBase::~GetUploadStatusRequestBase() {}
725 std::vector
<std::string
>
726 GetUploadStatusRequestBase::GetExtraRequestHeaders() const {
727 // The header looks like
728 // Content-Range: bytes */<content_length>
730 // Content-Range: bytes */13851821
731 DCHECK_GE(content_length_
, 0);
733 std::vector
<std::string
> headers
;
735 std::string(kUploadContentRange
) + "*/" +
736 base::Int64ToString(content_length_
));
740 //============================ DownloadFileRequestBase =========================
742 DownloadFileRequestBase::DownloadFileRequestBase(
743 RequestSender
* sender
,
744 const DownloadActionCallback
& download_action_callback
,
745 const GetContentCallback
& get_content_callback
,
746 const ProgressCallback
& progress_callback
,
747 const GURL
& download_url
,
748 const base::FilePath
& output_file_path
)
749 : UrlFetchRequestBase(sender
),
750 download_action_callback_(download_action_callback
),
751 get_content_callback_(get_content_callback
),
752 progress_callback_(progress_callback
),
753 download_url_(download_url
),
754 output_file_path_(output_file_path
) {
755 DCHECK(!download_action_callback_
.is_null());
756 DCHECK(!output_file_path_
.empty());
757 // get_content_callback may be null.
760 DownloadFileRequestBase::~DownloadFileRequestBase() {}
762 // Overridden from UrlFetchRequestBase.
763 GURL
DownloadFileRequestBase::GetURL() const {
764 return download_url_
;
767 void DownloadFileRequestBase::GetOutputFilePath(
768 base::FilePath
* local_file_path
,
769 GetContentCallback
* get_content_callback
) {
770 // Configure so that the downloaded content is saved to |output_file_path_|.
771 *local_file_path
= output_file_path_
;
772 *get_content_callback
= get_content_callback_
;
775 void DownloadFileRequestBase::OnURLFetchDownloadProgress(
776 const URLFetcher
* source
,
779 if (!progress_callback_
.is_null())
780 progress_callback_
.Run(current
, total
);
783 void DownloadFileRequestBase::ProcessURLFetchResults(const URLFetcher
* source
) {
784 GDataErrorCode code
= GetErrorCode();
786 // Take over the ownership of the the downloaded temp file.
787 base::FilePath temp_file
;
788 if (code
== HTTP_SUCCESS
) {
789 response_writer()->DisownFile();
790 temp_file
= output_file_path_
;
793 download_action_callback_
.Run(code
, temp_file
);
794 OnProcessURLFetchResultsComplete();
797 void DownloadFileRequestBase::RunCallbackOnPrematureFailure(
798 GDataErrorCode code
) {
799 download_action_callback_
.Run(code
, base::FilePath());
802 } // namespace google_apis