Roll src/third_party/WebKit d26421b:4b1dbe3 (svn 194839:194840)
[chromium-blink-merge.git] / google_apis / drive / base_requests.cc
blob164be2e16a3b3fb7197bed7be2706bbefaf78b2a
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(
132 google_apis::MULTIPART_RELATED, predetermined_boundary, parts, &output);
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::string boundary;
171 // Generate random boundary.
172 if (predetermined_boundary.empty()) {
173 while (true) {
174 boundary.resize(kBoundarySize);
175 for (int i = 0; i < kBoundarySize; ++i) {
176 // Subtract 2 from the array size to exclude '\0', and to turn the size
177 // into the last index.
178 const int last_char_index = arraysize(kBoundaryCharacters) - 2;
179 boundary[i] = kBoundaryCharacters[base::RandInt(0, last_char_index)];
181 bool conflict_with_content = false;
182 for (auto& part : parts) {
183 if (part.data.find(boundary, 0) != std::string::npos) {
184 conflict_with_content = true;
185 break;
188 if (!conflict_with_content)
189 break;
191 } else {
192 boundary = predetermined_boundary;
195 switch (multipart_type) {
196 case MULTIPART_RELATED:
197 output->type = kMultipartRelatedMimeTypePrefix + boundary;
198 break;
199 case MULTIPART_MIXED:
200 output->type = kMultipartMixedMimeTypePrefix + boundary;
201 break;
204 output->data.clear();
205 for (auto& part : parts) {
206 output->data.append(base::StringPrintf(
207 kMultipartItemHeaderFormat, boundary.c_str(), part.type.c_str()));
208 output->data.append(part.data);
209 output->data.append("\n");
211 output->data.append(
212 base::StringPrintf(kMultipartFooterFormat, boundary.c_str()));
215 //=========================== ResponseWriter ==================================
216 ResponseWriter::ResponseWriter(base::SequencedTaskRunner* file_task_runner,
217 const base::FilePath& file_path,
218 const GetContentCallback& get_content_callback)
219 : get_content_callback_(get_content_callback),
220 weak_ptr_factory_(this) {
221 if (!file_path.empty()) {
222 file_writer_.reset(
223 new net::URLFetcherFileWriter(file_task_runner, file_path));
227 ResponseWriter::~ResponseWriter() {
230 void ResponseWriter::DisownFile() {
231 DCHECK(file_writer_);
232 file_writer_->DisownFile();
235 int ResponseWriter::Initialize(const net::CompletionCallback& callback) {
236 if (file_writer_)
237 return file_writer_->Initialize(callback);
239 data_.clear();
240 return net::OK;
243 int ResponseWriter::Write(net::IOBuffer* buffer,
244 int num_bytes,
245 const net::CompletionCallback& callback) {
246 if (!get_content_callback_.is_null()) {
247 get_content_callback_.Run(
248 HTTP_SUCCESS,
249 make_scoped_ptr(new std::string(buffer->data(), num_bytes)));
252 if (file_writer_) {
253 const int result = file_writer_->Write(
254 buffer, num_bytes,
255 base::Bind(&ResponseWriter::DidWrite,
256 weak_ptr_factory_.GetWeakPtr(),
257 make_scoped_refptr(buffer), callback));
258 if (result != net::ERR_IO_PENDING)
259 DidWrite(buffer, net::CompletionCallback(), result);
260 return result;
263 data_.append(buffer->data(), num_bytes);
264 return num_bytes;
267 int ResponseWriter::Finish(const net::CompletionCallback& callback) {
268 if (file_writer_)
269 return file_writer_->Finish(callback);
271 return net::OK;
274 void ResponseWriter::DidWrite(scoped_refptr<net::IOBuffer> buffer,
275 const net::CompletionCallback& callback,
276 int result) {
277 if (result > 0) {
278 // Even if file_writer_ is used, append the data to |data_|, so that it can
279 // be used to get error information in case of server side errors.
280 // The size limit is to avoid consuming too much redundant memory.
281 const size_t kMaxStringSize = 1024*1024;
282 if (data_.size() < kMaxStringSize) {
283 data_.append(buffer->data(), std::min(static_cast<size_t>(result),
284 kMaxStringSize - data_.size()));
288 if (!callback.is_null())
289 callback.Run(result);
292 //============================ UrlFetchRequestBase ===========================
294 UrlFetchRequestBase::UrlFetchRequestBase(RequestSender* sender)
295 : re_authenticate_count_(0),
296 response_writer_(NULL),
297 sender_(sender),
298 error_code_(DRIVE_OTHER_ERROR),
299 weak_ptr_factory_(this) {
302 UrlFetchRequestBase::~UrlFetchRequestBase() {}
304 void UrlFetchRequestBase::Start(const std::string& access_token,
305 const std::string& custom_user_agent,
306 const ReAuthenticateCallback& callback) {
307 DCHECK(CalledOnValidThread());
308 DCHECK(!access_token.empty());
309 DCHECK(!callback.is_null());
310 DCHECK(re_authenticate_callback_.is_null());
311 Prepare(base::Bind(&UrlFetchRequestBase::StartAfterPrepare,
312 weak_ptr_factory_.GetWeakPtr(), access_token,
313 custom_user_agent, callback));
316 void UrlFetchRequestBase::Prepare(const PrepareCallback& callback) {
317 DCHECK(CalledOnValidThread());
318 DCHECK(!callback.is_null());
319 callback.Run(HTTP_SUCCESS);
322 void UrlFetchRequestBase::StartAfterPrepare(
323 const std::string& access_token,
324 const std::string& custom_user_agent,
325 const ReAuthenticateCallback& callback,
326 DriveApiErrorCode code) {
327 DCHECK(CalledOnValidThread());
328 DCHECK(!access_token.empty());
329 DCHECK(!callback.is_null());
330 DCHECK(re_authenticate_callback_.is_null());
332 const GURL url = GetURL();
333 DriveApiErrorCode error_code;
334 if (IsSuccessfulDriveApiErrorCode(code))
335 error_code = code;
336 else if (url.is_empty())
337 error_code = DRIVE_OTHER_ERROR;
338 else
339 error_code = HTTP_SUCCESS;
341 if (error_code != HTTP_SUCCESS) {
342 // Error is found on generating the url or preparing the request. Send the
343 // error message to the callback, and then return immediately without trying
344 // to connect to the server. We need to call CompleteRequestWithError
345 // asynchronously because client code does not assume result callback is
346 // called synchronously.
347 base::ThreadTaskRunnerHandle::Get()->PostTask(
348 FROM_HERE, base::Bind(&UrlFetchRequestBase::CompleteRequestWithError,
349 weak_ptr_factory_.GetWeakPtr(), error_code));
350 return;
353 re_authenticate_callback_ = callback;
354 DVLOG(1) << "URL: " << url.spec();
356 URLFetcher::RequestType request_type = GetRequestType();
357 url_fetcher_ = URLFetcher::Create(url, request_type, this);
358 url_fetcher_->SetRequestContext(sender_->url_request_context_getter());
359 // Always set flags to neither send nor save cookies.
360 url_fetcher_->SetLoadFlags(
361 net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES |
362 net::LOAD_DISABLE_CACHE);
364 base::FilePath output_file_path;
365 GetContentCallback get_content_callback;
366 GetOutputFilePath(&output_file_path, &get_content_callback);
367 if (!get_content_callback.is_null())
368 get_content_callback = CreateRelayCallback(get_content_callback);
369 response_writer_ = new ResponseWriter(blocking_task_runner(),
370 output_file_path,
371 get_content_callback);
372 url_fetcher_->SaveResponseWithWriter(
373 scoped_ptr<net::URLFetcherResponseWriter>(response_writer_));
375 // Add request headers.
376 // Note that SetExtraRequestHeaders clears the current headers and sets it
377 // to the passed-in headers, so calling it for each header will result in
378 // only the last header being set in request headers.
379 if (!custom_user_agent.empty())
380 url_fetcher_->AddExtraRequestHeader("User-Agent: " + custom_user_agent);
381 url_fetcher_->AddExtraRequestHeader(kGDataVersionHeader);
382 url_fetcher_->AddExtraRequestHeader(
383 base::StringPrintf(kAuthorizationHeaderFormat, access_token.data()));
384 std::vector<std::string> headers = GetExtraRequestHeaders();
385 for (size_t i = 0; i < headers.size(); ++i) {
386 url_fetcher_->AddExtraRequestHeader(headers[i]);
387 DVLOG(1) << "Extra header: " << headers[i];
390 // Set upload data if available.
391 std::string upload_content_type;
392 std::string upload_content;
393 if (GetContentData(&upload_content_type, &upload_content)) {
394 url_fetcher_->SetUploadData(upload_content_type, upload_content);
395 } else {
396 base::FilePath local_file_path;
397 int64 range_offset = 0;
398 int64 range_length = 0;
399 if (GetContentFile(&local_file_path, &range_offset, &range_length,
400 &upload_content_type)) {
401 url_fetcher_->SetUploadFilePath(
402 upload_content_type,
403 local_file_path,
404 range_offset,
405 range_length,
406 blocking_task_runner());
407 } else {
408 // Even if there is no content data, UrlFetcher requires to set empty
409 // upload data string for POST, PUT and PATCH methods, explicitly.
410 // It is because that most requests of those methods have non-empty
411 // body, and UrlFetcher checks whether it is actually not forgotten.
412 if (request_type == URLFetcher::POST ||
413 request_type == URLFetcher::PUT ||
414 request_type == URLFetcher::PATCH) {
415 // Set empty upload content-type and upload content, so that
416 // the request will have no "Content-type: " header and no content.
417 url_fetcher_->SetUploadData(std::string(), std::string());
422 url_fetcher_->Start();
425 URLFetcher::RequestType UrlFetchRequestBase::GetRequestType() const {
426 return URLFetcher::GET;
429 std::vector<std::string> UrlFetchRequestBase::GetExtraRequestHeaders() const {
430 return std::vector<std::string>();
433 bool UrlFetchRequestBase::GetContentData(std::string* upload_content_type,
434 std::string* upload_content) {
435 return false;
438 bool UrlFetchRequestBase::GetContentFile(base::FilePath* local_file_path,
439 int64* range_offset,
440 int64* range_length,
441 std::string* upload_content_type) {
442 return false;
445 void UrlFetchRequestBase::GetOutputFilePath(
446 base::FilePath* local_file_path,
447 GetContentCallback* get_content_callback) {
450 void UrlFetchRequestBase::Cancel() {
451 response_writer_ = NULL;
452 url_fetcher_.reset(NULL);
453 CompleteRequestWithError(DRIVE_CANCELLED);
456 DriveApiErrorCode UrlFetchRequestBase::GetErrorCode() {
457 return error_code_;
460 bool UrlFetchRequestBase::CalledOnValidThread() {
461 return thread_checker_.CalledOnValidThread();
464 base::SequencedTaskRunner* UrlFetchRequestBase::blocking_task_runner() const {
465 return sender_->blocking_task_runner();
468 void UrlFetchRequestBase::OnProcessURLFetchResultsComplete() {
469 sender_->RequestFinished(this);
472 void UrlFetchRequestBase::OnURLFetchComplete(const URLFetcher* source) {
473 DVLOG(1) << "Response headers:\n" << GetResponseHeadersAsString(source);
475 // Determine error code.
476 error_code_ = static_cast<DriveApiErrorCode>(source->GetResponseCode());
477 if (!source->GetStatus().is_success()) {
478 switch (source->GetStatus().error()) {
479 case net::ERR_NETWORK_CHANGED:
480 error_code_ = DRIVE_NO_CONNECTION;
481 break;
482 default:
483 error_code_ = DRIVE_OTHER_ERROR;
487 // The server may return detailed error status in JSON.
488 // See https://developers.google.com/drive/handle-errors
489 if (!IsSuccessfulDriveApiErrorCode(error_code_)) {
490 DVLOG(1) << response_writer_->data();
492 const char kErrorKey[] = "error";
493 const char kErrorErrorsKey[] = "errors";
494 const char kErrorReasonKey[] = "reason";
495 const char kErrorMessageKey[] = "message";
496 const char kErrorReasonRateLimitExceeded[] = "rateLimitExceeded";
497 const char kErrorReasonUserRateLimitExceeded[] = "userRateLimitExceeded";
498 const char kErrorReasonQuotaExceeded[] = "quotaExceeded";
500 scoped_ptr<base::Value> value(ParseJson(response_writer_->data()));
501 base::DictionaryValue* dictionary = NULL;
502 base::DictionaryValue* error = NULL;
503 if (value &&
504 value->GetAsDictionary(&dictionary) &&
505 dictionary->GetDictionaryWithoutPathExpansion(kErrorKey, &error)) {
506 // Get error message.
507 std::string message;
508 error->GetStringWithoutPathExpansion(kErrorMessageKey, &message);
509 DLOG(ERROR) << "code: " << error_code_ << ", message: " << message;
511 // Override the error code based on the reason of the first error.
512 base::ListValue* errors = NULL;
513 base::DictionaryValue* first_error = NULL;
514 if (error->GetListWithoutPathExpansion(kErrorErrorsKey, &errors) &&
515 errors->GetDictionary(0, &first_error)) {
516 std::string reason;
517 first_error->GetStringWithoutPathExpansion(kErrorReasonKey, &reason);
518 if (reason == kErrorReasonRateLimitExceeded ||
519 reason == kErrorReasonUserRateLimitExceeded)
520 error_code_ = HTTP_SERVICE_UNAVAILABLE;
521 if (reason == kErrorReasonQuotaExceeded)
522 error_code_ = DRIVE_NO_SPACE;
527 // Handle authentication failure.
528 if (error_code_ == HTTP_UNAUTHORIZED) {
529 if (++re_authenticate_count_ <= kMaxReAuthenticateAttemptsPerRequest) {
530 // Reset re_authenticate_callback_ so Start() can be called again.
531 ReAuthenticateCallback callback = re_authenticate_callback_;
532 re_authenticate_callback_.Reset();
533 callback.Run(this);
534 return;
537 OnAuthFailed(error_code_);
538 return;
541 // Overridden by each specialization
542 ProcessURLFetchResults(source);
545 void UrlFetchRequestBase::CompleteRequestWithError(DriveApiErrorCode code) {
546 RunCallbackOnPrematureFailure(code);
547 sender_->RequestFinished(this);
550 void UrlFetchRequestBase::OnAuthFailed(DriveApiErrorCode code) {
551 CompleteRequestWithError(code);
554 base::WeakPtr<AuthenticatedRequestInterface>
555 UrlFetchRequestBase::GetWeakPtr() {
556 return weak_ptr_factory_.GetWeakPtr();
559 //============================ BatchableRequestBase ============================
561 net::URLFetcher::RequestType BatchableRequestBase::GetRequestType() const {
562 return UrlFetchRequestBase::GetRequestType();
565 std::vector<std::string> BatchableRequestBase::GetExtraRequestHeaders() const {
566 return UrlFetchRequestBase::GetExtraRequestHeaders();
569 void BatchableRequestBase::Prepare(const PrepareCallback& callback) {
570 return UrlFetchRequestBase::Prepare(callback);
573 bool BatchableRequestBase::GetContentData(
574 std::string* upload_content_type, std::string* upload_content) {
575 return UrlFetchRequestBase::GetContentData(
576 upload_content_type, upload_content);
579 void BatchableRequestBase::ProcessURLFetchResults(
580 const net::URLFetcher* source) {
581 ProcessURLFetchResults(GetErrorCode(), response_writer()->data());
584 //============================ EntryActionRequest ============================
586 EntryActionRequest::EntryActionRequest(RequestSender* sender,
587 const EntryActionCallback& callback)
588 : UrlFetchRequestBase(sender),
589 callback_(callback) {
590 DCHECK(!callback_.is_null());
593 EntryActionRequest::~EntryActionRequest() {}
595 void EntryActionRequest::ProcessURLFetchResults(const URLFetcher* source) {
596 callback_.Run(GetErrorCode());
597 OnProcessURLFetchResultsComplete();
600 void EntryActionRequest::RunCallbackOnPrematureFailure(DriveApiErrorCode code) {
601 callback_.Run(code);
604 //========================= InitiateUploadRequestBase ========================
606 InitiateUploadRequestBase::InitiateUploadRequestBase(
607 RequestSender* sender,
608 const InitiateUploadCallback& callback,
609 const std::string& content_type,
610 int64 content_length)
611 : UrlFetchRequestBase(sender),
612 callback_(callback),
613 content_type_(content_type),
614 content_length_(content_length) {
615 DCHECK(!callback_.is_null());
616 DCHECK(!content_type_.empty());
617 DCHECK_GE(content_length_, 0);
620 InitiateUploadRequestBase::~InitiateUploadRequestBase() {}
622 void InitiateUploadRequestBase::ProcessURLFetchResults(
623 const URLFetcher* source) {
624 DriveApiErrorCode code = GetErrorCode();
626 std::string upload_location;
627 if (code == HTTP_SUCCESS) {
628 // Retrieve value of the first "Location" header.
629 source->GetResponseHeaders()->EnumerateHeader(NULL,
630 kUploadResponseLocation,
631 &upload_location);
634 callback_.Run(code, GURL(upload_location));
635 OnProcessURLFetchResultsComplete();
638 void InitiateUploadRequestBase::RunCallbackOnPrematureFailure(
639 DriveApiErrorCode code) {
640 callback_.Run(code, GURL());
643 std::vector<std::string>
644 InitiateUploadRequestBase::GetExtraRequestHeaders() const {
645 std::vector<std::string> headers;
646 headers.push_back(kUploadContentType + content_type_);
647 headers.push_back(
648 kUploadContentLength + base::Int64ToString(content_length_));
649 return headers;
652 //============================ UploadRangeResponse =============================
654 UploadRangeResponse::UploadRangeResponse()
655 : code(HTTP_SUCCESS),
656 start_position_received(0),
657 end_position_received(0) {
660 UploadRangeResponse::UploadRangeResponse(DriveApiErrorCode code,
661 int64 start_position_received,
662 int64 end_position_received)
663 : code(code),
664 start_position_received(start_position_received),
665 end_position_received(end_position_received) {
668 UploadRangeResponse::~UploadRangeResponse() {
671 //========================== UploadRangeRequestBase ==========================
673 UploadRangeRequestBase::UploadRangeRequestBase(RequestSender* sender,
674 const GURL& upload_url)
675 : UrlFetchRequestBase(sender),
676 upload_url_(upload_url),
677 weak_ptr_factory_(this) {
680 UploadRangeRequestBase::~UploadRangeRequestBase() {}
682 GURL UploadRangeRequestBase::GetURL() const {
683 // This is very tricky to get json from this request. To do that, &alt=json
684 // has to be appended not here but in InitiateUploadRequestBase::GetURL().
685 return upload_url_;
688 URLFetcher::RequestType UploadRangeRequestBase::GetRequestType() const {
689 return URLFetcher::PUT;
692 void UploadRangeRequestBase::ProcessURLFetchResults(
693 const URLFetcher* source) {
694 DriveApiErrorCode code = GetErrorCode();
695 net::HttpResponseHeaders* hdrs = source->GetResponseHeaders();
697 if (code == HTTP_RESUME_INCOMPLETE) {
698 // Retrieve value of the first "Range" header.
699 // The Range header is appeared only if there is at least one received
700 // byte. So, initialize the positions by 0 so that the [0,0) will be
701 // returned via the |callback_| for empty data case.
702 int64 start_position_received = 0;
703 int64 end_position_received = 0;
704 std::string range_received;
705 hdrs->EnumerateHeader(NULL, kUploadResponseRange, &range_received);
706 if (!range_received.empty()) { // Parse the range header.
707 std::vector<net::HttpByteRange> ranges;
708 if (net::HttpUtil::ParseRangeHeader(range_received, &ranges) &&
709 !ranges.empty() ) {
710 // We only care about the first start-end pair in the range.
712 // Range header represents the range inclusively, while we are treating
713 // ranges exclusively (i.e., end_position_received should be one passed
714 // the last valid index). So "+ 1" is added.
715 start_position_received = ranges[0].first_byte_position();
716 end_position_received = ranges[0].last_byte_position() + 1;
719 // The Range header has the received data range, so the start position
720 // should be always 0.
721 DCHECK_EQ(start_position_received, 0);
723 OnRangeRequestComplete(UploadRangeResponse(code,
724 start_position_received,
725 end_position_received),
726 scoped_ptr<base::Value>());
728 OnProcessURLFetchResultsComplete();
729 } else if (code == HTTP_CREATED || code == HTTP_SUCCESS) {
730 // The upload is successfully done. Parse the response which should be
731 // the entry's metadata.
732 ParseJsonOnBlockingPool(blocking_task_runner(),
733 response_writer()->data(),
734 base::Bind(&UploadRangeRequestBase::OnDataParsed,
735 weak_ptr_factory_.GetWeakPtr(),
736 code));
737 } else {
738 // Failed to upload. Run callbacks to notify the error.
739 OnRangeRequestComplete(
740 UploadRangeResponse(code, -1, -1), scoped_ptr<base::Value>());
741 OnProcessURLFetchResultsComplete();
745 void UploadRangeRequestBase::OnDataParsed(DriveApiErrorCode code,
746 scoped_ptr<base::Value> value) {
747 DCHECK(CalledOnValidThread());
748 DCHECK(code == HTTP_CREATED || code == HTTP_SUCCESS);
750 OnRangeRequestComplete(UploadRangeResponse(code, -1, -1), value.Pass());
751 OnProcessURLFetchResultsComplete();
754 void UploadRangeRequestBase::RunCallbackOnPrematureFailure(
755 DriveApiErrorCode code) {
756 OnRangeRequestComplete(
757 UploadRangeResponse(code, 0, 0), scoped_ptr<base::Value>());
760 //========================== ResumeUploadRequestBase =========================
762 ResumeUploadRequestBase::ResumeUploadRequestBase(
763 RequestSender* sender,
764 const GURL& upload_location,
765 int64 start_position,
766 int64 end_position,
767 int64 content_length,
768 const std::string& content_type,
769 const base::FilePath& local_file_path)
770 : UploadRangeRequestBase(sender, upload_location),
771 start_position_(start_position),
772 end_position_(end_position),
773 content_length_(content_length),
774 content_type_(content_type),
775 local_file_path_(local_file_path) {
776 DCHECK_LE(start_position_, end_position_);
779 ResumeUploadRequestBase::~ResumeUploadRequestBase() {}
781 std::vector<std::string>
782 ResumeUploadRequestBase::GetExtraRequestHeaders() const {
783 if (content_length_ == 0) {
784 // For uploading an empty document, just PUT an empty content.
785 DCHECK_EQ(start_position_, 0);
786 DCHECK_EQ(end_position_, 0);
787 return std::vector<std::string>();
790 // The header looks like
791 // Content-Range: bytes <start_position>-<end_position>/<content_length>
792 // for example:
793 // Content-Range: bytes 7864320-8388607/13851821
794 // The header takes inclusive range, so we adjust by "end_position - 1".
795 DCHECK_GE(start_position_, 0);
796 DCHECK_GT(end_position_, 0);
797 DCHECK_GE(content_length_, 0);
799 std::vector<std::string> headers;
800 headers.push_back(
801 std::string(kUploadContentRange) +
802 base::Int64ToString(start_position_) + "-" +
803 base::Int64ToString(end_position_ - 1) + "/" +
804 base::Int64ToString(content_length_));
805 return headers;
808 bool ResumeUploadRequestBase::GetContentFile(
809 base::FilePath* local_file_path,
810 int64* range_offset,
811 int64* range_length,
812 std::string* upload_content_type) {
813 if (start_position_ == end_position_) {
814 // No content data.
815 return false;
818 *local_file_path = local_file_path_;
819 *range_offset = start_position_;
820 *range_length = end_position_ - start_position_;
821 *upload_content_type = content_type_;
822 return true;
825 //======================== GetUploadStatusRequestBase ========================
827 GetUploadStatusRequestBase::GetUploadStatusRequestBase(RequestSender* sender,
828 const GURL& upload_url,
829 int64 content_length)
830 : UploadRangeRequestBase(sender, upload_url),
831 content_length_(content_length) {}
833 GetUploadStatusRequestBase::~GetUploadStatusRequestBase() {}
835 std::vector<std::string>
836 GetUploadStatusRequestBase::GetExtraRequestHeaders() const {
837 // The header looks like
838 // Content-Range: bytes */<content_length>
839 // for example:
840 // Content-Range: bytes */13851821
841 DCHECK_GE(content_length_, 0);
843 std::vector<std::string> headers;
844 headers.push_back(
845 std::string(kUploadContentRange) + "*/" +
846 base::Int64ToString(content_length_));
847 return headers;
850 //========================= MultipartUploadRequestBase ========================
852 MultipartUploadRequestBase::MultipartUploadRequestBase(
853 RequestSender* sender,
854 const std::string& metadata_json,
855 const std::string& content_type,
856 int64 content_length,
857 const base::FilePath& local_file_path,
858 const FileResourceCallback& callback,
859 const ProgressCallback& progress_callback)
860 : BatchableRequestBase(sender),
861 metadata_json_(metadata_json),
862 content_type_(content_type),
863 local_path_(local_file_path),
864 callback_(callback),
865 progress_callback_(progress_callback),
866 weak_ptr_factory_(this) {
867 DCHECK(!content_type.empty());
868 DCHECK_GE(content_length, 0);
869 DCHECK(!local_file_path.empty());
870 DCHECK(!callback.is_null());
873 MultipartUploadRequestBase::~MultipartUploadRequestBase() {
876 void MultipartUploadRequestBase::Prepare(const PrepareCallback& callback) {
877 // If the request is cancelled, the request instance will be deleted in
878 // |UrlFetchRequestBase::Cancel| and OnPrepareUploadContent won't be called.
879 std::string* const upload_content_type = new std::string();
880 std::string* const upload_content_data = new std::string();
881 PostTaskAndReplyWithResult(
882 blocking_task_runner(), FROM_HERE,
883 base::Bind(&GetMultipartContent, boundary_, metadata_json_, content_type_,
884 local_path_, base::Unretained(upload_content_type),
885 base::Unretained(upload_content_data)),
886 base::Bind(&MultipartUploadRequestBase::OnPrepareUploadContent,
887 weak_ptr_factory_.GetWeakPtr(), callback,
888 base::Owned(upload_content_type),
889 base::Owned(upload_content_data)));
892 void MultipartUploadRequestBase::OnPrepareUploadContent(
893 const PrepareCallback& callback,
894 std::string* upload_content_type,
895 std::string* upload_content_data,
896 bool result) {
897 if (!result) {
898 callback.Run(DRIVE_FILE_ERROR);
899 return;
901 upload_content_type_.swap(*upload_content_type);
902 upload_content_data_.swap(*upload_content_data);
903 callback.Run(HTTP_SUCCESS);
906 void MultipartUploadRequestBase::SetBoundaryForTesting(
907 const std::string& boundary) {
908 boundary_ = boundary;
911 bool MultipartUploadRequestBase::GetContentData(
912 std::string* upload_content_type,
913 std::string* upload_content_data) {
914 // TODO(hirono): Pass stream instead of actual data to reduce memory usage.
915 upload_content_type->swap(upload_content_type_);
916 upload_content_data->swap(upload_content_data_);
917 return true;
920 void MultipartUploadRequestBase::ProcessURLFetchResults(
921 DriveApiErrorCode code, const std::string& body) {
922 // The upload is successfully done. Parse the response which should be
923 // the entry's metadata.
924 if (code == HTTP_CREATED || code == HTTP_SUCCESS) {
925 ParseJsonOnBlockingPool(
926 blocking_task_runner(), body,
927 base::Bind(&MultipartUploadRequestBase::OnDataParsed,
928 weak_ptr_factory_.GetWeakPtr(), code));
929 } else {
930 OnDataParsed(code, scoped_ptr<base::Value>());
934 void MultipartUploadRequestBase::RunCallbackOnPrematureFailure(
935 DriveApiErrorCode code) {
936 callback_.Run(code, scoped_ptr<FileResource>());
939 void MultipartUploadRequestBase::OnURLFetchUploadProgress(
940 const net::URLFetcher* source,
941 int64 current,
942 int64 total) {
943 if (!progress_callback_.is_null())
944 progress_callback_.Run(current, total);
947 void MultipartUploadRequestBase::OnDataParsed(DriveApiErrorCode code,
948 scoped_ptr<base::Value> value) {
949 DCHECK(CalledOnValidThread());
950 if (value)
951 callback_.Run(code, google_apis::FileResource::CreateFrom(*value));
952 else
953 callback_.Run(DRIVE_PARSE_ERROR, scoped_ptr<FileResource>());
954 OnProcessURLFetchResultsComplete();
957 //============================ DownloadFileRequestBase =========================
959 DownloadFileRequestBase::DownloadFileRequestBase(
960 RequestSender* sender,
961 const DownloadActionCallback& download_action_callback,
962 const GetContentCallback& get_content_callback,
963 const ProgressCallback& progress_callback,
964 const GURL& download_url,
965 const base::FilePath& output_file_path)
966 : UrlFetchRequestBase(sender),
967 download_action_callback_(download_action_callback),
968 get_content_callback_(get_content_callback),
969 progress_callback_(progress_callback),
970 download_url_(download_url),
971 output_file_path_(output_file_path) {
972 DCHECK(!download_action_callback_.is_null());
973 DCHECK(!output_file_path_.empty());
974 // get_content_callback may be null.
977 DownloadFileRequestBase::~DownloadFileRequestBase() {}
979 // Overridden from UrlFetchRequestBase.
980 GURL DownloadFileRequestBase::GetURL() const {
981 return download_url_;
984 void DownloadFileRequestBase::GetOutputFilePath(
985 base::FilePath* local_file_path,
986 GetContentCallback* get_content_callback) {
987 // Configure so that the downloaded content is saved to |output_file_path_|.
988 *local_file_path = output_file_path_;
989 *get_content_callback = get_content_callback_;
992 void DownloadFileRequestBase::OnURLFetchDownloadProgress(
993 const URLFetcher* source,
994 int64 current,
995 int64 total) {
996 if (!progress_callback_.is_null())
997 progress_callback_.Run(current, total);
1000 void DownloadFileRequestBase::ProcessURLFetchResults(const URLFetcher* source) {
1001 DriveApiErrorCode code = GetErrorCode();
1003 // Take over the ownership of the the downloaded temp file.
1004 base::FilePath temp_file;
1005 if (code == HTTP_SUCCESS) {
1006 response_writer()->DisownFile();
1007 temp_file = output_file_path_;
1010 download_action_callback_.Run(code, temp_file);
1011 OnProcessURLFetchResultsComplete();
1014 void DownloadFileRequestBase::RunCallbackOnPrematureFailure(
1015 DriveApiErrorCode code) {
1016 download_action_callback_.Run(code, base::FilePath());
1019 } // namespace google_apis