Update V8 to version 4.5.23.
[chromium-blink-merge.git] / google_apis / drive / drive_api_requests.cc
blob57a3ec116bafe25769ef37344ba7d06c7401da98
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/sequenced_task_runner.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_piece.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/task_runner_util.h"
16 #include "base/values.h"
17 #include "google_apis/drive/request_sender.h"
18 #include "google_apis/drive/request_util.h"
19 #include "google_apis/drive/time_util.h"
20 #include "net/base/url_util.h"
21 #include "net/http/http_response_headers.h"
23 namespace google_apis {
24 namespace drive {
25 namespace {
27 // Format of one request in batch uploading request.
28 const char kBatchUploadRequestFormat[] =
29 "%s %s HTTP/1.1\n"
30 "Host: %s\n"
31 "X-Goog-Upload-Protocol: multipart\n"
32 "Content-Type: %s\n"
33 "\n";
35 // Request header for specifying batch upload.
36 const char kBatchUploadHeader[] = "X-Goog-Upload-Protocol: batch";
38 // Content type of HTTP request.
39 const char kHttpContentType[] = "application/http";
41 // Break line in HTTP message.
42 const char kHttpBr[] = "\r\n";
44 // Mime type of multipart mixed.
45 const char kMultipartMixedMimeTypePrefix[] = "multipart/mixed; boundary=";
47 // Parses the JSON value to FileResource instance and runs |callback| on the
48 // UI thread once parsing is done.
49 // This is customized version of ParseJsonAndRun defined above to adapt the
50 // remaining response type.
51 void ParseFileResourceWithUploadRangeAndRun(const UploadRangeCallback& callback,
52 const UploadRangeResponse& response,
53 scoped_ptr<base::Value> value) {
54 DCHECK(!callback.is_null());
56 scoped_ptr<FileResource> file_resource;
57 if (value) {
58 file_resource = FileResource::CreateFrom(*value);
59 if (!file_resource) {
60 callback.Run(
61 UploadRangeResponse(DRIVE_PARSE_ERROR,
62 response.start_position_received,
63 response.end_position_received),
64 scoped_ptr<FileResource>());
65 return;
69 callback.Run(response, file_resource.Pass());
72 // Attaches |properties| to the |request_body| if |properties| is not empty.
73 // |request_body| must not be NULL.
74 void AttachProperties(const Properties& properties,
75 base::DictionaryValue* request_body) {
76 DCHECK(request_body);
77 if (properties.empty())
78 return;
80 base::ListValue* const properties_value = new base::ListValue;
81 for (const auto& property : properties) {
82 base::DictionaryValue* const property_value = new base::DictionaryValue;
83 std::string visibility_as_string;
84 switch (property.visibility()) {
85 case Property::VISIBILITY_PRIVATE:
86 visibility_as_string = "PRIVATE";
87 break;
88 case Property::VISIBILITY_PUBLIC:
89 visibility_as_string = "PUBLIC";
90 break;
92 property_value->SetString("visibility", visibility_as_string);
93 property_value->SetString("key", property.key());
94 property_value->SetString("value", property.value());
95 properties_value->Append(property_value);
97 request_body->Set("properties", properties_value);
100 // Creates metadata JSON string for multipart uploading.
101 // All the values are optional. If the value is empty or null, the value does
102 // not appear in the metadata.
103 std::string CreateMultipartUploadMetadataJson(
104 const std::string& title,
105 const std::string& parent_resource_id,
106 const base::Time& modified_date,
107 const base::Time& last_viewed_by_me_date,
108 const Properties& properties) {
109 base::DictionaryValue root;
110 if (!title.empty())
111 root.SetString("title", title);
113 // Fill parent link.
114 if (!parent_resource_id.empty()) {
115 scoped_ptr<base::ListValue> parents(new base::ListValue);
116 parents->Append(
117 google_apis::util::CreateParentValue(parent_resource_id).release());
118 root.Set("parents", parents.release());
121 if (!modified_date.is_null()) {
122 root.SetString("modifiedDate",
123 google_apis::util::FormatTimeAsString(modified_date));
126 if (!last_viewed_by_me_date.is_null()) {
127 root.SetString("lastViewedByMeDate", google_apis::util::FormatTimeAsString(
128 last_viewed_by_me_date));
131 AttachProperties(properties, &root);
132 std::string json_string;
133 base::JSONWriter::Write(root, &json_string);
134 return json_string;
137 // Splits |string| into lines by |kHttpBr|.
138 // Each line does not include |kHttpBr|.
139 void SplitIntoLines(const std::string& string,
140 std::vector<base::StringPiece>* output) {
141 const size_t br_size = std::string(kHttpBr).size();
142 std::string::const_iterator it = string.begin();
143 std::vector<base::StringPiece> lines;
144 while (true) {
145 const std::string::const_iterator next_pos =
146 std::search(it, string.end(), kHttpBr, kHttpBr + br_size);
147 lines.push_back(base::StringPiece(it, next_pos));
148 if (next_pos == string.end())
149 break;
150 it = next_pos + br_size;
152 output->swap(lines);
155 // Remove transport padding (spaces and tabs at the end of line) from |piece|.
156 base::StringPiece TrimTransportPadding(const base::StringPiece& piece) {
157 size_t trim_size = 0;
158 while (trim_size < piece.size() &&
159 (piece[piece.size() - 1 - trim_size] == ' ' ||
160 piece[piece.size() - 1 - trim_size] == '\t')) {
161 ++trim_size;
163 return piece.substr(0, piece.size() - trim_size);
166 void EmptyClosure(scoped_ptr<BatchableDelegate>) {
169 } // namespace
171 MultipartHttpResponse::MultipartHttpResponse() : code(HTTP_SUCCESS) {
174 MultipartHttpResponse::~MultipartHttpResponse() {
177 // The |response| must be multipart/mixed format that contains child HTTP
178 // response of drive batch request.
179 // https://www.ietf.org/rfc/rfc2046.txt
181 // It looks like:
182 // --Boundary
183 // Content-type: application/http
185 // HTTP/1.1 200 OK
186 // Header of child response
188 // Body of child response
189 // --Boundary
190 // Content-type: application/http
192 // HTTP/1.1 404 Not Found
193 // Header of child response
195 // Body of child response
196 // --Boundary--
197 bool ParseMultipartResponse(const std::string& content_type,
198 const std::string& response,
199 std::vector<MultipartHttpResponse>* parts) {
200 if (response.empty())
201 return false;
203 base::StringPiece content_type_piece(content_type);
204 if (!content_type_piece.starts_with(kMultipartMixedMimeTypePrefix)) {
205 return false;
207 content_type_piece.remove_prefix(
208 base::StringPiece(kMultipartMixedMimeTypePrefix).size());
210 if (content_type_piece.empty())
211 return false;
212 if (content_type_piece[0] == '"') {
213 if (content_type_piece.size() <= 2 ||
214 content_type_piece[content_type_piece.size() - 1] != '"') {
215 return false;
217 content_type_piece =
218 content_type_piece.substr(1, content_type_piece.size() - 2);
221 std::string boundary;
222 content_type_piece.CopyToString(&boundary);
223 const std::string header = "--" + boundary;
224 const std::string terminator = "--" + boundary + "--";
226 std::vector<base::StringPiece> lines;
227 SplitIntoLines(response, &lines);
229 enum {
230 STATE_START,
231 STATE_PART_HEADER,
232 STATE_PART_HTTP_STATUS_LINE,
233 STATE_PART_HTTP_HEADER,
234 STATE_PART_HTTP_BODY
235 } state = STATE_START;
237 const std::string kHttpStatusPrefix = "HTTP/1.1 ";
238 std::vector<MultipartHttpResponse> responses;
239 DriveApiErrorCode code = DRIVE_PARSE_ERROR;
240 std::string body;
241 for (const auto& line : lines) {
242 if (state == STATE_PART_HEADER && line.empty()) {
243 state = STATE_PART_HTTP_STATUS_LINE;
244 continue;
247 if (state == STATE_PART_HTTP_STATUS_LINE) {
248 if (line.starts_with(kHttpStatusPrefix)) {
249 int int_code;
250 base::StringToInt(
251 line.substr(base::StringPiece(kHttpStatusPrefix).size()),
252 &int_code);
253 if (int_code > 0)
254 code = static_cast<DriveApiErrorCode>(int_code);
255 else
256 code = DRIVE_PARSE_ERROR;
257 } else {
258 code = DRIVE_PARSE_ERROR;
260 state = STATE_PART_HTTP_HEADER;
261 continue;
264 if (state == STATE_PART_HTTP_HEADER && line.empty()) {
265 state = STATE_PART_HTTP_BODY;
266 body.clear();
267 continue;
269 const base::StringPiece chopped_line = TrimTransportPadding(line);
270 const bool is_new_part = chopped_line == header;
271 const bool was_last_part = chopped_line == terminator;
272 if (is_new_part || was_last_part) {
273 switch (state) {
274 case STATE_START:
275 break;
276 case STATE_PART_HEADER:
277 case STATE_PART_HTTP_STATUS_LINE:
278 responses.push_back(MultipartHttpResponse());
279 responses.back().code = DRIVE_PARSE_ERROR;
280 break;
281 case STATE_PART_HTTP_HEADER:
282 responses.push_back(MultipartHttpResponse());
283 responses.back().code = code;
284 break;
285 case STATE_PART_HTTP_BODY:
286 // Drop the last kHttpBr.
287 if (!body.empty())
288 body.resize(body.size() - 2);
289 responses.push_back(MultipartHttpResponse());
290 responses.back().code = code;
291 responses.back().body.swap(body);
292 break;
294 if (is_new_part)
295 state = STATE_PART_HEADER;
296 if (was_last_part)
297 break;
298 } else if (state == STATE_PART_HTTP_BODY) {
299 line.AppendToString(&body);
300 body.append(kHttpBr);
304 parts->swap(responses);
305 return true;
308 Property::Property() : visibility_(VISIBILITY_PRIVATE) {
311 Property::~Property() {
314 //============================ DriveApiPartialFieldRequest ====================
316 DriveApiPartialFieldRequest::DriveApiPartialFieldRequest(
317 RequestSender* sender) : UrlFetchRequestBase(sender) {
320 DriveApiPartialFieldRequest::~DriveApiPartialFieldRequest() {
323 GURL DriveApiPartialFieldRequest::GetURL() const {
324 GURL url = GetURLInternal();
325 if (!fields_.empty())
326 url = net::AppendOrReplaceQueryParameter(url, "fields", fields_);
327 return url;
330 //=============================== FilesGetRequest =============================
332 FilesGetRequest::FilesGetRequest(
333 RequestSender* sender,
334 const DriveApiUrlGenerator& url_generator,
335 bool use_internal_endpoint,
336 const FileResourceCallback& callback)
337 : DriveApiDataRequest<FileResource>(sender, callback),
338 url_generator_(url_generator),
339 use_internal_endpoint_(use_internal_endpoint) {
340 DCHECK(!callback.is_null());
343 FilesGetRequest::~FilesGetRequest() {}
345 GURL FilesGetRequest::GetURLInternal() const {
346 return url_generator_.GetFilesGetUrl(file_id_,
347 use_internal_endpoint_,
348 embed_origin_);
351 //============================ FilesAuthorizeRequest ===========================
353 FilesAuthorizeRequest::FilesAuthorizeRequest(
354 RequestSender* sender,
355 const DriveApiUrlGenerator& url_generator,
356 const FileResourceCallback& callback)
357 : DriveApiDataRequest<FileResource>(sender, callback),
358 url_generator_(url_generator) {
359 DCHECK(!callback.is_null());
362 FilesAuthorizeRequest::~FilesAuthorizeRequest() {}
364 net::URLFetcher::RequestType FilesAuthorizeRequest::GetRequestType() const {
365 return net::URLFetcher::POST;
368 GURL FilesAuthorizeRequest::GetURLInternal() const {
369 return url_generator_.GetFilesAuthorizeUrl(file_id_, app_id_);
372 //============================ FilesInsertRequest ============================
374 FilesInsertRequest::FilesInsertRequest(
375 RequestSender* sender,
376 const DriveApiUrlGenerator& url_generator,
377 const FileResourceCallback& callback)
378 : DriveApiDataRequest<FileResource>(sender, callback),
379 url_generator_(url_generator) {
380 DCHECK(!callback.is_null());
383 FilesInsertRequest::~FilesInsertRequest() {}
385 net::URLFetcher::RequestType FilesInsertRequest::GetRequestType() const {
386 return net::URLFetcher::POST;
389 bool FilesInsertRequest::GetContentData(std::string* upload_content_type,
390 std::string* upload_content) {
391 *upload_content_type = util::kContentTypeApplicationJson;
393 base::DictionaryValue root;
395 if (!last_viewed_by_me_date_.is_null()) {
396 root.SetString("lastViewedByMeDate",
397 util::FormatTimeAsString(last_viewed_by_me_date_));
400 if (!mime_type_.empty())
401 root.SetString("mimeType", mime_type_);
403 if (!modified_date_.is_null())
404 root.SetString("modifiedDate", util::FormatTimeAsString(modified_date_));
406 if (!parents_.empty()) {
407 base::ListValue* parents_value = new base::ListValue;
408 for (size_t i = 0; i < parents_.size(); ++i) {
409 base::DictionaryValue* parent = new base::DictionaryValue;
410 parent->SetString("id", parents_[i]);
411 parents_value->Append(parent);
413 root.Set("parents", parents_value);
416 if (!title_.empty())
417 root.SetString("title", title_);
419 AttachProperties(properties_, &root);
420 base::JSONWriter::Write(root, upload_content);
422 DVLOG(1) << "FilesInsert data: " << *upload_content_type << ", ["
423 << *upload_content << "]";
424 return true;
427 GURL FilesInsertRequest::GetURLInternal() const {
428 return url_generator_.GetFilesInsertUrl();
431 //============================== FilesPatchRequest ============================
433 FilesPatchRequest::FilesPatchRequest(
434 RequestSender* sender,
435 const DriveApiUrlGenerator& url_generator,
436 const FileResourceCallback& callback)
437 : DriveApiDataRequest<FileResource>(sender, callback),
438 url_generator_(url_generator),
439 set_modified_date_(false),
440 update_viewed_date_(true) {
441 DCHECK(!callback.is_null());
444 FilesPatchRequest::~FilesPatchRequest() {}
446 net::URLFetcher::RequestType FilesPatchRequest::GetRequestType() const {
447 return net::URLFetcher::PATCH;
450 std::vector<std::string> FilesPatchRequest::GetExtraRequestHeaders() const {
451 std::vector<std::string> headers;
452 headers.push_back(util::kIfMatchAllHeader);
453 return headers;
456 GURL FilesPatchRequest::GetURLInternal() const {
457 return url_generator_.GetFilesPatchUrl(
458 file_id_, set_modified_date_, update_viewed_date_);
461 bool FilesPatchRequest::GetContentData(std::string* upload_content_type,
462 std::string* upload_content) {
463 if (title_.empty() &&
464 modified_date_.is_null() &&
465 last_viewed_by_me_date_.is_null() &&
466 parents_.empty())
467 return false;
469 *upload_content_type = util::kContentTypeApplicationJson;
471 base::DictionaryValue root;
472 if (!title_.empty())
473 root.SetString("title", title_);
475 if (!modified_date_.is_null())
476 root.SetString("modifiedDate", util::FormatTimeAsString(modified_date_));
478 if (!last_viewed_by_me_date_.is_null()) {
479 root.SetString("lastViewedByMeDate",
480 util::FormatTimeAsString(last_viewed_by_me_date_));
483 if (!parents_.empty()) {
484 base::ListValue* parents_value = new base::ListValue;
485 for (size_t i = 0; i < parents_.size(); ++i) {
486 base::DictionaryValue* parent = new base::DictionaryValue;
487 parent->SetString("id", parents_[i]);
488 parents_value->Append(parent);
490 root.Set("parents", parents_value);
493 AttachProperties(properties_, &root);
494 base::JSONWriter::Write(root, upload_content);
496 DVLOG(1) << "FilesPatch data: " << *upload_content_type << ", ["
497 << *upload_content << "]";
498 return true;
501 //============================= FilesCopyRequest ==============================
503 FilesCopyRequest::FilesCopyRequest(
504 RequestSender* sender,
505 const DriveApiUrlGenerator& url_generator,
506 const FileResourceCallback& callback)
507 : DriveApiDataRequest<FileResource>(sender, callback),
508 url_generator_(url_generator) {
509 DCHECK(!callback.is_null());
512 FilesCopyRequest::~FilesCopyRequest() {
515 net::URLFetcher::RequestType FilesCopyRequest::GetRequestType() const {
516 return net::URLFetcher::POST;
519 GURL FilesCopyRequest::GetURLInternal() const {
520 return url_generator_.GetFilesCopyUrl(file_id_);
523 bool FilesCopyRequest::GetContentData(std::string* upload_content_type,
524 std::string* upload_content) {
525 if (parents_.empty() && title_.empty())
526 return false;
528 *upload_content_type = util::kContentTypeApplicationJson;
530 base::DictionaryValue root;
532 if (!modified_date_.is_null())
533 root.SetString("modifiedDate", util::FormatTimeAsString(modified_date_));
535 if (!parents_.empty()) {
536 base::ListValue* parents_value = new base::ListValue;
537 for (size_t i = 0; i < parents_.size(); ++i) {
538 base::DictionaryValue* parent = new base::DictionaryValue;
539 parent->SetString("id", parents_[i]);
540 parents_value->Append(parent);
542 root.Set("parents", parents_value);
545 if (!title_.empty())
546 root.SetString("title", title_);
548 base::JSONWriter::Write(root, upload_content);
549 DVLOG(1) << "FilesCopy data: " << *upload_content_type << ", ["
550 << *upload_content << "]";
551 return true;
554 //============================= FilesListRequest =============================
556 FilesListRequest::FilesListRequest(
557 RequestSender* sender,
558 const DriveApiUrlGenerator& url_generator,
559 const FileListCallback& callback)
560 : DriveApiDataRequest<FileList>(sender, callback),
561 url_generator_(url_generator),
562 max_results_(100) {
563 DCHECK(!callback.is_null());
566 FilesListRequest::~FilesListRequest() {}
568 GURL FilesListRequest::GetURLInternal() const {
569 return url_generator_.GetFilesListUrl(max_results_, page_token_, q_);
572 //======================== FilesListNextPageRequest =========================
574 FilesListNextPageRequest::FilesListNextPageRequest(
575 RequestSender* sender,
576 const FileListCallback& callback)
577 : DriveApiDataRequest<FileList>(sender, callback) {
578 DCHECK(!callback.is_null());
581 FilesListNextPageRequest::~FilesListNextPageRequest() {
584 GURL FilesListNextPageRequest::GetURLInternal() const {
585 return next_link_;
588 //============================ FilesDeleteRequest =============================
590 FilesDeleteRequest::FilesDeleteRequest(
591 RequestSender* sender,
592 const DriveApiUrlGenerator& url_generator,
593 const EntryActionCallback& callback)
594 : EntryActionRequest(sender, callback),
595 url_generator_(url_generator) {
596 DCHECK(!callback.is_null());
599 FilesDeleteRequest::~FilesDeleteRequest() {}
601 net::URLFetcher::RequestType FilesDeleteRequest::GetRequestType() const {
602 return net::URLFetcher::DELETE_REQUEST;
605 GURL FilesDeleteRequest::GetURL() const {
606 return url_generator_.GetFilesDeleteUrl(file_id_);
609 std::vector<std::string> FilesDeleteRequest::GetExtraRequestHeaders() const {
610 std::vector<std::string> headers(
611 EntryActionRequest::GetExtraRequestHeaders());
612 headers.push_back(util::GenerateIfMatchHeader(etag_));
613 return headers;
616 //============================ FilesTrashRequest =============================
618 FilesTrashRequest::FilesTrashRequest(
619 RequestSender* sender,
620 const DriveApiUrlGenerator& url_generator,
621 const FileResourceCallback& callback)
622 : DriveApiDataRequest<FileResource>(sender, callback),
623 url_generator_(url_generator) {
624 DCHECK(!callback.is_null());
627 FilesTrashRequest::~FilesTrashRequest() {}
629 net::URLFetcher::RequestType FilesTrashRequest::GetRequestType() const {
630 return net::URLFetcher::POST;
633 GURL FilesTrashRequest::GetURLInternal() const {
634 return url_generator_.GetFilesTrashUrl(file_id_);
637 //============================== AboutGetRequest =============================
639 AboutGetRequest::AboutGetRequest(
640 RequestSender* sender,
641 const DriveApiUrlGenerator& url_generator,
642 const AboutResourceCallback& callback)
643 : DriveApiDataRequest<AboutResource>(sender, callback),
644 url_generator_(url_generator) {
645 DCHECK(!callback.is_null());
648 AboutGetRequest::~AboutGetRequest() {}
650 GURL AboutGetRequest::GetURLInternal() const {
651 return url_generator_.GetAboutGetUrl();
654 //============================ ChangesListRequest ===========================
656 ChangesListRequest::ChangesListRequest(
657 RequestSender* sender,
658 const DriveApiUrlGenerator& url_generator,
659 const ChangeListCallback& callback)
660 : DriveApiDataRequest<ChangeList>(sender, callback),
661 url_generator_(url_generator),
662 include_deleted_(true),
663 max_results_(100),
664 start_change_id_(0) {
665 DCHECK(!callback.is_null());
668 ChangesListRequest::~ChangesListRequest() {}
670 GURL ChangesListRequest::GetURLInternal() const {
671 return url_generator_.GetChangesListUrl(
672 include_deleted_, max_results_, page_token_, start_change_id_);
675 //======================== ChangesListNextPageRequest =========================
677 ChangesListNextPageRequest::ChangesListNextPageRequest(
678 RequestSender* sender,
679 const ChangeListCallback& callback)
680 : DriveApiDataRequest<ChangeList>(sender, callback) {
681 DCHECK(!callback.is_null());
684 ChangesListNextPageRequest::~ChangesListNextPageRequest() {
687 GURL ChangesListNextPageRequest::GetURLInternal() const {
688 return next_link_;
691 //============================== AppsListRequest ===========================
693 AppsListRequest::AppsListRequest(
694 RequestSender* sender,
695 const DriveApiUrlGenerator& url_generator,
696 bool use_internal_endpoint,
697 const AppListCallback& callback)
698 : DriveApiDataRequest<AppList>(sender, callback),
699 url_generator_(url_generator),
700 use_internal_endpoint_(use_internal_endpoint) {
701 DCHECK(!callback.is_null());
704 AppsListRequest::~AppsListRequest() {}
706 GURL AppsListRequest::GetURLInternal() const {
707 return url_generator_.GetAppsListUrl(use_internal_endpoint_);
710 //============================== AppsDeleteRequest ===========================
712 AppsDeleteRequest::AppsDeleteRequest(RequestSender* sender,
713 const DriveApiUrlGenerator& url_generator,
714 const EntryActionCallback& callback)
715 : EntryActionRequest(sender, callback),
716 url_generator_(url_generator) {
717 DCHECK(!callback.is_null());
720 AppsDeleteRequest::~AppsDeleteRequest() {}
722 net::URLFetcher::RequestType AppsDeleteRequest::GetRequestType() const {
723 return net::URLFetcher::DELETE_REQUEST;
726 GURL AppsDeleteRequest::GetURL() const {
727 return url_generator_.GetAppsDeleteUrl(app_id_);
730 //========================== ChildrenInsertRequest ============================
732 ChildrenInsertRequest::ChildrenInsertRequest(
733 RequestSender* sender,
734 const DriveApiUrlGenerator& url_generator,
735 const EntryActionCallback& callback)
736 : EntryActionRequest(sender, callback),
737 url_generator_(url_generator) {
738 DCHECK(!callback.is_null());
741 ChildrenInsertRequest::~ChildrenInsertRequest() {}
743 net::URLFetcher::RequestType ChildrenInsertRequest::GetRequestType() const {
744 return net::URLFetcher::POST;
747 GURL ChildrenInsertRequest::GetURL() const {
748 return url_generator_.GetChildrenInsertUrl(folder_id_);
751 bool ChildrenInsertRequest::GetContentData(std::string* upload_content_type,
752 std::string* upload_content) {
753 *upload_content_type = util::kContentTypeApplicationJson;
755 base::DictionaryValue root;
756 root.SetString("id", id_);
758 base::JSONWriter::Write(root, upload_content);
759 DVLOG(1) << "InsertResource data: " << *upload_content_type << ", ["
760 << *upload_content << "]";
761 return true;
764 //========================== ChildrenDeleteRequest ============================
766 ChildrenDeleteRequest::ChildrenDeleteRequest(
767 RequestSender* sender,
768 const DriveApiUrlGenerator& url_generator,
769 const EntryActionCallback& callback)
770 : EntryActionRequest(sender, callback),
771 url_generator_(url_generator) {
772 DCHECK(!callback.is_null());
775 ChildrenDeleteRequest::~ChildrenDeleteRequest() {}
777 net::URLFetcher::RequestType ChildrenDeleteRequest::GetRequestType() const {
778 return net::URLFetcher::DELETE_REQUEST;
781 GURL ChildrenDeleteRequest::GetURL() const {
782 return url_generator_.GetChildrenDeleteUrl(child_id_, folder_id_);
785 //======================= InitiateUploadNewFileRequest =======================
787 InitiateUploadNewFileRequest::InitiateUploadNewFileRequest(
788 RequestSender* sender,
789 const DriveApiUrlGenerator& url_generator,
790 const std::string& content_type,
791 int64 content_length,
792 const std::string& parent_resource_id,
793 const std::string& title,
794 const InitiateUploadCallback& callback)
795 : InitiateUploadRequestBase(sender,
796 callback,
797 content_type,
798 content_length),
799 url_generator_(url_generator),
800 parent_resource_id_(parent_resource_id),
801 title_(title) {
804 InitiateUploadNewFileRequest::~InitiateUploadNewFileRequest() {}
806 GURL InitiateUploadNewFileRequest::GetURL() const {
807 return url_generator_.GetInitiateUploadNewFileUrl(!modified_date_.is_null());
810 net::URLFetcher::RequestType
811 InitiateUploadNewFileRequest::GetRequestType() const {
812 return net::URLFetcher::POST;
815 bool InitiateUploadNewFileRequest::GetContentData(
816 std::string* upload_content_type,
817 std::string* upload_content) {
818 *upload_content_type = util::kContentTypeApplicationJson;
820 base::DictionaryValue root;
821 root.SetString("title", title_);
823 // Fill parent link.
824 scoped_ptr<base::ListValue> parents(new base::ListValue);
825 parents->Append(util::CreateParentValue(parent_resource_id_).release());
826 root.Set("parents", parents.release());
828 if (!modified_date_.is_null())
829 root.SetString("modifiedDate", util::FormatTimeAsString(modified_date_));
831 if (!last_viewed_by_me_date_.is_null()) {
832 root.SetString("lastViewedByMeDate",
833 util::FormatTimeAsString(last_viewed_by_me_date_));
836 AttachProperties(properties_, &root);
837 base::JSONWriter::Write(root, upload_content);
839 DVLOG(1) << "InitiateUploadNewFile data: " << *upload_content_type << ", ["
840 << *upload_content << "]";
841 return true;
844 //===================== InitiateUploadExistingFileRequest ====================
846 InitiateUploadExistingFileRequest::InitiateUploadExistingFileRequest(
847 RequestSender* sender,
848 const DriveApiUrlGenerator& url_generator,
849 const std::string& content_type,
850 int64 content_length,
851 const std::string& resource_id,
852 const std::string& etag,
853 const InitiateUploadCallback& callback)
854 : InitiateUploadRequestBase(sender,
855 callback,
856 content_type,
857 content_length),
858 url_generator_(url_generator),
859 resource_id_(resource_id),
860 etag_(etag) {
863 InitiateUploadExistingFileRequest::~InitiateUploadExistingFileRequest() {}
865 GURL InitiateUploadExistingFileRequest::GetURL() const {
866 return url_generator_.GetInitiateUploadExistingFileUrl(
867 resource_id_, !modified_date_.is_null());
870 net::URLFetcher::RequestType
871 InitiateUploadExistingFileRequest::GetRequestType() const {
872 return net::URLFetcher::PUT;
875 std::vector<std::string>
876 InitiateUploadExistingFileRequest::GetExtraRequestHeaders() const {
877 std::vector<std::string> headers(
878 InitiateUploadRequestBase::GetExtraRequestHeaders());
879 headers.push_back(util::GenerateIfMatchHeader(etag_));
880 return headers;
883 bool InitiateUploadExistingFileRequest::GetContentData(
884 std::string* upload_content_type,
885 std::string* upload_content) {
886 base::DictionaryValue root;
887 if (!parent_resource_id_.empty()) {
888 scoped_ptr<base::ListValue> parents(new base::ListValue);
889 parents->Append(util::CreateParentValue(parent_resource_id_).release());
890 root.Set("parents", parents.release());
893 if (!title_.empty())
894 root.SetString("title", title_);
896 if (!modified_date_.is_null())
897 root.SetString("modifiedDate", util::FormatTimeAsString(modified_date_));
899 if (!last_viewed_by_me_date_.is_null()) {
900 root.SetString("lastViewedByMeDate",
901 util::FormatTimeAsString(last_viewed_by_me_date_));
904 AttachProperties(properties_, &root);
905 if (root.empty())
906 return false;
908 *upload_content_type = util::kContentTypeApplicationJson;
909 base::JSONWriter::Write(root, upload_content);
910 DVLOG(1) << "InitiateUploadExistingFile data: " << *upload_content_type
911 << ", [" << *upload_content << "]";
912 return true;
915 //============================ ResumeUploadRequest ===========================
917 ResumeUploadRequest::ResumeUploadRequest(
918 RequestSender* sender,
919 const GURL& upload_location,
920 int64 start_position,
921 int64 end_position,
922 int64 content_length,
923 const std::string& content_type,
924 const base::FilePath& local_file_path,
925 const UploadRangeCallback& callback,
926 const ProgressCallback& progress_callback)
927 : ResumeUploadRequestBase(sender,
928 upload_location,
929 start_position,
930 end_position,
931 content_length,
932 content_type,
933 local_file_path),
934 callback_(callback),
935 progress_callback_(progress_callback) {
936 DCHECK(!callback_.is_null());
939 ResumeUploadRequest::~ResumeUploadRequest() {}
941 void ResumeUploadRequest::OnRangeRequestComplete(
942 const UploadRangeResponse& response,
943 scoped_ptr<base::Value> value) {
944 DCHECK(CalledOnValidThread());
945 ParseFileResourceWithUploadRangeAndRun(callback_, response, value.Pass());
948 void ResumeUploadRequest::OnURLFetchUploadProgress(
949 const net::URLFetcher* source, int64 current, int64 total) {
950 if (!progress_callback_.is_null())
951 progress_callback_.Run(current, total);
954 //========================== GetUploadStatusRequest ==========================
956 GetUploadStatusRequest::GetUploadStatusRequest(
957 RequestSender* sender,
958 const GURL& upload_url,
959 int64 content_length,
960 const UploadRangeCallback& callback)
961 : GetUploadStatusRequestBase(sender,
962 upload_url,
963 content_length),
964 callback_(callback) {
965 DCHECK(!callback.is_null());
968 GetUploadStatusRequest::~GetUploadStatusRequest() {}
970 void GetUploadStatusRequest::OnRangeRequestComplete(
971 const UploadRangeResponse& response,
972 scoped_ptr<base::Value> value) {
973 DCHECK(CalledOnValidThread());
974 ParseFileResourceWithUploadRangeAndRun(callback_, response, value.Pass());
977 //======================= MultipartUploadNewFileDelegate =======================
979 MultipartUploadNewFileDelegate::MultipartUploadNewFileDelegate(
980 RequestSender* sender,
981 const std::string& title,
982 const std::string& parent_resource_id,
983 const std::string& content_type,
984 int64 content_length,
985 const base::Time& modified_date,
986 const base::Time& last_viewed_by_me_date,
987 const base::FilePath& local_file_path,
988 const Properties& properties,
989 const DriveApiUrlGenerator& url_generator,
990 const FileResourceCallback& callback,
991 const ProgressCallback& progress_callback)
992 : MultipartUploadRequestBase(
993 sender->blocking_task_runner(),
994 CreateMultipartUploadMetadataJson(title,
995 parent_resource_id,
996 modified_date,
997 last_viewed_by_me_date,
998 properties),
999 content_type,
1000 content_length,
1001 local_file_path,
1002 callback,
1003 progress_callback),
1004 has_modified_date_(!modified_date.is_null()),
1005 url_generator_(url_generator) {
1008 MultipartUploadNewFileDelegate::~MultipartUploadNewFileDelegate() {
1011 GURL MultipartUploadNewFileDelegate::GetURL() const {
1012 return url_generator_.GetMultipartUploadNewFileUrl(has_modified_date_);
1015 net::URLFetcher::RequestType MultipartUploadNewFileDelegate::GetRequestType()
1016 const {
1017 return net::URLFetcher::POST;
1020 //====================== MultipartUploadExistingFileDelegate ===================
1022 MultipartUploadExistingFileDelegate::MultipartUploadExistingFileDelegate(
1023 RequestSender* sender,
1024 const std::string& title,
1025 const std::string& resource_id,
1026 const std::string& parent_resource_id,
1027 const std::string& content_type,
1028 int64 content_length,
1029 const base::Time& modified_date,
1030 const base::Time& last_viewed_by_me_date,
1031 const base::FilePath& local_file_path,
1032 const std::string& etag,
1033 const Properties& properties,
1034 const DriveApiUrlGenerator& url_generator,
1035 const FileResourceCallback& callback,
1036 const ProgressCallback& progress_callback)
1037 : MultipartUploadRequestBase(
1038 sender->blocking_task_runner(),
1039 CreateMultipartUploadMetadataJson(title,
1040 parent_resource_id,
1041 modified_date,
1042 last_viewed_by_me_date,
1043 properties),
1044 content_type,
1045 content_length,
1046 local_file_path,
1047 callback,
1048 progress_callback),
1049 resource_id_(resource_id),
1050 etag_(etag),
1051 has_modified_date_(!modified_date.is_null()),
1052 url_generator_(url_generator) {
1055 MultipartUploadExistingFileDelegate::~MultipartUploadExistingFileDelegate() {
1058 std::vector<std::string>
1059 MultipartUploadExistingFileDelegate::GetExtraRequestHeaders() const {
1060 std::vector<std::string> headers(
1061 MultipartUploadRequestBase::GetExtraRequestHeaders());
1062 headers.push_back(util::GenerateIfMatchHeader(etag_));
1063 return headers;
1066 GURL MultipartUploadExistingFileDelegate::GetURL() const {
1067 return url_generator_.GetMultipartUploadExistingFileUrl(resource_id_,
1068 has_modified_date_);
1071 net::URLFetcher::RequestType
1072 MultipartUploadExistingFileDelegate::GetRequestType() const {
1073 return net::URLFetcher::PUT;
1076 //========================== DownloadFileRequest ==========================
1078 DownloadFileRequest::DownloadFileRequest(
1079 RequestSender* sender,
1080 const DriveApiUrlGenerator& url_generator,
1081 const std::string& resource_id,
1082 const base::FilePath& output_file_path,
1083 const DownloadActionCallback& download_action_callback,
1084 const GetContentCallback& get_content_callback,
1085 const ProgressCallback& progress_callback)
1086 : DownloadFileRequestBase(
1087 sender,
1088 download_action_callback,
1089 get_content_callback,
1090 progress_callback,
1091 url_generator.GenerateDownloadFileUrl(resource_id),
1092 output_file_path) {
1095 DownloadFileRequest::~DownloadFileRequest() {
1098 //========================== PermissionsInsertRequest ==========================
1100 PermissionsInsertRequest::PermissionsInsertRequest(
1101 RequestSender* sender,
1102 const DriveApiUrlGenerator& url_generator,
1103 const EntryActionCallback& callback)
1104 : EntryActionRequest(sender, callback),
1105 url_generator_(url_generator),
1106 type_(PERMISSION_TYPE_USER),
1107 role_(PERMISSION_ROLE_READER) {
1110 PermissionsInsertRequest::~PermissionsInsertRequest() {
1113 GURL PermissionsInsertRequest::GetURL() const {
1114 return url_generator_.GetPermissionsInsertUrl(id_);
1117 net::URLFetcher::RequestType
1118 PermissionsInsertRequest::GetRequestType() const {
1119 return net::URLFetcher::POST;
1122 bool PermissionsInsertRequest::GetContentData(std::string* upload_content_type,
1123 std::string* upload_content) {
1124 *upload_content_type = util::kContentTypeApplicationJson;
1126 base::DictionaryValue root;
1127 switch (type_) {
1128 case PERMISSION_TYPE_ANYONE:
1129 root.SetString("type", "anyone");
1130 break;
1131 case PERMISSION_TYPE_DOMAIN:
1132 root.SetString("type", "domain");
1133 break;
1134 case PERMISSION_TYPE_GROUP:
1135 root.SetString("type", "group");
1136 break;
1137 case PERMISSION_TYPE_USER:
1138 root.SetString("type", "user");
1139 break;
1141 switch (role_) {
1142 case PERMISSION_ROLE_OWNER:
1143 root.SetString("role", "owner");
1144 break;
1145 case PERMISSION_ROLE_READER:
1146 root.SetString("role", "reader");
1147 break;
1148 case PERMISSION_ROLE_WRITER:
1149 root.SetString("role", "writer");
1150 break;
1151 case PERMISSION_ROLE_COMMENTER:
1152 root.SetString("role", "reader");
1154 base::ListValue* list = new base::ListValue;
1155 list->AppendString("commenter");
1156 root.Set("additionalRoles", list);
1158 break;
1160 root.SetString("value", value_);
1161 base::JSONWriter::Write(root, upload_content);
1162 return true;
1165 //======================= SingleBatchableDelegateRequest =======================
1167 SingleBatchableDelegateRequest::SingleBatchableDelegateRequest(
1168 RequestSender* sender,
1169 BatchableDelegate* delegate)
1170 : UrlFetchRequestBase(sender),
1171 delegate_(delegate),
1172 weak_ptr_factory_(this) {
1175 SingleBatchableDelegateRequest::~SingleBatchableDelegateRequest() {
1178 GURL SingleBatchableDelegateRequest::GetURL() const {
1179 return delegate_->GetURL();
1182 net::URLFetcher::RequestType SingleBatchableDelegateRequest::GetRequestType()
1183 const {
1184 return delegate_->GetRequestType();
1187 std::vector<std::string>
1188 SingleBatchableDelegateRequest::GetExtraRequestHeaders() const {
1189 return delegate_->GetExtraRequestHeaders();
1192 void SingleBatchableDelegateRequest::Prepare(const PrepareCallback& callback) {
1193 delegate_->Prepare(callback);
1196 bool SingleBatchableDelegateRequest::GetContentData(
1197 std::string* upload_content_type,
1198 std::string* upload_content) {
1199 return delegate_->GetContentData(upload_content_type, upload_content);
1202 void SingleBatchableDelegateRequest::ProcessURLFetchResults(
1203 const net::URLFetcher* source) {
1204 delegate_->NotifyResult(
1205 GetErrorCode(), response_writer()->data(),
1206 base::Bind(
1207 &SingleBatchableDelegateRequest::OnProcessURLFetchResultsComplete,
1208 weak_ptr_factory_.GetWeakPtr()));
1211 void SingleBatchableDelegateRequest::RunCallbackOnPrematureFailure(
1212 DriveApiErrorCode code) {
1213 delegate_->NotifyError(code);
1216 void SingleBatchableDelegateRequest::OnURLFetchUploadProgress(
1217 const net::URLFetcher* source,
1218 int64 current,
1219 int64 total) {
1220 delegate_->NotifyUploadProgress(source, current, total);
1223 //========================== BatchUploadRequest ==========================
1225 BatchUploadChildEntry::BatchUploadChildEntry(BatchableDelegate* request)
1226 : request(request), prepared(false), data_offset(0), data_size(0) {
1229 BatchUploadChildEntry::~BatchUploadChildEntry() {
1232 BatchUploadRequest::BatchUploadRequest(
1233 RequestSender* sender,
1234 const DriveApiUrlGenerator& url_generator)
1235 : UrlFetchRequestBase(sender),
1236 sender_(sender),
1237 url_generator_(url_generator),
1238 committed_(false),
1239 last_progress_value_(0),
1240 weak_ptr_factory_(this) {
1243 BatchUploadRequest::~BatchUploadRequest() {
1246 void BatchUploadRequest::SetBoundaryForTesting(const std::string& boundary) {
1247 boundary_ = boundary;
1250 void BatchUploadRequest::AddRequest(BatchableDelegate* request) {
1251 DCHECK(CalledOnValidThread());
1252 DCHECK(request);
1253 DCHECK(GetChildEntry(request) == child_requests_.end());
1254 DCHECK(!committed_);
1255 child_requests_.push_back(new BatchUploadChildEntry(request));
1256 request->Prepare(base::Bind(&BatchUploadRequest::OnChildRequestPrepared,
1257 weak_ptr_factory_.GetWeakPtr(), request));
1260 void BatchUploadRequest::OnChildRequestPrepared(RequestID request_id,
1261 DriveApiErrorCode result) {
1262 DCHECK(CalledOnValidThread());
1263 auto const child = GetChildEntry(request_id);
1264 DCHECK(child != child_requests_.end());
1265 if (IsSuccessfulDriveApiErrorCode(result)) {
1266 (*child)->prepared = true;
1267 } else {
1268 (*child)->request->NotifyError(result);
1269 child_requests_.erase(child);
1271 MayCompletePrepare();
1274 void BatchUploadRequest::Commit() {
1275 DCHECK(CalledOnValidThread());
1276 DCHECK(!committed_);
1277 if (child_requests_.empty()) {
1278 Cancel();
1279 } else {
1280 committed_ = true;
1281 MayCompletePrepare();
1285 void BatchUploadRequest::Prepare(const PrepareCallback& callback) {
1286 DCHECK(CalledOnValidThread());
1287 DCHECK(!callback.is_null());
1288 prepare_callback_ = callback;
1289 MayCompletePrepare();
1292 void BatchUploadRequest::Cancel() {
1293 child_requests_.clear();
1294 UrlFetchRequestBase::Cancel();
1297 // Obtains corresponding child entry of |request_id|. Returns NULL if the
1298 // entry is not found.
1299 ScopedVector<BatchUploadChildEntry>::iterator BatchUploadRequest::GetChildEntry(
1300 RequestID request_id) {
1301 for (auto it = child_requests_.begin(); it != child_requests_.end(); ++it) {
1302 if ((*it)->request.get() == request_id)
1303 return it;
1305 return child_requests_.end();
1308 void BatchUploadRequest::MayCompletePrepare() {
1309 if (!committed_ || prepare_callback_.is_null())
1310 return;
1311 for (const auto& child : child_requests_) {
1312 if (!child->prepared)
1313 return;
1316 // Build multipart body here.
1317 std::vector<ContentTypeAndData> parts;
1318 for (auto& child : child_requests_) {
1319 std::string type;
1320 std::string data;
1321 const bool result = child->request->GetContentData(&type, &data);
1322 // Upload request must have content data.
1323 DCHECK(result);
1325 const GURL url = child->request->GetURL();
1326 std::string method;
1327 switch (child->request->GetRequestType()) {
1328 case net::URLFetcher::POST:
1329 method = "POST";
1330 break;
1331 case net::URLFetcher::PUT:
1332 method = "PUT";
1333 break;
1334 default:
1335 NOTREACHED();
1336 break;
1338 const std::string header = base::StringPrintf(
1339 kBatchUploadRequestFormat, method.c_str(), url.path().c_str(),
1340 url_generator_.GetBatchUploadUrl().host().c_str(), type.c_str());
1342 child->data_offset = header.size();
1343 child->data_size = data.size();
1345 parts.push_back(ContentTypeAndData());
1346 parts.back().type = kHttpContentType;
1347 parts.back().data = header;
1348 parts.back().data.append(data);
1351 std::vector<uint64> part_data_offset;
1352 GenerateMultipartBody(MULTIPART_MIXED, boundary_, parts, &upload_content_,
1353 &part_data_offset);
1354 DCHECK(part_data_offset.size() == child_requests_.size());
1355 for (size_t i = 0; i < child_requests_.size(); ++i) {
1356 child_requests_[i]->data_offset += part_data_offset[i];
1358 prepare_callback_.Run(HTTP_SUCCESS);
1361 bool BatchUploadRequest::GetContentData(std::string* upload_content_type,
1362 std::string* upload_content_data) {
1363 upload_content_type->assign(upload_content_.type);
1364 upload_content_data->assign(upload_content_.data);
1365 return true;
1368 base::WeakPtr<BatchUploadRequest>
1369 BatchUploadRequest::GetWeakPtrAsBatchUploadRequest() {
1370 return weak_ptr_factory_.GetWeakPtr();
1373 GURL BatchUploadRequest::GetURL() const {
1374 return url_generator_.GetBatchUploadUrl();
1377 net::URLFetcher::RequestType BatchUploadRequest::GetRequestType() const {
1378 return net::URLFetcher::PUT;
1381 std::vector<std::string> BatchUploadRequest::GetExtraRequestHeaders() const {
1382 std::vector<std::string> headers;
1383 headers.push_back(kBatchUploadHeader);
1384 return headers;
1387 void BatchUploadRequest::ProcessURLFetchResults(const net::URLFetcher* source) {
1388 if (!IsSuccessfulDriveApiErrorCode(GetErrorCode())) {
1389 RunCallbackOnPrematureFailure(GetErrorCode());
1390 sender_->RequestFinished(this);
1391 return;
1394 std::string content_type;
1395 source->GetResponseHeaders()->EnumerateHeader(
1396 /* need only first header */ NULL, "Content-Type", &content_type);
1398 std::vector<MultipartHttpResponse> parts;
1399 if (!ParseMultipartResponse(content_type, response_writer()->data(),
1400 &parts) ||
1401 child_requests_.size() != parts.size()) {
1402 RunCallbackOnPrematureFailure(DRIVE_PARSE_ERROR);
1403 sender_->RequestFinished(this);
1404 return;
1407 for (size_t i = 0; i < parts.size(); ++i) {
1408 BatchableDelegate* const delegate = child_requests_[i]->request.get();
1409 // Pass onwership of |delegate| so that child_requests_.clear() won't
1410 // kill the delegate. It has to be deleted after the notification.
1411 delegate->NotifyResult(
1412 parts[i].code, parts[i].body,
1413 base::Bind(&EmptyClosure, base::Passed(&child_requests_[i]->request)));
1415 child_requests_.clear();
1417 sender_->RequestFinished(this);
1420 void BatchUploadRequest::RunCallbackOnPrematureFailure(DriveApiErrorCode code) {
1421 for (auto child : child_requests_) {
1422 child->request->NotifyError(code);
1424 child_requests_.clear();
1427 void BatchUploadRequest::OnURLFetchUploadProgress(const net::URLFetcher* source,
1428 int64 current,
1429 int64 total) {
1430 for (auto child : child_requests_) {
1431 if (child->data_offset <= current &&
1432 current <= child->data_offset + child->data_size) {
1433 child->request->NotifyUploadProgress(source, current - child->data_offset,
1434 child->data_size);
1435 } else if (last_progress_value_ < child->data_offset + child->data_size &&
1436 child->data_offset + child->data_size < current) {
1437 child->request->NotifyUploadProgress(source, child->data_size,
1438 child->data_size);
1441 last_progress_value_ = current;
1443 } // namespace drive
1444 } // namespace google_apis