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/thread_task_runner_handle.h"
17 #include "base/values.h"
18 #include "google_apis/drive/drive_api_parser.h"
19 #include "google_apis/drive/request_sender.h"
20 #include "google_apis/drive/request_util.h"
21 #include "google_apis/drive/task_util.h"
22 #include "google_apis/drive/time_util.h"
23 #include "net/base/elements_upload_data_stream.h"
24 #include "net/base/io_buffer.h"
25 #include "net/base/load_flags.h"
26 #include "net/base/net_errors.h"
27 #include "net/base/upload_bytes_element_reader.h"
28 #include "net/base/upload_data_stream.h"
29 #include "net/base/upload_element_reader.h"
30 #include "net/base/upload_file_element_reader.h"
31 #include "net/http/http_byte_range.h"
32 #include "net/http/http_response_headers.h"
33 #include "net/http/http_util.h"
34 #include "net/url_request/url_fetcher.h"
35 #include "net/url_request/url_request_status.h"
37 using net::URLFetcher
;
41 // Template for optional OAuth2 authorization HTTP header.
42 const char kAuthorizationHeaderFormat
[] = "Authorization: Bearer %s";
43 // Template for GData API version HTTP header.
44 const char kGDataVersionHeader
[] = "GData-Version: 3.0";
46 // Maximum number of attempts for re-authentication per request.
47 const int kMaxReAuthenticateAttemptsPerRequest
= 1;
49 // Template for initiate upload of both GData WAPI and Drive API v2.
50 const char kUploadContentType
[] = "X-Upload-Content-Type: ";
51 const char kUploadContentLength
[] = "X-Upload-Content-Length: ";
52 const char kUploadResponseLocation
[] = "location";
54 // Template for upload data range of both GData WAPI and Drive API v2.
55 const char kUploadContentRange
[] = "Content-Range: bytes ";
56 const char kUploadResponseRange
[] = "range";
59 const char kJsonMimeType
[] = "application/json";
61 // Mime type of multipart related.
62 const char kMultipartRelatedMimeTypePrefix
[] =
63 "multipart/related; boundary=";
65 // Mime type of multipart mixed.
66 const char kMultipartMixedMimeTypePrefix
[] =
67 "multipart/mixed; boundary=";
69 // Header for each item in a multipart message.
70 const char kMultipartItemHeaderFormat
[] = "--%s\nContent-Type: %s\n\n";
72 // Footer for whole multipart message.
73 const char kMultipartFooterFormat
[] = "--%s--";
75 // Characters to be used for multipart/related boundary.
76 const char kBoundaryCharacters
[] =
77 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
79 // Size of multipart/related's boundary.
80 const char kBoundarySize
= 70;
82 // Parses JSON passed in |json| on |blocking_task_runner|. Runs |callback| on
83 // the calling thread when finished with either success or failure.
84 // The callback must not be null.
85 void ParseJsonOnBlockingPool(
86 base::TaskRunner
* blocking_task_runner
,
87 const std::string
& json
,
88 const base::Callback
<void(scoped_ptr
<base::Value
> value
)>& callback
) {
89 base::PostTaskAndReplyWithResult(
92 base::Bind(&google_apis::ParseJson
, json
),
96 // Returns response headers as a string. Returns a warning message if
97 // |url_fetcher| does not contain a valid response. Used only for debugging.
98 std::string
GetResponseHeadersAsString(const URLFetcher
* url_fetcher
) {
99 // net::HttpResponseHeaders::raw_headers(), as the name implies, stores
100 // all headers in their raw format, i.e each header is null-terminated.
101 // So logging raw_headers() only shows the first header, which is probably
102 // the status line. GetNormalizedHeaders, on the other hand, will show all
103 // the headers, one per line, which is probably what we want.
105 // Check that response code indicates response headers are valid (i.e. not
106 // malformed) before we retrieve the headers.
107 if (url_fetcher
->GetResponseCode() == URLFetcher::RESPONSE_CODE_INVALID
) {
108 headers
.assign("Response headers are malformed!!");
110 url_fetcher
->GetResponseHeaders()->GetNormalizedHeaders(&headers
);
115 // Obtains the multipart body for the metadata string and file contents. If
116 // predetermined_boundary is empty, the function generates the boundary string.
117 bool GetMultipartContent(const std::string
& predetermined_boundary
,
118 const std::string
& metadata_json
,
119 const std::string
& content_type
,
120 const base::FilePath
& path
,
121 std::string
* upload_content_type
,
122 std::string
* upload_content_data
) {
123 std::vector
<google_apis::ContentTypeAndData
> parts(2);
124 parts
[0].type
= kJsonMimeType
;
125 parts
[0].data
= metadata_json
;
126 parts
[1].type
= content_type
;
127 if (!ReadFileToString(path
, &parts
[1].data
))
130 google_apis::ContentTypeAndData output
;
131 GenerateMultipartBody(
132 google_apis::MULTIPART_RELATED
, predetermined_boundary
, parts
, &output
);
133 upload_content_type
->swap(output
.type
);
134 upload_content_data
->swap(output
.data
);
140 namespace google_apis
{
142 scoped_ptr
<base::Value
> ParseJson(const std::string
& json
) {
144 std::string error_message
;
145 scoped_ptr
<base::Value
> value(base::JSONReader::ReadAndReturnError(
146 json
, base::JSON_PARSE_RFC
, &error_code
, &error_message
));
149 std::string trimmed_json
;
150 if (json
.size() < 80) {
153 // Take the first 50 and the last 10 bytes.
154 trimmed_json
= base::StringPrintf(
156 json
.substr(0, 50).c_str(),
157 base::Uint64ToString(json
.size() - 60).c_str(),
158 json
.substr(json
.size() - 10).c_str());
160 LOG(WARNING
) << "Error while parsing entry response: " << error_message
161 << ", code: " << error_code
<< ", json:\n" << trimmed_json
;
166 void GenerateMultipartBody(MultipartType multipart_type
,
167 const std::string
& predetermined_boundary
,
168 const std::vector
<ContentTypeAndData
>& parts
,
169 ContentTypeAndData
* output
) {
170 std::string boundary
;
171 // Generate random boundary.
172 if (predetermined_boundary
.empty()) {
174 boundary
.resize(kBoundarySize
);
175 for (int i
= 0; i
< kBoundarySize
; ++i
) {
176 // Subtract 2 from the array size to exclude '\0', and to turn the size
177 // into the last index.
178 const int last_char_index
= arraysize(kBoundaryCharacters
) - 2;
179 boundary
[i
] = kBoundaryCharacters
[base::RandInt(0, last_char_index
)];
181 bool conflict_with_content
= false;
182 for (auto& part
: parts
) {
183 if (part
.data
.find(boundary
, 0) != std::string::npos
) {
184 conflict_with_content
= true;
188 if (!conflict_with_content
)
192 boundary
= predetermined_boundary
;
195 switch (multipart_type
) {
196 case MULTIPART_RELATED
:
197 output
->type
= kMultipartRelatedMimeTypePrefix
+ boundary
;
199 case MULTIPART_MIXED
:
200 output
->type
= kMultipartMixedMimeTypePrefix
+ boundary
;
204 output
->data
.clear();
205 for (auto& part
: parts
) {
206 output
->data
.append(base::StringPrintf(
207 kMultipartItemHeaderFormat
, boundary
.c_str(), part
.type
.c_str()));
208 output
->data
.append(part
.data
);
209 output
->data
.append("\n");
212 base::StringPrintf(kMultipartFooterFormat
, boundary
.c_str()));
215 //=========================== ResponseWriter ==================================
216 ResponseWriter::ResponseWriter(base::SequencedTaskRunner
* file_task_runner
,
217 const base::FilePath
& file_path
,
218 const GetContentCallback
& get_content_callback
)
219 : get_content_callback_(get_content_callback
),
220 weak_ptr_factory_(this) {
221 if (!file_path
.empty()) {
223 new net::URLFetcherFileWriter(file_task_runner
, file_path
));
227 ResponseWriter::~ResponseWriter() {
230 void ResponseWriter::DisownFile() {
231 DCHECK(file_writer_
);
232 file_writer_
->DisownFile();
235 int ResponseWriter::Initialize(const net::CompletionCallback
& callback
) {
237 return file_writer_
->Initialize(callback
);
243 int ResponseWriter::Write(net::IOBuffer
* buffer
,
245 const net::CompletionCallback
& callback
) {
246 if (!get_content_callback_
.is_null()) {
247 get_content_callback_
.Run(
249 make_scoped_ptr(new std::string(buffer
->data(), num_bytes
)));
253 const int result
= file_writer_
->Write(
255 base::Bind(&ResponseWriter::DidWrite
,
256 weak_ptr_factory_
.GetWeakPtr(),
257 make_scoped_refptr(buffer
), callback
));
258 if (result
!= net::ERR_IO_PENDING
)
259 DidWrite(buffer
, net::CompletionCallback(), result
);
263 data_
.append(buffer
->data(), num_bytes
);
267 int ResponseWriter::Finish(const net::CompletionCallback
& callback
) {
269 return file_writer_
->Finish(callback
);
274 void ResponseWriter::DidWrite(scoped_refptr
<net::IOBuffer
> buffer
,
275 const net::CompletionCallback
& callback
,
278 // Even if file_writer_ is used, append the data to |data_|, so that it can
279 // be used to get error information in case of server side errors.
280 // The size limit is to avoid consuming too much redundant memory.
281 const size_t kMaxStringSize
= 1024*1024;
282 if (data_
.size() < kMaxStringSize
) {
283 data_
.append(buffer
->data(), std::min(static_cast<size_t>(result
),
284 kMaxStringSize
- data_
.size()));
288 if (!callback
.is_null())
289 callback
.Run(result
);
292 //============================ UrlFetchRequestBase ===========================
294 UrlFetchRequestBase::UrlFetchRequestBase(RequestSender
* sender
)
295 : re_authenticate_count_(0),
296 response_writer_(NULL
),
298 error_code_(DRIVE_OTHER_ERROR
),
299 weak_ptr_factory_(this) {
302 UrlFetchRequestBase::~UrlFetchRequestBase() {}
304 void UrlFetchRequestBase::Start(const std::string
& access_token
,
305 const std::string
& custom_user_agent
,
306 const ReAuthenticateCallback
& callback
) {
307 DCHECK(CalledOnValidThread());
308 DCHECK(!access_token
.empty());
309 DCHECK(!callback
.is_null());
310 DCHECK(re_authenticate_callback_
.is_null());
311 Prepare(base::Bind(&UrlFetchRequestBase::StartAfterPrepare
,
312 weak_ptr_factory_
.GetWeakPtr(), access_token
,
313 custom_user_agent
, callback
));
316 void UrlFetchRequestBase::Prepare(const PrepareCallback
& callback
) {
317 DCHECK(CalledOnValidThread());
318 DCHECK(!callback
.is_null());
319 callback
.Run(HTTP_SUCCESS
);
322 void UrlFetchRequestBase::StartAfterPrepare(
323 const std::string
& access_token
,
324 const std::string
& custom_user_agent
,
325 const ReAuthenticateCallback
& callback
,
326 DriveApiErrorCode code
) {
327 DCHECK(CalledOnValidThread());
328 DCHECK(!access_token
.empty());
329 DCHECK(!callback
.is_null());
330 DCHECK(re_authenticate_callback_
.is_null());
332 const GURL url
= GetURL();
333 DriveApiErrorCode error_code
;
334 if (IsSuccessfulDriveApiErrorCode(code
))
336 else if (url
.is_empty())
337 error_code
= DRIVE_OTHER_ERROR
;
339 error_code
= HTTP_SUCCESS
;
341 if (error_code
!= HTTP_SUCCESS
) {
342 // Error is found on generating the url or preparing the request. Send the
343 // error message to the callback, and then return immediately without trying
344 // to connect to the server. We need to call CompleteRequestWithError
345 // asynchronously because client code does not assume result callback is
346 // called synchronously.
347 base::ThreadTaskRunnerHandle::Get()->PostTask(
348 FROM_HERE
, base::Bind(&UrlFetchRequestBase::CompleteRequestWithError
,
349 weak_ptr_factory_
.GetWeakPtr(), error_code
));
353 re_authenticate_callback_
= callback
;
354 DVLOG(1) << "URL: " << url
.spec();
356 URLFetcher::RequestType request_type
= GetRequestType();
357 url_fetcher_
= URLFetcher::Create(url
, request_type
, this);
358 url_fetcher_
->SetRequestContext(sender_
->url_request_context_getter());
359 // Always set flags to neither send nor save cookies.
360 url_fetcher_
->SetLoadFlags(
361 net::LOAD_DO_NOT_SEND_COOKIES
| net::LOAD_DO_NOT_SAVE_COOKIES
|
362 net::LOAD_DISABLE_CACHE
);
364 base::FilePath output_file_path
;
365 GetContentCallback get_content_callback
;
366 GetOutputFilePath(&output_file_path
, &get_content_callback
);
367 if (!get_content_callback
.is_null())
368 get_content_callback
= CreateRelayCallback(get_content_callback
);
369 response_writer_
= new ResponseWriter(blocking_task_runner(),
371 get_content_callback
);
372 url_fetcher_
->SaveResponseWithWriter(
373 scoped_ptr
<net::URLFetcherResponseWriter
>(response_writer_
));
375 // Add request headers.
376 // Note that SetExtraRequestHeaders clears the current headers and sets it
377 // to the passed-in headers, so calling it for each header will result in
378 // only the last header being set in request headers.
379 if (!custom_user_agent
.empty())
380 url_fetcher_
->AddExtraRequestHeader("User-Agent: " + custom_user_agent
);
381 url_fetcher_
->AddExtraRequestHeader(kGDataVersionHeader
);
382 url_fetcher_
->AddExtraRequestHeader(
383 base::StringPrintf(kAuthorizationHeaderFormat
, access_token
.data()));
384 std::vector
<std::string
> headers
= GetExtraRequestHeaders();
385 for (size_t i
= 0; i
< headers
.size(); ++i
) {
386 url_fetcher_
->AddExtraRequestHeader(headers
[i
]);
387 DVLOG(1) << "Extra header: " << headers
[i
];
390 // Set upload data if available.
391 std::string upload_content_type
;
392 std::string upload_content
;
393 if (GetContentData(&upload_content_type
, &upload_content
)) {
394 url_fetcher_
->SetUploadData(upload_content_type
, upload_content
);
396 base::FilePath local_file_path
;
397 int64 range_offset
= 0;
398 int64 range_length
= 0;
399 if (GetContentFile(&local_file_path
, &range_offset
, &range_length
,
400 &upload_content_type
)) {
401 url_fetcher_
->SetUploadFilePath(
406 blocking_task_runner());
408 // Even if there is no content data, UrlFetcher requires to set empty
409 // upload data string for POST, PUT and PATCH methods, explicitly.
410 // It is because that most requests of those methods have non-empty
411 // body, and UrlFetcher checks whether it is actually not forgotten.
412 if (request_type
== URLFetcher::POST
||
413 request_type
== URLFetcher::PUT
||
414 request_type
== URLFetcher::PATCH
) {
415 // Set empty upload content-type and upload content, so that
416 // the request will have no "Content-type: " header and no content.
417 url_fetcher_
->SetUploadData(std::string(), std::string());
422 url_fetcher_
->Start();
425 URLFetcher::RequestType
UrlFetchRequestBase::GetRequestType() const {
426 return URLFetcher::GET
;
429 std::vector
<std::string
> UrlFetchRequestBase::GetExtraRequestHeaders() const {
430 return std::vector
<std::string
>();
433 bool UrlFetchRequestBase::GetContentData(std::string
* upload_content_type
,
434 std::string
* upload_content
) {
438 bool UrlFetchRequestBase::GetContentFile(base::FilePath
* local_file_path
,
441 std::string
* upload_content_type
) {
445 void UrlFetchRequestBase::GetOutputFilePath(
446 base::FilePath
* local_file_path
,
447 GetContentCallback
* get_content_callback
) {
450 void UrlFetchRequestBase::Cancel() {
451 response_writer_
= NULL
;
452 url_fetcher_
.reset(NULL
);
453 CompleteRequestWithError(DRIVE_CANCELLED
);
456 DriveApiErrorCode
UrlFetchRequestBase::GetErrorCode() {
460 bool UrlFetchRequestBase::CalledOnValidThread() {
461 return thread_checker_
.CalledOnValidThread();
464 base::SequencedTaskRunner
* UrlFetchRequestBase::blocking_task_runner() const {
465 return sender_
->blocking_task_runner();
468 void UrlFetchRequestBase::OnProcessURLFetchResultsComplete() {
469 sender_
->RequestFinished(this);
472 void UrlFetchRequestBase::OnURLFetchComplete(const URLFetcher
* source
) {
473 DVLOG(1) << "Response headers:\n" << GetResponseHeadersAsString(source
);
475 // Determine error code.
476 error_code_
= static_cast<DriveApiErrorCode
>(source
->GetResponseCode());
477 if (!source
->GetStatus().is_success()) {
478 switch (source
->GetStatus().error()) {
479 case net::ERR_NETWORK_CHANGED
:
480 error_code_
= DRIVE_NO_CONNECTION
;
483 error_code_
= DRIVE_OTHER_ERROR
;
487 // The server may return detailed error status in JSON.
488 // See https://developers.google.com/drive/handle-errors
489 if (!IsSuccessfulDriveApiErrorCode(error_code_
)) {
490 DVLOG(1) << response_writer_
->data();
492 const char kErrorKey
[] = "error";
493 const char kErrorErrorsKey
[] = "errors";
494 const char kErrorReasonKey
[] = "reason";
495 const char kErrorMessageKey
[] = "message";
496 const char kErrorReasonRateLimitExceeded
[] = "rateLimitExceeded";
497 const char kErrorReasonUserRateLimitExceeded
[] = "userRateLimitExceeded";
498 const char kErrorReasonQuotaExceeded
[] = "quotaExceeded";
500 scoped_ptr
<base::Value
> value(ParseJson(response_writer_
->data()));
501 base::DictionaryValue
* dictionary
= NULL
;
502 base::DictionaryValue
* error
= NULL
;
504 value
->GetAsDictionary(&dictionary
) &&
505 dictionary
->GetDictionaryWithoutPathExpansion(kErrorKey
, &error
)) {
506 // Get error message.
508 error
->GetStringWithoutPathExpansion(kErrorMessageKey
, &message
);
509 DLOG(ERROR
) << "code: " << error_code_
<< ", message: " << message
;
511 // Override the error code based on the reason of the first error.
512 base::ListValue
* errors
= NULL
;
513 base::DictionaryValue
* first_error
= NULL
;
514 if (error
->GetListWithoutPathExpansion(kErrorErrorsKey
, &errors
) &&
515 errors
->GetDictionary(0, &first_error
)) {
517 first_error
->GetStringWithoutPathExpansion(kErrorReasonKey
, &reason
);
518 if (reason
== kErrorReasonRateLimitExceeded
||
519 reason
== kErrorReasonUserRateLimitExceeded
)
520 error_code_
= HTTP_SERVICE_UNAVAILABLE
;
521 if (reason
== kErrorReasonQuotaExceeded
)
522 error_code_
= DRIVE_NO_SPACE
;
527 // Handle authentication failure.
528 if (error_code_
== HTTP_UNAUTHORIZED
) {
529 if (++re_authenticate_count_
<= kMaxReAuthenticateAttemptsPerRequest
) {
530 // Reset re_authenticate_callback_ so Start() can be called again.
531 ReAuthenticateCallback callback
= re_authenticate_callback_
;
532 re_authenticate_callback_
.Reset();
537 OnAuthFailed(error_code_
);
541 // Overridden by each specialization
542 ProcessURLFetchResults(source
);
545 void UrlFetchRequestBase::CompleteRequestWithError(DriveApiErrorCode code
) {
546 RunCallbackOnPrematureFailure(code
);
547 sender_
->RequestFinished(this);
550 void UrlFetchRequestBase::OnAuthFailed(DriveApiErrorCode code
) {
551 CompleteRequestWithError(code
);
554 base::WeakPtr
<AuthenticatedRequestInterface
>
555 UrlFetchRequestBase::GetWeakPtr() {
556 return weak_ptr_factory_
.GetWeakPtr();
559 //============================ BatchableRequestBase ============================
561 net::URLFetcher::RequestType
BatchableRequestBase::GetRequestType() const {
562 return UrlFetchRequestBase::GetRequestType();
565 std::vector
<std::string
> BatchableRequestBase::GetExtraRequestHeaders() const {
566 return UrlFetchRequestBase::GetExtraRequestHeaders();
569 void BatchableRequestBase::Prepare(const PrepareCallback
& callback
) {
570 return UrlFetchRequestBase::Prepare(callback
);
573 bool BatchableRequestBase::GetContentData(
574 std::string
* upload_content_type
, std::string
* upload_content
) {
575 return UrlFetchRequestBase::GetContentData(
576 upload_content_type
, upload_content
);
579 void BatchableRequestBase::ProcessURLFetchResults(
580 const net::URLFetcher
* source
) {
581 ProcessURLFetchResults(GetErrorCode(), response_writer()->data());
584 //============================ EntryActionRequest ============================
586 EntryActionRequest::EntryActionRequest(RequestSender
* sender
,
587 const EntryActionCallback
& callback
)
588 : UrlFetchRequestBase(sender
),
589 callback_(callback
) {
590 DCHECK(!callback_
.is_null());
593 EntryActionRequest::~EntryActionRequest() {}
595 void EntryActionRequest::ProcessURLFetchResults(const URLFetcher
* source
) {
596 callback_
.Run(GetErrorCode());
597 OnProcessURLFetchResultsComplete();
600 void EntryActionRequest::RunCallbackOnPrematureFailure(DriveApiErrorCode code
) {
604 //========================= InitiateUploadRequestBase ========================
606 InitiateUploadRequestBase::InitiateUploadRequestBase(
607 RequestSender
* sender
,
608 const InitiateUploadCallback
& callback
,
609 const std::string
& content_type
,
610 int64 content_length
)
611 : UrlFetchRequestBase(sender
),
613 content_type_(content_type
),
614 content_length_(content_length
) {
615 DCHECK(!callback_
.is_null());
616 DCHECK(!content_type_
.empty());
617 DCHECK_GE(content_length_
, 0);
620 InitiateUploadRequestBase::~InitiateUploadRequestBase() {}
622 void InitiateUploadRequestBase::ProcessURLFetchResults(
623 const URLFetcher
* source
) {
624 DriveApiErrorCode code
= GetErrorCode();
626 std::string upload_location
;
627 if (code
== HTTP_SUCCESS
) {
628 // Retrieve value of the first "Location" header.
629 source
->GetResponseHeaders()->EnumerateHeader(NULL
,
630 kUploadResponseLocation
,
634 callback_
.Run(code
, GURL(upload_location
));
635 OnProcessURLFetchResultsComplete();
638 void InitiateUploadRequestBase::RunCallbackOnPrematureFailure(
639 DriveApiErrorCode code
) {
640 callback_
.Run(code
, GURL());
643 std::vector
<std::string
>
644 InitiateUploadRequestBase::GetExtraRequestHeaders() const {
645 std::vector
<std::string
> headers
;
646 headers
.push_back(kUploadContentType
+ content_type_
);
648 kUploadContentLength
+ base::Int64ToString(content_length_
));
652 //============================ UploadRangeResponse =============================
654 UploadRangeResponse::UploadRangeResponse()
655 : code(HTTP_SUCCESS
),
656 start_position_received(0),
657 end_position_received(0) {
660 UploadRangeResponse::UploadRangeResponse(DriveApiErrorCode code
,
661 int64 start_position_received
,
662 int64 end_position_received
)
664 start_position_received(start_position_received
),
665 end_position_received(end_position_received
) {
668 UploadRangeResponse::~UploadRangeResponse() {
671 //========================== UploadRangeRequestBase ==========================
673 UploadRangeRequestBase::UploadRangeRequestBase(RequestSender
* sender
,
674 const GURL
& upload_url
)
675 : UrlFetchRequestBase(sender
),
676 upload_url_(upload_url
),
677 weak_ptr_factory_(this) {
680 UploadRangeRequestBase::~UploadRangeRequestBase() {}
682 GURL
UploadRangeRequestBase::GetURL() const {
683 // This is very tricky to get json from this request. To do that, &alt=json
684 // has to be appended not here but in InitiateUploadRequestBase::GetURL().
688 URLFetcher::RequestType
UploadRangeRequestBase::GetRequestType() const {
689 return URLFetcher::PUT
;
692 void UploadRangeRequestBase::ProcessURLFetchResults(
693 const URLFetcher
* source
) {
694 DriveApiErrorCode code
= GetErrorCode();
695 net::HttpResponseHeaders
* hdrs
= source
->GetResponseHeaders();
697 if (code
== HTTP_RESUME_INCOMPLETE
) {
698 // Retrieve value of the first "Range" header.
699 // The Range header is appeared only if there is at least one received
700 // byte. So, initialize the positions by 0 so that the [0,0) will be
701 // returned via the |callback_| for empty data case.
702 int64 start_position_received
= 0;
703 int64 end_position_received
= 0;
704 std::string range_received
;
705 hdrs
->EnumerateHeader(NULL
, kUploadResponseRange
, &range_received
);
706 if (!range_received
.empty()) { // Parse the range header.
707 std::vector
<net::HttpByteRange
> ranges
;
708 if (net::HttpUtil::ParseRangeHeader(range_received
, &ranges
) &&
710 // We only care about the first start-end pair in the range.
712 // Range header represents the range inclusively, while we are treating
713 // ranges exclusively (i.e., end_position_received should be one passed
714 // the last valid index). So "+ 1" is added.
715 start_position_received
= ranges
[0].first_byte_position();
716 end_position_received
= ranges
[0].last_byte_position() + 1;
719 // The Range header has the received data range, so the start position
720 // should be always 0.
721 DCHECK_EQ(start_position_received
, 0);
723 OnRangeRequestComplete(UploadRangeResponse(code
,
724 start_position_received
,
725 end_position_received
),
726 scoped_ptr
<base::Value
>());
728 OnProcessURLFetchResultsComplete();
729 } else if (code
== HTTP_CREATED
|| code
== HTTP_SUCCESS
) {
730 // The upload is successfully done. Parse the response which should be
731 // the entry's metadata.
732 ParseJsonOnBlockingPool(blocking_task_runner(),
733 response_writer()->data(),
734 base::Bind(&UploadRangeRequestBase::OnDataParsed
,
735 weak_ptr_factory_
.GetWeakPtr(),
738 // Failed to upload. Run callbacks to notify the error.
739 OnRangeRequestComplete(
740 UploadRangeResponse(code
, -1, -1), scoped_ptr
<base::Value
>());
741 OnProcessURLFetchResultsComplete();
745 void UploadRangeRequestBase::OnDataParsed(DriveApiErrorCode code
,
746 scoped_ptr
<base::Value
> value
) {
747 DCHECK(CalledOnValidThread());
748 DCHECK(code
== HTTP_CREATED
|| code
== HTTP_SUCCESS
);
750 OnRangeRequestComplete(UploadRangeResponse(code
, -1, -1), value
.Pass());
751 OnProcessURLFetchResultsComplete();
754 void UploadRangeRequestBase::RunCallbackOnPrematureFailure(
755 DriveApiErrorCode code
) {
756 OnRangeRequestComplete(
757 UploadRangeResponse(code
, 0, 0), scoped_ptr
<base::Value
>());
760 //========================== ResumeUploadRequestBase =========================
762 ResumeUploadRequestBase::ResumeUploadRequestBase(
763 RequestSender
* sender
,
764 const GURL
& upload_location
,
765 int64 start_position
,
767 int64 content_length
,
768 const std::string
& content_type
,
769 const base::FilePath
& local_file_path
)
770 : UploadRangeRequestBase(sender
, upload_location
),
771 start_position_(start_position
),
772 end_position_(end_position
),
773 content_length_(content_length
),
774 content_type_(content_type
),
775 local_file_path_(local_file_path
) {
776 DCHECK_LE(start_position_
, end_position_
);
779 ResumeUploadRequestBase::~ResumeUploadRequestBase() {}
781 std::vector
<std::string
>
782 ResumeUploadRequestBase::GetExtraRequestHeaders() const {
783 if (content_length_
== 0) {
784 // For uploading an empty document, just PUT an empty content.
785 DCHECK_EQ(start_position_
, 0);
786 DCHECK_EQ(end_position_
, 0);
787 return std::vector
<std::string
>();
790 // The header looks like
791 // Content-Range: bytes <start_position>-<end_position>/<content_length>
793 // Content-Range: bytes 7864320-8388607/13851821
794 // The header takes inclusive range, so we adjust by "end_position - 1".
795 DCHECK_GE(start_position_
, 0);
796 DCHECK_GT(end_position_
, 0);
797 DCHECK_GE(content_length_
, 0);
799 std::vector
<std::string
> headers
;
801 std::string(kUploadContentRange
) +
802 base::Int64ToString(start_position_
) + "-" +
803 base::Int64ToString(end_position_
- 1) + "/" +
804 base::Int64ToString(content_length_
));
808 bool ResumeUploadRequestBase::GetContentFile(
809 base::FilePath
* local_file_path
,
812 std::string
* upload_content_type
) {
813 if (start_position_
== end_position_
) {
818 *local_file_path
= local_file_path_
;
819 *range_offset
= start_position_
;
820 *range_length
= end_position_
- start_position_
;
821 *upload_content_type
= content_type_
;
825 //======================== GetUploadStatusRequestBase ========================
827 GetUploadStatusRequestBase::GetUploadStatusRequestBase(RequestSender
* sender
,
828 const GURL
& upload_url
,
829 int64 content_length
)
830 : UploadRangeRequestBase(sender
, upload_url
),
831 content_length_(content_length
) {}
833 GetUploadStatusRequestBase::~GetUploadStatusRequestBase() {}
835 std::vector
<std::string
>
836 GetUploadStatusRequestBase::GetExtraRequestHeaders() const {
837 // The header looks like
838 // Content-Range: bytes */<content_length>
840 // Content-Range: bytes */13851821
841 DCHECK_GE(content_length_
, 0);
843 std::vector
<std::string
> headers
;
845 std::string(kUploadContentRange
) + "*/" +
846 base::Int64ToString(content_length_
));
850 //========================= MultipartUploadRequestBase ========================
852 MultipartUploadRequestBase::MultipartUploadRequestBase(
853 RequestSender
* sender
,
854 const std::string
& metadata_json
,
855 const std::string
& content_type
,
856 int64 content_length
,
857 const base::FilePath
& local_file_path
,
858 const FileResourceCallback
& callback
,
859 const ProgressCallback
& progress_callback
)
860 : BatchableRequestBase(sender
),
861 metadata_json_(metadata_json
),
862 content_type_(content_type
),
863 local_path_(local_file_path
),
865 progress_callback_(progress_callback
),
866 weak_ptr_factory_(this) {
867 DCHECK(!content_type
.empty());
868 DCHECK_GE(content_length
, 0);
869 DCHECK(!local_file_path
.empty());
870 DCHECK(!callback
.is_null());
873 MultipartUploadRequestBase::~MultipartUploadRequestBase() {
876 void MultipartUploadRequestBase::Prepare(const PrepareCallback
& callback
) {
877 // If the request is cancelled, the request instance will be deleted in
878 // |UrlFetchRequestBase::Cancel| and OnPrepareUploadContent won't be called.
879 std::string
* const upload_content_type
= new std::string();
880 std::string
* const upload_content_data
= new std::string();
881 PostTaskAndReplyWithResult(
882 blocking_task_runner(), FROM_HERE
,
883 base::Bind(&GetMultipartContent
, boundary_
, metadata_json_
, content_type_
,
884 local_path_
, base::Unretained(upload_content_type
),
885 base::Unretained(upload_content_data
)),
886 base::Bind(&MultipartUploadRequestBase::OnPrepareUploadContent
,
887 weak_ptr_factory_
.GetWeakPtr(), callback
,
888 base::Owned(upload_content_type
),
889 base::Owned(upload_content_data
)));
892 void MultipartUploadRequestBase::OnPrepareUploadContent(
893 const PrepareCallback
& callback
,
894 std::string
* upload_content_type
,
895 std::string
* upload_content_data
,
898 callback
.Run(DRIVE_FILE_ERROR
);
901 upload_content_type_
.swap(*upload_content_type
);
902 upload_content_data_
.swap(*upload_content_data
);
903 callback
.Run(HTTP_SUCCESS
);
906 void MultipartUploadRequestBase::SetBoundaryForTesting(
907 const std::string
& boundary
) {
908 boundary_
= boundary
;
911 bool MultipartUploadRequestBase::GetContentData(
912 std::string
* upload_content_type
,
913 std::string
* upload_content_data
) {
914 // TODO(hirono): Pass stream instead of actual data to reduce memory usage.
915 upload_content_type
->swap(upload_content_type_
);
916 upload_content_data
->swap(upload_content_data_
);
920 void MultipartUploadRequestBase::ProcessURLFetchResults(
921 DriveApiErrorCode code
, const std::string
& body
) {
922 // The upload is successfully done. Parse the response which should be
923 // the entry's metadata.
924 if (code
== HTTP_CREATED
|| code
== HTTP_SUCCESS
) {
925 ParseJsonOnBlockingPool(
926 blocking_task_runner(), body
,
927 base::Bind(&MultipartUploadRequestBase::OnDataParsed
,
928 weak_ptr_factory_
.GetWeakPtr(), code
));
930 OnDataParsed(code
, scoped_ptr
<base::Value
>());
934 void MultipartUploadRequestBase::RunCallbackOnPrematureFailure(
935 DriveApiErrorCode code
) {
936 callback_
.Run(code
, scoped_ptr
<FileResource
>());
939 void MultipartUploadRequestBase::OnURLFetchUploadProgress(
940 const net::URLFetcher
* source
,
943 if (!progress_callback_
.is_null())
944 progress_callback_
.Run(current
, total
);
947 void MultipartUploadRequestBase::OnDataParsed(DriveApiErrorCode code
,
948 scoped_ptr
<base::Value
> value
) {
949 DCHECK(CalledOnValidThread());
951 callback_
.Run(code
, google_apis::FileResource::CreateFrom(*value
));
953 callback_
.Run(DRIVE_PARSE_ERROR
, scoped_ptr
<FileResource
>());
954 OnProcessURLFetchResultsComplete();
957 //============================ DownloadFileRequestBase =========================
959 DownloadFileRequestBase::DownloadFileRequestBase(
960 RequestSender
* sender
,
961 const DownloadActionCallback
& download_action_callback
,
962 const GetContentCallback
& get_content_callback
,
963 const ProgressCallback
& progress_callback
,
964 const GURL
& download_url
,
965 const base::FilePath
& output_file_path
)
966 : UrlFetchRequestBase(sender
),
967 download_action_callback_(download_action_callback
),
968 get_content_callback_(get_content_callback
),
969 progress_callback_(progress_callback
),
970 download_url_(download_url
),
971 output_file_path_(output_file_path
) {
972 DCHECK(!download_action_callback_
.is_null());
973 DCHECK(!output_file_path_
.empty());
974 // get_content_callback may be null.
977 DownloadFileRequestBase::~DownloadFileRequestBase() {}
979 // Overridden from UrlFetchRequestBase.
980 GURL
DownloadFileRequestBase::GetURL() const {
981 return download_url_
;
984 void DownloadFileRequestBase::GetOutputFilePath(
985 base::FilePath
* local_file_path
,
986 GetContentCallback
* get_content_callback
) {
987 // Configure so that the downloaded content is saved to |output_file_path_|.
988 *local_file_path
= output_file_path_
;
989 *get_content_callback
= get_content_callback_
;
992 void DownloadFileRequestBase::OnURLFetchDownloadProgress(
993 const URLFetcher
* source
,
996 if (!progress_callback_
.is_null())
997 progress_callback_
.Run(current
, total
);
1000 void DownloadFileRequestBase::ProcessURLFetchResults(const URLFetcher
* source
) {
1001 DriveApiErrorCode code
= GetErrorCode();
1003 // Take over the ownership of the the downloaded temp file.
1004 base::FilePath temp_file
;
1005 if (code
== HTTP_SUCCESS
) {
1006 response_writer()->DisownFile();
1007 temp_file
= output_file_path_
;
1010 download_action_callback_
.Run(code
, temp_file
);
1011 OnProcessURLFetchResultsComplete();
1014 void DownloadFileRequestBase::RunCallbackOnPrematureFailure(
1015 DriveApiErrorCode code
) {
1016 download_action_callback_
.Run(code
, base::FilePath());
1019 } // namespace google_apis