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/files/file_util.h"
8 #include "base/json/json_reader.h"
9 #include "base/json/json_writer.h"
10 #include "base/location.h"
11 #include "base/rand_util.h"
12 #include "base/sequenced_task_runner.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/task_runner_util.h"
16 #include "base/values.h"
17 #include "google_apis/drive/drive_api_parser.h"
18 #include "google_apis/drive/request_sender.h"
19 #include "google_apis/drive/request_util.h"
20 #include "google_apis/drive/task_util.h"
21 #include "google_apis/drive/time_util.h"
22 #include "net/base/elements_upload_data_stream.h"
23 #include "net/base/io_buffer.h"
24 #include "net/base/load_flags.h"
25 #include "net/base/net_errors.h"
26 #include "net/base/upload_bytes_element_reader.h"
27 #include "net/base/upload_data_stream.h"
28 #include "net/base/upload_element_reader.h"
29 #include "net/base/upload_file_element_reader.h"
30 #include "net/http/http_byte_range.h"
31 #include "net/http/http_response_headers.h"
32 #include "net/http/http_util.h"
33 #include "net/url_request/url_fetcher.h"
34 #include "net/url_request/url_request_status.h"
36 using net::URLFetcher
;
40 // Template for optional OAuth2 authorization HTTP header.
41 const char kAuthorizationHeaderFormat
[] = "Authorization: Bearer %s";
42 // Template for GData API version HTTP header.
43 const char kGDataVersionHeader
[] = "GData-Version: 3.0";
45 // Maximum number of attempts for re-authentication per request.
46 const int kMaxReAuthenticateAttemptsPerRequest
= 1;
48 // Template for initiate upload of both GData WAPI and Drive API v2.
49 const char kUploadContentType
[] = "X-Upload-Content-Type: ";
50 const char kUploadContentLength
[] = "X-Upload-Content-Length: ";
51 const char kUploadResponseLocation
[] = "location";
53 // Template for upload data range of both GData WAPI and Drive API v2.
54 const char kUploadContentRange
[] = "Content-Range: bytes ";
55 const char kUploadResponseRange
[] = "range";
57 // The prefix of multipart/related mime type.
58 const char kMultipartMimeTypePrefix
[] = "multipart/related; boundary=";
60 // Template for multipart request body.
61 const char kMessageFormatBeforeFile
[] =
62 "--%s\nContent-Type: %s\n\n%s\n--%s\nContent-Type: %s\n\n";
63 const char kMessageFormatAfterFile
[] = "\n--%s--";
65 // Characters to be used for multipart/related boundary.
66 const char kBoundaryCharacters
[] =
67 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
68 // Size of multipart/related's boundary.
69 const char kBoundarySize
= 70;
71 // Parses JSON passed in |json| on |blocking_task_runner|. Runs |callback| on
72 // the calling thread when finished with either success or failure.
73 // The callback must not be null.
74 void ParseJsonOnBlockingPool(
75 base::TaskRunner
* blocking_task_runner
,
76 const std::string
& json
,
77 const base::Callback
<void(scoped_ptr
<base::Value
> value
)>& callback
) {
78 base::PostTaskAndReplyWithResult(
81 base::Bind(&google_apis::ParseJson
, json
),
85 // Returns response headers as a string. Returns a warning message if
86 // |url_fetcher| does not contain a valid response. Used only for debugging.
87 std::string
GetResponseHeadersAsString(const URLFetcher
* url_fetcher
) {
88 // net::HttpResponseHeaders::raw_headers(), as the name implies, stores
89 // all headers in their raw format, i.e each header is null-terminated.
90 // So logging raw_headers() only shows the first header, which is probably
91 // the status line. GetNormalizedHeaders, on the other hand, will show all
92 // the headers, one per line, which is probably what we want.
94 // Check that response code indicates response headers are valid (i.e. not
95 // malformed) before we retrieve the headers.
96 if (url_fetcher
->GetResponseCode() == URLFetcher::RESPONSE_CODE_INVALID
) {
97 headers
.assign("Response headers are malformed!!");
99 url_fetcher
->GetResponseHeaders()->GetNormalizedHeaders(&headers
);
104 bool IsSuccessfulResponseCode(int response_code
) {
105 return 200 <= response_code
&& response_code
<= 299;
108 // Obtains the multipart body for the metadata string and file contents. If
109 // predetermined_boundary is empty, the function generates the boundary string.
110 bool GetMultipartContent(const std::string
& predetermined_boundary
,
111 const std::string
& metadata_json
,
112 const std::string
& content_type
,
113 const base::FilePath
& path
,
114 std::string
* upload_content_type
,
115 std::string
* upload_content_data
) {
116 std::string file_content
;
117 if (!ReadFileToString(path
, &file_content
))
120 std::string boundary
;
121 if (predetermined_boundary
.empty()) {
123 boundary
.resize(kBoundarySize
);
124 for (int i
= 0; i
< kBoundarySize
; ++i
) {
125 // Subtract 2 from the array size to exclude '\0', and to turn the size
126 // into the last index.
127 const int last_char_index
= arraysize(kBoundaryCharacters
) - 2;
128 boundary
[i
] = kBoundaryCharacters
[base::RandInt(0, last_char_index
)];
130 if (metadata_json
.find(boundary
, 0) == std::string::npos
&&
131 file_content
.find(boundary
, 0) == std::string::npos
) {
136 boundary
= predetermined_boundary
;
138 const std::string body_before_file
= base::StringPrintf(
139 kMessageFormatBeforeFile
, boundary
.c_str(), "application/json",
140 metadata_json
.c_str(), boundary
.c_str(), content_type
.c_str());
141 const std::string body_after_file
=
142 base::StringPrintf(kMessageFormatAfterFile
, boundary
.c_str());
144 *upload_content_type
= kMultipartMimeTypePrefix
+ boundary
;
145 *upload_content_data
= body_before_file
+ file_content
+ body_after_file
;
151 namespace google_apis
{
153 scoped_ptr
<base::Value
> ParseJson(const std::string
& json
) {
155 std::string error_message
;
156 scoped_ptr
<base::Value
> value(base::JSONReader::ReadAndReturnError(
157 json
, base::JSON_PARSE_RFC
, &error_code
, &error_message
));
160 std::string trimmed_json
;
161 if (json
.size() < 80) {
164 // Take the first 50 and the last 10 bytes.
165 trimmed_json
= base::StringPrintf(
167 json
.substr(0, 50).c_str(),
168 base::Uint64ToString(json
.size() - 60).c_str(),
169 json
.substr(json
.size() - 10).c_str());
171 LOG(WARNING
) << "Error while parsing entry response: " << error_message
172 << ", code: " << error_code
<< ", json:\n" << trimmed_json
;
177 //=========================== ResponseWriter ==================================
178 ResponseWriter::ResponseWriter(base::SequencedTaskRunner
* file_task_runner
,
179 const base::FilePath
& file_path
,
180 const GetContentCallback
& get_content_callback
)
181 : get_content_callback_(get_content_callback
),
182 weak_ptr_factory_(this) {
183 if (!file_path
.empty()) {
185 new net::URLFetcherFileWriter(file_task_runner
, file_path
));
189 ResponseWriter::~ResponseWriter() {
192 void ResponseWriter::DisownFile() {
193 DCHECK(file_writer_
);
194 file_writer_
->DisownFile();
197 int ResponseWriter::Initialize(const net::CompletionCallback
& callback
) {
199 return file_writer_
->Initialize(callback
);
205 int ResponseWriter::Write(net::IOBuffer
* buffer
,
207 const net::CompletionCallback
& callback
) {
208 if (!get_content_callback_
.is_null()) {
209 get_content_callback_
.Run(
211 make_scoped_ptr(new std::string(buffer
->data(), num_bytes
)));
215 const int result
= file_writer_
->Write(
217 base::Bind(&ResponseWriter::DidWrite
,
218 weak_ptr_factory_
.GetWeakPtr(),
219 make_scoped_refptr(buffer
), callback
));
220 if (result
!= net::ERR_IO_PENDING
)
221 DidWrite(buffer
, net::CompletionCallback(), result
);
225 data_
.append(buffer
->data(), num_bytes
);
229 int ResponseWriter::Finish(const net::CompletionCallback
& callback
) {
231 return file_writer_
->Finish(callback
);
236 void ResponseWriter::DidWrite(scoped_refptr
<net::IOBuffer
> buffer
,
237 const net::CompletionCallback
& callback
,
240 // Even if file_writer_ is used, append the data to |data_|, so that it can
241 // be used to get error information in case of server side errors.
242 // The size limit is to avoid consuming too much redundant memory.
243 const size_t kMaxStringSize
= 1024*1024;
244 if (data_
.size() < kMaxStringSize
) {
245 data_
.append(buffer
->data(), std::min(static_cast<size_t>(result
),
246 kMaxStringSize
- data_
.size()));
250 if (!callback
.is_null())
251 callback
.Run(result
);
254 //============================ UrlFetchRequestBase ===========================
256 UrlFetchRequestBase::UrlFetchRequestBase(RequestSender
* sender
)
257 : re_authenticate_count_(0),
258 response_writer_(NULL
),
260 error_code_(DRIVE_OTHER_ERROR
),
261 weak_ptr_factory_(this) {
264 UrlFetchRequestBase::~UrlFetchRequestBase() {}
266 void UrlFetchRequestBase::Start(const std::string
& access_token
,
267 const std::string
& custom_user_agent
,
268 const ReAuthenticateCallback
& callback
) {
269 DCHECK(CalledOnValidThread());
270 DCHECK(!access_token
.empty());
271 DCHECK(!callback
.is_null());
272 DCHECK(re_authenticate_callback_
.is_null());
274 re_authenticate_callback_
= callback
;
277 if (url
.is_empty()) {
278 // Error is found on generating the url. Send the error message to the
279 // callback, and then return immediately without trying to connect
281 RunCallbackOnPrematureFailure(DRIVE_OTHER_ERROR
);
284 DVLOG(1) << "URL: " << url
.spec();
286 URLFetcher::RequestType request_type
= GetRequestType();
287 url_fetcher_
.reset(URLFetcher::Create(url
, request_type
, this));
288 url_fetcher_
->SetRequestContext(sender_
->url_request_context_getter());
289 // Always set flags to neither send nor save cookies.
290 url_fetcher_
->SetLoadFlags(
291 net::LOAD_DO_NOT_SEND_COOKIES
| net::LOAD_DO_NOT_SAVE_COOKIES
|
292 net::LOAD_DISABLE_CACHE
);
294 base::FilePath output_file_path
;
295 GetContentCallback get_content_callback
;
296 GetOutputFilePath(&output_file_path
, &get_content_callback
);
297 if (!get_content_callback
.is_null())
298 get_content_callback
= CreateRelayCallback(get_content_callback
);
299 response_writer_
= new ResponseWriter(blocking_task_runner(),
301 get_content_callback
);
302 url_fetcher_
->SaveResponseWithWriter(
303 scoped_ptr
<net::URLFetcherResponseWriter
>(response_writer_
));
305 // Add request headers.
306 // Note that SetExtraRequestHeaders clears the current headers and sets it
307 // to the passed-in headers, so calling it for each header will result in
308 // only the last header being set in request headers.
309 if (!custom_user_agent
.empty())
310 url_fetcher_
->AddExtraRequestHeader("User-Agent: " + custom_user_agent
);
311 url_fetcher_
->AddExtraRequestHeader(kGDataVersionHeader
);
312 url_fetcher_
->AddExtraRequestHeader(
313 base::StringPrintf(kAuthorizationHeaderFormat
, access_token
.data()));
314 std::vector
<std::string
> headers
= GetExtraRequestHeaders();
315 for (size_t i
= 0; i
< headers
.size(); ++i
) {
316 url_fetcher_
->AddExtraRequestHeader(headers
[i
]);
317 DVLOG(1) << "Extra header: " << headers
[i
];
320 // Set upload data if available.
321 std::string upload_content_type
;
322 std::string upload_content
;
323 if (GetContentData(&upload_content_type
, &upload_content
)) {
324 url_fetcher_
->SetUploadData(upload_content_type
, upload_content
);
326 base::FilePath local_file_path
;
327 int64 range_offset
= 0;
328 int64 range_length
= 0;
329 if (GetContentFile(&local_file_path
, &range_offset
, &range_length
,
330 &upload_content_type
)) {
331 url_fetcher_
->SetUploadFilePath(
336 blocking_task_runner());
338 // Even if there is no content data, UrlFetcher requires to set empty
339 // upload data string for POST, PUT and PATCH methods, explicitly.
340 // It is because that most requests of those methods have non-empty
341 // body, and UrlFetcher checks whether it is actually not forgotten.
342 if (request_type
== URLFetcher::POST
||
343 request_type
== URLFetcher::PUT
||
344 request_type
== URLFetcher::PATCH
) {
345 // Set empty upload content-type and upload content, so that
346 // the request will have no "Content-type: " header and no content.
347 url_fetcher_
->SetUploadData(std::string(), std::string());
352 url_fetcher_
->Start();
355 URLFetcher::RequestType
UrlFetchRequestBase::GetRequestType() const {
356 return URLFetcher::GET
;
359 std::vector
<std::string
> UrlFetchRequestBase::GetExtraRequestHeaders() const {
360 return std::vector
<std::string
>();
363 bool UrlFetchRequestBase::GetContentData(std::string
* upload_content_type
,
364 std::string
* upload_content
) {
368 bool UrlFetchRequestBase::GetContentFile(base::FilePath
* local_file_path
,
371 std::string
* upload_content_type
) {
375 void UrlFetchRequestBase::GetOutputFilePath(
376 base::FilePath
* local_file_path
,
377 GetContentCallback
* get_content_callback
) {
380 void UrlFetchRequestBase::Cancel() {
381 response_writer_
= NULL
;
382 url_fetcher_
.reset(NULL
);
383 RunCallbackOnPrematureFailure(DRIVE_CANCELLED
);
384 sender_
->RequestFinished(this);
387 DriveApiErrorCode
UrlFetchRequestBase::GetErrorCode() {
391 bool UrlFetchRequestBase::CalledOnValidThread() {
392 return thread_checker_
.CalledOnValidThread();
395 base::SequencedTaskRunner
* UrlFetchRequestBase::blocking_task_runner() const {
396 return sender_
->blocking_task_runner();
399 void UrlFetchRequestBase::OnProcessURLFetchResultsComplete() {
400 sender_
->RequestFinished(this);
403 void UrlFetchRequestBase::OnURLFetchComplete(const URLFetcher
* source
) {
404 DVLOG(1) << "Response headers:\n" << GetResponseHeadersAsString(source
);
406 // Determine error code.
407 error_code_
= static_cast<DriveApiErrorCode
>(source
->GetResponseCode());
408 if (!source
->GetStatus().is_success()) {
409 switch (source
->GetStatus().error()) {
410 case net::ERR_NETWORK_CHANGED
:
411 error_code_
= DRIVE_NO_CONNECTION
;
414 error_code_
= DRIVE_OTHER_ERROR
;
418 // The server may return detailed error status in JSON.
419 // See https://developers.google.com/drive/handle-errors
420 if (!IsSuccessfulResponseCode(error_code_
)) {
421 DVLOG(1) << response_writer_
->data();
423 const char kErrorKey
[] = "error";
424 const char kErrorErrorsKey
[] = "errors";
425 const char kErrorReasonKey
[] = "reason";
426 const char kErrorMessageKey
[] = "message";
427 const char kErrorReasonRateLimitExceeded
[] = "rateLimitExceeded";
428 const char kErrorReasonUserRateLimitExceeded
[] = "userRateLimitExceeded";
429 const char kErrorReasonQuotaExceeded
[] = "quotaExceeded";
431 scoped_ptr
<base::Value
> value(ParseJson(response_writer_
->data()));
432 base::DictionaryValue
* dictionary
= NULL
;
433 base::DictionaryValue
* error
= NULL
;
435 value
->GetAsDictionary(&dictionary
) &&
436 dictionary
->GetDictionaryWithoutPathExpansion(kErrorKey
, &error
)) {
437 // Get error message.
439 error
->GetStringWithoutPathExpansion(kErrorMessageKey
, &message
);
440 DLOG(ERROR
) << "code: " << error_code_
<< ", message: " << message
;
442 // Override the error code based on the reason of the first error.
443 base::ListValue
* errors
= NULL
;
444 base::DictionaryValue
* first_error
= NULL
;
445 if (error
->GetListWithoutPathExpansion(kErrorErrorsKey
, &errors
) &&
446 errors
->GetDictionary(0, &first_error
)) {
448 first_error
->GetStringWithoutPathExpansion(kErrorReasonKey
, &reason
);
449 if (reason
== kErrorReasonRateLimitExceeded
||
450 reason
== kErrorReasonUserRateLimitExceeded
)
451 error_code_
= HTTP_SERVICE_UNAVAILABLE
;
452 if (reason
== kErrorReasonQuotaExceeded
)
453 error_code_
= DRIVE_NO_SPACE
;
458 // Handle authentication failure.
459 if (error_code_
== HTTP_UNAUTHORIZED
) {
460 if (++re_authenticate_count_
<= kMaxReAuthenticateAttemptsPerRequest
) {
461 // Reset re_authenticate_callback_ so Start() can be called again.
462 ReAuthenticateCallback callback
= re_authenticate_callback_
;
463 re_authenticate_callback_
.Reset();
468 OnAuthFailed(error_code_
);
472 // Overridden by each specialization
473 ProcessURLFetchResults(source
);
476 void UrlFetchRequestBase::OnAuthFailed(DriveApiErrorCode code
) {
477 RunCallbackOnPrematureFailure(code
);
478 sender_
->RequestFinished(this);
481 base::WeakPtr
<AuthenticatedRequestInterface
>
482 UrlFetchRequestBase::GetWeakPtr() {
483 return weak_ptr_factory_
.GetWeakPtr();
486 //============================ EntryActionRequest ============================
488 EntryActionRequest::EntryActionRequest(RequestSender
* sender
,
489 const EntryActionCallback
& callback
)
490 : UrlFetchRequestBase(sender
),
491 callback_(callback
) {
492 DCHECK(!callback_
.is_null());
495 EntryActionRequest::~EntryActionRequest() {}
497 void EntryActionRequest::ProcessURLFetchResults(const URLFetcher
* source
) {
498 callback_
.Run(GetErrorCode());
499 OnProcessURLFetchResultsComplete();
502 void EntryActionRequest::RunCallbackOnPrematureFailure(DriveApiErrorCode code
) {
506 //========================= InitiateUploadRequestBase ========================
508 InitiateUploadRequestBase::InitiateUploadRequestBase(
509 RequestSender
* sender
,
510 const InitiateUploadCallback
& callback
,
511 const std::string
& content_type
,
512 int64 content_length
)
513 : UrlFetchRequestBase(sender
),
515 content_type_(content_type
),
516 content_length_(content_length
) {
517 DCHECK(!callback_
.is_null());
518 DCHECK(!content_type_
.empty());
519 DCHECK_GE(content_length_
, 0);
522 InitiateUploadRequestBase::~InitiateUploadRequestBase() {}
524 void InitiateUploadRequestBase::ProcessURLFetchResults(
525 const URLFetcher
* source
) {
526 DriveApiErrorCode code
= GetErrorCode();
528 std::string upload_location
;
529 if (code
== HTTP_SUCCESS
) {
530 // Retrieve value of the first "Location" header.
531 source
->GetResponseHeaders()->EnumerateHeader(NULL
,
532 kUploadResponseLocation
,
536 callback_
.Run(code
, GURL(upload_location
));
537 OnProcessURLFetchResultsComplete();
540 void InitiateUploadRequestBase::RunCallbackOnPrematureFailure(
541 DriveApiErrorCode code
) {
542 callback_
.Run(code
, GURL());
545 std::vector
<std::string
>
546 InitiateUploadRequestBase::GetExtraRequestHeaders() const {
547 std::vector
<std::string
> headers
;
548 headers
.push_back(kUploadContentType
+ content_type_
);
550 kUploadContentLength
+ base::Int64ToString(content_length_
));
554 //============================ UploadRangeResponse =============================
556 UploadRangeResponse::UploadRangeResponse()
557 : code(HTTP_SUCCESS
),
558 start_position_received(0),
559 end_position_received(0) {
562 UploadRangeResponse::UploadRangeResponse(DriveApiErrorCode code
,
563 int64 start_position_received
,
564 int64 end_position_received
)
566 start_position_received(start_position_received
),
567 end_position_received(end_position_received
) {
570 UploadRangeResponse::~UploadRangeResponse() {
573 //========================== UploadRangeRequestBase ==========================
575 UploadRangeRequestBase::UploadRangeRequestBase(RequestSender
* sender
,
576 const GURL
& upload_url
)
577 : UrlFetchRequestBase(sender
),
578 upload_url_(upload_url
),
579 weak_ptr_factory_(this) {
582 UploadRangeRequestBase::~UploadRangeRequestBase() {}
584 GURL
UploadRangeRequestBase::GetURL() const {
585 // This is very tricky to get json from this request. To do that, &alt=json
586 // has to be appended not here but in InitiateUploadRequestBase::GetURL().
590 URLFetcher::RequestType
UploadRangeRequestBase::GetRequestType() const {
591 return URLFetcher::PUT
;
594 void UploadRangeRequestBase::ProcessURLFetchResults(
595 const URLFetcher
* source
) {
596 DriveApiErrorCode code
= GetErrorCode();
597 net::HttpResponseHeaders
* hdrs
= source
->GetResponseHeaders();
599 if (code
== HTTP_RESUME_INCOMPLETE
) {
600 // Retrieve value of the first "Range" header.
601 // The Range header is appeared only if there is at least one received
602 // byte. So, initialize the positions by 0 so that the [0,0) will be
603 // returned via the |callback_| for empty data case.
604 int64 start_position_received
= 0;
605 int64 end_position_received
= 0;
606 std::string range_received
;
607 hdrs
->EnumerateHeader(NULL
, kUploadResponseRange
, &range_received
);
608 if (!range_received
.empty()) { // Parse the range header.
609 std::vector
<net::HttpByteRange
> ranges
;
610 if (net::HttpUtil::ParseRangeHeader(range_received
, &ranges
) &&
612 // We only care about the first start-end pair in the range.
614 // Range header represents the range inclusively, while we are treating
615 // ranges exclusively (i.e., end_position_received should be one passed
616 // the last valid index). So "+ 1" is added.
617 start_position_received
= ranges
[0].first_byte_position();
618 end_position_received
= ranges
[0].last_byte_position() + 1;
621 // The Range header has the received data range, so the start position
622 // should be always 0.
623 DCHECK_EQ(start_position_received
, 0);
625 OnRangeRequestComplete(UploadRangeResponse(code
,
626 start_position_received
,
627 end_position_received
),
628 scoped_ptr
<base::Value
>());
630 OnProcessURLFetchResultsComplete();
631 } else if (code
== HTTP_CREATED
|| code
== HTTP_SUCCESS
) {
632 // The upload is successfully done. Parse the response which should be
633 // the entry's metadata.
634 ParseJsonOnBlockingPool(blocking_task_runner(),
635 response_writer()->data(),
636 base::Bind(&UploadRangeRequestBase::OnDataParsed
,
637 weak_ptr_factory_
.GetWeakPtr(),
640 // Failed to upload. Run callbacks to notify the error.
641 OnRangeRequestComplete(
642 UploadRangeResponse(code
, -1, -1), scoped_ptr
<base::Value
>());
643 OnProcessURLFetchResultsComplete();
647 void UploadRangeRequestBase::OnDataParsed(DriveApiErrorCode code
,
648 scoped_ptr
<base::Value
> value
) {
649 DCHECK(CalledOnValidThread());
650 DCHECK(code
== HTTP_CREATED
|| code
== HTTP_SUCCESS
);
652 OnRangeRequestComplete(UploadRangeResponse(code
, -1, -1), value
.Pass());
653 OnProcessURLFetchResultsComplete();
656 void UploadRangeRequestBase::RunCallbackOnPrematureFailure(
657 DriveApiErrorCode code
) {
658 OnRangeRequestComplete(
659 UploadRangeResponse(code
, 0, 0), scoped_ptr
<base::Value
>());
662 //========================== ResumeUploadRequestBase =========================
664 ResumeUploadRequestBase::ResumeUploadRequestBase(
665 RequestSender
* sender
,
666 const GURL
& upload_location
,
667 int64 start_position
,
669 int64 content_length
,
670 const std::string
& content_type
,
671 const base::FilePath
& local_file_path
)
672 : UploadRangeRequestBase(sender
, upload_location
),
673 start_position_(start_position
),
674 end_position_(end_position
),
675 content_length_(content_length
),
676 content_type_(content_type
),
677 local_file_path_(local_file_path
) {
678 DCHECK_LE(start_position_
, end_position_
);
681 ResumeUploadRequestBase::~ResumeUploadRequestBase() {}
683 std::vector
<std::string
>
684 ResumeUploadRequestBase::GetExtraRequestHeaders() const {
685 if (content_length_
== 0) {
686 // For uploading an empty document, just PUT an empty content.
687 DCHECK_EQ(start_position_
, 0);
688 DCHECK_EQ(end_position_
, 0);
689 return std::vector
<std::string
>();
692 // The header looks like
693 // Content-Range: bytes <start_position>-<end_position>/<content_length>
695 // Content-Range: bytes 7864320-8388607/13851821
696 // The header takes inclusive range, so we adjust by "end_position - 1".
697 DCHECK_GE(start_position_
, 0);
698 DCHECK_GT(end_position_
, 0);
699 DCHECK_GE(content_length_
, 0);
701 std::vector
<std::string
> headers
;
703 std::string(kUploadContentRange
) +
704 base::Int64ToString(start_position_
) + "-" +
705 base::Int64ToString(end_position_
- 1) + "/" +
706 base::Int64ToString(content_length_
));
710 bool ResumeUploadRequestBase::GetContentFile(
711 base::FilePath
* local_file_path
,
714 std::string
* upload_content_type
) {
715 if (start_position_
== end_position_
) {
720 *local_file_path
= local_file_path_
;
721 *range_offset
= start_position_
;
722 *range_length
= end_position_
- start_position_
;
723 *upload_content_type
= content_type_
;
727 //======================== GetUploadStatusRequestBase ========================
729 GetUploadStatusRequestBase::GetUploadStatusRequestBase(RequestSender
* sender
,
730 const GURL
& upload_url
,
731 int64 content_length
)
732 : UploadRangeRequestBase(sender
, upload_url
),
733 content_length_(content_length
) {}
735 GetUploadStatusRequestBase::~GetUploadStatusRequestBase() {}
737 std::vector
<std::string
>
738 GetUploadStatusRequestBase::GetExtraRequestHeaders() const {
739 // The header looks like
740 // Content-Range: bytes */<content_length>
742 // Content-Range: bytes */13851821
743 DCHECK_GE(content_length_
, 0);
745 std::vector
<std::string
> headers
;
747 std::string(kUploadContentRange
) + "*/" +
748 base::Int64ToString(content_length_
));
752 //========================= MultipartUploadRequestBase ========================
754 MultipartUploadRequestBase::MultipartUploadRequestBase(
755 RequestSender
* sender
,
756 const std::string
& metadata_json
,
757 const std::string
& content_type
,
758 int64 content_length
,
759 const base::FilePath
& local_file_path
,
760 const FileResourceCallback
& callback
,
761 const ProgressCallback
& progress_callback
)
762 : UrlFetchRequestBase(sender
),
763 metadata_json_(metadata_json
),
764 content_type_(content_type
),
765 local_path_(local_file_path
),
767 progress_callback_(progress_callback
),
768 weak_ptr_factory_(this) {
769 DCHECK(!content_type
.empty());
770 DCHECK_GE(content_length
, 0);
771 DCHECK(!local_file_path
.empty());
772 DCHECK(!callback
.is_null());
775 MultipartUploadRequestBase::~MultipartUploadRequestBase() {
778 void MultipartUploadRequestBase::Start(const std::string
& access_token
,
779 const std::string
& custom_user_agent
,
780 const ReAuthenticateCallback
& callback
) {
781 // If the request is cancelled, the request instance will be deleted in
782 // |UrlFetchRequestBase::Cancel| and OnPrepareUploadContent won't be called.
783 std::string
* const upload_content_type
= new std::string();
784 std::string
* const upload_content_data
= new std::string();
785 PostTaskAndReplyWithResult(
786 blocking_task_runner(), FROM_HERE
,
787 base::Bind(&GetMultipartContent
, boundary_
, metadata_json_
, content_type_
,
788 local_path_
, base::Unretained(upload_content_type
),
789 base::Unretained(upload_content_data
)),
790 base::Bind(&MultipartUploadRequestBase::OnPrepareUploadContent
,
791 weak_ptr_factory_
.GetWeakPtr(), access_token
,
792 custom_user_agent
, callback
, base::Owned(upload_content_type
),
793 base::Owned(upload_content_data
)));
796 void MultipartUploadRequestBase::OnPrepareUploadContent(
797 const std::string
& access_token
,
798 const std::string
& custom_user_agent
,
799 const ReAuthenticateCallback
& callback
,
800 std::string
* upload_content_type
,
801 std::string
* upload_content_data
,
804 RunCallbackOnPrematureFailure(DRIVE_FILE_ERROR
);
807 upload_content_type_
.swap(*upload_content_type
);
808 upload_content_data_
.swap(*upload_content_data
);
809 UrlFetchRequestBase::Start(access_token
, custom_user_agent
, callback
);
812 void MultipartUploadRequestBase::SetBoundaryForTesting(
813 const std::string
& boundary
) {
814 boundary_
= boundary
;
817 bool MultipartUploadRequestBase::GetContentData(
818 std::string
* upload_content_type
,
819 std::string
* upload_content_data
) {
820 // TODO(hirono): Pass stream instead of actual data to reduce memory usage.
821 upload_content_type
->swap(upload_content_type_
);
822 upload_content_data
->swap(upload_content_data_
);
826 void MultipartUploadRequestBase::ProcessURLFetchResults(
827 const URLFetcher
* source
) {
828 // The upload is successfully done. Parse the response which should be
829 // the entry's metadata.
830 const DriveApiErrorCode code
= GetErrorCode();
831 if (code
== HTTP_CREATED
|| code
== HTTP_SUCCESS
) {
832 ParseJsonOnBlockingPool(
833 blocking_task_runner(), response_writer()->data(),
834 base::Bind(&MultipartUploadRequestBase::OnDataParsed
,
835 weak_ptr_factory_
.GetWeakPtr(), code
));
837 OnDataParsed(code
, scoped_ptr
<base::Value
>());
841 void MultipartUploadRequestBase::RunCallbackOnPrematureFailure(
842 DriveApiErrorCode code
) {
843 callback_
.Run(code
, scoped_ptr
<FileResource
>());
846 void MultipartUploadRequestBase::OnURLFetchUploadProgress(
847 const net::URLFetcher
* source
,
850 if (!progress_callback_
.is_null())
851 progress_callback_
.Run(current
, total
);
854 void MultipartUploadRequestBase::OnDataParsed(DriveApiErrorCode code
,
855 scoped_ptr
<base::Value
> value
) {
856 DCHECK(CalledOnValidThread());
858 callback_
.Run(code
, google_apis::FileResource::CreateFrom(*value
));
860 callback_
.Run(DRIVE_PARSE_ERROR
, scoped_ptr
<FileResource
>());
861 OnProcessURLFetchResultsComplete();
864 //============================ DownloadFileRequestBase =========================
866 DownloadFileRequestBase::DownloadFileRequestBase(
867 RequestSender
* sender
,
868 const DownloadActionCallback
& download_action_callback
,
869 const GetContentCallback
& get_content_callback
,
870 const ProgressCallback
& progress_callback
,
871 const GURL
& download_url
,
872 const base::FilePath
& output_file_path
)
873 : UrlFetchRequestBase(sender
),
874 download_action_callback_(download_action_callback
),
875 get_content_callback_(get_content_callback
),
876 progress_callback_(progress_callback
),
877 download_url_(download_url
),
878 output_file_path_(output_file_path
) {
879 DCHECK(!download_action_callback_
.is_null());
880 DCHECK(!output_file_path_
.empty());
881 // get_content_callback may be null.
884 DownloadFileRequestBase::~DownloadFileRequestBase() {}
886 // Overridden from UrlFetchRequestBase.
887 GURL
DownloadFileRequestBase::GetURL() const {
888 return download_url_
;
891 void DownloadFileRequestBase::GetOutputFilePath(
892 base::FilePath
* local_file_path
,
893 GetContentCallback
* get_content_callback
) {
894 // Configure so that the downloaded content is saved to |output_file_path_|.
895 *local_file_path
= output_file_path_
;
896 *get_content_callback
= get_content_callback_
;
899 void DownloadFileRequestBase::OnURLFetchDownloadProgress(
900 const URLFetcher
* source
,
903 if (!progress_callback_
.is_null())
904 progress_callback_
.Run(current
, total
);
907 void DownloadFileRequestBase::ProcessURLFetchResults(const URLFetcher
* source
) {
908 DriveApiErrorCode code
= GetErrorCode();
910 // Take over the ownership of the the downloaded temp file.
911 base::FilePath temp_file
;
912 if (code
== HTTP_SUCCESS
) {
913 response_writer()->DisownFile();
914 temp_file
= output_file_path_
;
917 download_action_callback_
.Run(code
, temp_file
);
918 OnProcessURLFetchResultsComplete();
921 void DownloadFileRequestBase::RunCallbackOnPrematureFailure(
922 DriveApiErrorCode code
) {
923 download_action_callback_
.Run(code
, base::FilePath());
926 } // namespace google_apis