Update user pod message to use Smart Lock.
[chromium-blink-merge.git] / google_apis / drive / base_requests.cc
blob84e3d585260c93b396c9d73213f471a8eb204c94
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;
38 namespace {
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(
79 blocking_task_runner,
80 FROM_HERE,
81 base::Bind(&google_apis::ParseJson, json),
82 callback);
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.
93 std::string headers;
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!!");
98 } else {
99 url_fetcher->GetResponseHeaders()->GetNormalizedHeaders(&headers);
101 return headers;
104 bool IsSuccessfulResponseCode(int response_code) {
105 return 200 <= response_code && response_code <= 299;
108 // Creates metadata JSON string for multipart uploading.
109 // All the values are optional. If the value is empty or null, the value does
110 // not appear in the metadata.
111 std::string CreateMultipartUploadMetadataJson(
112 const std::string& title,
113 const std::string& parent_resource_id,
114 const base::Time& modified_date,
115 const base::Time& last_viewed_by_me_date) {
116 base::DictionaryValue root;
117 if (!title.empty())
118 root.SetString("title", title);
120 // Fill parent link.
121 if (!parent_resource_id.empty()) {
122 scoped_ptr<base::ListValue> parents(new base::ListValue);
123 parents->Append(
124 google_apis::util::CreateParentValue(parent_resource_id).release());
125 root.Set("parents", parents.release());
128 if (!modified_date.is_null())
129 root.SetString("modifiedDate",
130 google_apis::util::FormatTimeAsString(modified_date));
132 if (!last_viewed_by_me_date.is_null()) {
133 root.SetString("lastViewedByMeDate", google_apis::util::FormatTimeAsString(
134 last_viewed_by_me_date));
137 std::string json_string;
138 base::JSONWriter::Write(&root, &json_string);
139 return json_string;
142 // Obtains the multipart body for the metadata string and file contents. If
143 // predetermined_boundary is empty, the function generates the boundary string.
144 bool GetMultipartContent(const std::string& predetermined_boundary,
145 const std::string& metadata_json,
146 const std::string& content_type,
147 const base::FilePath& path,
148 std::string* upload_content_type,
149 std::string* upload_content_data) {
150 std::string file_content;
151 if (!ReadFileToString(path, &file_content))
152 return false;
154 std::string boundary;
155 if (predetermined_boundary.empty()) {
156 while (true) {
157 boundary.resize(kBoundarySize);
158 for (int i = 0; i < kBoundarySize; ++i) {
159 // Subtract 2 from the array size to exclude '\0', and to turn the size
160 // into the last index.
161 const int last_char_index = arraysize(kBoundaryCharacters) - 2;
162 boundary[i] = kBoundaryCharacters[base::RandInt(0, last_char_index)];
164 if (metadata_json.find(boundary, 0) == std::string::npos &&
165 file_content.find(boundary, 0) == std::string::npos) {
166 break;
169 } else {
170 boundary = predetermined_boundary;
172 const std::string body_before_file = base::StringPrintf(
173 kMessageFormatBeforeFile, boundary.c_str(), "application/json",
174 metadata_json.c_str(), boundary.c_str(), content_type.c_str());
175 const std::string body_after_file =
176 base::StringPrintf(kMessageFormatAfterFile, boundary.c_str());
178 *upload_content_type = kMultipartMimeTypePrefix + boundary;
179 *upload_content_data = body_before_file + file_content + body_after_file;
180 return true;
183 } // namespace
185 namespace google_apis {
187 scoped_ptr<base::Value> ParseJson(const std::string& json) {
188 int error_code = -1;
189 std::string error_message;
190 scoped_ptr<base::Value> value(base::JSONReader::ReadAndReturnError(
191 json, base::JSON_PARSE_RFC, &error_code, &error_message));
193 if (!value.get()) {
194 std::string trimmed_json;
195 if (json.size() < 80) {
196 trimmed_json = json;
197 } else {
198 // Take the first 50 and the last 10 bytes.
199 trimmed_json = base::StringPrintf(
200 "%s [%s bytes] %s",
201 json.substr(0, 50).c_str(),
202 base::Uint64ToString(json.size() - 60).c_str(),
203 json.substr(json.size() - 10).c_str());
205 LOG(WARNING) << "Error while parsing entry response: " << error_message
206 << ", code: " << error_code << ", json:\n" << trimmed_json;
208 return value.Pass();
211 //=========================== ResponseWriter ==================================
212 ResponseWriter::ResponseWriter(base::SequencedTaskRunner* file_task_runner,
213 const base::FilePath& file_path,
214 const GetContentCallback& get_content_callback)
215 : get_content_callback_(get_content_callback),
216 weak_ptr_factory_(this) {
217 if (!file_path.empty()) {
218 file_writer_.reset(
219 new net::URLFetcherFileWriter(file_task_runner, file_path));
223 ResponseWriter::~ResponseWriter() {
226 void ResponseWriter::DisownFile() {
227 DCHECK(file_writer_);
228 file_writer_->DisownFile();
231 int ResponseWriter::Initialize(const net::CompletionCallback& callback) {
232 if (file_writer_)
233 return file_writer_->Initialize(callback);
235 data_.clear();
236 return net::OK;
239 int ResponseWriter::Write(net::IOBuffer* buffer,
240 int num_bytes,
241 const net::CompletionCallback& callback) {
242 if (!get_content_callback_.is_null()) {
243 get_content_callback_.Run(
244 HTTP_SUCCESS,
245 make_scoped_ptr(new std::string(buffer->data(), num_bytes)));
248 if (file_writer_) {
249 const int result = file_writer_->Write(
250 buffer, num_bytes,
251 base::Bind(&ResponseWriter::DidWrite,
252 weak_ptr_factory_.GetWeakPtr(),
253 make_scoped_refptr(buffer), callback));
254 if (result != net::ERR_IO_PENDING)
255 DidWrite(buffer, net::CompletionCallback(), result);
256 return result;
259 data_.append(buffer->data(), num_bytes);
260 return num_bytes;
263 int ResponseWriter::Finish(const net::CompletionCallback& callback) {
264 if (file_writer_)
265 return file_writer_->Finish(callback);
267 return net::OK;
270 void ResponseWriter::DidWrite(scoped_refptr<net::IOBuffer> buffer,
271 const net::CompletionCallback& callback,
272 int result) {
273 if (result > 0) {
274 // Even if file_writer_ is used, append the data to |data_|, so that it can
275 // be used to get error information in case of server side errors.
276 // The size limit is to avoid consuming too much redundant memory.
277 const size_t kMaxStringSize = 1024*1024;
278 if (data_.size() < kMaxStringSize) {
279 data_.append(buffer->data(), std::min(static_cast<size_t>(result),
280 kMaxStringSize - data_.size()));
284 if (!callback.is_null())
285 callback.Run(result);
288 //============================ UrlFetchRequestBase ===========================
290 UrlFetchRequestBase::UrlFetchRequestBase(RequestSender* sender)
291 : re_authenticate_count_(0),
292 response_writer_(NULL),
293 sender_(sender),
294 error_code_(GDATA_OTHER_ERROR),
295 weak_ptr_factory_(this) {
298 UrlFetchRequestBase::~UrlFetchRequestBase() {}
300 void UrlFetchRequestBase::Start(const std::string& access_token,
301 const std::string& custom_user_agent,
302 const ReAuthenticateCallback& callback) {
303 DCHECK(CalledOnValidThread());
304 DCHECK(!access_token.empty());
305 DCHECK(!callback.is_null());
306 DCHECK(re_authenticate_callback_.is_null());
308 re_authenticate_callback_ = callback;
310 GURL url = GetURL();
311 if (url.is_empty()) {
312 // Error is found on generating the url. Send the error message to the
313 // callback, and then return immediately without trying to connect
314 // to the server.
315 RunCallbackOnPrematureFailure(GDATA_OTHER_ERROR);
316 return;
318 DVLOG(1) << "URL: " << url.spec();
320 URLFetcher::RequestType request_type = GetRequestType();
321 url_fetcher_.reset(URLFetcher::Create(url, request_type, this));
322 url_fetcher_->SetRequestContext(sender_->url_request_context_getter());
323 // Always set flags to neither send nor save cookies.
324 url_fetcher_->SetLoadFlags(
325 net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES |
326 net::LOAD_DISABLE_CACHE);
328 base::FilePath output_file_path;
329 GetContentCallback get_content_callback;
330 GetOutputFilePath(&output_file_path, &get_content_callback);
331 if (!get_content_callback.is_null())
332 get_content_callback = CreateRelayCallback(get_content_callback);
333 response_writer_ = new ResponseWriter(blocking_task_runner(),
334 output_file_path,
335 get_content_callback);
336 url_fetcher_->SaveResponseWithWriter(
337 scoped_ptr<net::URLFetcherResponseWriter>(response_writer_));
339 // Add request headers.
340 // Note that SetExtraRequestHeaders clears the current headers and sets it
341 // to the passed-in headers, so calling it for each header will result in
342 // only the last header being set in request headers.
343 if (!custom_user_agent.empty())
344 url_fetcher_->AddExtraRequestHeader("User-Agent: " + custom_user_agent);
345 url_fetcher_->AddExtraRequestHeader(kGDataVersionHeader);
346 url_fetcher_->AddExtraRequestHeader(
347 base::StringPrintf(kAuthorizationHeaderFormat, access_token.data()));
348 std::vector<std::string> headers = GetExtraRequestHeaders();
349 for (size_t i = 0; i < headers.size(); ++i) {
350 url_fetcher_->AddExtraRequestHeader(headers[i]);
351 DVLOG(1) << "Extra header: " << headers[i];
354 // Set upload data if available.
355 std::string upload_content_type;
356 std::string upload_content;
357 if (GetContentData(&upload_content_type, &upload_content)) {
358 url_fetcher_->SetUploadData(upload_content_type, upload_content);
359 } else {
360 base::FilePath local_file_path;
361 int64 range_offset = 0;
362 int64 range_length = 0;
363 if (GetContentFile(&local_file_path, &range_offset, &range_length,
364 &upload_content_type)) {
365 url_fetcher_->SetUploadFilePath(
366 upload_content_type,
367 local_file_path,
368 range_offset,
369 range_length,
370 blocking_task_runner());
371 } else {
372 // Even if there is no content data, UrlFetcher requires to set empty
373 // upload data string for POST, PUT and PATCH methods, explicitly.
374 // It is because that most requests of those methods have non-empty
375 // body, and UrlFetcher checks whether it is actually not forgotten.
376 if (request_type == URLFetcher::POST ||
377 request_type == URLFetcher::PUT ||
378 request_type == URLFetcher::PATCH) {
379 // Set empty upload content-type and upload content, so that
380 // the request will have no "Content-type: " header and no content.
381 url_fetcher_->SetUploadData(std::string(), std::string());
386 url_fetcher_->Start();
389 URLFetcher::RequestType UrlFetchRequestBase::GetRequestType() const {
390 return URLFetcher::GET;
393 std::vector<std::string> UrlFetchRequestBase::GetExtraRequestHeaders() const {
394 return std::vector<std::string>();
397 bool UrlFetchRequestBase::GetContentData(std::string* upload_content_type,
398 std::string* upload_content) {
399 return false;
402 bool UrlFetchRequestBase::GetContentFile(base::FilePath* local_file_path,
403 int64* range_offset,
404 int64* range_length,
405 std::string* upload_content_type) {
406 return false;
409 void UrlFetchRequestBase::GetOutputFilePath(
410 base::FilePath* local_file_path,
411 GetContentCallback* get_content_callback) {
414 void UrlFetchRequestBase::Cancel() {
415 response_writer_ = NULL;
416 url_fetcher_.reset(NULL);
417 RunCallbackOnPrematureFailure(GDATA_CANCELLED);
418 sender_->RequestFinished(this);
421 GDataErrorCode UrlFetchRequestBase::GetErrorCode() {
422 return error_code_;
425 bool UrlFetchRequestBase::CalledOnValidThread() {
426 return thread_checker_.CalledOnValidThread();
429 base::SequencedTaskRunner* UrlFetchRequestBase::blocking_task_runner() const {
430 return sender_->blocking_task_runner();
433 void UrlFetchRequestBase::OnProcessURLFetchResultsComplete() {
434 sender_->RequestFinished(this);
437 void UrlFetchRequestBase::OnURLFetchComplete(const URLFetcher* source) {
438 DVLOG(1) << "Response headers:\n" << GetResponseHeadersAsString(source);
440 // Determine error code.
441 error_code_ = static_cast<GDataErrorCode>(source->GetResponseCode());
442 if (!source->GetStatus().is_success()) {
443 switch (source->GetStatus().error()) {
444 case net::ERR_NETWORK_CHANGED:
445 error_code_ = GDATA_NO_CONNECTION;
446 break;
447 default:
448 error_code_ = GDATA_OTHER_ERROR;
452 // The server may return detailed error status in JSON.
453 // See https://developers.google.com/drive/handle-errors
454 if (!IsSuccessfulResponseCode(error_code_)) {
455 DVLOG(1) << response_writer_->data();
457 const char kErrorKey[] = "error";
458 const char kErrorErrorsKey[] = "errors";
459 const char kErrorReasonKey[] = "reason";
460 const char kErrorMessageKey[] = "message";
461 const char kErrorReasonRateLimitExceeded[] = "rateLimitExceeded";
462 const char kErrorReasonUserRateLimitExceeded[] = "userRateLimitExceeded";
463 const char kErrorReasonQuotaExceeded[] = "quotaExceeded";
465 scoped_ptr<base::Value> value(ParseJson(response_writer_->data()));
466 base::DictionaryValue* dictionary = NULL;
467 base::DictionaryValue* error = NULL;
468 if (value &&
469 value->GetAsDictionary(&dictionary) &&
470 dictionary->GetDictionaryWithoutPathExpansion(kErrorKey, &error)) {
471 // Get error message.
472 std::string message;
473 error->GetStringWithoutPathExpansion(kErrorMessageKey, &message);
474 DLOG(ERROR) << "code: " << error_code_ << ", message: " << message;
476 // Override the error code based on the reason of the first error.
477 base::ListValue* errors = NULL;
478 base::DictionaryValue* first_error = NULL;
479 if (error->GetListWithoutPathExpansion(kErrorErrorsKey, &errors) &&
480 errors->GetDictionary(0, &first_error)) {
481 std::string reason;
482 first_error->GetStringWithoutPathExpansion(kErrorReasonKey, &reason);
483 if (reason == kErrorReasonRateLimitExceeded ||
484 reason == kErrorReasonUserRateLimitExceeded)
485 error_code_ = HTTP_SERVICE_UNAVAILABLE;
486 if (reason == kErrorReasonQuotaExceeded)
487 error_code_ = GDATA_NO_SPACE;
492 // Handle authentication failure.
493 if (error_code_ == HTTP_UNAUTHORIZED) {
494 if (++re_authenticate_count_ <= kMaxReAuthenticateAttemptsPerRequest) {
495 // Reset re_authenticate_callback_ so Start() can be called again.
496 ReAuthenticateCallback callback = re_authenticate_callback_;
497 re_authenticate_callback_.Reset();
498 callback.Run(this);
499 return;
502 OnAuthFailed(error_code_);
503 return;
506 // Overridden by each specialization
507 ProcessURLFetchResults(source);
510 void UrlFetchRequestBase::OnAuthFailed(GDataErrorCode code) {
511 RunCallbackOnPrematureFailure(code);
512 sender_->RequestFinished(this);
515 base::WeakPtr<AuthenticatedRequestInterface>
516 UrlFetchRequestBase::GetWeakPtr() {
517 return weak_ptr_factory_.GetWeakPtr();
520 //============================ EntryActionRequest ============================
522 EntryActionRequest::EntryActionRequest(RequestSender* sender,
523 const EntryActionCallback& callback)
524 : UrlFetchRequestBase(sender),
525 callback_(callback) {
526 DCHECK(!callback_.is_null());
529 EntryActionRequest::~EntryActionRequest() {}
531 void EntryActionRequest::ProcessURLFetchResults(const URLFetcher* source) {
532 callback_.Run(GetErrorCode());
533 OnProcessURLFetchResultsComplete();
536 void EntryActionRequest::RunCallbackOnPrematureFailure(GDataErrorCode code) {
537 callback_.Run(code);
540 //========================= InitiateUploadRequestBase ========================
542 InitiateUploadRequestBase::InitiateUploadRequestBase(
543 RequestSender* sender,
544 const InitiateUploadCallback& callback,
545 const std::string& content_type,
546 int64 content_length)
547 : UrlFetchRequestBase(sender),
548 callback_(callback),
549 content_type_(content_type),
550 content_length_(content_length) {
551 DCHECK(!callback_.is_null());
552 DCHECK(!content_type_.empty());
553 DCHECK_GE(content_length_, 0);
556 InitiateUploadRequestBase::~InitiateUploadRequestBase() {}
558 void InitiateUploadRequestBase::ProcessURLFetchResults(
559 const URLFetcher* source) {
560 GDataErrorCode code = GetErrorCode();
562 std::string upload_location;
563 if (code == HTTP_SUCCESS) {
564 // Retrieve value of the first "Location" header.
565 source->GetResponseHeaders()->EnumerateHeader(NULL,
566 kUploadResponseLocation,
567 &upload_location);
570 callback_.Run(code, GURL(upload_location));
571 OnProcessURLFetchResultsComplete();
574 void InitiateUploadRequestBase::RunCallbackOnPrematureFailure(
575 GDataErrorCode code) {
576 callback_.Run(code, GURL());
579 std::vector<std::string>
580 InitiateUploadRequestBase::GetExtraRequestHeaders() const {
581 std::vector<std::string> headers;
582 headers.push_back(kUploadContentType + content_type_);
583 headers.push_back(
584 kUploadContentLength + base::Int64ToString(content_length_));
585 return headers;
588 //============================ UploadRangeResponse =============================
590 UploadRangeResponse::UploadRangeResponse()
591 : code(HTTP_SUCCESS),
592 start_position_received(0),
593 end_position_received(0) {
596 UploadRangeResponse::UploadRangeResponse(GDataErrorCode code,
597 int64 start_position_received,
598 int64 end_position_received)
599 : code(code),
600 start_position_received(start_position_received),
601 end_position_received(end_position_received) {
604 UploadRangeResponse::~UploadRangeResponse() {
607 //========================== UploadRangeRequestBase ==========================
609 UploadRangeRequestBase::UploadRangeRequestBase(RequestSender* sender,
610 const GURL& upload_url)
611 : UrlFetchRequestBase(sender),
612 upload_url_(upload_url),
613 weak_ptr_factory_(this) {
616 UploadRangeRequestBase::~UploadRangeRequestBase() {}
618 GURL UploadRangeRequestBase::GetURL() const {
619 // This is very tricky to get json from this request. To do that, &alt=json
620 // has to be appended not here but in InitiateUploadRequestBase::GetURL().
621 return upload_url_;
624 URLFetcher::RequestType UploadRangeRequestBase::GetRequestType() const {
625 return URLFetcher::PUT;
628 void UploadRangeRequestBase::ProcessURLFetchResults(
629 const URLFetcher* source) {
630 GDataErrorCode code = GetErrorCode();
631 net::HttpResponseHeaders* hdrs = source->GetResponseHeaders();
633 if (code == HTTP_RESUME_INCOMPLETE) {
634 // Retrieve value of the first "Range" header.
635 // The Range header is appeared only if there is at least one received
636 // byte. So, initialize the positions by 0 so that the [0,0) will be
637 // returned via the |callback_| for empty data case.
638 int64 start_position_received = 0;
639 int64 end_position_received = 0;
640 std::string range_received;
641 hdrs->EnumerateHeader(NULL, kUploadResponseRange, &range_received);
642 if (!range_received.empty()) { // Parse the range header.
643 std::vector<net::HttpByteRange> ranges;
644 if (net::HttpUtil::ParseRangeHeader(range_received, &ranges) &&
645 !ranges.empty() ) {
646 // We only care about the first start-end pair in the range.
648 // Range header represents the range inclusively, while we are treating
649 // ranges exclusively (i.e., end_position_received should be one passed
650 // the last valid index). So "+ 1" is added.
651 start_position_received = ranges[0].first_byte_position();
652 end_position_received = ranges[0].last_byte_position() + 1;
655 // The Range header has the received data range, so the start position
656 // should be always 0.
657 DCHECK_EQ(start_position_received, 0);
659 OnRangeRequestComplete(UploadRangeResponse(code,
660 start_position_received,
661 end_position_received),
662 scoped_ptr<base::Value>());
664 OnProcessURLFetchResultsComplete();
665 } else if (code == HTTP_CREATED || code == HTTP_SUCCESS) {
666 // The upload is successfully done. Parse the response which should be
667 // the entry's metadata.
668 ParseJsonOnBlockingPool(blocking_task_runner(),
669 response_writer()->data(),
670 base::Bind(&UploadRangeRequestBase::OnDataParsed,
671 weak_ptr_factory_.GetWeakPtr(),
672 code));
673 } else {
674 // Failed to upload. Run callbacks to notify the error.
675 OnRangeRequestComplete(
676 UploadRangeResponse(code, -1, -1), scoped_ptr<base::Value>());
677 OnProcessURLFetchResultsComplete();
681 void UploadRangeRequestBase::OnDataParsed(GDataErrorCode code,
682 scoped_ptr<base::Value> value) {
683 DCHECK(CalledOnValidThread());
684 DCHECK(code == HTTP_CREATED || code == HTTP_SUCCESS);
686 OnRangeRequestComplete(UploadRangeResponse(code, -1, -1), value.Pass());
687 OnProcessURLFetchResultsComplete();
690 void UploadRangeRequestBase::RunCallbackOnPrematureFailure(
691 GDataErrorCode code) {
692 OnRangeRequestComplete(
693 UploadRangeResponse(code, 0, 0), scoped_ptr<base::Value>());
696 //========================== ResumeUploadRequestBase =========================
698 ResumeUploadRequestBase::ResumeUploadRequestBase(
699 RequestSender* sender,
700 const GURL& upload_location,
701 int64 start_position,
702 int64 end_position,
703 int64 content_length,
704 const std::string& content_type,
705 const base::FilePath& local_file_path)
706 : UploadRangeRequestBase(sender, upload_location),
707 start_position_(start_position),
708 end_position_(end_position),
709 content_length_(content_length),
710 content_type_(content_type),
711 local_file_path_(local_file_path) {
712 DCHECK_LE(start_position_, end_position_);
715 ResumeUploadRequestBase::~ResumeUploadRequestBase() {}
717 std::vector<std::string>
718 ResumeUploadRequestBase::GetExtraRequestHeaders() const {
719 if (content_length_ == 0) {
720 // For uploading an empty document, just PUT an empty content.
721 DCHECK_EQ(start_position_, 0);
722 DCHECK_EQ(end_position_, 0);
723 return std::vector<std::string>();
726 // The header looks like
727 // Content-Range: bytes <start_position>-<end_position>/<content_length>
728 // for example:
729 // Content-Range: bytes 7864320-8388607/13851821
730 // The header takes inclusive range, so we adjust by "end_position - 1".
731 DCHECK_GE(start_position_, 0);
732 DCHECK_GT(end_position_, 0);
733 DCHECK_GE(content_length_, 0);
735 std::vector<std::string> headers;
736 headers.push_back(
737 std::string(kUploadContentRange) +
738 base::Int64ToString(start_position_) + "-" +
739 base::Int64ToString(end_position_ - 1) + "/" +
740 base::Int64ToString(content_length_));
741 return headers;
744 bool ResumeUploadRequestBase::GetContentFile(
745 base::FilePath* local_file_path,
746 int64* range_offset,
747 int64* range_length,
748 std::string* upload_content_type) {
749 if (start_position_ == end_position_) {
750 // No content data.
751 return false;
754 *local_file_path = local_file_path_;
755 *range_offset = start_position_;
756 *range_length = end_position_ - start_position_;
757 *upload_content_type = content_type_;
758 return true;
761 //======================== GetUploadStatusRequestBase ========================
763 GetUploadStatusRequestBase::GetUploadStatusRequestBase(RequestSender* sender,
764 const GURL& upload_url,
765 int64 content_length)
766 : UploadRangeRequestBase(sender, upload_url),
767 content_length_(content_length) {}
769 GetUploadStatusRequestBase::~GetUploadStatusRequestBase() {}
771 std::vector<std::string>
772 GetUploadStatusRequestBase::GetExtraRequestHeaders() const {
773 // The header looks like
774 // Content-Range: bytes */<content_length>
775 // for example:
776 // Content-Range: bytes */13851821
777 DCHECK_GE(content_length_, 0);
779 std::vector<std::string> headers;
780 headers.push_back(
781 std::string(kUploadContentRange) + "*/" +
782 base::Int64ToString(content_length_));
783 return headers;
786 //========================= MultipartUploadRequestBase ========================
788 MultipartUploadRequestBase::MultipartUploadRequestBase(
789 RequestSender* sender,
790 const std::string& title,
791 const std::string& parent_resource_id,
792 const std::string& content_type,
793 int64 content_length,
794 const base::Time& modified_date,
795 const base::Time& last_viewed_by_me_date,
796 const base::FilePath& local_file_path,
797 const FileResourceCallback& callback,
798 const ProgressCallback& progress_callback)
799 : UrlFetchRequestBase(sender),
800 metadata_json_(CreateMultipartUploadMetadataJson(title,
801 parent_resource_id,
802 modified_date,
803 last_viewed_by_me_date)),
804 content_type_(content_type),
805 local_path_(local_file_path),
806 has_modified_date_(!modified_date.is_null()),
807 callback_(callback),
808 progress_callback_(progress_callback),
809 weak_ptr_factory_(this) {
810 DCHECK(!content_type.empty());
811 DCHECK_GE(content_length, 0);
812 DCHECK(!local_file_path.empty());
813 DCHECK(!callback.is_null());
816 MultipartUploadRequestBase::~MultipartUploadRequestBase() {
819 void MultipartUploadRequestBase::Start(const std::string& access_token,
820 const std::string& custom_user_agent,
821 const ReAuthenticateCallback& callback) {
822 // If the request is cancelled, the request instance will be deleted in
823 // |UrlFetchRequestBase::Cancel| and OnPrepareUploadContent won't be called.
824 std::string* const upload_content_type = new std::string();
825 std::string* const upload_content_data = new std::string();
826 PostTaskAndReplyWithResult(
827 blocking_task_runner(), FROM_HERE,
828 base::Bind(&GetMultipartContent, boundary_, metadata_json_, content_type_,
829 local_path_, base::Unretained(upload_content_type),
830 base::Unretained(upload_content_data)),
831 base::Bind(&MultipartUploadRequestBase::OnPrepareUploadContent,
832 weak_ptr_factory_.GetWeakPtr(), access_token,
833 custom_user_agent, callback, base::Owned(upload_content_type),
834 base::Owned(upload_content_data)));
837 void MultipartUploadRequestBase::OnPrepareUploadContent(
838 const std::string& access_token,
839 const std::string& custom_user_agent,
840 const ReAuthenticateCallback& callback,
841 std::string* upload_content_type,
842 std::string* upload_content_data,
843 bool result) {
844 if (!result) {
845 RunCallbackOnPrematureFailure(GDATA_FILE_ERROR);
846 return;
848 upload_content_type_.swap(*upload_content_type);
849 upload_content_data_.swap(*upload_content_data);
850 UrlFetchRequestBase::Start(access_token, custom_user_agent, callback);
853 void MultipartUploadRequestBase::SetBoundaryForTesting(
854 const std::string& boundary) {
855 boundary_ = boundary;
858 bool MultipartUploadRequestBase::GetContentData(
859 std::string* upload_content_type,
860 std::string* upload_content_data) {
861 // TODO(hirono): Pass stream instead of actual data to reduce memory usage.
862 upload_content_type->swap(upload_content_type_);
863 upload_content_data->swap(upload_content_data_);
864 return true;
867 void MultipartUploadRequestBase::ProcessURLFetchResults(
868 const URLFetcher* source) {
869 // The upload is successfully done. Parse the response which should be
870 // the entry's metadata.
871 const GDataErrorCode code = GetErrorCode();
872 if (code == HTTP_CREATED || code == HTTP_SUCCESS) {
873 ParseJsonOnBlockingPool(
874 blocking_task_runner(), response_writer()->data(),
875 base::Bind(&MultipartUploadRequestBase::OnDataParsed,
876 weak_ptr_factory_.GetWeakPtr(), code));
877 } else {
878 OnDataParsed(code, scoped_ptr<base::Value>());
882 void MultipartUploadRequestBase::RunCallbackOnPrematureFailure(
883 GDataErrorCode code) {
884 callback_.Run(code, scoped_ptr<FileResource>());
887 void MultipartUploadRequestBase::OnURLFetchUploadProgress(
888 const net::URLFetcher* source,
889 int64 current,
890 int64 total) {
891 if (!progress_callback_.is_null())
892 progress_callback_.Run(current, total);
895 void MultipartUploadRequestBase::OnDataParsed(GDataErrorCode code,
896 scoped_ptr<base::Value> value) {
897 DCHECK(CalledOnValidThread());
898 if (value)
899 callback_.Run(code, google_apis::FileResource::CreateFrom(*value));
900 else
901 callback_.Run(GDATA_PARSE_ERROR, scoped_ptr<FileResource>());
902 OnProcessURLFetchResultsComplete();
905 //============================ DownloadFileRequestBase =========================
907 DownloadFileRequestBase::DownloadFileRequestBase(
908 RequestSender* sender,
909 const DownloadActionCallback& download_action_callback,
910 const GetContentCallback& get_content_callback,
911 const ProgressCallback& progress_callback,
912 const GURL& download_url,
913 const base::FilePath& output_file_path)
914 : UrlFetchRequestBase(sender),
915 download_action_callback_(download_action_callback),
916 get_content_callback_(get_content_callback),
917 progress_callback_(progress_callback),
918 download_url_(download_url),
919 output_file_path_(output_file_path) {
920 DCHECK(!download_action_callback_.is_null());
921 DCHECK(!output_file_path_.empty());
922 // get_content_callback may be null.
925 DownloadFileRequestBase::~DownloadFileRequestBase() {}
927 // Overridden from UrlFetchRequestBase.
928 GURL DownloadFileRequestBase::GetURL() const {
929 return download_url_;
932 void DownloadFileRequestBase::GetOutputFilePath(
933 base::FilePath* local_file_path,
934 GetContentCallback* get_content_callback) {
935 // Configure so that the downloaded content is saved to |output_file_path_|.
936 *local_file_path = output_file_path_;
937 *get_content_callback = get_content_callback_;
940 void DownloadFileRequestBase::OnURLFetchDownloadProgress(
941 const URLFetcher* source,
942 int64 current,
943 int64 total) {
944 if (!progress_callback_.is_null())
945 progress_callback_.Run(current, total);
948 void DownloadFileRequestBase::ProcessURLFetchResults(const URLFetcher* source) {
949 GDataErrorCode code = GetErrorCode();
951 // Take over the ownership of the the downloaded temp file.
952 base::FilePath temp_file;
953 if (code == HTTP_SUCCESS) {
954 response_writer()->DisownFile();
955 temp_file = output_file_path_;
958 download_action_callback_.Run(code, temp_file);
959 OnProcessURLFetchResultsComplete();
962 void DownloadFileRequestBase::RunCallbackOnPrematureFailure(
963 GDataErrorCode code) {
964 download_action_callback_.Run(code, base::FilePath());
967 } // namespace google_apis