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"
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
{
27 // Format of one request in batch uploading request.
28 const char kBatchUploadRequestFormat
[] =
31 "X-Goog-Upload-Protocol: multipart\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
;
58 file_resource
= FileResource::CreateFrom(*value
);
61 UploadRangeResponse(DRIVE_PARSE_ERROR
,
62 response
.start_position_received
,
63 response
.end_position_received
),
64 scoped_ptr
<FileResource
>());
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
) {
77 if (properties
.empty())
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";
88 case Property::VISIBILITY_PUBLIC
:
89 visibility_as_string
= "PUBLIC";
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
;
111 root
.SetString("title", title
);
114 if (!parent_resource_id
.empty()) {
115 scoped_ptr
<base::ListValue
> parents(new base::ListValue
);
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
);
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
;
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())
150 it
= next_pos
+ br_size
;
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')) {
163 return piece
.substr(0, piece
.size() - trim_size
);
168 MultipartHttpResponse::MultipartHttpResponse() : code(HTTP_SUCCESS
) {
171 MultipartHttpResponse::~MultipartHttpResponse() {
174 // The |response| must be multipart/mixed format that contains child HTTP
175 // response of drive batch request.
176 // https://www.ietf.org/rfc/rfc2046.txt
180 // Content-type: application/http
183 // Header of child response
185 // Body of child response
187 // Content-type: application/http
189 // HTTP/1.1 404 Not Found
190 // Header of child response
192 // Body of child response
194 bool ParseMultipartResponse(const std::string
& content_type
,
195 const std::string
& response
,
196 std::vector
<MultipartHttpResponse
>* parts
) {
197 if (response
.empty())
200 base::StringPiece
content_type_piece(content_type
);
201 if (!content_type_piece
.starts_with(kMultipartMixedMimeTypePrefix
)) {
204 content_type_piece
.remove_prefix(
205 base::StringPiece(kMultipartMixedMimeTypePrefix
).size());
207 if (content_type_piece
.empty())
209 if (content_type_piece
[0] == '"') {
210 if (content_type_piece
.size() <= 2 ||
211 content_type_piece
[content_type_piece
.size() - 1] != '"') {
215 content_type_piece
.substr(1, content_type_piece
.size() - 2);
218 std::string boundary
;
219 content_type_piece
.CopyToString(&boundary
);
220 const std::string header
= "--" + boundary
;
221 const std::string terminator
= "--" + boundary
+ "--";
223 std::vector
<base::StringPiece
> lines
;
224 SplitIntoLines(response
, &lines
);
229 STATE_PART_HTTP_STATUS_LINE
,
230 STATE_PART_HTTP_HEADER
,
232 } state
= STATE_START
;
234 const std::string kHttpStatusPrefix
= "HTTP/1.1 ";
235 std::vector
<MultipartHttpResponse
> responses
;
236 DriveApiErrorCode code
= DRIVE_PARSE_ERROR
;
238 for (const auto& line
: lines
) {
239 if (state
== STATE_PART_HEADER
&& line
.empty()) {
240 state
= STATE_PART_HTTP_STATUS_LINE
;
244 if (state
== STATE_PART_HTTP_STATUS_LINE
) {
245 if (line
.starts_with(kHttpStatusPrefix
)) {
248 line
.substr(base::StringPiece(kHttpStatusPrefix
).size()),
251 code
= static_cast<DriveApiErrorCode
>(int_code
);
253 code
= DRIVE_PARSE_ERROR
;
255 code
= DRIVE_PARSE_ERROR
;
257 state
= STATE_PART_HTTP_HEADER
;
261 if (state
== STATE_PART_HTTP_HEADER
&& line
.empty()) {
262 state
= STATE_PART_HTTP_BODY
;
266 const base::StringPiece chopped_line
= TrimTransportPadding(line
);
267 const bool is_new_part
= chopped_line
== header
;
268 const bool was_last_part
= chopped_line
== terminator
;
269 if (is_new_part
|| was_last_part
) {
273 case STATE_PART_HEADER
:
274 case STATE_PART_HTTP_STATUS_LINE
:
275 responses
.push_back(MultipartHttpResponse());
276 responses
.back().code
= DRIVE_PARSE_ERROR
;
278 case STATE_PART_HTTP_HEADER
:
279 responses
.push_back(MultipartHttpResponse());
280 responses
.back().code
= code
;
282 case STATE_PART_HTTP_BODY
:
283 // Drop the last kHttpBr.
285 body
.resize(body
.size() - 2);
286 responses
.push_back(MultipartHttpResponse());
287 responses
.back().code
= code
;
288 responses
.back().body
.swap(body
);
292 state
= STATE_PART_HEADER
;
295 } else if (state
== STATE_PART_HTTP_BODY
) {
296 line
.AppendToString(&body
);
297 body
.append(kHttpBr
);
301 parts
->swap(responses
);
305 Property::Property() : visibility_(VISIBILITY_PRIVATE
) {
308 Property::~Property() {
311 //============================ DriveApiPartialFieldRequest ====================
313 DriveApiPartialFieldRequest::DriveApiPartialFieldRequest(
314 RequestSender
* sender
) : UrlFetchRequestBase(sender
) {
317 DriveApiPartialFieldRequest::~DriveApiPartialFieldRequest() {
320 GURL
DriveApiPartialFieldRequest::GetURL() const {
321 GURL url
= GetURLInternal();
322 if (!fields_
.empty())
323 url
= net::AppendOrReplaceQueryParameter(url
, "fields", fields_
);
327 //=============================== FilesGetRequest =============================
329 FilesGetRequest::FilesGetRequest(
330 RequestSender
* sender
,
331 const DriveApiUrlGenerator
& url_generator
,
332 bool use_internal_endpoint
,
333 const FileResourceCallback
& callback
)
334 : DriveApiDataRequest
<FileResource
>(sender
, callback
),
335 url_generator_(url_generator
),
336 use_internal_endpoint_(use_internal_endpoint
) {
337 DCHECK(!callback
.is_null());
340 FilesGetRequest::~FilesGetRequest() {}
342 GURL
FilesGetRequest::GetURLInternal() const {
343 return url_generator_
.GetFilesGetUrl(file_id_
,
344 use_internal_endpoint_
,
348 //============================ FilesAuthorizeRequest ===========================
350 FilesAuthorizeRequest::FilesAuthorizeRequest(
351 RequestSender
* sender
,
352 const DriveApiUrlGenerator
& url_generator
,
353 const FileResourceCallback
& callback
)
354 : DriveApiDataRequest
<FileResource
>(sender
, callback
),
355 url_generator_(url_generator
) {
356 DCHECK(!callback
.is_null());
359 FilesAuthorizeRequest::~FilesAuthorizeRequest() {}
361 net::URLFetcher::RequestType
FilesAuthorizeRequest::GetRequestType() const {
362 return net::URLFetcher::POST
;
365 GURL
FilesAuthorizeRequest::GetURLInternal() const {
366 return url_generator_
.GetFilesAuthorizeUrl(file_id_
, app_id_
);
369 //============================ FilesInsertRequest ============================
371 FilesInsertRequest::FilesInsertRequest(
372 RequestSender
* sender
,
373 const DriveApiUrlGenerator
& url_generator
,
374 const FileResourceCallback
& callback
)
375 : DriveApiDataRequest
<FileResource
>(sender
, callback
),
376 url_generator_(url_generator
) {
377 DCHECK(!callback
.is_null());
380 FilesInsertRequest::~FilesInsertRequest() {}
382 net::URLFetcher::RequestType
FilesInsertRequest::GetRequestType() const {
383 return net::URLFetcher::POST
;
386 bool FilesInsertRequest::GetContentData(std::string
* upload_content_type
,
387 std::string
* upload_content
) {
388 *upload_content_type
= util::kContentTypeApplicationJson
;
390 base::DictionaryValue root
;
392 if (!last_viewed_by_me_date_
.is_null()) {
393 root
.SetString("lastViewedByMeDate",
394 util::FormatTimeAsString(last_viewed_by_me_date_
));
397 if (!mime_type_
.empty())
398 root
.SetString("mimeType", mime_type_
);
400 if (!modified_date_
.is_null())
401 root
.SetString("modifiedDate", util::FormatTimeAsString(modified_date_
));
403 if (!parents_
.empty()) {
404 base::ListValue
* parents_value
= new base::ListValue
;
405 for (size_t i
= 0; i
< parents_
.size(); ++i
) {
406 base::DictionaryValue
* parent
= new base::DictionaryValue
;
407 parent
->SetString("id", parents_
[i
]);
408 parents_value
->Append(parent
);
410 root
.Set("parents", parents_value
);
414 root
.SetString("title", title_
);
416 AttachProperties(properties_
, &root
);
417 base::JSONWriter::Write(&root
, upload_content
);
419 DVLOG(1) << "FilesInsert data: " << *upload_content_type
<< ", ["
420 << *upload_content
<< "]";
424 GURL
FilesInsertRequest::GetURLInternal() const {
425 return url_generator_
.GetFilesInsertUrl();
428 //============================== FilesPatchRequest ============================
430 FilesPatchRequest::FilesPatchRequest(
431 RequestSender
* sender
,
432 const DriveApiUrlGenerator
& url_generator
,
433 const FileResourceCallback
& callback
)
434 : DriveApiDataRequest
<FileResource
>(sender
, callback
),
435 url_generator_(url_generator
),
436 set_modified_date_(false),
437 update_viewed_date_(true) {
438 DCHECK(!callback
.is_null());
441 FilesPatchRequest::~FilesPatchRequest() {}
443 net::URLFetcher::RequestType
FilesPatchRequest::GetRequestType() const {
444 return net::URLFetcher::PATCH
;
447 std::vector
<std::string
> FilesPatchRequest::GetExtraRequestHeaders() const {
448 std::vector
<std::string
> headers
;
449 headers
.push_back(util::kIfMatchAllHeader
);
453 GURL
FilesPatchRequest::GetURLInternal() const {
454 return url_generator_
.GetFilesPatchUrl(
455 file_id_
, set_modified_date_
, update_viewed_date_
);
458 bool FilesPatchRequest::GetContentData(std::string
* upload_content_type
,
459 std::string
* upload_content
) {
460 if (title_
.empty() &&
461 modified_date_
.is_null() &&
462 last_viewed_by_me_date_
.is_null() &&
466 *upload_content_type
= util::kContentTypeApplicationJson
;
468 base::DictionaryValue root
;
470 root
.SetString("title", title_
);
472 if (!modified_date_
.is_null())
473 root
.SetString("modifiedDate", util::FormatTimeAsString(modified_date_
));
475 if (!last_viewed_by_me_date_
.is_null()) {
476 root
.SetString("lastViewedByMeDate",
477 util::FormatTimeAsString(last_viewed_by_me_date_
));
480 if (!parents_
.empty()) {
481 base::ListValue
* parents_value
= new base::ListValue
;
482 for (size_t i
= 0; i
< parents_
.size(); ++i
) {
483 base::DictionaryValue
* parent
= new base::DictionaryValue
;
484 parent
->SetString("id", parents_
[i
]);
485 parents_value
->Append(parent
);
487 root
.Set("parents", parents_value
);
490 AttachProperties(properties_
, &root
);
491 base::JSONWriter::Write(&root
, upload_content
);
493 DVLOG(1) << "FilesPatch data: " << *upload_content_type
<< ", ["
494 << *upload_content
<< "]";
498 //============================= FilesCopyRequest ==============================
500 FilesCopyRequest::FilesCopyRequest(
501 RequestSender
* sender
,
502 const DriveApiUrlGenerator
& url_generator
,
503 const FileResourceCallback
& callback
)
504 : DriveApiDataRequest
<FileResource
>(sender
, callback
),
505 url_generator_(url_generator
) {
506 DCHECK(!callback
.is_null());
509 FilesCopyRequest::~FilesCopyRequest() {
512 net::URLFetcher::RequestType
FilesCopyRequest::GetRequestType() const {
513 return net::URLFetcher::POST
;
516 GURL
FilesCopyRequest::GetURLInternal() const {
517 return url_generator_
.GetFilesCopyUrl(file_id_
);
520 bool FilesCopyRequest::GetContentData(std::string
* upload_content_type
,
521 std::string
* upload_content
) {
522 if (parents_
.empty() && title_
.empty())
525 *upload_content_type
= util::kContentTypeApplicationJson
;
527 base::DictionaryValue root
;
529 if (!modified_date_
.is_null())
530 root
.SetString("modifiedDate", util::FormatTimeAsString(modified_date_
));
532 if (!parents_
.empty()) {
533 base::ListValue
* parents_value
= new base::ListValue
;
534 for (size_t i
= 0; i
< parents_
.size(); ++i
) {
535 base::DictionaryValue
* parent
= new base::DictionaryValue
;
536 parent
->SetString("id", parents_
[i
]);
537 parents_value
->Append(parent
);
539 root
.Set("parents", parents_value
);
543 root
.SetString("title", title_
);
545 base::JSONWriter::Write(&root
, upload_content
);
546 DVLOG(1) << "FilesCopy data: " << *upload_content_type
<< ", ["
547 << *upload_content
<< "]";
551 //============================= FilesListRequest =============================
553 FilesListRequest::FilesListRequest(
554 RequestSender
* sender
,
555 const DriveApiUrlGenerator
& url_generator
,
556 const FileListCallback
& callback
)
557 : DriveApiDataRequest
<FileList
>(sender
, callback
),
558 url_generator_(url_generator
),
560 DCHECK(!callback
.is_null());
563 FilesListRequest::~FilesListRequest() {}
565 GURL
FilesListRequest::GetURLInternal() const {
566 return url_generator_
.GetFilesListUrl(max_results_
, page_token_
, q_
);
569 //======================== FilesListNextPageRequest =========================
571 FilesListNextPageRequest::FilesListNextPageRequest(
572 RequestSender
* sender
,
573 const FileListCallback
& callback
)
574 : DriveApiDataRequest
<FileList
>(sender
, callback
) {
575 DCHECK(!callback
.is_null());
578 FilesListNextPageRequest::~FilesListNextPageRequest() {
581 GURL
FilesListNextPageRequest::GetURLInternal() const {
585 //============================ FilesDeleteRequest =============================
587 FilesDeleteRequest::FilesDeleteRequest(
588 RequestSender
* sender
,
589 const DriveApiUrlGenerator
& url_generator
,
590 const EntryActionCallback
& callback
)
591 : EntryActionRequest(sender
, callback
),
592 url_generator_(url_generator
) {
593 DCHECK(!callback
.is_null());
596 FilesDeleteRequest::~FilesDeleteRequest() {}
598 net::URLFetcher::RequestType
FilesDeleteRequest::GetRequestType() const {
599 return net::URLFetcher::DELETE_REQUEST
;
602 GURL
FilesDeleteRequest::GetURL() const {
603 return url_generator_
.GetFilesDeleteUrl(file_id_
);
606 std::vector
<std::string
> FilesDeleteRequest::GetExtraRequestHeaders() const {
607 std::vector
<std::string
> headers(
608 EntryActionRequest::GetExtraRequestHeaders());
609 headers
.push_back(util::GenerateIfMatchHeader(etag_
));
613 //============================ FilesTrashRequest =============================
615 FilesTrashRequest::FilesTrashRequest(
616 RequestSender
* sender
,
617 const DriveApiUrlGenerator
& url_generator
,
618 const FileResourceCallback
& callback
)
619 : DriveApiDataRequest
<FileResource
>(sender
, callback
),
620 url_generator_(url_generator
) {
621 DCHECK(!callback
.is_null());
624 FilesTrashRequest::~FilesTrashRequest() {}
626 net::URLFetcher::RequestType
FilesTrashRequest::GetRequestType() const {
627 return net::URLFetcher::POST
;
630 GURL
FilesTrashRequest::GetURLInternal() const {
631 return url_generator_
.GetFilesTrashUrl(file_id_
);
634 //============================== AboutGetRequest =============================
636 AboutGetRequest::AboutGetRequest(
637 RequestSender
* sender
,
638 const DriveApiUrlGenerator
& url_generator
,
639 const AboutResourceCallback
& callback
)
640 : DriveApiDataRequest
<AboutResource
>(sender
, callback
),
641 url_generator_(url_generator
) {
642 DCHECK(!callback
.is_null());
645 AboutGetRequest::~AboutGetRequest() {}
647 GURL
AboutGetRequest::GetURLInternal() const {
648 return url_generator_
.GetAboutGetUrl();
651 //============================ ChangesListRequest ===========================
653 ChangesListRequest::ChangesListRequest(
654 RequestSender
* sender
,
655 const DriveApiUrlGenerator
& url_generator
,
656 const ChangeListCallback
& callback
)
657 : DriveApiDataRequest
<ChangeList
>(sender
, callback
),
658 url_generator_(url_generator
),
659 include_deleted_(true),
661 start_change_id_(0) {
662 DCHECK(!callback
.is_null());
665 ChangesListRequest::~ChangesListRequest() {}
667 GURL
ChangesListRequest::GetURLInternal() const {
668 return url_generator_
.GetChangesListUrl(
669 include_deleted_
, max_results_
, page_token_
, start_change_id_
);
672 //======================== ChangesListNextPageRequest =========================
674 ChangesListNextPageRequest::ChangesListNextPageRequest(
675 RequestSender
* sender
,
676 const ChangeListCallback
& callback
)
677 : DriveApiDataRequest
<ChangeList
>(sender
, callback
) {
678 DCHECK(!callback
.is_null());
681 ChangesListNextPageRequest::~ChangesListNextPageRequest() {
684 GURL
ChangesListNextPageRequest::GetURLInternal() const {
688 //============================== AppsListRequest ===========================
690 AppsListRequest::AppsListRequest(
691 RequestSender
* sender
,
692 const DriveApiUrlGenerator
& url_generator
,
693 bool use_internal_endpoint
,
694 const AppListCallback
& callback
)
695 : DriveApiDataRequest
<AppList
>(sender
, callback
),
696 url_generator_(url_generator
),
697 use_internal_endpoint_(use_internal_endpoint
) {
698 DCHECK(!callback
.is_null());
701 AppsListRequest::~AppsListRequest() {}
703 GURL
AppsListRequest::GetURLInternal() const {
704 return url_generator_
.GetAppsListUrl(use_internal_endpoint_
);
707 //============================== AppsDeleteRequest ===========================
709 AppsDeleteRequest::AppsDeleteRequest(RequestSender
* sender
,
710 const DriveApiUrlGenerator
& url_generator
,
711 const EntryActionCallback
& callback
)
712 : EntryActionRequest(sender
, callback
),
713 url_generator_(url_generator
) {
714 DCHECK(!callback
.is_null());
717 AppsDeleteRequest::~AppsDeleteRequest() {}
719 net::URLFetcher::RequestType
AppsDeleteRequest::GetRequestType() const {
720 return net::URLFetcher::DELETE_REQUEST
;
723 GURL
AppsDeleteRequest::GetURL() const {
724 return url_generator_
.GetAppsDeleteUrl(app_id_
);
727 //========================== ChildrenInsertRequest ============================
729 ChildrenInsertRequest::ChildrenInsertRequest(
730 RequestSender
* sender
,
731 const DriveApiUrlGenerator
& url_generator
,
732 const EntryActionCallback
& callback
)
733 : EntryActionRequest(sender
, callback
),
734 url_generator_(url_generator
) {
735 DCHECK(!callback
.is_null());
738 ChildrenInsertRequest::~ChildrenInsertRequest() {}
740 net::URLFetcher::RequestType
ChildrenInsertRequest::GetRequestType() const {
741 return net::URLFetcher::POST
;
744 GURL
ChildrenInsertRequest::GetURL() const {
745 return url_generator_
.GetChildrenInsertUrl(folder_id_
);
748 bool ChildrenInsertRequest::GetContentData(std::string
* upload_content_type
,
749 std::string
* upload_content
) {
750 *upload_content_type
= util::kContentTypeApplicationJson
;
752 base::DictionaryValue root
;
753 root
.SetString("id", id_
);
755 base::JSONWriter::Write(&root
, upload_content
);
756 DVLOG(1) << "InsertResource data: " << *upload_content_type
<< ", ["
757 << *upload_content
<< "]";
761 //========================== ChildrenDeleteRequest ============================
763 ChildrenDeleteRequest::ChildrenDeleteRequest(
764 RequestSender
* sender
,
765 const DriveApiUrlGenerator
& url_generator
,
766 const EntryActionCallback
& callback
)
767 : EntryActionRequest(sender
, callback
),
768 url_generator_(url_generator
) {
769 DCHECK(!callback
.is_null());
772 ChildrenDeleteRequest::~ChildrenDeleteRequest() {}
774 net::URLFetcher::RequestType
ChildrenDeleteRequest::GetRequestType() const {
775 return net::URLFetcher::DELETE_REQUEST
;
778 GURL
ChildrenDeleteRequest::GetURL() const {
779 return url_generator_
.GetChildrenDeleteUrl(child_id_
, folder_id_
);
782 //======================= InitiateUploadNewFileRequest =======================
784 InitiateUploadNewFileRequest::InitiateUploadNewFileRequest(
785 RequestSender
* sender
,
786 const DriveApiUrlGenerator
& url_generator
,
787 const std::string
& content_type
,
788 int64 content_length
,
789 const std::string
& parent_resource_id
,
790 const std::string
& title
,
791 const InitiateUploadCallback
& callback
)
792 : InitiateUploadRequestBase(sender
,
796 url_generator_(url_generator
),
797 parent_resource_id_(parent_resource_id
),
801 InitiateUploadNewFileRequest::~InitiateUploadNewFileRequest() {}
803 GURL
InitiateUploadNewFileRequest::GetURL() const {
804 return url_generator_
.GetInitiateUploadNewFileUrl(!modified_date_
.is_null());
807 net::URLFetcher::RequestType
808 InitiateUploadNewFileRequest::GetRequestType() const {
809 return net::URLFetcher::POST
;
812 bool InitiateUploadNewFileRequest::GetContentData(
813 std::string
* upload_content_type
,
814 std::string
* upload_content
) {
815 *upload_content_type
= util::kContentTypeApplicationJson
;
817 base::DictionaryValue root
;
818 root
.SetString("title", title_
);
821 scoped_ptr
<base::ListValue
> parents(new base::ListValue
);
822 parents
->Append(util::CreateParentValue(parent_resource_id_
).release());
823 root
.Set("parents", parents
.release());
825 if (!modified_date_
.is_null())
826 root
.SetString("modifiedDate", util::FormatTimeAsString(modified_date_
));
828 if (!last_viewed_by_me_date_
.is_null()) {
829 root
.SetString("lastViewedByMeDate",
830 util::FormatTimeAsString(last_viewed_by_me_date_
));
833 AttachProperties(properties_
, &root
);
834 base::JSONWriter::Write(&root
, upload_content
);
836 DVLOG(1) << "InitiateUploadNewFile data: " << *upload_content_type
<< ", ["
837 << *upload_content
<< "]";
841 //===================== InitiateUploadExistingFileRequest ====================
843 InitiateUploadExistingFileRequest::InitiateUploadExistingFileRequest(
844 RequestSender
* sender
,
845 const DriveApiUrlGenerator
& url_generator
,
846 const std::string
& content_type
,
847 int64 content_length
,
848 const std::string
& resource_id
,
849 const std::string
& etag
,
850 const InitiateUploadCallback
& callback
)
851 : InitiateUploadRequestBase(sender
,
855 url_generator_(url_generator
),
856 resource_id_(resource_id
),
860 InitiateUploadExistingFileRequest::~InitiateUploadExistingFileRequest() {}
862 GURL
InitiateUploadExistingFileRequest::GetURL() const {
863 return url_generator_
.GetInitiateUploadExistingFileUrl(
864 resource_id_
, !modified_date_
.is_null());
867 net::URLFetcher::RequestType
868 InitiateUploadExistingFileRequest::GetRequestType() const {
869 return net::URLFetcher::PUT
;
872 std::vector
<std::string
>
873 InitiateUploadExistingFileRequest::GetExtraRequestHeaders() const {
874 std::vector
<std::string
> headers(
875 InitiateUploadRequestBase::GetExtraRequestHeaders());
876 headers
.push_back(util::GenerateIfMatchHeader(etag_
));
880 bool InitiateUploadExistingFileRequest::GetContentData(
881 std::string
* upload_content_type
,
882 std::string
* upload_content
) {
883 base::DictionaryValue root
;
884 if (!parent_resource_id_
.empty()) {
885 scoped_ptr
<base::ListValue
> parents(new base::ListValue
);
886 parents
->Append(util::CreateParentValue(parent_resource_id_
).release());
887 root
.Set("parents", parents
.release());
891 root
.SetString("title", title_
);
893 if (!modified_date_
.is_null())
894 root
.SetString("modifiedDate", util::FormatTimeAsString(modified_date_
));
896 if (!last_viewed_by_me_date_
.is_null()) {
897 root
.SetString("lastViewedByMeDate",
898 util::FormatTimeAsString(last_viewed_by_me_date_
));
901 AttachProperties(properties_
, &root
);
905 *upload_content_type
= util::kContentTypeApplicationJson
;
906 base::JSONWriter::Write(&root
, upload_content
);
907 DVLOG(1) << "InitiateUploadExistingFile data: " << *upload_content_type
908 << ", [" << *upload_content
<< "]";
912 //============================ ResumeUploadRequest ===========================
914 ResumeUploadRequest::ResumeUploadRequest(
915 RequestSender
* sender
,
916 const GURL
& upload_location
,
917 int64 start_position
,
919 int64 content_length
,
920 const std::string
& content_type
,
921 const base::FilePath
& local_file_path
,
922 const UploadRangeCallback
& callback
,
923 const ProgressCallback
& progress_callback
)
924 : ResumeUploadRequestBase(sender
,
932 progress_callback_(progress_callback
) {
933 DCHECK(!callback_
.is_null());
936 ResumeUploadRequest::~ResumeUploadRequest() {}
938 void ResumeUploadRequest::OnRangeRequestComplete(
939 const UploadRangeResponse
& response
,
940 scoped_ptr
<base::Value
> value
) {
941 DCHECK(CalledOnValidThread());
942 ParseFileResourceWithUploadRangeAndRun(callback_
, response
, value
.Pass());
945 void ResumeUploadRequest::OnURLFetchUploadProgress(
946 const net::URLFetcher
* source
, int64 current
, int64 total
) {
947 if (!progress_callback_
.is_null())
948 progress_callback_
.Run(current
, total
);
951 //========================== GetUploadStatusRequest ==========================
953 GetUploadStatusRequest::GetUploadStatusRequest(
954 RequestSender
* sender
,
955 const GURL
& upload_url
,
956 int64 content_length
,
957 const UploadRangeCallback
& callback
)
958 : GetUploadStatusRequestBase(sender
,
961 callback_(callback
) {
962 DCHECK(!callback
.is_null());
965 GetUploadStatusRequest::~GetUploadStatusRequest() {}
967 void GetUploadStatusRequest::OnRangeRequestComplete(
968 const UploadRangeResponse
& response
,
969 scoped_ptr
<base::Value
> value
) {
970 DCHECK(CalledOnValidThread());
971 ParseFileResourceWithUploadRangeAndRun(callback_
, response
, value
.Pass());
974 //======================= MultipartUploadNewFileRequest =======================
976 MultipartUploadNewFileRequest::MultipartUploadNewFileRequest(
977 RequestSender
* sender
,
978 const std::string
& title
,
979 const std::string
& parent_resource_id
,
980 const std::string
& content_type
,
981 int64 content_length
,
982 const base::Time
& modified_date
,
983 const base::Time
& last_viewed_by_me_date
,
984 const base::FilePath
& local_file_path
,
985 const Properties
& properties
,
986 const DriveApiUrlGenerator
& url_generator
,
987 const FileResourceCallback
& callback
,
988 const ProgressCallback
& progress_callback
)
989 : MultipartUploadRequestBase(
991 CreateMultipartUploadMetadataJson(title
,
994 last_viewed_by_me_date
,
1001 has_modified_date_(!modified_date
.is_null()),
1002 url_generator_(url_generator
) {
1005 MultipartUploadNewFileRequest::~MultipartUploadNewFileRequest() {
1008 GURL
MultipartUploadNewFileRequest::GetURL() const {
1009 return url_generator_
.GetMultipartUploadNewFileUrl(has_modified_date_
);
1012 net::URLFetcher::RequestType
MultipartUploadNewFileRequest::GetRequestType()
1014 return net::URLFetcher::POST
;
1017 //======================= MultipartUploadExistingFileRequest ===================
1019 MultipartUploadExistingFileRequest::MultipartUploadExistingFileRequest(
1020 RequestSender
* sender
,
1021 const std::string
& title
,
1022 const std::string
& resource_id
,
1023 const std::string
& parent_resource_id
,
1024 const std::string
& content_type
,
1025 int64 content_length
,
1026 const base::Time
& modified_date
,
1027 const base::Time
& last_viewed_by_me_date
,
1028 const base::FilePath
& local_file_path
,
1029 const std::string
& etag
,
1030 const Properties
& properties
,
1031 const DriveApiUrlGenerator
& url_generator
,
1032 const FileResourceCallback
& callback
,
1033 const ProgressCallback
& progress_callback
)
1034 : MultipartUploadRequestBase(
1036 CreateMultipartUploadMetadataJson(title
,
1039 last_viewed_by_me_date
,
1046 resource_id_(resource_id
),
1048 has_modified_date_(!modified_date
.is_null()),
1049 url_generator_(url_generator
) {
1052 MultipartUploadExistingFileRequest::~MultipartUploadExistingFileRequest() {
1055 std::vector
<std::string
>
1056 MultipartUploadExistingFileRequest::GetExtraRequestHeaders() const {
1057 std::vector
<std::string
> headers(
1058 MultipartUploadRequestBase::GetExtraRequestHeaders());
1059 headers
.push_back(util::GenerateIfMatchHeader(etag_
));
1063 GURL
MultipartUploadExistingFileRequest::GetURL() const {
1064 return url_generator_
.GetMultipartUploadExistingFileUrl(resource_id_
,
1065 has_modified_date_
);
1068 net::URLFetcher::RequestType
1069 MultipartUploadExistingFileRequest::GetRequestType() const {
1070 return net::URLFetcher::PUT
;
1073 //========================== DownloadFileRequest ==========================
1075 DownloadFileRequest::DownloadFileRequest(
1076 RequestSender
* sender
,
1077 const DriveApiUrlGenerator
& url_generator
,
1078 const std::string
& resource_id
,
1079 const base::FilePath
& output_file_path
,
1080 const DownloadActionCallback
& download_action_callback
,
1081 const GetContentCallback
& get_content_callback
,
1082 const ProgressCallback
& progress_callback
)
1083 : DownloadFileRequestBase(
1085 download_action_callback
,
1086 get_content_callback
,
1088 url_generator
.GenerateDownloadFileUrl(resource_id
),
1092 DownloadFileRequest::~DownloadFileRequest() {
1095 //========================== PermissionsInsertRequest ==========================
1097 PermissionsInsertRequest::PermissionsInsertRequest(
1098 RequestSender
* sender
,
1099 const DriveApiUrlGenerator
& url_generator
,
1100 const EntryActionCallback
& callback
)
1101 : EntryActionRequest(sender
, callback
),
1102 url_generator_(url_generator
),
1103 type_(PERMISSION_TYPE_USER
),
1104 role_(PERMISSION_ROLE_READER
) {
1107 PermissionsInsertRequest::~PermissionsInsertRequest() {
1110 GURL
PermissionsInsertRequest::GetURL() const {
1111 return url_generator_
.GetPermissionsInsertUrl(id_
);
1114 net::URLFetcher::RequestType
1115 PermissionsInsertRequest::GetRequestType() const {
1116 return net::URLFetcher::POST
;
1119 bool PermissionsInsertRequest::GetContentData(std::string
* upload_content_type
,
1120 std::string
* upload_content
) {
1121 *upload_content_type
= util::kContentTypeApplicationJson
;
1123 base::DictionaryValue root
;
1125 case PERMISSION_TYPE_ANYONE
:
1126 root
.SetString("type", "anyone");
1128 case PERMISSION_TYPE_DOMAIN
:
1129 root
.SetString("type", "domain");
1131 case PERMISSION_TYPE_GROUP
:
1132 root
.SetString("type", "group");
1134 case PERMISSION_TYPE_USER
:
1135 root
.SetString("type", "user");
1139 case PERMISSION_ROLE_OWNER
:
1140 root
.SetString("role", "owner");
1142 case PERMISSION_ROLE_READER
:
1143 root
.SetString("role", "reader");
1145 case PERMISSION_ROLE_WRITER
:
1146 root
.SetString("role", "writer");
1148 case PERMISSION_ROLE_COMMENTER
:
1149 root
.SetString("role", "reader");
1151 base::ListValue
* list
= new base::ListValue
;
1152 list
->AppendString("commenter");
1153 root
.Set("additionalRoles", list
);
1157 root
.SetString("value", value_
);
1158 base::JSONWriter::Write(&root
, upload_content
);
1162 //========================== BatchUploadRequest ==========================
1164 BatchUploadRequest::BatchUploadRequest(
1165 RequestSender
* sender
,
1166 const DriveApiUrlGenerator
& url_generator
)
1167 : UrlFetchRequestBase(sender
),
1169 url_generator_(url_generator
),
1171 last_progress_value_(0),
1172 weak_ptr_factory_(this) {
1175 BatchUploadRequest::~BatchUploadRequest() {
1176 for (const auto& child
: child_requests_
) {
1177 // Request will be deleted in |RequestFinished| method.
1178 sender_
->RequestFinished(child
.request
);
1182 void BatchUploadRequest::SetBoundaryForTesting(const std::string
& boundary
) {
1183 boundary_
= boundary
;
1186 void BatchUploadRequest::AddRequest(BatchableRequestBase
* request
) {
1187 DCHECK(CalledOnValidThread());
1189 DCHECK(GetChildEntry(request
) == child_requests_
.end());
1190 DCHECK(!committed_
);
1191 child_requests_
.push_back(BatchUploadChildEntry(request
));
1192 request
->Prepare(base::Bind(&BatchUploadRequest::OnChildRequestPrepared
,
1193 weak_ptr_factory_
.GetWeakPtr(), request
));
1196 void BatchUploadRequest::OnChildRequestPrepared(RequestID request_id
,
1197 DriveApiErrorCode result
) {
1198 DCHECK(CalledOnValidThread());
1199 auto const child
= GetChildEntry(request_id
);
1200 DCHECK(child
!= child_requests_
.end());
1201 if (IsSuccessfulDriveApiErrorCode(result
)) {
1202 child
->prepared
= true;
1204 child
->request
->RunCallbackOnPrematureFailure(result
);
1205 sender_
->RequestFinished(child
->request
);
1206 child_requests_
.erase(child
);
1208 MayCompletePrepare();
1211 void BatchUploadRequest::Commit() {
1212 DCHECK(CalledOnValidThread());
1213 DCHECK(!committed_
);
1214 CHECK(!child_requests_
.empty());
1216 MayCompletePrepare();
1219 void BatchUploadRequest::Prepare(const PrepareCallback
& callback
) {
1220 DCHECK(CalledOnValidThread());
1221 DCHECK(!callback
.is_null());
1222 prepare_callback_
= callback
;
1223 MayCompletePrepare();
1226 void BatchUploadRequest::Cancel() {
1227 for (auto& child
: child_requests_
) {
1228 // Request cancel should delete the request instance.
1229 child
.request
->Cancel();
1231 child_requests_
.clear();
1232 UrlFetchRequestBase::Cancel();
1235 // Obtains corresponding child entry of |request_id|. Returns NULL if the
1236 // entry is not found.
1237 std::vector
<BatchUploadChildEntry
>::iterator
BatchUploadRequest::GetChildEntry(
1238 RequestID request_id
) {
1239 for (auto it
= child_requests_
.begin(); it
!= child_requests_
.end(); ++it
) {
1240 if (it
->request
== request_id
)
1243 return child_requests_
.end();
1246 void BatchUploadRequest::MayCompletePrepare() {
1247 if (!committed_
|| prepare_callback_
.is_null())
1249 for (const auto& child
: child_requests_
) {
1250 if (!child
.prepared
)
1254 // Build multipart body here.
1255 std::vector
<ContentTypeAndData
> parts
;
1256 for (auto& child
: child_requests_
) {
1259 const bool result
= child
.request
->GetContentData(&type
, &data
);
1260 // Upload request must have content data.
1263 const GURL url
= child
.request
->GetURL();
1265 switch (child
.request
->GetRequestType()) {
1266 case net::URLFetcher::POST
:
1269 case net::URLFetcher::PUT
:
1276 const std::string header
= base::StringPrintf(
1277 kBatchUploadRequestFormat
, method
.c_str(), url
.path().c_str(),
1278 url_generator_
.GetBatchUploadUrl().host().c_str(), type
.c_str());
1280 child
.data_offset
= header
.size();
1281 child
.data_size
= data
.size();
1283 parts
.push_back(ContentTypeAndData());
1284 parts
.back().type
= kHttpContentType
;
1285 parts
.back().data
= header
;
1286 parts
.back().data
.append(data
);
1289 std::vector
<uint64
> part_data_offset
;
1290 GenerateMultipartBody(MULTIPART_MIXED
, boundary_
, parts
, &upload_content_
,
1292 DCHECK(part_data_offset
.size() == child_requests_
.size());
1293 for (size_t i
= 0; i
< child_requests_
.size(); ++i
) {
1294 child_requests_
[i
].data_offset
+= part_data_offset
[i
];
1296 prepare_callback_
.Run(HTTP_SUCCESS
);
1299 bool BatchUploadRequest::GetContentData(std::string
* upload_content_type
,
1300 std::string
* upload_content_data
) {
1301 upload_content_type
->assign(upload_content_
.type
);
1302 upload_content_data
->assign(upload_content_
.data
);
1306 base::WeakPtr
<BatchUploadRequest
>
1307 BatchUploadRequest::GetWeakPtrAsBatchUploadRequest() {
1308 return weak_ptr_factory_
.GetWeakPtr();
1311 GURL
BatchUploadRequest::GetURL() const {
1312 return url_generator_
.GetBatchUploadUrl();
1315 net::URLFetcher::RequestType
BatchUploadRequest::GetRequestType() const {
1316 return net::URLFetcher::PUT
;
1319 std::vector
<std::string
> BatchUploadRequest::GetExtraRequestHeaders() const {
1320 std::vector
<std::string
> headers
;
1321 headers
.push_back(kBatchUploadHeader
);
1325 void BatchUploadRequest::ProcessURLFetchResults(const net::URLFetcher
* source
) {
1326 if (!IsSuccessfulDriveApiErrorCode(GetErrorCode())) {
1327 RunCallbackOnPrematureFailure(GetErrorCode());
1328 sender_
->RequestFinished(this);
1332 std::string content_type
;
1333 source
->GetResponseHeaders()->EnumerateHeader(
1334 /* need only first header */ NULL
, "Content-Type", &content_type
);
1336 std::vector
<MultipartHttpResponse
> parts
;
1337 if (!ParseMultipartResponse(content_type
, response_writer()->data(),
1339 child_requests_
.size() != parts
.size()) {
1340 RunCallbackOnPrematureFailure(DRIVE_PARSE_ERROR
);
1341 sender_
->RequestFinished(this);
1345 for (size_t i
= 0; i
< parts
.size(); ++i
) {
1346 child_requests_
[i
].request
->ProcessURLFetchResults(parts
[i
].code
,
1350 child_requests_
.clear();
1351 sender_
->RequestFinished(this);
1354 void BatchUploadRequest::RunCallbackOnPrematureFailure(DriveApiErrorCode code
) {
1355 for (auto child
: child_requests_
) {
1356 child
.request
->RunCallbackOnPrematureFailure(code
);
1357 sender_
->RequestFinished(child
.request
);
1359 child_requests_
.clear();
1362 void BatchUploadRequest::OnURLFetchUploadProgress(const net::URLFetcher
* source
,
1365 for (auto child
: child_requests_
) {
1366 if (child
.data_offset
<= current
&&
1367 current
<= child
.data_offset
+ child
.data_size
) {
1368 child
.request
->OnURLFetchUploadProgress(
1369 source
, current
- child
.data_offset
, child
.data_size
);
1370 } else if (last_progress_value_
< child
.data_offset
+ child
.data_size
&&
1371 child
.data_offset
+ child
.data_size
< current
) {
1372 child
.request
->OnURLFetchUploadProgress(source
, child
.data_size
,
1376 last_progress_value_
= current
;
1378 } // namespace drive
1379 } // namespace google_apis