Fix dereference of NULL host in VersionUpdater::Create.
[chromium-blink-merge.git] / google_apis / drive / base_requests.cc
blobe526012eeccc41ccbb1735c1a18e41ee01dd7931
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "google_apis/drive/base_requests.h"
7 #include "base/files/file_util.h"
8 #include "base/json/json_reader.h"
9 #include "base/json/json_writer.h"
10 #include "base/location.h"
11 #include "base/rand_util.h"
12 #include "base/sequenced_task_runner.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/task_runner_util.h"
16 #include "base/thread_task_runner_handle.h"
17 #include "base/values.h"
18 #include "google_apis/drive/drive_api_parser.h"
19 #include "google_apis/drive/request_sender.h"
20 #include "google_apis/drive/request_util.h"
21 #include "google_apis/drive/task_util.h"
22 #include "google_apis/drive/time_util.h"
23 #include "net/base/elements_upload_data_stream.h"
24 #include "net/base/io_buffer.h"
25 #include "net/base/load_flags.h"
26 #include "net/base/net_errors.h"
27 #include "net/base/upload_bytes_element_reader.h"
28 #include "net/base/upload_data_stream.h"
29 #include "net/base/upload_element_reader.h"
30 #include "net/base/upload_file_element_reader.h"
31 #include "net/http/http_byte_range.h"
32 #include "net/http/http_response_headers.h"
33 #include "net/http/http_util.h"
34 #include "net/url_request/url_fetcher.h"
35 #include "net/url_request/url_request_status.h"
37 using net::URLFetcher;
39 namespace {
41 // Template for optional OAuth2 authorization HTTP header.
42 const char kAuthorizationHeaderFormat[] = "Authorization: Bearer %s";
43 // Template for GData API version HTTP header.
44 const char kGDataVersionHeader[] = "GData-Version: 3.0";
46 // Maximum number of attempts for re-authentication per request.
47 const int kMaxReAuthenticateAttemptsPerRequest = 1;
49 // Template for initiate upload of both GData WAPI and Drive API v2.
50 const char kUploadContentType[] = "X-Upload-Content-Type: ";
51 const char kUploadContentLength[] = "X-Upload-Content-Length: ";
52 const char kUploadResponseLocation[] = "location";
54 // Template for upload data range of both GData WAPI and Drive API v2.
55 const char kUploadContentRange[] = "Content-Range: bytes ";
56 const char kUploadResponseRange[] = "range";
58 // Mime type of JSON.
59 const char kJsonMimeType[] = "application/json";
61 // Mime type of multipart related.
62 const char kMultipartRelatedMimeTypePrefix[] =
63 "multipart/related; boundary=";
65 // Mime type of multipart mixed.
66 const char kMultipartMixedMimeTypePrefix[] =
67 "multipart/mixed; boundary=";
69 // Header for each item in a multipart message.
70 const char kMultipartItemHeaderFormat[] = "--%s\nContent-Type: %s\n\n";
72 // Footer for whole multipart message.
73 const char kMultipartFooterFormat[] = "--%s--";
75 // Characters to be used for multipart/related boundary.
76 const char kBoundaryCharacters[] =
77 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
79 // Size of multipart/related's boundary.
80 const char kBoundarySize = 70;
82 // Parses JSON passed in |json| on |blocking_task_runner|. Runs |callback| on
83 // the calling thread when finished with either success or failure.
84 // The callback must not be null.
85 void ParseJsonOnBlockingPool(
86 base::TaskRunner* blocking_task_runner,
87 const std::string& json,
88 const base::Callback<void(scoped_ptr<base::Value> value)>& callback) {
89 base::PostTaskAndReplyWithResult(
90 blocking_task_runner,
91 FROM_HERE,
92 base::Bind(&google_apis::ParseJson, json),
93 callback);
96 // Returns response headers as a string. Returns a warning message if
97 // |url_fetcher| does not contain a valid response. Used only for debugging.
98 std::string GetResponseHeadersAsString(const URLFetcher* url_fetcher) {
99 // net::HttpResponseHeaders::raw_headers(), as the name implies, stores
100 // all headers in their raw format, i.e each header is null-terminated.
101 // So logging raw_headers() only shows the first header, which is probably
102 // the status line. GetNormalizedHeaders, on the other hand, will show all
103 // the headers, one per line, which is probably what we want.
104 std::string headers;
105 // Check that response code indicates response headers are valid (i.e. not
106 // malformed) before we retrieve the headers.
107 if (url_fetcher->GetResponseCode() == URLFetcher::RESPONSE_CODE_INVALID) {
108 headers.assign("Response headers are malformed!!");
109 } else {
110 url_fetcher->GetResponseHeaders()->GetNormalizedHeaders(&headers);
112 return headers;
115 // Obtains the multipart body for the metadata string and file contents. If
116 // predetermined_boundary is empty, the function generates the boundary string.
117 bool GetMultipartContent(const std::string& predetermined_boundary,
118 const std::string& metadata_json,
119 const std::string& content_type,
120 const base::FilePath& path,
121 std::string* upload_content_type,
122 std::string* upload_content_data) {
123 std::vector<google_apis::ContentTypeAndData> parts(2);
124 parts[0].type = kJsonMimeType;
125 parts[0].data = metadata_json;
126 parts[1].type = content_type;
127 if (!ReadFileToString(path, &parts[1].data))
128 return false;
130 google_apis::ContentTypeAndData output;
131 GenerateMultipartBody(google_apis::MULTIPART_RELATED, predetermined_boundary,
132 parts, &output, nullptr);
133 upload_content_type->swap(output.type);
134 upload_content_data->swap(output.data);
135 return true;
138 // Parses JSON body and returns corresponding DriveApiErrorCode if it is found.
139 // The server may return detailed error status in JSON.
140 // See https://developers.google.com/drive/handle-errors
141 google_apis::DriveApiErrorCode MapJsonError(
142 google_apis::DriveApiErrorCode code,
143 const std::string& error_body) {
144 if (IsSuccessfulDriveApiErrorCode(code))
145 return code;
147 DVLOG(1) << error_body;
148 const char kErrorKey[] = "error";
149 const char kErrorErrorsKey[] = "errors";
150 const char kErrorReasonKey[] = "reason";
151 const char kErrorMessageKey[] = "message";
152 const char kErrorReasonRateLimitExceeded[] = "rateLimitExceeded";
153 const char kErrorReasonUserRateLimitExceeded[] = "userRateLimitExceeded";
154 const char kErrorReasonQuotaExceeded[] = "quotaExceeded";
155 const char kErrorReasonResponseTooLarge[] = "responseTooLarge";
157 scoped_ptr<const base::Value> value(google_apis::ParseJson(error_body));
158 const base::DictionaryValue* dictionary = NULL;
159 const base::DictionaryValue* error = NULL;
160 if (value &&
161 value->GetAsDictionary(&dictionary) &&
162 dictionary->GetDictionaryWithoutPathExpansion(kErrorKey, &error)) {
163 // Get error message.
164 std::string message;
165 error->GetStringWithoutPathExpansion(kErrorMessageKey, &message);
166 DLOG(ERROR) << "code: " << code << ", message: " << message;
168 // Override the error code based on the reason of the first error.
169 const base::ListValue* errors = NULL;
170 const base::DictionaryValue* first_error = NULL;
171 if (error->GetListWithoutPathExpansion(kErrorErrorsKey, &errors) &&
172 errors->GetDictionary(0, &first_error)) {
173 std::string reason;
174 first_error->GetStringWithoutPathExpansion(kErrorReasonKey, &reason);
175 if (reason == kErrorReasonRateLimitExceeded ||
176 reason == kErrorReasonUserRateLimitExceeded) {
177 return google_apis::HTTP_SERVICE_UNAVAILABLE;
179 if (reason == kErrorReasonQuotaExceeded)
180 return google_apis::DRIVE_NO_SPACE;
181 if (reason == kErrorReasonResponseTooLarge)
182 return google_apis::DRIVE_RESPONSE_TOO_LARGE;
186 return code;
189 } // namespace
191 namespace google_apis {
193 scoped_ptr<base::Value> ParseJson(const std::string& json) {
194 int error_code = -1;
195 std::string error_message;
196 scoped_ptr<base::Value> value(base::JSONReader::DeprecatedReadAndReturnError(
197 json, base::JSON_PARSE_RFC, &error_code, &error_message));
199 if (!value.get()) {
200 std::string trimmed_json;
201 if (json.size() < 80) {
202 trimmed_json = json;
203 } else {
204 // Take the first 50 and the last 10 bytes.
205 trimmed_json = base::StringPrintf(
206 "%s [%s bytes] %s",
207 json.substr(0, 50).c_str(),
208 base::Uint64ToString(json.size() - 60).c_str(),
209 json.substr(json.size() - 10).c_str());
211 LOG(WARNING) << "Error while parsing entry response: " << error_message
212 << ", code: " << error_code << ", json:\n" << trimmed_json;
214 return value.Pass();
217 void GenerateMultipartBody(MultipartType multipart_type,
218 const std::string& predetermined_boundary,
219 const std::vector<ContentTypeAndData>& parts,
220 ContentTypeAndData* output,
221 std::vector<uint64>* data_offset) {
222 std::string boundary;
223 // Generate random boundary.
224 if (predetermined_boundary.empty()) {
225 while (true) {
226 boundary.resize(kBoundarySize);
227 for (int i = 0; i < kBoundarySize; ++i) {
228 // Subtract 2 from the array size to exclude '\0', and to turn the size
229 // into the last index.
230 const int last_char_index = arraysize(kBoundaryCharacters) - 2;
231 boundary[i] = kBoundaryCharacters[base::RandInt(0, last_char_index)];
233 bool conflict_with_content = false;
234 for (auto& part : parts) {
235 if (part.data.find(boundary, 0) != std::string::npos) {
236 conflict_with_content = true;
237 break;
240 if (!conflict_with_content)
241 break;
243 } else {
244 boundary = predetermined_boundary;
247 switch (multipart_type) {
248 case MULTIPART_RELATED:
249 output->type = kMultipartRelatedMimeTypePrefix + boundary;
250 break;
251 case MULTIPART_MIXED:
252 output->type = kMultipartMixedMimeTypePrefix + boundary;
253 break;
256 output->data.clear();
257 if (data_offset)
258 data_offset->clear();
259 for (auto& part : parts) {
260 output->data.append(base::StringPrintf(
261 kMultipartItemHeaderFormat, boundary.c_str(), part.type.c_str()));
262 if (data_offset)
263 data_offset->push_back(output->data.size());
264 output->data.append(part.data);
265 output->data.append("\n");
267 output->data.append(
268 base::StringPrintf(kMultipartFooterFormat, boundary.c_str()));
271 //=========================== ResponseWriter ==================================
272 ResponseWriter::ResponseWriter(base::SequencedTaskRunner* file_task_runner,
273 const base::FilePath& file_path,
274 const GetContentCallback& get_content_callback)
275 : get_content_callback_(get_content_callback),
276 weak_ptr_factory_(this) {
277 if (!file_path.empty()) {
278 file_writer_.reset(
279 new net::URLFetcherFileWriter(file_task_runner, file_path));
283 ResponseWriter::~ResponseWriter() {
286 void ResponseWriter::DisownFile() {
287 DCHECK(file_writer_);
288 file_writer_->DisownFile();
291 int ResponseWriter::Initialize(const net::CompletionCallback& callback) {
292 if (file_writer_)
293 return file_writer_->Initialize(callback);
295 data_.clear();
296 return net::OK;
299 int ResponseWriter::Write(net::IOBuffer* buffer,
300 int num_bytes,
301 const net::CompletionCallback& callback) {
302 if (!get_content_callback_.is_null()) {
303 get_content_callback_.Run(
304 HTTP_SUCCESS,
305 make_scoped_ptr(new std::string(buffer->data(), num_bytes)));
308 if (file_writer_) {
309 const int result = file_writer_->Write(
310 buffer, num_bytes,
311 base::Bind(&ResponseWriter::DidWrite,
312 weak_ptr_factory_.GetWeakPtr(),
313 make_scoped_refptr(buffer), callback));
314 if (result != net::ERR_IO_PENDING)
315 DidWrite(buffer, net::CompletionCallback(), result);
316 return result;
319 data_.append(buffer->data(), num_bytes);
320 return num_bytes;
323 int ResponseWriter::Finish(const net::CompletionCallback& callback) {
324 if (file_writer_)
325 return file_writer_->Finish(callback);
327 return net::OK;
330 void ResponseWriter::DidWrite(scoped_refptr<net::IOBuffer> buffer,
331 const net::CompletionCallback& callback,
332 int result) {
333 if (result > 0) {
334 // Even if file_writer_ is used, append the data to |data_|, so that it can
335 // be used to get error information in case of server side errors.
336 // The size limit is to avoid consuming too much redundant memory.
337 const size_t kMaxStringSize = 1024*1024;
338 if (data_.size() < kMaxStringSize) {
339 data_.append(buffer->data(), std::min(static_cast<size_t>(result),
340 kMaxStringSize - data_.size()));
344 if (!callback.is_null())
345 callback.Run(result);
348 //============================ UrlFetchRequestBase ===========================
350 UrlFetchRequestBase::UrlFetchRequestBase(RequestSender* sender)
351 : re_authenticate_count_(0),
352 response_writer_(NULL),
353 sender_(sender),
354 error_code_(DRIVE_OTHER_ERROR),
355 weak_ptr_factory_(this) {
358 UrlFetchRequestBase::~UrlFetchRequestBase() {}
360 void UrlFetchRequestBase::Start(const std::string& access_token,
361 const std::string& custom_user_agent,
362 const ReAuthenticateCallback& callback) {
363 DCHECK(CalledOnValidThread());
364 DCHECK(!access_token.empty());
365 DCHECK(!callback.is_null());
366 DCHECK(re_authenticate_callback_.is_null());
367 Prepare(base::Bind(&UrlFetchRequestBase::StartAfterPrepare,
368 weak_ptr_factory_.GetWeakPtr(), access_token,
369 custom_user_agent, callback));
372 void UrlFetchRequestBase::Prepare(const PrepareCallback& callback) {
373 DCHECK(CalledOnValidThread());
374 DCHECK(!callback.is_null());
375 callback.Run(HTTP_SUCCESS);
378 void UrlFetchRequestBase::StartAfterPrepare(
379 const std::string& access_token,
380 const std::string& custom_user_agent,
381 const ReAuthenticateCallback& callback,
382 DriveApiErrorCode code) {
383 DCHECK(CalledOnValidThread());
384 DCHECK(!access_token.empty());
385 DCHECK(!callback.is_null());
386 DCHECK(re_authenticate_callback_.is_null());
388 const GURL url = GetURL();
389 DriveApiErrorCode error_code;
390 if (IsSuccessfulDriveApiErrorCode(code))
391 error_code = code;
392 else if (url.is_empty())
393 error_code = DRIVE_OTHER_ERROR;
394 else
395 error_code = HTTP_SUCCESS;
397 if (error_code != HTTP_SUCCESS) {
398 // Error is found on generating the url or preparing the request. Send the
399 // error message to the callback, and then return immediately without trying
400 // to connect to the server. We need to call CompleteRequestWithError
401 // asynchronously because client code does not assume result callback is
402 // called synchronously.
403 base::ThreadTaskRunnerHandle::Get()->PostTask(
404 FROM_HERE, base::Bind(&UrlFetchRequestBase::CompleteRequestWithError,
405 weak_ptr_factory_.GetWeakPtr(), error_code));
406 return;
409 re_authenticate_callback_ = callback;
410 DVLOG(1) << "URL: " << url.spec();
412 URLFetcher::RequestType request_type = GetRequestType();
413 url_fetcher_ = URLFetcher::Create(url, request_type, this);
414 url_fetcher_->SetRequestContext(sender_->url_request_context_getter());
415 // Always set flags to neither send nor save cookies.
416 url_fetcher_->SetLoadFlags(
417 net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES |
418 net::LOAD_DISABLE_CACHE);
420 base::FilePath output_file_path;
421 GetContentCallback get_content_callback;
422 GetOutputFilePath(&output_file_path, &get_content_callback);
423 if (!get_content_callback.is_null())
424 get_content_callback = CreateRelayCallback(get_content_callback);
425 response_writer_ = new ResponseWriter(blocking_task_runner(),
426 output_file_path,
427 get_content_callback);
428 url_fetcher_->SaveResponseWithWriter(
429 scoped_ptr<net::URLFetcherResponseWriter>(response_writer_));
431 // Add request headers.
432 // Note that SetExtraRequestHeaders clears the current headers and sets it
433 // to the passed-in headers, so calling it for each header will result in
434 // only the last header being set in request headers.
435 if (!custom_user_agent.empty())
436 url_fetcher_->AddExtraRequestHeader("User-Agent: " + custom_user_agent);
437 url_fetcher_->AddExtraRequestHeader(kGDataVersionHeader);
438 url_fetcher_->AddExtraRequestHeader(
439 base::StringPrintf(kAuthorizationHeaderFormat, access_token.data()));
440 std::vector<std::string> headers = GetExtraRequestHeaders();
441 for (size_t i = 0; i < headers.size(); ++i) {
442 url_fetcher_->AddExtraRequestHeader(headers[i]);
443 DVLOG(1) << "Extra header: " << headers[i];
446 // Set upload data if available.
447 std::string upload_content_type;
448 std::string upload_content;
449 if (GetContentData(&upload_content_type, &upload_content)) {
450 url_fetcher_->SetUploadData(upload_content_type, upload_content);
451 } else {
452 base::FilePath local_file_path;
453 int64 range_offset = 0;
454 int64 range_length = 0;
455 if (GetContentFile(&local_file_path, &range_offset, &range_length,
456 &upload_content_type)) {
457 url_fetcher_->SetUploadFilePath(
458 upload_content_type,
459 local_file_path,
460 range_offset,
461 range_length,
462 blocking_task_runner());
463 } else {
464 // Even if there is no content data, UrlFetcher requires to set empty
465 // upload data string for POST, PUT and PATCH methods, explicitly.
466 // It is because that most requests of those methods have non-empty
467 // body, and UrlFetcher checks whether it is actually not forgotten.
468 if (request_type == URLFetcher::POST ||
469 request_type == URLFetcher::PUT ||
470 request_type == URLFetcher::PATCH) {
471 // Set empty upload content-type and upload content, so that
472 // the request will have no "Content-type: " header and no content.
473 url_fetcher_->SetUploadData(std::string(), std::string());
478 url_fetcher_->Start();
481 URLFetcher::RequestType UrlFetchRequestBase::GetRequestType() const {
482 return URLFetcher::GET;
485 std::vector<std::string> UrlFetchRequestBase::GetExtraRequestHeaders() const {
486 return std::vector<std::string>();
489 bool UrlFetchRequestBase::GetContentData(std::string* upload_content_type,
490 std::string* upload_content) {
491 return false;
494 bool UrlFetchRequestBase::GetContentFile(base::FilePath* local_file_path,
495 int64* range_offset,
496 int64* range_length,
497 std::string* upload_content_type) {
498 return false;
501 void UrlFetchRequestBase::GetOutputFilePath(
502 base::FilePath* local_file_path,
503 GetContentCallback* get_content_callback) {
506 void UrlFetchRequestBase::Cancel() {
507 response_writer_ = NULL;
508 url_fetcher_.reset(NULL);
509 CompleteRequestWithError(DRIVE_CANCELLED);
512 DriveApiErrorCode UrlFetchRequestBase::GetErrorCode() {
513 return error_code_;
516 bool UrlFetchRequestBase::CalledOnValidThread() {
517 return thread_checker_.CalledOnValidThread();
520 base::SequencedTaskRunner* UrlFetchRequestBase::blocking_task_runner() const {
521 return sender_->blocking_task_runner();
524 void UrlFetchRequestBase::OnProcessURLFetchResultsComplete() {
525 sender_->RequestFinished(this);
528 void UrlFetchRequestBase::OnURLFetchComplete(const URLFetcher* source) {
529 DVLOG(1) << "Response headers:\n" << GetResponseHeadersAsString(source);
531 // Determine error code.
532 error_code_ = static_cast<DriveApiErrorCode>(source->GetResponseCode());
533 if (!source->GetStatus().is_success()) {
534 switch (source->GetStatus().error()) {
535 case net::ERR_NETWORK_CHANGED:
536 error_code_ = DRIVE_NO_CONNECTION;
537 break;
538 default:
539 error_code_ = DRIVE_OTHER_ERROR;
543 error_code_ = MapJsonError(error_code_, response_writer_->data());
545 // Handle authentication failure.
546 if (error_code_ == HTTP_UNAUTHORIZED) {
547 if (++re_authenticate_count_ <= kMaxReAuthenticateAttemptsPerRequest) {
548 // Reset re_authenticate_callback_ so Start() can be called again.
549 ReAuthenticateCallback callback = re_authenticate_callback_;
550 re_authenticate_callback_.Reset();
551 callback.Run(this);
552 return;
555 OnAuthFailed(error_code_);
556 return;
559 // Overridden by each specialization
560 ProcessURLFetchResults(source);
563 void UrlFetchRequestBase::CompleteRequestWithError(DriveApiErrorCode code) {
564 RunCallbackOnPrematureFailure(code);
565 sender_->RequestFinished(this);
568 void UrlFetchRequestBase::OnAuthFailed(DriveApiErrorCode code) {
569 CompleteRequestWithError(code);
572 base::WeakPtr<AuthenticatedRequestInterface>
573 UrlFetchRequestBase::GetWeakPtr() {
574 return weak_ptr_factory_.GetWeakPtr();
577 //============================ EntryActionRequest ============================
579 EntryActionRequest::EntryActionRequest(RequestSender* sender,
580 const EntryActionCallback& callback)
581 : UrlFetchRequestBase(sender),
582 callback_(callback) {
583 DCHECK(!callback_.is_null());
586 EntryActionRequest::~EntryActionRequest() {}
588 void EntryActionRequest::ProcessURLFetchResults(const URLFetcher* source) {
589 callback_.Run(GetErrorCode());
590 OnProcessURLFetchResultsComplete();
593 void EntryActionRequest::RunCallbackOnPrematureFailure(DriveApiErrorCode code) {
594 callback_.Run(code);
597 //========================= InitiateUploadRequestBase ========================
599 InitiateUploadRequestBase::InitiateUploadRequestBase(
600 RequestSender* sender,
601 const InitiateUploadCallback& callback,
602 const std::string& content_type,
603 int64 content_length)
604 : UrlFetchRequestBase(sender),
605 callback_(callback),
606 content_type_(content_type),
607 content_length_(content_length) {
608 DCHECK(!callback_.is_null());
609 DCHECK(!content_type_.empty());
610 DCHECK_GE(content_length_, 0);
613 InitiateUploadRequestBase::~InitiateUploadRequestBase() {}
615 void InitiateUploadRequestBase::ProcessURLFetchResults(
616 const URLFetcher* source) {
617 DriveApiErrorCode code = GetErrorCode();
619 std::string upload_location;
620 if (code == HTTP_SUCCESS) {
621 // Retrieve value of the first "Location" header.
622 source->GetResponseHeaders()->EnumerateHeader(NULL,
623 kUploadResponseLocation,
624 &upload_location);
627 callback_.Run(code, GURL(upload_location));
628 OnProcessURLFetchResultsComplete();
631 void InitiateUploadRequestBase::RunCallbackOnPrematureFailure(
632 DriveApiErrorCode code) {
633 callback_.Run(code, GURL());
636 std::vector<std::string>
637 InitiateUploadRequestBase::GetExtraRequestHeaders() const {
638 std::vector<std::string> headers;
639 headers.push_back(kUploadContentType + content_type_);
640 headers.push_back(
641 kUploadContentLength + base::Int64ToString(content_length_));
642 return headers;
645 //============================ UploadRangeResponse =============================
647 UploadRangeResponse::UploadRangeResponse()
648 : code(HTTP_SUCCESS),
649 start_position_received(0),
650 end_position_received(0) {
653 UploadRangeResponse::UploadRangeResponse(DriveApiErrorCode code,
654 int64 start_position_received,
655 int64 end_position_received)
656 : code(code),
657 start_position_received(start_position_received),
658 end_position_received(end_position_received) {
661 UploadRangeResponse::~UploadRangeResponse() {
664 //========================== UploadRangeRequestBase ==========================
666 UploadRangeRequestBase::UploadRangeRequestBase(RequestSender* sender,
667 const GURL& upload_url)
668 : UrlFetchRequestBase(sender),
669 upload_url_(upload_url),
670 weak_ptr_factory_(this) {
673 UploadRangeRequestBase::~UploadRangeRequestBase() {}
675 GURL UploadRangeRequestBase::GetURL() const {
676 // This is very tricky to get json from this request. To do that, &alt=json
677 // has to be appended not here but in InitiateUploadRequestBase::GetURL().
678 return upload_url_;
681 URLFetcher::RequestType UploadRangeRequestBase::GetRequestType() const {
682 return URLFetcher::PUT;
685 void UploadRangeRequestBase::ProcessURLFetchResults(
686 const URLFetcher* source) {
687 DriveApiErrorCode code = GetErrorCode();
688 net::HttpResponseHeaders* hdrs = source->GetResponseHeaders();
690 if (code == HTTP_RESUME_INCOMPLETE) {
691 // Retrieve value of the first "Range" header.
692 // The Range header is appeared only if there is at least one received
693 // byte. So, initialize the positions by 0 so that the [0,0) will be
694 // returned via the |callback_| for empty data case.
695 int64 start_position_received = 0;
696 int64 end_position_received = 0;
697 std::string range_received;
698 hdrs->EnumerateHeader(NULL, kUploadResponseRange, &range_received);
699 if (!range_received.empty()) { // Parse the range header.
700 std::vector<net::HttpByteRange> ranges;
701 if (net::HttpUtil::ParseRangeHeader(range_received, &ranges) &&
702 !ranges.empty() ) {
703 // We only care about the first start-end pair in the range.
705 // Range header represents the range inclusively, while we are treating
706 // ranges exclusively (i.e., end_position_received should be one passed
707 // the last valid index). So "+ 1" is added.
708 start_position_received = ranges[0].first_byte_position();
709 end_position_received = ranges[0].last_byte_position() + 1;
712 // The Range header has the received data range, so the start position
713 // should be always 0.
714 DCHECK_EQ(start_position_received, 0);
716 OnRangeRequestComplete(UploadRangeResponse(code,
717 start_position_received,
718 end_position_received),
719 scoped_ptr<base::Value>());
721 OnProcessURLFetchResultsComplete();
722 } else if (code == HTTP_CREATED || code == HTTP_SUCCESS) {
723 // The upload is successfully done. Parse the response which should be
724 // the entry's metadata.
725 ParseJsonOnBlockingPool(blocking_task_runner(),
726 response_writer()->data(),
727 base::Bind(&UploadRangeRequestBase::OnDataParsed,
728 weak_ptr_factory_.GetWeakPtr(),
729 code));
730 } else {
731 // Failed to upload. Run callbacks to notify the error.
732 OnRangeRequestComplete(
733 UploadRangeResponse(code, -1, -1), scoped_ptr<base::Value>());
734 OnProcessURLFetchResultsComplete();
738 void UploadRangeRequestBase::OnDataParsed(DriveApiErrorCode code,
739 scoped_ptr<base::Value> value) {
740 DCHECK(CalledOnValidThread());
741 DCHECK(code == HTTP_CREATED || code == HTTP_SUCCESS);
743 OnRangeRequestComplete(UploadRangeResponse(code, -1, -1), value.Pass());
744 OnProcessURLFetchResultsComplete();
747 void UploadRangeRequestBase::RunCallbackOnPrematureFailure(
748 DriveApiErrorCode code) {
749 OnRangeRequestComplete(
750 UploadRangeResponse(code, 0, 0), scoped_ptr<base::Value>());
753 //========================== ResumeUploadRequestBase =========================
755 ResumeUploadRequestBase::ResumeUploadRequestBase(
756 RequestSender* sender,
757 const GURL& upload_location,
758 int64 start_position,
759 int64 end_position,
760 int64 content_length,
761 const std::string& content_type,
762 const base::FilePath& local_file_path)
763 : UploadRangeRequestBase(sender, upload_location),
764 start_position_(start_position),
765 end_position_(end_position),
766 content_length_(content_length),
767 content_type_(content_type),
768 local_file_path_(local_file_path) {
769 DCHECK_LE(start_position_, end_position_);
772 ResumeUploadRequestBase::~ResumeUploadRequestBase() {}
774 std::vector<std::string>
775 ResumeUploadRequestBase::GetExtraRequestHeaders() const {
776 if (content_length_ == 0) {
777 // For uploading an empty document, just PUT an empty content.
778 DCHECK_EQ(start_position_, 0);
779 DCHECK_EQ(end_position_, 0);
780 return std::vector<std::string>();
783 // The header looks like
784 // Content-Range: bytes <start_position>-<end_position>/<content_length>
785 // for example:
786 // Content-Range: bytes 7864320-8388607/13851821
787 // The header takes inclusive range, so we adjust by "end_position - 1".
788 DCHECK_GE(start_position_, 0);
789 DCHECK_GT(end_position_, 0);
790 DCHECK_GE(content_length_, 0);
792 std::vector<std::string> headers;
793 headers.push_back(
794 std::string(kUploadContentRange) +
795 base::Int64ToString(start_position_) + "-" +
796 base::Int64ToString(end_position_ - 1) + "/" +
797 base::Int64ToString(content_length_));
798 return headers;
801 bool ResumeUploadRequestBase::GetContentFile(
802 base::FilePath* local_file_path,
803 int64* range_offset,
804 int64* range_length,
805 std::string* upload_content_type) {
806 if (start_position_ == end_position_) {
807 // No content data.
808 return false;
811 *local_file_path = local_file_path_;
812 *range_offset = start_position_;
813 *range_length = end_position_ - start_position_;
814 *upload_content_type = content_type_;
815 return true;
818 //======================== GetUploadStatusRequestBase ========================
820 GetUploadStatusRequestBase::GetUploadStatusRequestBase(RequestSender* sender,
821 const GURL& upload_url,
822 int64 content_length)
823 : UploadRangeRequestBase(sender, upload_url),
824 content_length_(content_length) {}
826 GetUploadStatusRequestBase::~GetUploadStatusRequestBase() {}
828 std::vector<std::string>
829 GetUploadStatusRequestBase::GetExtraRequestHeaders() const {
830 // The header looks like
831 // Content-Range: bytes */<content_length>
832 // for example:
833 // Content-Range: bytes */13851821
834 DCHECK_GE(content_length_, 0);
836 std::vector<std::string> headers;
837 headers.push_back(
838 std::string(kUploadContentRange) + "*/" +
839 base::Int64ToString(content_length_));
840 return headers;
843 //========================= MultipartUploadRequestBase ========================
845 MultipartUploadRequestBase::MultipartUploadRequestBase(
846 base::SequencedTaskRunner* blocking_task_runner,
847 const std::string& metadata_json,
848 const std::string& content_type,
849 int64 content_length,
850 const base::FilePath& local_file_path,
851 const FileResourceCallback& callback,
852 const ProgressCallback& progress_callback)
853 : blocking_task_runner_(blocking_task_runner),
854 metadata_json_(metadata_json),
855 content_type_(content_type),
856 local_path_(local_file_path),
857 callback_(callback),
858 progress_callback_(progress_callback),
859 weak_ptr_factory_(this) {
860 DCHECK(!content_type.empty());
861 DCHECK_GE(content_length, 0);
862 DCHECK(!local_file_path.empty());
863 DCHECK(!callback.is_null());
866 MultipartUploadRequestBase::~MultipartUploadRequestBase() {
869 std::vector<std::string> MultipartUploadRequestBase::GetExtraRequestHeaders()
870 const {
871 return std::vector<std::string>();
874 void MultipartUploadRequestBase::Prepare(const PrepareCallback& callback) {
875 // If the request is cancelled, the request instance will be deleted in
876 // |UrlFetchRequestBase::Cancel| and OnPrepareUploadContent won't be called.
877 std::string* const upload_content_type = new std::string();
878 std::string* const upload_content_data = new std::string();
879 PostTaskAndReplyWithResult(
880 blocking_task_runner_.get(), FROM_HERE,
881 base::Bind(&GetMultipartContent, boundary_, metadata_json_, content_type_,
882 local_path_, base::Unretained(upload_content_type),
883 base::Unretained(upload_content_data)),
884 base::Bind(&MultipartUploadRequestBase::OnPrepareUploadContent,
885 weak_ptr_factory_.GetWeakPtr(), callback,
886 base::Owned(upload_content_type),
887 base::Owned(upload_content_data)));
890 void MultipartUploadRequestBase::OnPrepareUploadContent(
891 const PrepareCallback& callback,
892 std::string* upload_content_type,
893 std::string* upload_content_data,
894 bool result) {
895 if (!result) {
896 callback.Run(DRIVE_FILE_ERROR);
897 return;
899 upload_content_type_.swap(*upload_content_type);
900 upload_content_data_.swap(*upload_content_data);
901 callback.Run(HTTP_SUCCESS);
904 void MultipartUploadRequestBase::SetBoundaryForTesting(
905 const std::string& boundary) {
906 boundary_ = boundary;
909 bool MultipartUploadRequestBase::GetContentData(
910 std::string* upload_content_type,
911 std::string* upload_content_data) {
912 // TODO(hirono): Pass stream instead of actual data to reduce memory usage.
913 upload_content_type->swap(upload_content_type_);
914 upload_content_data->swap(upload_content_data_);
915 return true;
918 void MultipartUploadRequestBase::NotifyResult(
919 DriveApiErrorCode code,
920 const std::string& body,
921 const base::Closure& notify_complete_callback) {
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_.get(), body,
927 base::Bind(&MultipartUploadRequestBase::OnDataParsed,
928 weak_ptr_factory_.GetWeakPtr(), code,
929 notify_complete_callback));
930 } else {
931 NotifyError(MapJsonError(code, body));
932 notify_complete_callback.Run();
936 void MultipartUploadRequestBase::NotifyError(DriveApiErrorCode code) {
937 callback_.Run(code, scoped_ptr<FileResource>());
940 void MultipartUploadRequestBase::NotifyUploadProgress(
941 const net::URLFetcher* source,
942 int64 current,
943 int64 total) {
944 if (!progress_callback_.is_null())
945 progress_callback_.Run(current, total);
948 void MultipartUploadRequestBase::OnDataParsed(
949 DriveApiErrorCode code,
950 const base::Closure& notify_complete_callback,
951 scoped_ptr<base::Value> value) {
952 DCHECK(thread_checker_.CalledOnValidThread());
953 if (value)
954 callback_.Run(code, google_apis::FileResource::CreateFrom(*value));
955 else
956 NotifyError(DRIVE_PARSE_ERROR);
957 notify_complete_callback.Run();
960 //============================ DownloadFileRequestBase =========================
962 DownloadFileRequestBase::DownloadFileRequestBase(
963 RequestSender* sender,
964 const DownloadActionCallback& download_action_callback,
965 const GetContentCallback& get_content_callback,
966 const ProgressCallback& progress_callback,
967 const GURL& download_url,
968 const base::FilePath& output_file_path)
969 : UrlFetchRequestBase(sender),
970 download_action_callback_(download_action_callback),
971 get_content_callback_(get_content_callback),
972 progress_callback_(progress_callback),
973 download_url_(download_url),
974 output_file_path_(output_file_path) {
975 DCHECK(!download_action_callback_.is_null());
976 DCHECK(!output_file_path_.empty());
977 // get_content_callback may be null.
980 DownloadFileRequestBase::~DownloadFileRequestBase() {}
982 // Overridden from UrlFetchRequestBase.
983 GURL DownloadFileRequestBase::GetURL() const {
984 return download_url_;
987 void DownloadFileRequestBase::GetOutputFilePath(
988 base::FilePath* local_file_path,
989 GetContentCallback* get_content_callback) {
990 // Configure so that the downloaded content is saved to |output_file_path_|.
991 *local_file_path = output_file_path_;
992 *get_content_callback = get_content_callback_;
995 void DownloadFileRequestBase::OnURLFetchDownloadProgress(
996 const URLFetcher* source,
997 int64 current,
998 int64 total) {
999 if (!progress_callback_.is_null())
1000 progress_callback_.Run(current, total);
1003 void DownloadFileRequestBase::ProcessURLFetchResults(const URLFetcher* source) {
1004 DriveApiErrorCode code = GetErrorCode();
1006 // Take over the ownership of the the downloaded temp file.
1007 base::FilePath temp_file;
1008 if (code == HTTP_SUCCESS) {
1009 response_writer()->DisownFile();
1010 temp_file = output_file_path_;
1013 download_action_callback_.Run(code, temp_file);
1014 OnProcessURLFetchResultsComplete();
1017 void DownloadFileRequestBase::RunCallbackOnPrematureFailure(
1018 DriveApiErrorCode code) {
1019 download_action_callback_.Run(code, base::FilePath());
1022 } // namespace google_apis