ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / google_apis / drive / base_requests.cc
blob37a49e3346f6d85f19ba42783a8e6d7b7ad77e10
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 // Obtains the multipart body for the metadata string and file contents. If
109 // predetermined_boundary is empty, the function generates the boundary string.
110 bool GetMultipartContent(const std::string& predetermined_boundary,
111 const std::string& metadata_json,
112 const std::string& content_type,
113 const base::FilePath& path,
114 std::string* upload_content_type,
115 std::string* upload_content_data) {
116 std::string file_content;
117 if (!ReadFileToString(path, &file_content))
118 return false;
120 std::string boundary;
121 if (predetermined_boundary.empty()) {
122 while (true) {
123 boundary.resize(kBoundarySize);
124 for (int i = 0; i < kBoundarySize; ++i) {
125 // Subtract 2 from the array size to exclude '\0', and to turn the size
126 // into the last index.
127 const int last_char_index = arraysize(kBoundaryCharacters) - 2;
128 boundary[i] = kBoundaryCharacters[base::RandInt(0, last_char_index)];
130 if (metadata_json.find(boundary, 0) == std::string::npos &&
131 file_content.find(boundary, 0) == std::string::npos) {
132 break;
135 } else {
136 boundary = predetermined_boundary;
138 const std::string body_before_file = base::StringPrintf(
139 kMessageFormatBeforeFile, boundary.c_str(), "application/json",
140 metadata_json.c_str(), boundary.c_str(), content_type.c_str());
141 const std::string body_after_file =
142 base::StringPrintf(kMessageFormatAfterFile, boundary.c_str());
144 *upload_content_type = kMultipartMimeTypePrefix + boundary;
145 *upload_content_data = body_before_file + file_content + body_after_file;
146 return true;
149 } // namespace
151 namespace google_apis {
153 scoped_ptr<base::Value> ParseJson(const std::string& json) {
154 int error_code = -1;
155 std::string error_message;
156 scoped_ptr<base::Value> value(base::JSONReader::ReadAndReturnError(
157 json, base::JSON_PARSE_RFC, &error_code, &error_message));
159 if (!value.get()) {
160 std::string trimmed_json;
161 if (json.size() < 80) {
162 trimmed_json = json;
163 } else {
164 // Take the first 50 and the last 10 bytes.
165 trimmed_json = base::StringPrintf(
166 "%s [%s bytes] %s",
167 json.substr(0, 50).c_str(),
168 base::Uint64ToString(json.size() - 60).c_str(),
169 json.substr(json.size() - 10).c_str());
171 LOG(WARNING) << "Error while parsing entry response: " << error_message
172 << ", code: " << error_code << ", json:\n" << trimmed_json;
174 return value.Pass();
177 //=========================== ResponseWriter ==================================
178 ResponseWriter::ResponseWriter(base::SequencedTaskRunner* file_task_runner,
179 const base::FilePath& file_path,
180 const GetContentCallback& get_content_callback)
181 : get_content_callback_(get_content_callback),
182 weak_ptr_factory_(this) {
183 if (!file_path.empty()) {
184 file_writer_.reset(
185 new net::URLFetcherFileWriter(file_task_runner, file_path));
189 ResponseWriter::~ResponseWriter() {
192 void ResponseWriter::DisownFile() {
193 DCHECK(file_writer_);
194 file_writer_->DisownFile();
197 int ResponseWriter::Initialize(const net::CompletionCallback& callback) {
198 if (file_writer_)
199 return file_writer_->Initialize(callback);
201 data_.clear();
202 return net::OK;
205 int ResponseWriter::Write(net::IOBuffer* buffer,
206 int num_bytes,
207 const net::CompletionCallback& callback) {
208 if (!get_content_callback_.is_null()) {
209 get_content_callback_.Run(
210 HTTP_SUCCESS,
211 make_scoped_ptr(new std::string(buffer->data(), num_bytes)));
214 if (file_writer_) {
215 const int result = file_writer_->Write(
216 buffer, num_bytes,
217 base::Bind(&ResponseWriter::DidWrite,
218 weak_ptr_factory_.GetWeakPtr(),
219 make_scoped_refptr(buffer), callback));
220 if (result != net::ERR_IO_PENDING)
221 DidWrite(buffer, net::CompletionCallback(), result);
222 return result;
225 data_.append(buffer->data(), num_bytes);
226 return num_bytes;
229 int ResponseWriter::Finish(const net::CompletionCallback& callback) {
230 if (file_writer_)
231 return file_writer_->Finish(callback);
233 return net::OK;
236 void ResponseWriter::DidWrite(scoped_refptr<net::IOBuffer> buffer,
237 const net::CompletionCallback& callback,
238 int result) {
239 if (result > 0) {
240 // Even if file_writer_ is used, append the data to |data_|, so that it can
241 // be used to get error information in case of server side errors.
242 // The size limit is to avoid consuming too much redundant memory.
243 const size_t kMaxStringSize = 1024*1024;
244 if (data_.size() < kMaxStringSize) {
245 data_.append(buffer->data(), std::min(static_cast<size_t>(result),
246 kMaxStringSize - data_.size()));
250 if (!callback.is_null())
251 callback.Run(result);
254 //============================ UrlFetchRequestBase ===========================
256 UrlFetchRequestBase::UrlFetchRequestBase(RequestSender* sender)
257 : re_authenticate_count_(0),
258 response_writer_(NULL),
259 sender_(sender),
260 error_code_(DRIVE_OTHER_ERROR),
261 weak_ptr_factory_(this) {
264 UrlFetchRequestBase::~UrlFetchRequestBase() {}
266 void UrlFetchRequestBase::Start(const std::string& access_token,
267 const std::string& custom_user_agent,
268 const ReAuthenticateCallback& callback) {
269 DCHECK(CalledOnValidThread());
270 DCHECK(!access_token.empty());
271 DCHECK(!callback.is_null());
272 DCHECK(re_authenticate_callback_.is_null());
274 re_authenticate_callback_ = callback;
276 GURL url = GetURL();
277 if (url.is_empty()) {
278 // Error is found on generating the url. Send the error message to the
279 // callback, and then return immediately without trying to connect
280 // to the server.
281 RunCallbackOnPrematureFailure(DRIVE_OTHER_ERROR);
282 return;
284 DVLOG(1) << "URL: " << url.spec();
286 URLFetcher::RequestType request_type = GetRequestType();
287 url_fetcher_.reset(URLFetcher::Create(url, request_type, this));
288 url_fetcher_->SetRequestContext(sender_->url_request_context_getter());
289 // Always set flags to neither send nor save cookies.
290 url_fetcher_->SetLoadFlags(
291 net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES |
292 net::LOAD_DISABLE_CACHE);
294 base::FilePath output_file_path;
295 GetContentCallback get_content_callback;
296 GetOutputFilePath(&output_file_path, &get_content_callback);
297 if (!get_content_callback.is_null())
298 get_content_callback = CreateRelayCallback(get_content_callback);
299 response_writer_ = new ResponseWriter(blocking_task_runner(),
300 output_file_path,
301 get_content_callback);
302 url_fetcher_->SaveResponseWithWriter(
303 scoped_ptr<net::URLFetcherResponseWriter>(response_writer_));
305 // Add request headers.
306 // Note that SetExtraRequestHeaders clears the current headers and sets it
307 // to the passed-in headers, so calling it for each header will result in
308 // only the last header being set in request headers.
309 if (!custom_user_agent.empty())
310 url_fetcher_->AddExtraRequestHeader("User-Agent: " + custom_user_agent);
311 url_fetcher_->AddExtraRequestHeader(kGDataVersionHeader);
312 url_fetcher_->AddExtraRequestHeader(
313 base::StringPrintf(kAuthorizationHeaderFormat, access_token.data()));
314 std::vector<std::string> headers = GetExtraRequestHeaders();
315 for (size_t i = 0; i < headers.size(); ++i) {
316 url_fetcher_->AddExtraRequestHeader(headers[i]);
317 DVLOG(1) << "Extra header: " << headers[i];
320 // Set upload data if available.
321 std::string upload_content_type;
322 std::string upload_content;
323 if (GetContentData(&upload_content_type, &upload_content)) {
324 url_fetcher_->SetUploadData(upload_content_type, upload_content);
325 } else {
326 base::FilePath local_file_path;
327 int64 range_offset = 0;
328 int64 range_length = 0;
329 if (GetContentFile(&local_file_path, &range_offset, &range_length,
330 &upload_content_type)) {
331 url_fetcher_->SetUploadFilePath(
332 upload_content_type,
333 local_file_path,
334 range_offset,
335 range_length,
336 blocking_task_runner());
337 } else {
338 // Even if there is no content data, UrlFetcher requires to set empty
339 // upload data string for POST, PUT and PATCH methods, explicitly.
340 // It is because that most requests of those methods have non-empty
341 // body, and UrlFetcher checks whether it is actually not forgotten.
342 if (request_type == URLFetcher::POST ||
343 request_type == URLFetcher::PUT ||
344 request_type == URLFetcher::PATCH) {
345 // Set empty upload content-type and upload content, so that
346 // the request will have no "Content-type: " header and no content.
347 url_fetcher_->SetUploadData(std::string(), std::string());
352 url_fetcher_->Start();
355 URLFetcher::RequestType UrlFetchRequestBase::GetRequestType() const {
356 return URLFetcher::GET;
359 std::vector<std::string> UrlFetchRequestBase::GetExtraRequestHeaders() const {
360 return std::vector<std::string>();
363 bool UrlFetchRequestBase::GetContentData(std::string* upload_content_type,
364 std::string* upload_content) {
365 return false;
368 bool UrlFetchRequestBase::GetContentFile(base::FilePath* local_file_path,
369 int64* range_offset,
370 int64* range_length,
371 std::string* upload_content_type) {
372 return false;
375 void UrlFetchRequestBase::GetOutputFilePath(
376 base::FilePath* local_file_path,
377 GetContentCallback* get_content_callback) {
380 void UrlFetchRequestBase::Cancel() {
381 response_writer_ = NULL;
382 url_fetcher_.reset(NULL);
383 RunCallbackOnPrematureFailure(DRIVE_CANCELLED);
384 sender_->RequestFinished(this);
387 DriveApiErrorCode UrlFetchRequestBase::GetErrorCode() {
388 return error_code_;
391 bool UrlFetchRequestBase::CalledOnValidThread() {
392 return thread_checker_.CalledOnValidThread();
395 base::SequencedTaskRunner* UrlFetchRequestBase::blocking_task_runner() const {
396 return sender_->blocking_task_runner();
399 void UrlFetchRequestBase::OnProcessURLFetchResultsComplete() {
400 sender_->RequestFinished(this);
403 void UrlFetchRequestBase::OnURLFetchComplete(const URLFetcher* source) {
404 DVLOG(1) << "Response headers:\n" << GetResponseHeadersAsString(source);
406 // Determine error code.
407 error_code_ = static_cast<DriveApiErrorCode>(source->GetResponseCode());
408 if (!source->GetStatus().is_success()) {
409 switch (source->GetStatus().error()) {
410 case net::ERR_NETWORK_CHANGED:
411 error_code_ = DRIVE_NO_CONNECTION;
412 break;
413 default:
414 error_code_ = DRIVE_OTHER_ERROR;
418 // The server may return detailed error status in JSON.
419 // See https://developers.google.com/drive/handle-errors
420 if (!IsSuccessfulResponseCode(error_code_)) {
421 DVLOG(1) << response_writer_->data();
423 const char kErrorKey[] = "error";
424 const char kErrorErrorsKey[] = "errors";
425 const char kErrorReasonKey[] = "reason";
426 const char kErrorMessageKey[] = "message";
427 const char kErrorReasonRateLimitExceeded[] = "rateLimitExceeded";
428 const char kErrorReasonUserRateLimitExceeded[] = "userRateLimitExceeded";
429 const char kErrorReasonQuotaExceeded[] = "quotaExceeded";
431 scoped_ptr<base::Value> value(ParseJson(response_writer_->data()));
432 base::DictionaryValue* dictionary = NULL;
433 base::DictionaryValue* error = NULL;
434 if (value &&
435 value->GetAsDictionary(&dictionary) &&
436 dictionary->GetDictionaryWithoutPathExpansion(kErrorKey, &error)) {
437 // Get error message.
438 std::string message;
439 error->GetStringWithoutPathExpansion(kErrorMessageKey, &message);
440 DLOG(ERROR) << "code: " << error_code_ << ", message: " << message;
442 // Override the error code based on the reason of the first error.
443 base::ListValue* errors = NULL;
444 base::DictionaryValue* first_error = NULL;
445 if (error->GetListWithoutPathExpansion(kErrorErrorsKey, &errors) &&
446 errors->GetDictionary(0, &first_error)) {
447 std::string reason;
448 first_error->GetStringWithoutPathExpansion(kErrorReasonKey, &reason);
449 if (reason == kErrorReasonRateLimitExceeded ||
450 reason == kErrorReasonUserRateLimitExceeded)
451 error_code_ = HTTP_SERVICE_UNAVAILABLE;
452 if (reason == kErrorReasonQuotaExceeded)
453 error_code_ = DRIVE_NO_SPACE;
458 // Handle authentication failure.
459 if (error_code_ == HTTP_UNAUTHORIZED) {
460 if (++re_authenticate_count_ <= kMaxReAuthenticateAttemptsPerRequest) {
461 // Reset re_authenticate_callback_ so Start() can be called again.
462 ReAuthenticateCallback callback = re_authenticate_callback_;
463 re_authenticate_callback_.Reset();
464 callback.Run(this);
465 return;
468 OnAuthFailed(error_code_);
469 return;
472 // Overridden by each specialization
473 ProcessURLFetchResults(source);
476 void UrlFetchRequestBase::OnAuthFailed(DriveApiErrorCode code) {
477 RunCallbackOnPrematureFailure(code);
478 sender_->RequestFinished(this);
481 base::WeakPtr<AuthenticatedRequestInterface>
482 UrlFetchRequestBase::GetWeakPtr() {
483 return weak_ptr_factory_.GetWeakPtr();
486 //============================ EntryActionRequest ============================
488 EntryActionRequest::EntryActionRequest(RequestSender* sender,
489 const EntryActionCallback& callback)
490 : UrlFetchRequestBase(sender),
491 callback_(callback) {
492 DCHECK(!callback_.is_null());
495 EntryActionRequest::~EntryActionRequest() {}
497 void EntryActionRequest::ProcessURLFetchResults(const URLFetcher* source) {
498 callback_.Run(GetErrorCode());
499 OnProcessURLFetchResultsComplete();
502 void EntryActionRequest::RunCallbackOnPrematureFailure(DriveApiErrorCode code) {
503 callback_.Run(code);
506 //========================= InitiateUploadRequestBase ========================
508 InitiateUploadRequestBase::InitiateUploadRequestBase(
509 RequestSender* sender,
510 const InitiateUploadCallback& callback,
511 const std::string& content_type,
512 int64 content_length)
513 : UrlFetchRequestBase(sender),
514 callback_(callback),
515 content_type_(content_type),
516 content_length_(content_length) {
517 DCHECK(!callback_.is_null());
518 DCHECK(!content_type_.empty());
519 DCHECK_GE(content_length_, 0);
522 InitiateUploadRequestBase::~InitiateUploadRequestBase() {}
524 void InitiateUploadRequestBase::ProcessURLFetchResults(
525 const URLFetcher* source) {
526 DriveApiErrorCode code = GetErrorCode();
528 std::string upload_location;
529 if (code == HTTP_SUCCESS) {
530 // Retrieve value of the first "Location" header.
531 source->GetResponseHeaders()->EnumerateHeader(NULL,
532 kUploadResponseLocation,
533 &upload_location);
536 callback_.Run(code, GURL(upload_location));
537 OnProcessURLFetchResultsComplete();
540 void InitiateUploadRequestBase::RunCallbackOnPrematureFailure(
541 DriveApiErrorCode code) {
542 callback_.Run(code, GURL());
545 std::vector<std::string>
546 InitiateUploadRequestBase::GetExtraRequestHeaders() const {
547 std::vector<std::string> headers;
548 headers.push_back(kUploadContentType + content_type_);
549 headers.push_back(
550 kUploadContentLength + base::Int64ToString(content_length_));
551 return headers;
554 //============================ UploadRangeResponse =============================
556 UploadRangeResponse::UploadRangeResponse()
557 : code(HTTP_SUCCESS),
558 start_position_received(0),
559 end_position_received(0) {
562 UploadRangeResponse::UploadRangeResponse(DriveApiErrorCode code,
563 int64 start_position_received,
564 int64 end_position_received)
565 : code(code),
566 start_position_received(start_position_received),
567 end_position_received(end_position_received) {
570 UploadRangeResponse::~UploadRangeResponse() {
573 //========================== UploadRangeRequestBase ==========================
575 UploadRangeRequestBase::UploadRangeRequestBase(RequestSender* sender,
576 const GURL& upload_url)
577 : UrlFetchRequestBase(sender),
578 upload_url_(upload_url),
579 weak_ptr_factory_(this) {
582 UploadRangeRequestBase::~UploadRangeRequestBase() {}
584 GURL UploadRangeRequestBase::GetURL() const {
585 // This is very tricky to get json from this request. To do that, &alt=json
586 // has to be appended not here but in InitiateUploadRequestBase::GetURL().
587 return upload_url_;
590 URLFetcher::RequestType UploadRangeRequestBase::GetRequestType() const {
591 return URLFetcher::PUT;
594 void UploadRangeRequestBase::ProcessURLFetchResults(
595 const URLFetcher* source) {
596 DriveApiErrorCode code = GetErrorCode();
597 net::HttpResponseHeaders* hdrs = source->GetResponseHeaders();
599 if (code == HTTP_RESUME_INCOMPLETE) {
600 // Retrieve value of the first "Range" header.
601 // The Range header is appeared only if there is at least one received
602 // byte. So, initialize the positions by 0 so that the [0,0) will be
603 // returned via the |callback_| for empty data case.
604 int64 start_position_received = 0;
605 int64 end_position_received = 0;
606 std::string range_received;
607 hdrs->EnumerateHeader(NULL, kUploadResponseRange, &range_received);
608 if (!range_received.empty()) { // Parse the range header.
609 std::vector<net::HttpByteRange> ranges;
610 if (net::HttpUtil::ParseRangeHeader(range_received, &ranges) &&
611 !ranges.empty() ) {
612 // We only care about the first start-end pair in the range.
614 // Range header represents the range inclusively, while we are treating
615 // ranges exclusively (i.e., end_position_received should be one passed
616 // the last valid index). So "+ 1" is added.
617 start_position_received = ranges[0].first_byte_position();
618 end_position_received = ranges[0].last_byte_position() + 1;
621 // The Range header has the received data range, so the start position
622 // should be always 0.
623 DCHECK_EQ(start_position_received, 0);
625 OnRangeRequestComplete(UploadRangeResponse(code,
626 start_position_received,
627 end_position_received),
628 scoped_ptr<base::Value>());
630 OnProcessURLFetchResultsComplete();
631 } else if (code == HTTP_CREATED || code == HTTP_SUCCESS) {
632 // The upload is successfully done. Parse the response which should be
633 // the entry's metadata.
634 ParseJsonOnBlockingPool(blocking_task_runner(),
635 response_writer()->data(),
636 base::Bind(&UploadRangeRequestBase::OnDataParsed,
637 weak_ptr_factory_.GetWeakPtr(),
638 code));
639 } else {
640 // Failed to upload. Run callbacks to notify the error.
641 OnRangeRequestComplete(
642 UploadRangeResponse(code, -1, -1), scoped_ptr<base::Value>());
643 OnProcessURLFetchResultsComplete();
647 void UploadRangeRequestBase::OnDataParsed(DriveApiErrorCode code,
648 scoped_ptr<base::Value> value) {
649 DCHECK(CalledOnValidThread());
650 DCHECK(code == HTTP_CREATED || code == HTTP_SUCCESS);
652 OnRangeRequestComplete(UploadRangeResponse(code, -1, -1), value.Pass());
653 OnProcessURLFetchResultsComplete();
656 void UploadRangeRequestBase::RunCallbackOnPrematureFailure(
657 DriveApiErrorCode code) {
658 OnRangeRequestComplete(
659 UploadRangeResponse(code, 0, 0), scoped_ptr<base::Value>());
662 //========================== ResumeUploadRequestBase =========================
664 ResumeUploadRequestBase::ResumeUploadRequestBase(
665 RequestSender* sender,
666 const GURL& upload_location,
667 int64 start_position,
668 int64 end_position,
669 int64 content_length,
670 const std::string& content_type,
671 const base::FilePath& local_file_path)
672 : UploadRangeRequestBase(sender, upload_location),
673 start_position_(start_position),
674 end_position_(end_position),
675 content_length_(content_length),
676 content_type_(content_type),
677 local_file_path_(local_file_path) {
678 DCHECK_LE(start_position_, end_position_);
681 ResumeUploadRequestBase::~ResumeUploadRequestBase() {}
683 std::vector<std::string>
684 ResumeUploadRequestBase::GetExtraRequestHeaders() const {
685 if (content_length_ == 0) {
686 // For uploading an empty document, just PUT an empty content.
687 DCHECK_EQ(start_position_, 0);
688 DCHECK_EQ(end_position_, 0);
689 return std::vector<std::string>();
692 // The header looks like
693 // Content-Range: bytes <start_position>-<end_position>/<content_length>
694 // for example:
695 // Content-Range: bytes 7864320-8388607/13851821
696 // The header takes inclusive range, so we adjust by "end_position - 1".
697 DCHECK_GE(start_position_, 0);
698 DCHECK_GT(end_position_, 0);
699 DCHECK_GE(content_length_, 0);
701 std::vector<std::string> headers;
702 headers.push_back(
703 std::string(kUploadContentRange) +
704 base::Int64ToString(start_position_) + "-" +
705 base::Int64ToString(end_position_ - 1) + "/" +
706 base::Int64ToString(content_length_));
707 return headers;
710 bool ResumeUploadRequestBase::GetContentFile(
711 base::FilePath* local_file_path,
712 int64* range_offset,
713 int64* range_length,
714 std::string* upload_content_type) {
715 if (start_position_ == end_position_) {
716 // No content data.
717 return false;
720 *local_file_path = local_file_path_;
721 *range_offset = start_position_;
722 *range_length = end_position_ - start_position_;
723 *upload_content_type = content_type_;
724 return true;
727 //======================== GetUploadStatusRequestBase ========================
729 GetUploadStatusRequestBase::GetUploadStatusRequestBase(RequestSender* sender,
730 const GURL& upload_url,
731 int64 content_length)
732 : UploadRangeRequestBase(sender, upload_url),
733 content_length_(content_length) {}
735 GetUploadStatusRequestBase::~GetUploadStatusRequestBase() {}
737 std::vector<std::string>
738 GetUploadStatusRequestBase::GetExtraRequestHeaders() const {
739 // The header looks like
740 // Content-Range: bytes */<content_length>
741 // for example:
742 // Content-Range: bytes */13851821
743 DCHECK_GE(content_length_, 0);
745 std::vector<std::string> headers;
746 headers.push_back(
747 std::string(kUploadContentRange) + "*/" +
748 base::Int64ToString(content_length_));
749 return headers;
752 //========================= MultipartUploadRequestBase ========================
754 MultipartUploadRequestBase::MultipartUploadRequestBase(
755 RequestSender* sender,
756 const std::string& metadata_json,
757 const std::string& content_type,
758 int64 content_length,
759 const base::FilePath& local_file_path,
760 const FileResourceCallback& callback,
761 const ProgressCallback& progress_callback)
762 : UrlFetchRequestBase(sender),
763 metadata_json_(metadata_json),
764 content_type_(content_type),
765 local_path_(local_file_path),
766 callback_(callback),
767 progress_callback_(progress_callback),
768 weak_ptr_factory_(this) {
769 DCHECK(!content_type.empty());
770 DCHECK_GE(content_length, 0);
771 DCHECK(!local_file_path.empty());
772 DCHECK(!callback.is_null());
775 MultipartUploadRequestBase::~MultipartUploadRequestBase() {
778 void MultipartUploadRequestBase::Start(const std::string& access_token,
779 const std::string& custom_user_agent,
780 const ReAuthenticateCallback& callback) {
781 // If the request is cancelled, the request instance will be deleted in
782 // |UrlFetchRequestBase::Cancel| and OnPrepareUploadContent won't be called.
783 std::string* const upload_content_type = new std::string();
784 std::string* const upload_content_data = new std::string();
785 PostTaskAndReplyWithResult(
786 blocking_task_runner(), FROM_HERE,
787 base::Bind(&GetMultipartContent, boundary_, metadata_json_, content_type_,
788 local_path_, base::Unretained(upload_content_type),
789 base::Unretained(upload_content_data)),
790 base::Bind(&MultipartUploadRequestBase::OnPrepareUploadContent,
791 weak_ptr_factory_.GetWeakPtr(), access_token,
792 custom_user_agent, callback, base::Owned(upload_content_type),
793 base::Owned(upload_content_data)));
796 void MultipartUploadRequestBase::OnPrepareUploadContent(
797 const std::string& access_token,
798 const std::string& custom_user_agent,
799 const ReAuthenticateCallback& callback,
800 std::string* upload_content_type,
801 std::string* upload_content_data,
802 bool result) {
803 if (!result) {
804 RunCallbackOnPrematureFailure(DRIVE_FILE_ERROR);
805 return;
807 upload_content_type_.swap(*upload_content_type);
808 upload_content_data_.swap(*upload_content_data);
809 UrlFetchRequestBase::Start(access_token, custom_user_agent, callback);
812 void MultipartUploadRequestBase::SetBoundaryForTesting(
813 const std::string& boundary) {
814 boundary_ = boundary;
817 bool MultipartUploadRequestBase::GetContentData(
818 std::string* upload_content_type,
819 std::string* upload_content_data) {
820 // TODO(hirono): Pass stream instead of actual data to reduce memory usage.
821 upload_content_type->swap(upload_content_type_);
822 upload_content_data->swap(upload_content_data_);
823 return true;
826 void MultipartUploadRequestBase::ProcessURLFetchResults(
827 const URLFetcher* source) {
828 // The upload is successfully done. Parse the response which should be
829 // the entry's metadata.
830 const DriveApiErrorCode code = GetErrorCode();
831 if (code == HTTP_CREATED || code == HTTP_SUCCESS) {
832 ParseJsonOnBlockingPool(
833 blocking_task_runner(), response_writer()->data(),
834 base::Bind(&MultipartUploadRequestBase::OnDataParsed,
835 weak_ptr_factory_.GetWeakPtr(), code));
836 } else {
837 OnDataParsed(code, scoped_ptr<base::Value>());
841 void MultipartUploadRequestBase::RunCallbackOnPrematureFailure(
842 DriveApiErrorCode code) {
843 callback_.Run(code, scoped_ptr<FileResource>());
846 void MultipartUploadRequestBase::OnURLFetchUploadProgress(
847 const net::URLFetcher* source,
848 int64 current,
849 int64 total) {
850 if (!progress_callback_.is_null())
851 progress_callback_.Run(current, total);
854 void MultipartUploadRequestBase::OnDataParsed(DriveApiErrorCode code,
855 scoped_ptr<base::Value> value) {
856 DCHECK(CalledOnValidThread());
857 if (value)
858 callback_.Run(code, google_apis::FileResource::CreateFrom(*value));
859 else
860 callback_.Run(DRIVE_PARSE_ERROR, scoped_ptr<FileResource>());
861 OnProcessURLFetchResultsComplete();
864 //============================ DownloadFileRequestBase =========================
866 DownloadFileRequestBase::DownloadFileRequestBase(
867 RequestSender* sender,
868 const DownloadActionCallback& download_action_callback,
869 const GetContentCallback& get_content_callback,
870 const ProgressCallback& progress_callback,
871 const GURL& download_url,
872 const base::FilePath& output_file_path)
873 : UrlFetchRequestBase(sender),
874 download_action_callback_(download_action_callback),
875 get_content_callback_(get_content_callback),
876 progress_callback_(progress_callback),
877 download_url_(download_url),
878 output_file_path_(output_file_path) {
879 DCHECK(!download_action_callback_.is_null());
880 DCHECK(!output_file_path_.empty());
881 // get_content_callback may be null.
884 DownloadFileRequestBase::~DownloadFileRequestBase() {}
886 // Overridden from UrlFetchRequestBase.
887 GURL DownloadFileRequestBase::GetURL() const {
888 return download_url_;
891 void DownloadFileRequestBase::GetOutputFilePath(
892 base::FilePath* local_file_path,
893 GetContentCallback* get_content_callback) {
894 // Configure so that the downloaded content is saved to |output_file_path_|.
895 *local_file_path = output_file_path_;
896 *get_content_callback = get_content_callback_;
899 void DownloadFileRequestBase::OnURLFetchDownloadProgress(
900 const URLFetcher* source,
901 int64 current,
902 int64 total) {
903 if (!progress_callback_.is_null())
904 progress_callback_.Run(current, total);
907 void DownloadFileRequestBase::ProcessURLFetchResults(const URLFetcher* source) {
908 DriveApiErrorCode code = GetErrorCode();
910 // Take over the ownership of the the downloaded temp file.
911 base::FilePath temp_file;
912 if (code == HTTP_SUCCESS) {
913 response_writer()->DisownFile();
914 temp_file = output_file_path_;
917 download_action_callback_.Run(code, temp_file);
918 OnProcessURLFetchResultsComplete();
921 void DownloadFileRequestBase::RunCallbackOnPrematureFailure(
922 DriveApiErrorCode code) {
923 download_action_callback_.Run(code, base::FilePath());
926 } // namespace google_apis