Mandoline: support IME for HTMLWidgetRootLocal & HTMLWidgetLocalRoot.
[chromium-blink-merge.git] / google_apis / drive / drive_api_requests.cc
blobeee0f8106a66f8784c7e5a642954ca2f6ecca6c0
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/drive_api_requests.h"
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/json/json_writer.h"
10 #include "base/location.h"
11 #include "base/metrics/histogram_macros.h"
12 #include "base/metrics/sparse_histogram.h"
13 #include "base/sequenced_task_runner.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_piece.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/task_runner_util.h"
18 #include "base/values.h"
19 #include "google_apis/drive/request_sender.h"
20 #include "google_apis/drive/request_util.h"
21 #include "google_apis/drive/time_util.h"
22 #include "net/base/url_util.h"
23 #include "net/http/http_response_headers.h"
25 namespace google_apis {
26 namespace drive {
27 namespace {
29 // Format of one request in batch uploading request.
30 const char kBatchUploadRequestFormat[] =
31 "%s %s HTTP/1.1\n"
32 "Host: %s\n"
33 "X-Goog-Upload-Protocol: multipart\n"
34 "Content-Type: %s\n"
35 "\n";
37 // Request header for specifying batch upload.
38 const char kBatchUploadHeader[] = "X-Goog-Upload-Protocol: batch";
40 // Content type of HTTP request.
41 const char kHttpContentType[] = "application/http";
43 // Break line in HTTP message.
44 const char kHttpBr[] = "\r\n";
46 // Mime type of multipart mixed.
47 const char kMultipartMixedMimeTypePrefix[] = "multipart/mixed; boundary=";
49 // UMA names.
50 const char kUMADriveBatchUploadResponseCode[] = "Drive.BatchUploadResponseCode";
51 const char kUMADriveTotalFileCountInBatchUpload[] =
52 "Drive.TotalFileCountInBatchUpload";
53 const char kUMADriveTotalFileSizeInBatchUpload[] =
54 "Drive.TotalFileSizeInBatchUpload";
56 // Parses the JSON value to FileResource instance and runs |callback| on the
57 // UI thread once parsing is done.
58 // This is customized version of ParseJsonAndRun defined above to adapt the
59 // remaining response type.
60 void ParseFileResourceWithUploadRangeAndRun(const UploadRangeCallback& callback,
61 const UploadRangeResponse& response,
62 scoped_ptr<base::Value> value) {
63 DCHECK(!callback.is_null());
65 scoped_ptr<FileResource> file_resource;
66 if (value) {
67 file_resource = FileResource::CreateFrom(*value);
68 if (!file_resource) {
69 callback.Run(
70 UploadRangeResponse(DRIVE_PARSE_ERROR,
71 response.start_position_received,
72 response.end_position_received),
73 scoped_ptr<FileResource>());
74 return;
78 callback.Run(response, file_resource.Pass());
81 // Attaches |properties| to the |request_body| if |properties| is not empty.
82 // |request_body| must not be NULL.
83 void AttachProperties(const Properties& properties,
84 base::DictionaryValue* request_body) {
85 DCHECK(request_body);
86 if (properties.empty())
87 return;
89 base::ListValue* const properties_value = new base::ListValue;
90 for (const auto& property : properties) {
91 base::DictionaryValue* const property_value = new base::DictionaryValue;
92 std::string visibility_as_string;
93 switch (property.visibility()) {
94 case Property::VISIBILITY_PRIVATE:
95 visibility_as_string = "PRIVATE";
96 break;
97 case Property::VISIBILITY_PUBLIC:
98 visibility_as_string = "PUBLIC";
99 break;
101 property_value->SetString("visibility", visibility_as_string);
102 property_value->SetString("key", property.key());
103 property_value->SetString("value", property.value());
104 properties_value->Append(property_value);
106 request_body->Set("properties", properties_value);
109 // Creates metadata JSON string for multipart uploading.
110 // All the values are optional. If the value is empty or null, the value does
111 // not appear in the metadata.
112 std::string CreateMultipartUploadMetadataJson(
113 const std::string& title,
114 const std::string& parent_resource_id,
115 const base::Time& modified_date,
116 const base::Time& last_viewed_by_me_date,
117 const Properties& properties) {
118 base::DictionaryValue root;
119 if (!title.empty())
120 root.SetString("title", title);
122 // Fill parent link.
123 if (!parent_resource_id.empty()) {
124 scoped_ptr<base::ListValue> parents(new base::ListValue);
125 parents->Append(
126 google_apis::util::CreateParentValue(parent_resource_id).release());
127 root.Set("parents", parents.release());
130 if (!modified_date.is_null()) {
131 root.SetString("modifiedDate",
132 google_apis::util::FormatTimeAsString(modified_date));
135 if (!last_viewed_by_me_date.is_null()) {
136 root.SetString("lastViewedByMeDate", google_apis::util::FormatTimeAsString(
137 last_viewed_by_me_date));
140 AttachProperties(properties, &root);
141 std::string json_string;
142 base::JSONWriter::Write(root, &json_string);
143 return json_string;
146 // Splits |string| into lines by |kHttpBr|.
147 // Each line does not include |kHttpBr|.
148 void SplitIntoLines(const std::string& string,
149 std::vector<base::StringPiece>* output) {
150 const size_t br_size = std::string(kHttpBr).size();
151 std::string::const_iterator it = string.begin();
152 std::vector<base::StringPiece> lines;
153 while (true) {
154 const std::string::const_iterator next_pos =
155 std::search(it, string.end(), kHttpBr, kHttpBr + br_size);
156 lines.push_back(base::StringPiece(it, next_pos));
157 if (next_pos == string.end())
158 break;
159 it = next_pos + br_size;
161 output->swap(lines);
164 // Remove transport padding (spaces and tabs at the end of line) from |piece|.
165 base::StringPiece TrimTransportPadding(const base::StringPiece& piece) {
166 size_t trim_size = 0;
167 while (trim_size < piece.size() &&
168 (piece[piece.size() - 1 - trim_size] == ' ' ||
169 piece[piece.size() - 1 - trim_size] == '\t')) {
170 ++trim_size;
172 return piece.substr(0, piece.size() - trim_size);
175 void EmptyClosure(scoped_ptr<BatchableDelegate>) {
178 } // namespace
180 MultipartHttpResponse::MultipartHttpResponse() : code(HTTP_SUCCESS) {
183 MultipartHttpResponse::~MultipartHttpResponse() {
186 // The |response| must be multipart/mixed format that contains child HTTP
187 // response of drive batch request.
188 // https://www.ietf.org/rfc/rfc2046.txt
190 // It looks like:
191 // --Boundary
192 // Content-type: application/http
194 // HTTP/1.1 200 OK
195 // Header of child response
197 // Body of child response
198 // --Boundary
199 // Content-type: application/http
201 // HTTP/1.1 404 Not Found
202 // Header of child response
204 // Body of child response
205 // --Boundary--
206 bool ParseMultipartResponse(const std::string& content_type,
207 const std::string& response,
208 std::vector<MultipartHttpResponse>* parts) {
209 if (response.empty())
210 return false;
212 base::StringPiece content_type_piece(content_type);
213 if (!content_type_piece.starts_with(kMultipartMixedMimeTypePrefix)) {
214 return false;
216 content_type_piece.remove_prefix(
217 base::StringPiece(kMultipartMixedMimeTypePrefix).size());
219 if (content_type_piece.empty())
220 return false;
221 if (content_type_piece[0] == '"') {
222 if (content_type_piece.size() <= 2 ||
223 content_type_piece[content_type_piece.size() - 1] != '"') {
224 return false;
226 content_type_piece =
227 content_type_piece.substr(1, content_type_piece.size() - 2);
230 std::string boundary;
231 content_type_piece.CopyToString(&boundary);
232 const std::string header = "--" + boundary;
233 const std::string terminator = "--" + boundary + "--";
235 std::vector<base::StringPiece> lines;
236 SplitIntoLines(response, &lines);
238 enum {
239 STATE_START,
240 STATE_PART_HEADER,
241 STATE_PART_HTTP_STATUS_LINE,
242 STATE_PART_HTTP_HEADER,
243 STATE_PART_HTTP_BODY
244 } state = STATE_START;
246 const std::string kHttpStatusPrefix = "HTTP/1.1 ";
247 std::vector<MultipartHttpResponse> responses;
248 DriveApiErrorCode code = DRIVE_PARSE_ERROR;
249 std::string body;
250 for (const auto& line : lines) {
251 if (state == STATE_PART_HEADER && line.empty()) {
252 state = STATE_PART_HTTP_STATUS_LINE;
253 continue;
256 if (state == STATE_PART_HTTP_STATUS_LINE) {
257 if (line.starts_with(kHttpStatusPrefix)) {
258 int int_code;
259 base::StringToInt(
260 line.substr(base::StringPiece(kHttpStatusPrefix).size()),
261 &int_code);
262 if (int_code > 0)
263 code = static_cast<DriveApiErrorCode>(int_code);
264 else
265 code = DRIVE_PARSE_ERROR;
266 } else {
267 code = DRIVE_PARSE_ERROR;
269 state = STATE_PART_HTTP_HEADER;
270 continue;
273 if (state == STATE_PART_HTTP_HEADER && line.empty()) {
274 state = STATE_PART_HTTP_BODY;
275 body.clear();
276 continue;
278 const base::StringPiece chopped_line = TrimTransportPadding(line);
279 const bool is_new_part = chopped_line == header;
280 const bool was_last_part = chopped_line == terminator;
281 if (is_new_part || was_last_part) {
282 switch (state) {
283 case STATE_START:
284 break;
285 case STATE_PART_HEADER:
286 case STATE_PART_HTTP_STATUS_LINE:
287 responses.push_back(MultipartHttpResponse());
288 responses.back().code = DRIVE_PARSE_ERROR;
289 break;
290 case STATE_PART_HTTP_HEADER:
291 responses.push_back(MultipartHttpResponse());
292 responses.back().code = code;
293 break;
294 case STATE_PART_HTTP_BODY:
295 // Drop the last kHttpBr.
296 if (!body.empty())
297 body.resize(body.size() - 2);
298 responses.push_back(MultipartHttpResponse());
299 responses.back().code = code;
300 responses.back().body.swap(body);
301 break;
303 if (is_new_part)
304 state = STATE_PART_HEADER;
305 if (was_last_part)
306 break;
307 } else if (state == STATE_PART_HTTP_BODY) {
308 line.AppendToString(&body);
309 body.append(kHttpBr);
313 parts->swap(responses);
314 return true;
317 Property::Property() : visibility_(VISIBILITY_PRIVATE) {
320 Property::~Property() {
323 //============================ DriveApiPartialFieldRequest ====================
325 DriveApiPartialFieldRequest::DriveApiPartialFieldRequest(
326 RequestSender* sender) : UrlFetchRequestBase(sender) {
329 DriveApiPartialFieldRequest::~DriveApiPartialFieldRequest() {
332 GURL DriveApiPartialFieldRequest::GetURL() const {
333 GURL url = GetURLInternal();
334 if (!fields_.empty())
335 url = net::AppendOrReplaceQueryParameter(url, "fields", fields_);
336 return url;
339 //=============================== FilesGetRequest =============================
341 FilesGetRequest::FilesGetRequest(
342 RequestSender* sender,
343 const DriveApiUrlGenerator& url_generator,
344 bool use_internal_endpoint,
345 const FileResourceCallback& callback)
346 : DriveApiDataRequest<FileResource>(sender, callback),
347 url_generator_(url_generator),
348 use_internal_endpoint_(use_internal_endpoint) {
349 DCHECK(!callback.is_null());
352 FilesGetRequest::~FilesGetRequest() {}
354 GURL FilesGetRequest::GetURLInternal() const {
355 return url_generator_.GetFilesGetUrl(file_id_,
356 use_internal_endpoint_,
357 embed_origin_);
360 //============================ FilesAuthorizeRequest ===========================
362 FilesAuthorizeRequest::FilesAuthorizeRequest(
363 RequestSender* sender,
364 const DriveApiUrlGenerator& url_generator,
365 const FileResourceCallback& callback)
366 : DriveApiDataRequest<FileResource>(sender, callback),
367 url_generator_(url_generator) {
368 DCHECK(!callback.is_null());
371 FilesAuthorizeRequest::~FilesAuthorizeRequest() {}
373 net::URLFetcher::RequestType FilesAuthorizeRequest::GetRequestType() const {
374 return net::URLFetcher::POST;
377 GURL FilesAuthorizeRequest::GetURLInternal() const {
378 return url_generator_.GetFilesAuthorizeUrl(file_id_, app_id_);
381 //============================ FilesInsertRequest ============================
383 FilesInsertRequest::FilesInsertRequest(
384 RequestSender* sender,
385 const DriveApiUrlGenerator& url_generator,
386 const FileResourceCallback& callback)
387 : DriveApiDataRequest<FileResource>(sender, callback),
388 url_generator_(url_generator),
389 visibility_(FILE_VISIBILITY_DEFAULT) {
390 DCHECK(!callback.is_null());
393 FilesInsertRequest::~FilesInsertRequest() {}
395 net::URLFetcher::RequestType FilesInsertRequest::GetRequestType() const {
396 return net::URLFetcher::POST;
399 bool FilesInsertRequest::GetContentData(std::string* upload_content_type,
400 std::string* upload_content) {
401 *upload_content_type = util::kContentTypeApplicationJson;
403 base::DictionaryValue root;
405 if (!last_viewed_by_me_date_.is_null()) {
406 root.SetString("lastViewedByMeDate",
407 util::FormatTimeAsString(last_viewed_by_me_date_));
410 if (!mime_type_.empty())
411 root.SetString("mimeType", mime_type_);
413 if (!modified_date_.is_null())
414 root.SetString("modifiedDate", util::FormatTimeAsString(modified_date_));
416 if (!parents_.empty()) {
417 base::ListValue* parents_value = new base::ListValue;
418 for (size_t i = 0; i < parents_.size(); ++i) {
419 base::DictionaryValue* parent = new base::DictionaryValue;
420 parent->SetString("id", parents_[i]);
421 parents_value->Append(parent);
423 root.Set("parents", parents_value);
426 if (!title_.empty())
427 root.SetString("title", title_);
429 AttachProperties(properties_, &root);
430 base::JSONWriter::Write(root, upload_content);
432 DVLOG(1) << "FilesInsert data: " << *upload_content_type << ", ["
433 << *upload_content << "]";
434 return true;
437 GURL FilesInsertRequest::GetURLInternal() const {
438 return url_generator_.GetFilesInsertUrl(
439 visibility_ == FILE_VISIBILITY_PRIVATE ? "PRIVATE" : "");
442 //============================== FilesPatchRequest ============================
444 FilesPatchRequest::FilesPatchRequest(
445 RequestSender* sender,
446 const DriveApiUrlGenerator& url_generator,
447 const FileResourceCallback& callback)
448 : DriveApiDataRequest<FileResource>(sender, callback),
449 url_generator_(url_generator),
450 set_modified_date_(false),
451 update_viewed_date_(true) {
452 DCHECK(!callback.is_null());
455 FilesPatchRequest::~FilesPatchRequest() {}
457 net::URLFetcher::RequestType FilesPatchRequest::GetRequestType() const {
458 return net::URLFetcher::PATCH;
461 std::vector<std::string> FilesPatchRequest::GetExtraRequestHeaders() const {
462 std::vector<std::string> headers;
463 headers.push_back(util::kIfMatchAllHeader);
464 return headers;
467 GURL FilesPatchRequest::GetURLInternal() const {
468 return url_generator_.GetFilesPatchUrl(
469 file_id_, set_modified_date_, update_viewed_date_);
472 bool FilesPatchRequest::GetContentData(std::string* upload_content_type,
473 std::string* upload_content) {
474 if (title_.empty() &&
475 modified_date_.is_null() &&
476 last_viewed_by_me_date_.is_null() &&
477 parents_.empty())
478 return false;
480 *upload_content_type = util::kContentTypeApplicationJson;
482 base::DictionaryValue root;
483 if (!title_.empty())
484 root.SetString("title", title_);
486 if (!modified_date_.is_null())
487 root.SetString("modifiedDate", util::FormatTimeAsString(modified_date_));
489 if (!last_viewed_by_me_date_.is_null()) {
490 root.SetString("lastViewedByMeDate",
491 util::FormatTimeAsString(last_viewed_by_me_date_));
494 if (!parents_.empty()) {
495 base::ListValue* parents_value = new base::ListValue;
496 for (size_t i = 0; i < parents_.size(); ++i) {
497 base::DictionaryValue* parent = new base::DictionaryValue;
498 parent->SetString("id", parents_[i]);
499 parents_value->Append(parent);
501 root.Set("parents", parents_value);
504 AttachProperties(properties_, &root);
505 base::JSONWriter::Write(root, upload_content);
507 DVLOG(1) << "FilesPatch data: " << *upload_content_type << ", ["
508 << *upload_content << "]";
509 return true;
512 //============================= FilesCopyRequest ==============================
514 FilesCopyRequest::FilesCopyRequest(
515 RequestSender* sender,
516 const DriveApiUrlGenerator& url_generator,
517 const FileResourceCallback& callback)
518 : DriveApiDataRequest<FileResource>(sender, callback),
519 url_generator_(url_generator),
520 visibility_(FILE_VISIBILITY_DEFAULT) {
521 DCHECK(!callback.is_null());
524 FilesCopyRequest::~FilesCopyRequest() {
527 net::URLFetcher::RequestType FilesCopyRequest::GetRequestType() const {
528 return net::URLFetcher::POST;
531 GURL FilesCopyRequest::GetURLInternal() const {
532 return url_generator_.GetFilesCopyUrl(
533 file_id_, visibility_ == FILE_VISIBILITY_PRIVATE ? "PRIVATE" : "");
536 bool FilesCopyRequest::GetContentData(std::string* upload_content_type,
537 std::string* upload_content) {
538 if (parents_.empty() && title_.empty())
539 return false;
541 *upload_content_type = util::kContentTypeApplicationJson;
543 base::DictionaryValue root;
545 if (!modified_date_.is_null())
546 root.SetString("modifiedDate", util::FormatTimeAsString(modified_date_));
548 if (!parents_.empty()) {
549 base::ListValue* parents_value = new base::ListValue;
550 for (size_t i = 0; i < parents_.size(); ++i) {
551 base::DictionaryValue* parent = new base::DictionaryValue;
552 parent->SetString("id", parents_[i]);
553 parents_value->Append(parent);
555 root.Set("parents", parents_value);
558 if (!title_.empty())
559 root.SetString("title", title_);
561 base::JSONWriter::Write(root, upload_content);
562 DVLOG(1) << "FilesCopy data: " << *upload_content_type << ", ["
563 << *upload_content << "]";
564 return true;
567 //============================= FilesListRequest =============================
569 FilesListRequest::FilesListRequest(
570 RequestSender* sender,
571 const DriveApiUrlGenerator& url_generator,
572 const FileListCallback& callback)
573 : DriveApiDataRequest<FileList>(sender, callback),
574 url_generator_(url_generator),
575 max_results_(100) {
576 DCHECK(!callback.is_null());
579 FilesListRequest::~FilesListRequest() {}
581 GURL FilesListRequest::GetURLInternal() const {
582 return url_generator_.GetFilesListUrl(max_results_, page_token_, q_);
585 //======================== FilesListNextPageRequest =========================
587 FilesListNextPageRequest::FilesListNextPageRequest(
588 RequestSender* sender,
589 const FileListCallback& callback)
590 : DriveApiDataRequest<FileList>(sender, callback) {
591 DCHECK(!callback.is_null());
594 FilesListNextPageRequest::~FilesListNextPageRequest() {
597 GURL FilesListNextPageRequest::GetURLInternal() const {
598 return next_link_;
601 //============================ FilesDeleteRequest =============================
603 FilesDeleteRequest::FilesDeleteRequest(
604 RequestSender* sender,
605 const DriveApiUrlGenerator& url_generator,
606 const EntryActionCallback& callback)
607 : EntryActionRequest(sender, callback),
608 url_generator_(url_generator) {
609 DCHECK(!callback.is_null());
612 FilesDeleteRequest::~FilesDeleteRequest() {}
614 net::URLFetcher::RequestType FilesDeleteRequest::GetRequestType() const {
615 return net::URLFetcher::DELETE_REQUEST;
618 GURL FilesDeleteRequest::GetURL() const {
619 return url_generator_.GetFilesDeleteUrl(file_id_);
622 std::vector<std::string> FilesDeleteRequest::GetExtraRequestHeaders() const {
623 std::vector<std::string> headers(
624 EntryActionRequest::GetExtraRequestHeaders());
625 headers.push_back(util::GenerateIfMatchHeader(etag_));
626 return headers;
629 //============================ FilesTrashRequest =============================
631 FilesTrashRequest::FilesTrashRequest(
632 RequestSender* sender,
633 const DriveApiUrlGenerator& url_generator,
634 const FileResourceCallback& callback)
635 : DriveApiDataRequest<FileResource>(sender, callback),
636 url_generator_(url_generator) {
637 DCHECK(!callback.is_null());
640 FilesTrashRequest::~FilesTrashRequest() {}
642 net::URLFetcher::RequestType FilesTrashRequest::GetRequestType() const {
643 return net::URLFetcher::POST;
646 GURL FilesTrashRequest::GetURLInternal() const {
647 return url_generator_.GetFilesTrashUrl(file_id_);
650 //============================== AboutGetRequest =============================
652 AboutGetRequest::AboutGetRequest(
653 RequestSender* sender,
654 const DriveApiUrlGenerator& url_generator,
655 const AboutResourceCallback& callback)
656 : DriveApiDataRequest<AboutResource>(sender, callback),
657 url_generator_(url_generator) {
658 DCHECK(!callback.is_null());
661 AboutGetRequest::~AboutGetRequest() {}
663 GURL AboutGetRequest::GetURLInternal() const {
664 return url_generator_.GetAboutGetUrl();
667 //============================ ChangesListRequest ===========================
669 ChangesListRequest::ChangesListRequest(
670 RequestSender* sender,
671 const DriveApiUrlGenerator& url_generator,
672 const ChangeListCallback& callback)
673 : DriveApiDataRequest<ChangeList>(sender, callback),
674 url_generator_(url_generator),
675 include_deleted_(true),
676 max_results_(100),
677 start_change_id_(0) {
678 DCHECK(!callback.is_null());
681 ChangesListRequest::~ChangesListRequest() {}
683 GURL ChangesListRequest::GetURLInternal() const {
684 return url_generator_.GetChangesListUrl(
685 include_deleted_, max_results_, page_token_, start_change_id_);
688 //======================== ChangesListNextPageRequest =========================
690 ChangesListNextPageRequest::ChangesListNextPageRequest(
691 RequestSender* sender,
692 const ChangeListCallback& callback)
693 : DriveApiDataRequest<ChangeList>(sender, callback) {
694 DCHECK(!callback.is_null());
697 ChangesListNextPageRequest::~ChangesListNextPageRequest() {
700 GURL ChangesListNextPageRequest::GetURLInternal() const {
701 return next_link_;
704 //============================== AppsListRequest ===========================
706 AppsListRequest::AppsListRequest(
707 RequestSender* sender,
708 const DriveApiUrlGenerator& url_generator,
709 bool use_internal_endpoint,
710 const AppListCallback& callback)
711 : DriveApiDataRequest<AppList>(sender, callback),
712 url_generator_(url_generator),
713 use_internal_endpoint_(use_internal_endpoint) {
714 DCHECK(!callback.is_null());
717 AppsListRequest::~AppsListRequest() {}
719 GURL AppsListRequest::GetURLInternal() const {
720 return url_generator_.GetAppsListUrl(use_internal_endpoint_);
723 //============================== AppsDeleteRequest ===========================
725 AppsDeleteRequest::AppsDeleteRequest(RequestSender* sender,
726 const DriveApiUrlGenerator& url_generator,
727 const EntryActionCallback& callback)
728 : EntryActionRequest(sender, callback),
729 url_generator_(url_generator) {
730 DCHECK(!callback.is_null());
733 AppsDeleteRequest::~AppsDeleteRequest() {}
735 net::URLFetcher::RequestType AppsDeleteRequest::GetRequestType() const {
736 return net::URLFetcher::DELETE_REQUEST;
739 GURL AppsDeleteRequest::GetURL() const {
740 return url_generator_.GetAppsDeleteUrl(app_id_);
743 //========================== ChildrenInsertRequest ============================
745 ChildrenInsertRequest::ChildrenInsertRequest(
746 RequestSender* sender,
747 const DriveApiUrlGenerator& url_generator,
748 const EntryActionCallback& callback)
749 : EntryActionRequest(sender, callback),
750 url_generator_(url_generator) {
751 DCHECK(!callback.is_null());
754 ChildrenInsertRequest::~ChildrenInsertRequest() {}
756 net::URLFetcher::RequestType ChildrenInsertRequest::GetRequestType() const {
757 return net::URLFetcher::POST;
760 GURL ChildrenInsertRequest::GetURL() const {
761 return url_generator_.GetChildrenInsertUrl(folder_id_);
764 bool ChildrenInsertRequest::GetContentData(std::string* upload_content_type,
765 std::string* upload_content) {
766 *upload_content_type = util::kContentTypeApplicationJson;
768 base::DictionaryValue root;
769 root.SetString("id", id_);
771 base::JSONWriter::Write(root, upload_content);
772 DVLOG(1) << "InsertResource data: " << *upload_content_type << ", ["
773 << *upload_content << "]";
774 return true;
777 //========================== ChildrenDeleteRequest ============================
779 ChildrenDeleteRequest::ChildrenDeleteRequest(
780 RequestSender* sender,
781 const DriveApiUrlGenerator& url_generator,
782 const EntryActionCallback& callback)
783 : EntryActionRequest(sender, callback),
784 url_generator_(url_generator) {
785 DCHECK(!callback.is_null());
788 ChildrenDeleteRequest::~ChildrenDeleteRequest() {}
790 net::URLFetcher::RequestType ChildrenDeleteRequest::GetRequestType() const {
791 return net::URLFetcher::DELETE_REQUEST;
794 GURL ChildrenDeleteRequest::GetURL() const {
795 return url_generator_.GetChildrenDeleteUrl(child_id_, folder_id_);
798 //======================= InitiateUploadNewFileRequest =======================
800 InitiateUploadNewFileRequest::InitiateUploadNewFileRequest(
801 RequestSender* sender,
802 const DriveApiUrlGenerator& url_generator,
803 const std::string& content_type,
804 int64 content_length,
805 const std::string& parent_resource_id,
806 const std::string& title,
807 const InitiateUploadCallback& callback)
808 : InitiateUploadRequestBase(sender,
809 callback,
810 content_type,
811 content_length),
812 url_generator_(url_generator),
813 parent_resource_id_(parent_resource_id),
814 title_(title) {
817 InitiateUploadNewFileRequest::~InitiateUploadNewFileRequest() {}
819 GURL InitiateUploadNewFileRequest::GetURL() const {
820 return url_generator_.GetInitiateUploadNewFileUrl(!modified_date_.is_null());
823 net::URLFetcher::RequestType
824 InitiateUploadNewFileRequest::GetRequestType() const {
825 return net::URLFetcher::POST;
828 bool InitiateUploadNewFileRequest::GetContentData(
829 std::string* upload_content_type,
830 std::string* upload_content) {
831 *upload_content_type = util::kContentTypeApplicationJson;
833 base::DictionaryValue root;
834 root.SetString("title", title_);
836 // Fill parent link.
837 scoped_ptr<base::ListValue> parents(new base::ListValue);
838 parents->Append(util::CreateParentValue(parent_resource_id_).release());
839 root.Set("parents", parents.release());
841 if (!modified_date_.is_null())
842 root.SetString("modifiedDate", util::FormatTimeAsString(modified_date_));
844 if (!last_viewed_by_me_date_.is_null()) {
845 root.SetString("lastViewedByMeDate",
846 util::FormatTimeAsString(last_viewed_by_me_date_));
849 AttachProperties(properties_, &root);
850 base::JSONWriter::Write(root, upload_content);
852 DVLOG(1) << "InitiateUploadNewFile data: " << *upload_content_type << ", ["
853 << *upload_content << "]";
854 return true;
857 //===================== InitiateUploadExistingFileRequest ====================
859 InitiateUploadExistingFileRequest::InitiateUploadExistingFileRequest(
860 RequestSender* sender,
861 const DriveApiUrlGenerator& url_generator,
862 const std::string& content_type,
863 int64 content_length,
864 const std::string& resource_id,
865 const std::string& etag,
866 const InitiateUploadCallback& callback)
867 : InitiateUploadRequestBase(sender,
868 callback,
869 content_type,
870 content_length),
871 url_generator_(url_generator),
872 resource_id_(resource_id),
873 etag_(etag) {
876 InitiateUploadExistingFileRequest::~InitiateUploadExistingFileRequest() {}
878 GURL InitiateUploadExistingFileRequest::GetURL() const {
879 return url_generator_.GetInitiateUploadExistingFileUrl(
880 resource_id_, !modified_date_.is_null());
883 net::URLFetcher::RequestType
884 InitiateUploadExistingFileRequest::GetRequestType() const {
885 return net::URLFetcher::PUT;
888 std::vector<std::string>
889 InitiateUploadExistingFileRequest::GetExtraRequestHeaders() const {
890 std::vector<std::string> headers(
891 InitiateUploadRequestBase::GetExtraRequestHeaders());
892 headers.push_back(util::GenerateIfMatchHeader(etag_));
893 return headers;
896 bool InitiateUploadExistingFileRequest::GetContentData(
897 std::string* upload_content_type,
898 std::string* upload_content) {
899 base::DictionaryValue root;
900 if (!parent_resource_id_.empty()) {
901 scoped_ptr<base::ListValue> parents(new base::ListValue);
902 parents->Append(util::CreateParentValue(parent_resource_id_).release());
903 root.Set("parents", parents.release());
906 if (!title_.empty())
907 root.SetString("title", title_);
909 if (!modified_date_.is_null())
910 root.SetString("modifiedDate", util::FormatTimeAsString(modified_date_));
912 if (!last_viewed_by_me_date_.is_null()) {
913 root.SetString("lastViewedByMeDate",
914 util::FormatTimeAsString(last_viewed_by_me_date_));
917 AttachProperties(properties_, &root);
918 if (root.empty())
919 return false;
921 *upload_content_type = util::kContentTypeApplicationJson;
922 base::JSONWriter::Write(root, upload_content);
923 DVLOG(1) << "InitiateUploadExistingFile data: " << *upload_content_type
924 << ", [" << *upload_content << "]";
925 return true;
928 //============================ ResumeUploadRequest ===========================
930 ResumeUploadRequest::ResumeUploadRequest(
931 RequestSender* sender,
932 const GURL& upload_location,
933 int64 start_position,
934 int64 end_position,
935 int64 content_length,
936 const std::string& content_type,
937 const base::FilePath& local_file_path,
938 const UploadRangeCallback& callback,
939 const ProgressCallback& progress_callback)
940 : ResumeUploadRequestBase(sender,
941 upload_location,
942 start_position,
943 end_position,
944 content_length,
945 content_type,
946 local_file_path),
947 callback_(callback),
948 progress_callback_(progress_callback) {
949 DCHECK(!callback_.is_null());
952 ResumeUploadRequest::~ResumeUploadRequest() {}
954 void ResumeUploadRequest::OnRangeRequestComplete(
955 const UploadRangeResponse& response,
956 scoped_ptr<base::Value> value) {
957 DCHECK(CalledOnValidThread());
958 ParseFileResourceWithUploadRangeAndRun(callback_, response, value.Pass());
961 void ResumeUploadRequest::OnURLFetchUploadProgress(
962 const net::URLFetcher* source, int64 current, int64 total) {
963 if (!progress_callback_.is_null())
964 progress_callback_.Run(current, total);
967 //========================== GetUploadStatusRequest ==========================
969 GetUploadStatusRequest::GetUploadStatusRequest(
970 RequestSender* sender,
971 const GURL& upload_url,
972 int64 content_length,
973 const UploadRangeCallback& callback)
974 : GetUploadStatusRequestBase(sender,
975 upload_url,
976 content_length),
977 callback_(callback) {
978 DCHECK(!callback.is_null());
981 GetUploadStatusRequest::~GetUploadStatusRequest() {}
983 void GetUploadStatusRequest::OnRangeRequestComplete(
984 const UploadRangeResponse& response,
985 scoped_ptr<base::Value> value) {
986 DCHECK(CalledOnValidThread());
987 ParseFileResourceWithUploadRangeAndRun(callback_, response, value.Pass());
990 //======================= MultipartUploadNewFileDelegate =======================
992 MultipartUploadNewFileDelegate::MultipartUploadNewFileDelegate(
993 base::SequencedTaskRunner* task_runner,
994 const std::string& title,
995 const std::string& parent_resource_id,
996 const std::string& content_type,
997 int64 content_length,
998 const base::Time& modified_date,
999 const base::Time& last_viewed_by_me_date,
1000 const base::FilePath& local_file_path,
1001 const Properties& properties,
1002 const DriveApiUrlGenerator& url_generator,
1003 const FileResourceCallback& callback,
1004 const ProgressCallback& progress_callback)
1005 : MultipartUploadRequestBase(
1006 task_runner,
1007 CreateMultipartUploadMetadataJson(title,
1008 parent_resource_id,
1009 modified_date,
1010 last_viewed_by_me_date,
1011 properties),
1012 content_type,
1013 content_length,
1014 local_file_path,
1015 callback,
1016 progress_callback),
1017 has_modified_date_(!modified_date.is_null()),
1018 url_generator_(url_generator) {
1021 MultipartUploadNewFileDelegate::~MultipartUploadNewFileDelegate() {
1024 GURL MultipartUploadNewFileDelegate::GetURL() const {
1025 return url_generator_.GetMultipartUploadNewFileUrl(has_modified_date_);
1028 net::URLFetcher::RequestType MultipartUploadNewFileDelegate::GetRequestType()
1029 const {
1030 return net::URLFetcher::POST;
1033 //====================== MultipartUploadExistingFileDelegate ===================
1035 MultipartUploadExistingFileDelegate::MultipartUploadExistingFileDelegate(
1036 base::SequencedTaskRunner* task_runner,
1037 const std::string& title,
1038 const std::string& resource_id,
1039 const std::string& parent_resource_id,
1040 const std::string& content_type,
1041 int64 content_length,
1042 const base::Time& modified_date,
1043 const base::Time& last_viewed_by_me_date,
1044 const base::FilePath& local_file_path,
1045 const std::string& etag,
1046 const Properties& properties,
1047 const DriveApiUrlGenerator& url_generator,
1048 const FileResourceCallback& callback,
1049 const ProgressCallback& progress_callback)
1050 : MultipartUploadRequestBase(
1051 task_runner,
1052 CreateMultipartUploadMetadataJson(title,
1053 parent_resource_id,
1054 modified_date,
1055 last_viewed_by_me_date,
1056 properties),
1057 content_type,
1058 content_length,
1059 local_file_path,
1060 callback,
1061 progress_callback),
1062 resource_id_(resource_id),
1063 etag_(etag),
1064 has_modified_date_(!modified_date.is_null()),
1065 url_generator_(url_generator) {
1068 MultipartUploadExistingFileDelegate::~MultipartUploadExistingFileDelegate() {
1071 std::vector<std::string>
1072 MultipartUploadExistingFileDelegate::GetExtraRequestHeaders() const {
1073 std::vector<std::string> headers(
1074 MultipartUploadRequestBase::GetExtraRequestHeaders());
1075 headers.push_back(util::GenerateIfMatchHeader(etag_));
1076 return headers;
1079 GURL MultipartUploadExistingFileDelegate::GetURL() const {
1080 return url_generator_.GetMultipartUploadExistingFileUrl(resource_id_,
1081 has_modified_date_);
1084 net::URLFetcher::RequestType
1085 MultipartUploadExistingFileDelegate::GetRequestType() const {
1086 return net::URLFetcher::PUT;
1089 //========================== DownloadFileRequest ==========================
1091 DownloadFileRequest::DownloadFileRequest(
1092 RequestSender* sender,
1093 const DriveApiUrlGenerator& url_generator,
1094 const std::string& resource_id,
1095 const base::FilePath& output_file_path,
1096 const DownloadActionCallback& download_action_callback,
1097 const GetContentCallback& get_content_callback,
1098 const ProgressCallback& progress_callback)
1099 : DownloadFileRequestBase(
1100 sender,
1101 download_action_callback,
1102 get_content_callback,
1103 progress_callback,
1104 url_generator.GenerateDownloadFileUrl(resource_id),
1105 output_file_path) {
1108 DownloadFileRequest::~DownloadFileRequest() {
1111 //========================== PermissionsInsertRequest ==========================
1113 PermissionsInsertRequest::PermissionsInsertRequest(
1114 RequestSender* sender,
1115 const DriveApiUrlGenerator& url_generator,
1116 const EntryActionCallback& callback)
1117 : EntryActionRequest(sender, callback),
1118 url_generator_(url_generator),
1119 type_(PERMISSION_TYPE_USER),
1120 role_(PERMISSION_ROLE_READER) {
1123 PermissionsInsertRequest::~PermissionsInsertRequest() {
1126 GURL PermissionsInsertRequest::GetURL() const {
1127 return url_generator_.GetPermissionsInsertUrl(id_);
1130 net::URLFetcher::RequestType
1131 PermissionsInsertRequest::GetRequestType() const {
1132 return net::URLFetcher::POST;
1135 bool PermissionsInsertRequest::GetContentData(std::string* upload_content_type,
1136 std::string* upload_content) {
1137 *upload_content_type = util::kContentTypeApplicationJson;
1139 base::DictionaryValue root;
1140 switch (type_) {
1141 case PERMISSION_TYPE_ANYONE:
1142 root.SetString("type", "anyone");
1143 break;
1144 case PERMISSION_TYPE_DOMAIN:
1145 root.SetString("type", "domain");
1146 break;
1147 case PERMISSION_TYPE_GROUP:
1148 root.SetString("type", "group");
1149 break;
1150 case PERMISSION_TYPE_USER:
1151 root.SetString("type", "user");
1152 break;
1154 switch (role_) {
1155 case PERMISSION_ROLE_OWNER:
1156 root.SetString("role", "owner");
1157 break;
1158 case PERMISSION_ROLE_READER:
1159 root.SetString("role", "reader");
1160 break;
1161 case PERMISSION_ROLE_WRITER:
1162 root.SetString("role", "writer");
1163 break;
1164 case PERMISSION_ROLE_COMMENTER:
1165 root.SetString("role", "reader");
1167 base::ListValue* list = new base::ListValue;
1168 list->AppendString("commenter");
1169 root.Set("additionalRoles", list);
1171 break;
1173 root.SetString("value", value_);
1174 base::JSONWriter::Write(root, upload_content);
1175 return true;
1178 //======================= SingleBatchableDelegateRequest =======================
1180 SingleBatchableDelegateRequest::SingleBatchableDelegateRequest(
1181 RequestSender* sender,
1182 BatchableDelegate* delegate)
1183 : UrlFetchRequestBase(sender),
1184 delegate_(delegate),
1185 weak_ptr_factory_(this) {
1188 SingleBatchableDelegateRequest::~SingleBatchableDelegateRequest() {
1191 GURL SingleBatchableDelegateRequest::GetURL() const {
1192 return delegate_->GetURL();
1195 net::URLFetcher::RequestType SingleBatchableDelegateRequest::GetRequestType()
1196 const {
1197 return delegate_->GetRequestType();
1200 std::vector<std::string>
1201 SingleBatchableDelegateRequest::GetExtraRequestHeaders() const {
1202 return delegate_->GetExtraRequestHeaders();
1205 void SingleBatchableDelegateRequest::Prepare(const PrepareCallback& callback) {
1206 delegate_->Prepare(callback);
1209 bool SingleBatchableDelegateRequest::GetContentData(
1210 std::string* upload_content_type,
1211 std::string* upload_content) {
1212 return delegate_->GetContentData(upload_content_type, upload_content);
1215 void SingleBatchableDelegateRequest::ProcessURLFetchResults(
1216 const net::URLFetcher* source) {
1217 delegate_->NotifyResult(
1218 GetErrorCode(), response_writer()->data(),
1219 base::Bind(
1220 &SingleBatchableDelegateRequest::OnProcessURLFetchResultsComplete,
1221 weak_ptr_factory_.GetWeakPtr()));
1224 void SingleBatchableDelegateRequest::RunCallbackOnPrematureFailure(
1225 DriveApiErrorCode code) {
1226 delegate_->NotifyError(code);
1229 void SingleBatchableDelegateRequest::OnURLFetchUploadProgress(
1230 const net::URLFetcher* source,
1231 int64 current,
1232 int64 total) {
1233 delegate_->NotifyUploadProgress(source, current, total);
1236 //========================== BatchUploadRequest ==========================
1238 BatchUploadChildEntry::BatchUploadChildEntry(BatchableDelegate* request)
1239 : request(request), prepared(false), data_offset(0), data_size(0) {
1242 BatchUploadChildEntry::~BatchUploadChildEntry() {
1245 BatchUploadRequest::BatchUploadRequest(
1246 RequestSender* sender,
1247 const DriveApiUrlGenerator& url_generator)
1248 : UrlFetchRequestBase(sender),
1249 sender_(sender),
1250 url_generator_(url_generator),
1251 committed_(false),
1252 last_progress_value_(0),
1253 weak_ptr_factory_(this) {
1256 BatchUploadRequest::~BatchUploadRequest() {
1259 void BatchUploadRequest::SetBoundaryForTesting(const std::string& boundary) {
1260 boundary_ = boundary;
1263 void BatchUploadRequest::AddRequest(BatchableDelegate* request) {
1264 DCHECK(CalledOnValidThread());
1265 DCHECK(request);
1266 DCHECK(GetChildEntry(request) == child_requests_.end());
1267 DCHECK(!committed_);
1268 child_requests_.push_back(new BatchUploadChildEntry(request));
1269 request->Prepare(base::Bind(&BatchUploadRequest::OnChildRequestPrepared,
1270 weak_ptr_factory_.GetWeakPtr(), request));
1273 void BatchUploadRequest::OnChildRequestPrepared(RequestID request_id,
1274 DriveApiErrorCode result) {
1275 DCHECK(CalledOnValidThread());
1276 auto const child = GetChildEntry(request_id);
1277 DCHECK(child != child_requests_.end());
1278 if (IsSuccessfulDriveApiErrorCode(result)) {
1279 (*child)->prepared = true;
1280 } else {
1281 (*child)->request->NotifyError(result);
1282 child_requests_.erase(child);
1284 MayCompletePrepare();
1287 void BatchUploadRequest::Commit() {
1288 DCHECK(CalledOnValidThread());
1289 DCHECK(!committed_);
1290 if (child_requests_.empty()) {
1291 Cancel();
1292 } else {
1293 committed_ = true;
1294 MayCompletePrepare();
1298 void BatchUploadRequest::Prepare(const PrepareCallback& callback) {
1299 DCHECK(CalledOnValidThread());
1300 DCHECK(!callback.is_null());
1301 prepare_callback_ = callback;
1302 MayCompletePrepare();
1305 void BatchUploadRequest::Cancel() {
1306 child_requests_.clear();
1307 UrlFetchRequestBase::Cancel();
1310 // Obtains corresponding child entry of |request_id|. Returns NULL if the
1311 // entry is not found.
1312 ScopedVector<BatchUploadChildEntry>::iterator BatchUploadRequest::GetChildEntry(
1313 RequestID request_id) {
1314 for (auto it = child_requests_.begin(); it != child_requests_.end(); ++it) {
1315 if ((*it)->request.get() == request_id)
1316 return it;
1318 return child_requests_.end();
1321 void BatchUploadRequest::MayCompletePrepare() {
1322 if (!committed_ || prepare_callback_.is_null())
1323 return;
1324 for (const auto& child : child_requests_) {
1325 if (!child->prepared)
1326 return;
1329 // Build multipart body here.
1330 int64 total_size = 0;
1331 std::vector<ContentTypeAndData> parts;
1332 for (auto& child : child_requests_) {
1333 std::string type;
1334 std::string data;
1335 const bool result = child->request->GetContentData(&type, &data);
1336 // Upload request must have content data.
1337 DCHECK(result);
1339 const GURL url = child->request->GetURL();
1340 std::string method;
1341 switch (child->request->GetRequestType()) {
1342 case net::URLFetcher::POST:
1343 method = "POST";
1344 break;
1345 case net::URLFetcher::PUT:
1346 method = "PUT";
1347 break;
1348 default:
1349 NOTREACHED();
1350 break;
1352 const std::string header = base::StringPrintf(
1353 kBatchUploadRequestFormat, method.c_str(), url.path().c_str(),
1354 url_generator_.GetBatchUploadUrl().host().c_str(), type.c_str());
1356 child->data_offset = header.size();
1357 child->data_size = data.size();
1358 total_size += data.size();
1360 parts.push_back(ContentTypeAndData());
1361 parts.back().type = kHttpContentType;
1362 parts.back().data = header;
1363 parts.back().data.append(data);
1366 UMA_HISTOGRAM_COUNTS_100(kUMADriveTotalFileCountInBatchUpload, parts.size());
1367 UMA_HISTOGRAM_MEMORY_KB(kUMADriveTotalFileSizeInBatchUpload,
1368 total_size / 1024);
1370 std::vector<uint64> part_data_offset;
1371 GenerateMultipartBody(MULTIPART_MIXED, boundary_, parts, &upload_content_,
1372 &part_data_offset);
1373 DCHECK(part_data_offset.size() == child_requests_.size());
1374 for (size_t i = 0; i < child_requests_.size(); ++i) {
1375 child_requests_[i]->data_offset += part_data_offset[i];
1377 prepare_callback_.Run(HTTP_SUCCESS);
1380 bool BatchUploadRequest::GetContentData(std::string* upload_content_type,
1381 std::string* upload_content_data) {
1382 upload_content_type->assign(upload_content_.type);
1383 upload_content_data->assign(upload_content_.data);
1384 return true;
1387 base::WeakPtr<BatchUploadRequest>
1388 BatchUploadRequest::GetWeakPtrAsBatchUploadRequest() {
1389 return weak_ptr_factory_.GetWeakPtr();
1392 GURL BatchUploadRequest::GetURL() const {
1393 return url_generator_.GetBatchUploadUrl();
1396 net::URLFetcher::RequestType BatchUploadRequest::GetRequestType() const {
1397 return net::URLFetcher::PUT;
1400 std::vector<std::string> BatchUploadRequest::GetExtraRequestHeaders() const {
1401 std::vector<std::string> headers;
1402 headers.push_back(kBatchUploadHeader);
1403 return headers;
1406 void BatchUploadRequest::ProcessURLFetchResults(const net::URLFetcher* source) {
1407 UMA_HISTOGRAM_SPARSE_SLOWLY(kUMADriveBatchUploadResponseCode, GetErrorCode());
1409 if (!IsSuccessfulDriveApiErrorCode(GetErrorCode())) {
1410 RunCallbackOnPrematureFailure(GetErrorCode());
1411 sender_->RequestFinished(this);
1412 return;
1415 std::string content_type;
1416 source->GetResponseHeaders()->EnumerateHeader(
1417 /* need only first header */ NULL, "Content-Type", &content_type);
1419 std::vector<MultipartHttpResponse> parts;
1420 if (!ParseMultipartResponse(content_type, response_writer()->data(),
1421 &parts) ||
1422 child_requests_.size() != parts.size()) {
1423 RunCallbackOnPrematureFailure(DRIVE_PARSE_ERROR);
1424 sender_->RequestFinished(this);
1425 return;
1428 for (size_t i = 0; i < parts.size(); ++i) {
1429 BatchableDelegate* const delegate = child_requests_[i]->request.get();
1430 // Pass onwership of |delegate| so that child_requests_.clear() won't
1431 // kill the delegate. It has to be deleted after the notification.
1432 delegate->NotifyResult(
1433 parts[i].code, parts[i].body,
1434 base::Bind(&EmptyClosure, base::Passed(&child_requests_[i]->request)));
1436 child_requests_.clear();
1438 sender_->RequestFinished(this);
1441 void BatchUploadRequest::RunCallbackOnPrematureFailure(DriveApiErrorCode code) {
1442 for (auto child : child_requests_) {
1443 child->request->NotifyError(code);
1445 child_requests_.clear();
1448 void BatchUploadRequest::OnURLFetchUploadProgress(const net::URLFetcher* source,
1449 int64 current,
1450 int64 total) {
1451 for (auto child : child_requests_) {
1452 if (child->data_offset <= current &&
1453 current <= child->data_offset + child->data_size) {
1454 child->request->NotifyUploadProgress(source, current - child->data_offset,
1455 child->data_size);
1456 } else if (last_progress_value_ < child->data_offset + child->data_size &&
1457 child->data_offset + child->data_size < current) {
1458 child->request->NotifyUploadProgress(source, child->data_size,
1459 child->data_size);
1462 last_progress_value_ = current;
1464 } // namespace drive
1465 } // namespace google_apis