Update V8 to version 4.4.65.
[chromium-blink-merge.git] / google_apis / drive / base_requests.cc
blob6a485e621d8262344bce1ac8611cfde967b550d5
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;
39 namespace {
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";
58 // Mime type of JSON.
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(
90 blocking_task_runner,
91 FROM_HERE,
92 base::Bind(&google_apis::ParseJson, json),
93 callback);
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.
104 std::string headers;
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!!");
109 } else {
110 url_fetcher->GetResponseHeaders()->GetNormalizedHeaders(&headers);
112 return 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))
128 return false;
130 google_apis::ContentTypeAndData output;
131 GenerateMultipartBody(google_apis::MULTIPART_RELATED, predetermined_boundary,
132 parts, &output, nullptr);
133 upload_content_type->swap(output.type);
134 upload_content_data->swap(output.data);
135 return true;
138 } // namespace
140 namespace google_apis {
142 scoped_ptr<base::Value> ParseJson(const std::string& json) {
143 int error_code = -1;
144 std::string error_message;
145 scoped_ptr<base::Value> value(base::JSONReader::ReadAndReturnError(
146 json, base::JSON_PARSE_RFC, &error_code, &error_message));
148 if (!value.get()) {
149 std::string trimmed_json;
150 if (json.size() < 80) {
151 trimmed_json = json;
152 } else {
153 // Take the first 50 and the last 10 bytes.
154 trimmed_json = base::StringPrintf(
155 "%s [%s bytes] %s",
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;
163 return value.Pass();
166 void GenerateMultipartBody(MultipartType multipart_type,
167 const std::string& predetermined_boundary,
168 const std::vector<ContentTypeAndData>& parts,
169 ContentTypeAndData* output,
170 std::vector<uint64>* data_offset) {
171 std::string boundary;
172 // Generate random boundary.
173 if (predetermined_boundary.empty()) {
174 while (true) {
175 boundary.resize(kBoundarySize);
176 for (int i = 0; i < kBoundarySize; ++i) {
177 // Subtract 2 from the array size to exclude '\0', and to turn the size
178 // into the last index.
179 const int last_char_index = arraysize(kBoundaryCharacters) - 2;
180 boundary[i] = kBoundaryCharacters[base::RandInt(0, last_char_index)];
182 bool conflict_with_content = false;
183 for (auto& part : parts) {
184 if (part.data.find(boundary, 0) != std::string::npos) {
185 conflict_with_content = true;
186 break;
189 if (!conflict_with_content)
190 break;
192 } else {
193 boundary = predetermined_boundary;
196 switch (multipart_type) {
197 case MULTIPART_RELATED:
198 output->type = kMultipartRelatedMimeTypePrefix + boundary;
199 break;
200 case MULTIPART_MIXED:
201 output->type = kMultipartMixedMimeTypePrefix + boundary;
202 break;
205 output->data.clear();
206 if (data_offset)
207 data_offset->clear();
208 for (auto& part : parts) {
209 output->data.append(base::StringPrintf(
210 kMultipartItemHeaderFormat, boundary.c_str(), part.type.c_str()));
211 if (data_offset)
212 data_offset->push_back(output->data.size());
213 output->data.append(part.data);
214 output->data.append("\n");
216 output->data.append(
217 base::StringPrintf(kMultipartFooterFormat, boundary.c_str()));
220 //=========================== ResponseWriter ==================================
221 ResponseWriter::ResponseWriter(base::SequencedTaskRunner* file_task_runner,
222 const base::FilePath& file_path,
223 const GetContentCallback& get_content_callback)
224 : get_content_callback_(get_content_callback),
225 weak_ptr_factory_(this) {
226 if (!file_path.empty()) {
227 file_writer_.reset(
228 new net::URLFetcherFileWriter(file_task_runner, file_path));
232 ResponseWriter::~ResponseWriter() {
235 void ResponseWriter::DisownFile() {
236 DCHECK(file_writer_);
237 file_writer_->DisownFile();
240 int ResponseWriter::Initialize(const net::CompletionCallback& callback) {
241 if (file_writer_)
242 return file_writer_->Initialize(callback);
244 data_.clear();
245 return net::OK;
248 int ResponseWriter::Write(net::IOBuffer* buffer,
249 int num_bytes,
250 const net::CompletionCallback& callback) {
251 if (!get_content_callback_.is_null()) {
252 get_content_callback_.Run(
253 HTTP_SUCCESS,
254 make_scoped_ptr(new std::string(buffer->data(), num_bytes)));
257 if (file_writer_) {
258 const int result = file_writer_->Write(
259 buffer, num_bytes,
260 base::Bind(&ResponseWriter::DidWrite,
261 weak_ptr_factory_.GetWeakPtr(),
262 make_scoped_refptr(buffer), callback));
263 if (result != net::ERR_IO_PENDING)
264 DidWrite(buffer, net::CompletionCallback(), result);
265 return result;
268 data_.append(buffer->data(), num_bytes);
269 return num_bytes;
272 int ResponseWriter::Finish(const net::CompletionCallback& callback) {
273 if (file_writer_)
274 return file_writer_->Finish(callback);
276 return net::OK;
279 void ResponseWriter::DidWrite(scoped_refptr<net::IOBuffer> buffer,
280 const net::CompletionCallback& callback,
281 int result) {
282 if (result > 0) {
283 // Even if file_writer_ is used, append the data to |data_|, so that it can
284 // be used to get error information in case of server side errors.
285 // The size limit is to avoid consuming too much redundant memory.
286 const size_t kMaxStringSize = 1024*1024;
287 if (data_.size() < kMaxStringSize) {
288 data_.append(buffer->data(), std::min(static_cast<size_t>(result),
289 kMaxStringSize - data_.size()));
293 if (!callback.is_null())
294 callback.Run(result);
297 //============================ UrlFetchRequestBase ===========================
299 UrlFetchRequestBase::UrlFetchRequestBase(RequestSender* sender)
300 : re_authenticate_count_(0),
301 response_writer_(NULL),
302 sender_(sender),
303 error_code_(DRIVE_OTHER_ERROR),
304 weak_ptr_factory_(this) {
307 UrlFetchRequestBase::~UrlFetchRequestBase() {}
309 void UrlFetchRequestBase::Start(const std::string& access_token,
310 const std::string& custom_user_agent,
311 const ReAuthenticateCallback& callback) {
312 DCHECK(CalledOnValidThread());
313 DCHECK(!access_token.empty());
314 DCHECK(!callback.is_null());
315 DCHECK(re_authenticate_callback_.is_null());
316 Prepare(base::Bind(&UrlFetchRequestBase::StartAfterPrepare,
317 weak_ptr_factory_.GetWeakPtr(), access_token,
318 custom_user_agent, callback));
321 void UrlFetchRequestBase::Prepare(const PrepareCallback& callback) {
322 DCHECK(CalledOnValidThread());
323 DCHECK(!callback.is_null());
324 callback.Run(HTTP_SUCCESS);
327 void UrlFetchRequestBase::StartAfterPrepare(
328 const std::string& access_token,
329 const std::string& custom_user_agent,
330 const ReAuthenticateCallback& callback,
331 DriveApiErrorCode code) {
332 DCHECK(CalledOnValidThread());
333 DCHECK(!access_token.empty());
334 DCHECK(!callback.is_null());
335 DCHECK(re_authenticate_callback_.is_null());
337 const GURL url = GetURL();
338 DriveApiErrorCode error_code;
339 if (IsSuccessfulDriveApiErrorCode(code))
340 error_code = code;
341 else if (url.is_empty())
342 error_code = DRIVE_OTHER_ERROR;
343 else
344 error_code = HTTP_SUCCESS;
346 if (error_code != HTTP_SUCCESS) {
347 // Error is found on generating the url or preparing the request. Send the
348 // error message to the callback, and then return immediately without trying
349 // to connect to the server. We need to call CompleteRequestWithError
350 // asynchronously because client code does not assume result callback is
351 // called synchronously.
352 base::ThreadTaskRunnerHandle::Get()->PostTask(
353 FROM_HERE, base::Bind(&UrlFetchRequestBase::CompleteRequestWithError,
354 weak_ptr_factory_.GetWeakPtr(), error_code));
355 return;
358 re_authenticate_callback_ = callback;
359 DVLOG(1) << "URL: " << url.spec();
361 URLFetcher::RequestType request_type = GetRequestType();
362 url_fetcher_ = URLFetcher::Create(url, request_type, this);
363 url_fetcher_->SetRequestContext(sender_->url_request_context_getter());
364 // Always set flags to neither send nor save cookies.
365 url_fetcher_->SetLoadFlags(
366 net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES |
367 net::LOAD_DISABLE_CACHE);
369 base::FilePath output_file_path;
370 GetContentCallback get_content_callback;
371 GetOutputFilePath(&output_file_path, &get_content_callback);
372 if (!get_content_callback.is_null())
373 get_content_callback = CreateRelayCallback(get_content_callback);
374 response_writer_ = new ResponseWriter(blocking_task_runner(),
375 output_file_path,
376 get_content_callback);
377 url_fetcher_->SaveResponseWithWriter(
378 scoped_ptr<net::URLFetcherResponseWriter>(response_writer_));
380 // Add request headers.
381 // Note that SetExtraRequestHeaders clears the current headers and sets it
382 // to the passed-in headers, so calling it for each header will result in
383 // only the last header being set in request headers.
384 if (!custom_user_agent.empty())
385 url_fetcher_->AddExtraRequestHeader("User-Agent: " + custom_user_agent);
386 url_fetcher_->AddExtraRequestHeader(kGDataVersionHeader);
387 url_fetcher_->AddExtraRequestHeader(
388 base::StringPrintf(kAuthorizationHeaderFormat, access_token.data()));
389 std::vector<std::string> headers = GetExtraRequestHeaders();
390 for (size_t i = 0; i < headers.size(); ++i) {
391 url_fetcher_->AddExtraRequestHeader(headers[i]);
392 DVLOG(1) << "Extra header: " << headers[i];
395 // Set upload data if available.
396 std::string upload_content_type;
397 std::string upload_content;
398 if (GetContentData(&upload_content_type, &upload_content)) {
399 url_fetcher_->SetUploadData(upload_content_type, upload_content);
400 } else {
401 base::FilePath local_file_path;
402 int64 range_offset = 0;
403 int64 range_length = 0;
404 if (GetContentFile(&local_file_path, &range_offset, &range_length,
405 &upload_content_type)) {
406 url_fetcher_->SetUploadFilePath(
407 upload_content_type,
408 local_file_path,
409 range_offset,
410 range_length,
411 blocking_task_runner());
412 } else {
413 // Even if there is no content data, UrlFetcher requires to set empty
414 // upload data string for POST, PUT and PATCH methods, explicitly.
415 // It is because that most requests of those methods have non-empty
416 // body, and UrlFetcher checks whether it is actually not forgotten.
417 if (request_type == URLFetcher::POST ||
418 request_type == URLFetcher::PUT ||
419 request_type == URLFetcher::PATCH) {
420 // Set empty upload content-type and upload content, so that
421 // the request will have no "Content-type: " header and no content.
422 url_fetcher_->SetUploadData(std::string(), std::string());
427 url_fetcher_->Start();
430 URLFetcher::RequestType UrlFetchRequestBase::GetRequestType() const {
431 return URLFetcher::GET;
434 std::vector<std::string> UrlFetchRequestBase::GetExtraRequestHeaders() const {
435 return std::vector<std::string>();
438 bool UrlFetchRequestBase::GetContentData(std::string* upload_content_type,
439 std::string* upload_content) {
440 return false;
443 bool UrlFetchRequestBase::GetContentFile(base::FilePath* local_file_path,
444 int64* range_offset,
445 int64* range_length,
446 std::string* upload_content_type) {
447 return false;
450 void UrlFetchRequestBase::GetOutputFilePath(
451 base::FilePath* local_file_path,
452 GetContentCallback* get_content_callback) {
455 void UrlFetchRequestBase::Cancel() {
456 response_writer_ = NULL;
457 url_fetcher_.reset(NULL);
458 CompleteRequestWithError(DRIVE_CANCELLED);
461 DriveApiErrorCode UrlFetchRequestBase::GetErrorCode() {
462 return error_code_;
465 bool UrlFetchRequestBase::CalledOnValidThread() {
466 return thread_checker_.CalledOnValidThread();
469 base::SequencedTaskRunner* UrlFetchRequestBase::blocking_task_runner() const {
470 return sender_->blocking_task_runner();
473 void UrlFetchRequestBase::OnProcessURLFetchResultsComplete() {
474 sender_->RequestFinished(this);
477 void UrlFetchRequestBase::OnURLFetchComplete(const URLFetcher* source) {
478 DVLOG(1) << "Response headers:\n" << GetResponseHeadersAsString(source);
480 // Determine error code.
481 error_code_ = static_cast<DriveApiErrorCode>(source->GetResponseCode());
482 if (!source->GetStatus().is_success()) {
483 switch (source->GetStatus().error()) {
484 case net::ERR_NETWORK_CHANGED:
485 error_code_ = DRIVE_NO_CONNECTION;
486 break;
487 default:
488 error_code_ = DRIVE_OTHER_ERROR;
492 // The server may return detailed error status in JSON.
493 // See https://developers.google.com/drive/handle-errors
494 if (!IsSuccessfulDriveApiErrorCode(error_code_)) {
495 DVLOG(1) << response_writer_->data();
497 const char kErrorKey[] = "error";
498 const char kErrorErrorsKey[] = "errors";
499 const char kErrorReasonKey[] = "reason";
500 const char kErrorMessageKey[] = "message";
501 const char kErrorReasonRateLimitExceeded[] = "rateLimitExceeded";
502 const char kErrorReasonUserRateLimitExceeded[] = "userRateLimitExceeded";
503 const char kErrorReasonQuotaExceeded[] = "quotaExceeded";
505 scoped_ptr<base::Value> value(ParseJson(response_writer_->data()));
506 base::DictionaryValue* dictionary = NULL;
507 base::DictionaryValue* error = NULL;
508 if (value &&
509 value->GetAsDictionary(&dictionary) &&
510 dictionary->GetDictionaryWithoutPathExpansion(kErrorKey, &error)) {
511 // Get error message.
512 std::string message;
513 error->GetStringWithoutPathExpansion(kErrorMessageKey, &message);
514 DLOG(ERROR) << "code: " << error_code_ << ", message: " << message;
516 // Override the error code based on the reason of the first error.
517 base::ListValue* errors = NULL;
518 base::DictionaryValue* first_error = NULL;
519 if (error->GetListWithoutPathExpansion(kErrorErrorsKey, &errors) &&
520 errors->GetDictionary(0, &first_error)) {
521 std::string reason;
522 first_error->GetStringWithoutPathExpansion(kErrorReasonKey, &reason);
523 if (reason == kErrorReasonRateLimitExceeded ||
524 reason == kErrorReasonUserRateLimitExceeded)
525 error_code_ = HTTP_SERVICE_UNAVAILABLE;
526 if (reason == kErrorReasonQuotaExceeded)
527 error_code_ = DRIVE_NO_SPACE;
532 // Handle authentication failure.
533 if (error_code_ == HTTP_UNAUTHORIZED) {
534 if (++re_authenticate_count_ <= kMaxReAuthenticateAttemptsPerRequest) {
535 // Reset re_authenticate_callback_ so Start() can be called again.
536 ReAuthenticateCallback callback = re_authenticate_callback_;
537 re_authenticate_callback_.Reset();
538 callback.Run(this);
539 return;
542 OnAuthFailed(error_code_);
543 return;
546 // Overridden by each specialization
547 ProcessURLFetchResults(source);
550 void UrlFetchRequestBase::CompleteRequestWithError(DriveApiErrorCode code) {
551 RunCallbackOnPrematureFailure(code);
552 sender_->RequestFinished(this);
555 void UrlFetchRequestBase::OnAuthFailed(DriveApiErrorCode code) {
556 CompleteRequestWithError(code);
559 base::WeakPtr<AuthenticatedRequestInterface>
560 UrlFetchRequestBase::GetWeakPtr() {
561 return weak_ptr_factory_.GetWeakPtr();
564 //============================ BatchableRequestBase ============================
566 net::URLFetcher::RequestType BatchableRequestBase::GetRequestType() const {
567 return UrlFetchRequestBase::GetRequestType();
570 std::vector<std::string> BatchableRequestBase::GetExtraRequestHeaders() const {
571 return UrlFetchRequestBase::GetExtraRequestHeaders();
574 void BatchableRequestBase::Prepare(const PrepareCallback& callback) {
575 return UrlFetchRequestBase::Prepare(callback);
578 bool BatchableRequestBase::GetContentData(
579 std::string* upload_content_type, std::string* upload_content) {
580 return UrlFetchRequestBase::GetContentData(
581 upload_content_type, upload_content);
584 void BatchableRequestBase::ProcessURLFetchResults(
585 const net::URLFetcher* source) {
586 ProcessURLFetchResults(GetErrorCode(), response_writer()->data());
589 //============================ EntryActionRequest ============================
591 EntryActionRequest::EntryActionRequest(RequestSender* sender,
592 const EntryActionCallback& callback)
593 : UrlFetchRequestBase(sender),
594 callback_(callback) {
595 DCHECK(!callback_.is_null());
598 EntryActionRequest::~EntryActionRequest() {}
600 void EntryActionRequest::ProcessURLFetchResults(const URLFetcher* source) {
601 callback_.Run(GetErrorCode());
602 OnProcessURLFetchResultsComplete();
605 void EntryActionRequest::RunCallbackOnPrematureFailure(DriveApiErrorCode code) {
606 callback_.Run(code);
609 //========================= InitiateUploadRequestBase ========================
611 InitiateUploadRequestBase::InitiateUploadRequestBase(
612 RequestSender* sender,
613 const InitiateUploadCallback& callback,
614 const std::string& content_type,
615 int64 content_length)
616 : UrlFetchRequestBase(sender),
617 callback_(callback),
618 content_type_(content_type),
619 content_length_(content_length) {
620 DCHECK(!callback_.is_null());
621 DCHECK(!content_type_.empty());
622 DCHECK_GE(content_length_, 0);
625 InitiateUploadRequestBase::~InitiateUploadRequestBase() {}
627 void InitiateUploadRequestBase::ProcessURLFetchResults(
628 const URLFetcher* source) {
629 DriveApiErrorCode code = GetErrorCode();
631 std::string upload_location;
632 if (code == HTTP_SUCCESS) {
633 // Retrieve value of the first "Location" header.
634 source->GetResponseHeaders()->EnumerateHeader(NULL,
635 kUploadResponseLocation,
636 &upload_location);
639 callback_.Run(code, GURL(upload_location));
640 OnProcessURLFetchResultsComplete();
643 void InitiateUploadRequestBase::RunCallbackOnPrematureFailure(
644 DriveApiErrorCode code) {
645 callback_.Run(code, GURL());
648 std::vector<std::string>
649 InitiateUploadRequestBase::GetExtraRequestHeaders() const {
650 std::vector<std::string> headers;
651 headers.push_back(kUploadContentType + content_type_);
652 headers.push_back(
653 kUploadContentLength + base::Int64ToString(content_length_));
654 return headers;
657 //============================ UploadRangeResponse =============================
659 UploadRangeResponse::UploadRangeResponse()
660 : code(HTTP_SUCCESS),
661 start_position_received(0),
662 end_position_received(0) {
665 UploadRangeResponse::UploadRangeResponse(DriveApiErrorCode code,
666 int64 start_position_received,
667 int64 end_position_received)
668 : code(code),
669 start_position_received(start_position_received),
670 end_position_received(end_position_received) {
673 UploadRangeResponse::~UploadRangeResponse() {
676 //========================== UploadRangeRequestBase ==========================
678 UploadRangeRequestBase::UploadRangeRequestBase(RequestSender* sender,
679 const GURL& upload_url)
680 : UrlFetchRequestBase(sender),
681 upload_url_(upload_url),
682 weak_ptr_factory_(this) {
685 UploadRangeRequestBase::~UploadRangeRequestBase() {}
687 GURL UploadRangeRequestBase::GetURL() const {
688 // This is very tricky to get json from this request. To do that, &alt=json
689 // has to be appended not here but in InitiateUploadRequestBase::GetURL().
690 return upload_url_;
693 URLFetcher::RequestType UploadRangeRequestBase::GetRequestType() const {
694 return URLFetcher::PUT;
697 void UploadRangeRequestBase::ProcessURLFetchResults(
698 const URLFetcher* source) {
699 DriveApiErrorCode code = GetErrorCode();
700 net::HttpResponseHeaders* hdrs = source->GetResponseHeaders();
702 if (code == HTTP_RESUME_INCOMPLETE) {
703 // Retrieve value of the first "Range" header.
704 // The Range header is appeared only if there is at least one received
705 // byte. So, initialize the positions by 0 so that the [0,0) will be
706 // returned via the |callback_| for empty data case.
707 int64 start_position_received = 0;
708 int64 end_position_received = 0;
709 std::string range_received;
710 hdrs->EnumerateHeader(NULL, kUploadResponseRange, &range_received);
711 if (!range_received.empty()) { // Parse the range header.
712 std::vector<net::HttpByteRange> ranges;
713 if (net::HttpUtil::ParseRangeHeader(range_received, &ranges) &&
714 !ranges.empty() ) {
715 // We only care about the first start-end pair in the range.
717 // Range header represents the range inclusively, while we are treating
718 // ranges exclusively (i.e., end_position_received should be one passed
719 // the last valid index). So "+ 1" is added.
720 start_position_received = ranges[0].first_byte_position();
721 end_position_received = ranges[0].last_byte_position() + 1;
724 // The Range header has the received data range, so the start position
725 // should be always 0.
726 DCHECK_EQ(start_position_received, 0);
728 OnRangeRequestComplete(UploadRangeResponse(code,
729 start_position_received,
730 end_position_received),
731 scoped_ptr<base::Value>());
733 OnProcessURLFetchResultsComplete();
734 } else if (code == HTTP_CREATED || code == HTTP_SUCCESS) {
735 // The upload is successfully done. Parse the response which should be
736 // the entry's metadata.
737 ParseJsonOnBlockingPool(blocking_task_runner(),
738 response_writer()->data(),
739 base::Bind(&UploadRangeRequestBase::OnDataParsed,
740 weak_ptr_factory_.GetWeakPtr(),
741 code));
742 } else {
743 // Failed to upload. Run callbacks to notify the error.
744 OnRangeRequestComplete(
745 UploadRangeResponse(code, -1, -1), scoped_ptr<base::Value>());
746 OnProcessURLFetchResultsComplete();
750 void UploadRangeRequestBase::OnDataParsed(DriveApiErrorCode code,
751 scoped_ptr<base::Value> value) {
752 DCHECK(CalledOnValidThread());
753 DCHECK(code == HTTP_CREATED || code == HTTP_SUCCESS);
755 OnRangeRequestComplete(UploadRangeResponse(code, -1, -1), value.Pass());
756 OnProcessURLFetchResultsComplete();
759 void UploadRangeRequestBase::RunCallbackOnPrematureFailure(
760 DriveApiErrorCode code) {
761 OnRangeRequestComplete(
762 UploadRangeResponse(code, 0, 0), scoped_ptr<base::Value>());
765 //========================== ResumeUploadRequestBase =========================
767 ResumeUploadRequestBase::ResumeUploadRequestBase(
768 RequestSender* sender,
769 const GURL& upload_location,
770 int64 start_position,
771 int64 end_position,
772 int64 content_length,
773 const std::string& content_type,
774 const base::FilePath& local_file_path)
775 : UploadRangeRequestBase(sender, upload_location),
776 start_position_(start_position),
777 end_position_(end_position),
778 content_length_(content_length),
779 content_type_(content_type),
780 local_file_path_(local_file_path) {
781 DCHECK_LE(start_position_, end_position_);
784 ResumeUploadRequestBase::~ResumeUploadRequestBase() {}
786 std::vector<std::string>
787 ResumeUploadRequestBase::GetExtraRequestHeaders() const {
788 if (content_length_ == 0) {
789 // For uploading an empty document, just PUT an empty content.
790 DCHECK_EQ(start_position_, 0);
791 DCHECK_EQ(end_position_, 0);
792 return std::vector<std::string>();
795 // The header looks like
796 // Content-Range: bytes <start_position>-<end_position>/<content_length>
797 // for example:
798 // Content-Range: bytes 7864320-8388607/13851821
799 // The header takes inclusive range, so we adjust by "end_position - 1".
800 DCHECK_GE(start_position_, 0);
801 DCHECK_GT(end_position_, 0);
802 DCHECK_GE(content_length_, 0);
804 std::vector<std::string> headers;
805 headers.push_back(
806 std::string(kUploadContentRange) +
807 base::Int64ToString(start_position_) + "-" +
808 base::Int64ToString(end_position_ - 1) + "/" +
809 base::Int64ToString(content_length_));
810 return headers;
813 bool ResumeUploadRequestBase::GetContentFile(
814 base::FilePath* local_file_path,
815 int64* range_offset,
816 int64* range_length,
817 std::string* upload_content_type) {
818 if (start_position_ == end_position_) {
819 // No content data.
820 return false;
823 *local_file_path = local_file_path_;
824 *range_offset = start_position_;
825 *range_length = end_position_ - start_position_;
826 *upload_content_type = content_type_;
827 return true;
830 //======================== GetUploadStatusRequestBase ========================
832 GetUploadStatusRequestBase::GetUploadStatusRequestBase(RequestSender* sender,
833 const GURL& upload_url,
834 int64 content_length)
835 : UploadRangeRequestBase(sender, upload_url),
836 content_length_(content_length) {}
838 GetUploadStatusRequestBase::~GetUploadStatusRequestBase() {}
840 std::vector<std::string>
841 GetUploadStatusRequestBase::GetExtraRequestHeaders() const {
842 // The header looks like
843 // Content-Range: bytes */<content_length>
844 // for example:
845 // Content-Range: bytes */13851821
846 DCHECK_GE(content_length_, 0);
848 std::vector<std::string> headers;
849 headers.push_back(
850 std::string(kUploadContentRange) + "*/" +
851 base::Int64ToString(content_length_));
852 return headers;
855 //========================= MultipartUploadRequestBase ========================
857 MultipartUploadRequestBase::MultipartUploadRequestBase(
858 RequestSender* sender,
859 const std::string& metadata_json,
860 const std::string& content_type,
861 int64 content_length,
862 const base::FilePath& local_file_path,
863 const FileResourceCallback& callback,
864 const ProgressCallback& progress_callback)
865 : BatchableRequestBase(sender),
866 metadata_json_(metadata_json),
867 content_type_(content_type),
868 local_path_(local_file_path),
869 callback_(callback),
870 progress_callback_(progress_callback),
871 weak_ptr_factory_(this) {
872 DCHECK(!content_type.empty());
873 DCHECK_GE(content_length, 0);
874 DCHECK(!local_file_path.empty());
875 DCHECK(!callback.is_null());
878 MultipartUploadRequestBase::~MultipartUploadRequestBase() {
881 void MultipartUploadRequestBase::Prepare(const PrepareCallback& callback) {
882 // If the request is cancelled, the request instance will be deleted in
883 // |UrlFetchRequestBase::Cancel| and OnPrepareUploadContent won't be called.
884 std::string* const upload_content_type = new std::string();
885 std::string* const upload_content_data = new std::string();
886 PostTaskAndReplyWithResult(
887 blocking_task_runner(), FROM_HERE,
888 base::Bind(&GetMultipartContent, boundary_, metadata_json_, content_type_,
889 local_path_, base::Unretained(upload_content_type),
890 base::Unretained(upload_content_data)),
891 base::Bind(&MultipartUploadRequestBase::OnPrepareUploadContent,
892 weak_ptr_factory_.GetWeakPtr(), callback,
893 base::Owned(upload_content_type),
894 base::Owned(upload_content_data)));
897 void MultipartUploadRequestBase::OnPrepareUploadContent(
898 const PrepareCallback& callback,
899 std::string* upload_content_type,
900 std::string* upload_content_data,
901 bool result) {
902 if (!result) {
903 callback.Run(DRIVE_FILE_ERROR);
904 return;
906 upload_content_type_.swap(*upload_content_type);
907 upload_content_data_.swap(*upload_content_data);
908 callback.Run(HTTP_SUCCESS);
911 void MultipartUploadRequestBase::SetBoundaryForTesting(
912 const std::string& boundary) {
913 boundary_ = boundary;
916 bool MultipartUploadRequestBase::GetContentData(
917 std::string* upload_content_type,
918 std::string* upload_content_data) {
919 // TODO(hirono): Pass stream instead of actual data to reduce memory usage.
920 upload_content_type->swap(upload_content_type_);
921 upload_content_data->swap(upload_content_data_);
922 return true;
925 void MultipartUploadRequestBase::ProcessURLFetchResults(
926 DriveApiErrorCode code, const std::string& body) {
927 // The upload is successfully done. Parse the response which should be
928 // the entry's metadata.
929 if (code == HTTP_CREATED || code == HTTP_SUCCESS) {
930 ParseJsonOnBlockingPool(
931 blocking_task_runner(), body,
932 base::Bind(&MultipartUploadRequestBase::OnDataParsed,
933 weak_ptr_factory_.GetWeakPtr(), code));
934 } else {
935 OnDataParsed(code, scoped_ptr<base::Value>());
939 void MultipartUploadRequestBase::RunCallbackOnPrematureFailure(
940 DriveApiErrorCode code) {
941 callback_.Run(code, scoped_ptr<FileResource>());
944 void MultipartUploadRequestBase::OnURLFetchUploadProgress(
945 const net::URLFetcher* source,
946 int64 current,
947 int64 total) {
948 if (!progress_callback_.is_null())
949 progress_callback_.Run(current, total);
952 void MultipartUploadRequestBase::OnDataParsed(DriveApiErrorCode code,
953 scoped_ptr<base::Value> value) {
954 DCHECK(CalledOnValidThread());
955 if (value)
956 callback_.Run(code, google_apis::FileResource::CreateFrom(*value));
957 else
958 callback_.Run(DRIVE_PARSE_ERROR, scoped_ptr<FileResource>());
959 OnProcessURLFetchResultsComplete();
962 //============================ DownloadFileRequestBase =========================
964 DownloadFileRequestBase::DownloadFileRequestBase(
965 RequestSender* sender,
966 const DownloadActionCallback& download_action_callback,
967 const GetContentCallback& get_content_callback,
968 const ProgressCallback& progress_callback,
969 const GURL& download_url,
970 const base::FilePath& output_file_path)
971 : UrlFetchRequestBase(sender),
972 download_action_callback_(download_action_callback),
973 get_content_callback_(get_content_callback),
974 progress_callback_(progress_callback),
975 download_url_(download_url),
976 output_file_path_(output_file_path) {
977 DCHECK(!download_action_callback_.is_null());
978 DCHECK(!output_file_path_.empty());
979 // get_content_callback may be null.
982 DownloadFileRequestBase::~DownloadFileRequestBase() {}
984 // Overridden from UrlFetchRequestBase.
985 GURL DownloadFileRequestBase::GetURL() const {
986 return download_url_;
989 void DownloadFileRequestBase::GetOutputFilePath(
990 base::FilePath* local_file_path,
991 GetContentCallback* get_content_callback) {
992 // Configure so that the downloaded content is saved to |output_file_path_|.
993 *local_file_path = output_file_path_;
994 *get_content_callback = get_content_callback_;
997 void DownloadFileRequestBase::OnURLFetchDownloadProgress(
998 const URLFetcher* source,
999 int64 current,
1000 int64 total) {
1001 if (!progress_callback_.is_null())
1002 progress_callback_.Run(current, total);
1005 void DownloadFileRequestBase::ProcessURLFetchResults(const URLFetcher* source) {
1006 DriveApiErrorCode code = GetErrorCode();
1008 // Take over the ownership of the the downloaded temp file.
1009 base::FilePath temp_file;
1010 if (code == HTTP_SUCCESS) {
1011 response_writer()->DisownFile();
1012 temp_file = output_file_path_;
1015 download_action_callback_.Run(code, temp_file);
1016 OnProcessURLFetchResultsComplete();
1019 void DownloadFileRequestBase::RunCallbackOnPrematureFailure(
1020 DriveApiErrorCode code) {
1021 download_action_callback_.Run(code, base::FilePath());
1024 } // namespace google_apis