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.
4
5#include "google_apis/drive/drive_api_requests.h"
6
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/task_runner_util.h"
13#include "base/values.h"
14#include "google_apis/drive/request_sender.h"
15#include "google_apis/drive/request_util.h"
16#include "google_apis/drive/time_util.h"
17#include "net/base/url_util.h"
18
19namespace google_apis {
20namespace {
21
22const char kContentTypeApplicationJson[] = "application/json";
23const char kParentLinkKind[] = "drive#fileLink";
24
25// Parses the JSON value to FileResource instance and runs |callback| on the
26// UI thread once parsing is done.
27// This is customized version of ParseJsonAndRun defined above to adapt the
28// remaining response type.
29void ParseFileResourceWithUploadRangeAndRun(
30    const drive::UploadRangeCallback& callback,
31    const UploadRangeResponse& response,
32    scoped_ptr<base::Value> value) {
33  DCHECK(!callback.is_null());
34
35  scoped_ptr<FileResource> file_resource;
36  if (value) {
37    file_resource = FileResource::CreateFrom(*value);
38    if (!file_resource) {
39      callback.Run(
40          UploadRangeResponse(GDATA_PARSE_ERROR,
41                              response.start_position_received,
42                              response.end_position_received),
43          scoped_ptr<FileResource>());
44      return;
45    }
46  }
47
48  callback.Run(response, file_resource.Pass());
49}
50
51// Creates a Parents value which can be used as a part of request body.
52scoped_ptr<base::DictionaryValue> CreateParentValue(
53    const std::string& file_id) {
54  scoped_ptr<base::DictionaryValue> parent(new base::DictionaryValue);
55  parent->SetString("kind", kParentLinkKind);
56  parent->SetString("id", file_id);
57  return parent.Pass();
58}
59
60}  // namespace
61
62namespace drive {
63
64//============================ DriveApiPartialFieldRequest ====================
65
66DriveApiPartialFieldRequest::DriveApiPartialFieldRequest(
67    RequestSender* sender) : UrlFetchRequestBase(sender) {
68}
69
70DriveApiPartialFieldRequest::~DriveApiPartialFieldRequest() {
71}
72
73GURL DriveApiPartialFieldRequest::GetURL() const {
74  GURL url = GetURLInternal();
75  if (!fields_.empty())
76    url = net::AppendOrReplaceQueryParameter(url, "fields", fields_);
77  return url;
78}
79
80//=============================== FilesGetRequest =============================
81
82FilesGetRequest::FilesGetRequest(
83    RequestSender* sender,
84    const DriveApiUrlGenerator& url_generator,
85    const FileResourceCallback& callback)
86    : DriveApiDataRequest<FileResource>(sender, callback),
87      url_generator_(url_generator) {
88  DCHECK(!callback.is_null());
89}
90
91FilesGetRequest::~FilesGetRequest() {}
92
93GURL FilesGetRequest::GetURLInternal() const {
94  return url_generator_.GetFilesGetUrl(file_id_);
95}
96
97//============================ FilesAuthorizeRequest ===========================
98
99FilesAuthorizeRequest::FilesAuthorizeRequest(
100    RequestSender* sender,
101    const DriveApiUrlGenerator& url_generator,
102    const FileResourceCallback& callback)
103    : DriveApiDataRequest<FileResource>(sender, callback),
104      url_generator_(url_generator) {
105  DCHECK(!callback.is_null());
106}
107
108FilesAuthorizeRequest::~FilesAuthorizeRequest() {}
109
110net::URLFetcher::RequestType FilesAuthorizeRequest::GetRequestType() const {
111  return net::URLFetcher::POST;
112}
113
114GURL FilesAuthorizeRequest::GetURLInternal() const {
115  return url_generator_.GetFilesAuthorizeUrl(file_id_, app_id_);
116}
117
118//============================ FilesInsertRequest ============================
119
120FilesInsertRequest::FilesInsertRequest(
121    RequestSender* sender,
122    const DriveApiUrlGenerator& url_generator,
123    const FileResourceCallback& callback)
124    : DriveApiDataRequest<FileResource>(sender, callback),
125      url_generator_(url_generator) {
126  DCHECK(!callback.is_null());
127}
128
129FilesInsertRequest::~FilesInsertRequest() {}
130
131net::URLFetcher::RequestType FilesInsertRequest::GetRequestType() const {
132  return net::URLFetcher::POST;
133}
134
135bool FilesInsertRequest::GetContentData(std::string* upload_content_type,
136                                        std::string* upload_content) {
137  *upload_content_type = kContentTypeApplicationJson;
138
139  base::DictionaryValue root;
140
141  if (!last_viewed_by_me_date_.is_null()) {
142    root.SetString("lastViewedByMeDate",
143                   util::FormatTimeAsString(last_viewed_by_me_date_));
144  }
145
146  if (!mime_type_.empty())
147    root.SetString("mimeType", mime_type_);
148
149  if (!modified_date_.is_null())
150    root.SetString("modifiedDate", util::FormatTimeAsString(modified_date_));
151
152  if (!parents_.empty()) {
153    base::ListValue* parents_value = new base::ListValue;
154    for (size_t i = 0; i < parents_.size(); ++i) {
155      base::DictionaryValue* parent = new base::DictionaryValue;
156      parent->SetString("id", parents_[i]);
157      parents_value->Append(parent);
158    }
159    root.Set("parents", parents_value);
160  }
161
162  if (!title_.empty())
163    root.SetString("title", title_);
164
165  base::JSONWriter::Write(&root, upload_content);
166  DVLOG(1) << "FilesInsert data: " << *upload_content_type << ", ["
167           << *upload_content << "]";
168  return true;
169}
170
171GURL FilesInsertRequest::GetURLInternal() const {
172  return url_generator_.GetFilesInsertUrl();
173}
174
175//============================== FilesPatchRequest ============================
176
177FilesPatchRequest::FilesPatchRequest(
178    RequestSender* sender,
179    const DriveApiUrlGenerator& url_generator,
180    const FileResourceCallback& callback)
181    : DriveApiDataRequest<FileResource>(sender, callback),
182      url_generator_(url_generator),
183      set_modified_date_(false),
184      update_viewed_date_(true) {
185  DCHECK(!callback.is_null());
186}
187
188FilesPatchRequest::~FilesPatchRequest() {}
189
190net::URLFetcher::RequestType FilesPatchRequest::GetRequestType() const {
191  return net::URLFetcher::PATCH;
192}
193
194std::vector<std::string> FilesPatchRequest::GetExtraRequestHeaders() const {
195  std::vector<std::string> headers;
196  headers.push_back(util::kIfMatchAllHeader);
197  return headers;
198}
199
200GURL FilesPatchRequest::GetURLInternal() const {
201  return url_generator_.GetFilesPatchUrl(
202      file_id_, set_modified_date_, update_viewed_date_);
203}
204
205bool FilesPatchRequest::GetContentData(std::string* upload_content_type,
206                                       std::string* upload_content) {
207  if (title_.empty() &&
208      modified_date_.is_null() &&
209      last_viewed_by_me_date_.is_null() &&
210      parents_.empty())
211    return false;
212
213  *upload_content_type = kContentTypeApplicationJson;
214
215  base::DictionaryValue root;
216  if (!title_.empty())
217    root.SetString("title", title_);
218
219  if (!modified_date_.is_null())
220    root.SetString("modifiedDate", util::FormatTimeAsString(modified_date_));
221
222  if (!last_viewed_by_me_date_.is_null()) {
223    root.SetString("lastViewedByMeDate",
224                   util::FormatTimeAsString(last_viewed_by_me_date_));
225  }
226
227  if (!parents_.empty()) {
228    base::ListValue* parents_value = new base::ListValue;
229    for (size_t i = 0; i < parents_.size(); ++i) {
230      base::DictionaryValue* parent = new base::DictionaryValue;
231      parent->SetString("id", parents_[i]);
232      parents_value->Append(parent);
233    }
234    root.Set("parents", parents_value);
235  }
236
237  base::JSONWriter::Write(&root, upload_content);
238  DVLOG(1) << "FilesPatch data: " << *upload_content_type << ", ["
239           << *upload_content << "]";
240  return true;
241}
242
243//============================= FilesCopyRequest ==============================
244
245FilesCopyRequest::FilesCopyRequest(
246    RequestSender* sender,
247    const DriveApiUrlGenerator& url_generator,
248    const FileResourceCallback& callback)
249    : DriveApiDataRequest<FileResource>(sender, callback),
250      url_generator_(url_generator) {
251  DCHECK(!callback.is_null());
252}
253
254FilesCopyRequest::~FilesCopyRequest() {
255}
256
257net::URLFetcher::RequestType FilesCopyRequest::GetRequestType() const {
258  return net::URLFetcher::POST;
259}
260
261GURL FilesCopyRequest::GetURLInternal() const {
262  return url_generator_.GetFilesCopyUrl(file_id_);
263}
264
265bool FilesCopyRequest::GetContentData(std::string* upload_content_type,
266                                      std::string* upload_content) {
267  if (parents_.empty() && title_.empty())
268    return false;
269
270  *upload_content_type = kContentTypeApplicationJson;
271
272  base::DictionaryValue root;
273
274  if (!modified_date_.is_null())
275    root.SetString("modifiedDate", util::FormatTimeAsString(modified_date_));
276
277  if (!parents_.empty()) {
278    base::ListValue* parents_value = new base::ListValue;
279    for (size_t i = 0; i < parents_.size(); ++i) {
280      base::DictionaryValue* parent = new base::DictionaryValue;
281      parent->SetString("id", parents_[i]);
282      parents_value->Append(parent);
283    }
284    root.Set("parents", parents_value);
285  }
286
287  if (!title_.empty())
288    root.SetString("title", title_);
289
290  base::JSONWriter::Write(&root, upload_content);
291  DVLOG(1) << "FilesCopy data: " << *upload_content_type << ", ["
292           << *upload_content << "]";
293  return true;
294}
295
296//============================= FilesListRequest =============================
297
298FilesListRequest::FilesListRequest(
299    RequestSender* sender,
300    const DriveApiUrlGenerator& url_generator,
301    const FileListCallback& callback)
302    : DriveApiDataRequest<FileList>(sender, callback),
303      url_generator_(url_generator),
304      max_results_(100) {
305  DCHECK(!callback.is_null());
306}
307
308FilesListRequest::~FilesListRequest() {}
309
310GURL FilesListRequest::GetURLInternal() const {
311  return url_generator_.GetFilesListUrl(max_results_, page_token_, q_);
312}
313
314//======================== FilesListNextPageRequest =========================
315
316FilesListNextPageRequest::FilesListNextPageRequest(
317    RequestSender* sender,
318    const FileListCallback& callback)
319    : DriveApiDataRequest<FileList>(sender, callback) {
320  DCHECK(!callback.is_null());
321}
322
323FilesListNextPageRequest::~FilesListNextPageRequest() {
324}
325
326GURL FilesListNextPageRequest::GetURLInternal() const {
327  return next_link_;
328}
329
330//============================ FilesDeleteRequest =============================
331
332FilesDeleteRequest::FilesDeleteRequest(
333    RequestSender* sender,
334    const DriveApiUrlGenerator& url_generator,
335    const EntryActionCallback& callback)
336    : EntryActionRequest(sender, callback),
337      url_generator_(url_generator) {
338  DCHECK(!callback.is_null());
339}
340
341FilesDeleteRequest::~FilesDeleteRequest() {}
342
343net::URLFetcher::RequestType FilesDeleteRequest::GetRequestType() const {
344  return net::URLFetcher::DELETE_REQUEST;
345}
346
347GURL FilesDeleteRequest::GetURL() const {
348  return url_generator_.GetFilesDeleteUrl(file_id_);
349}
350
351std::vector<std::string> FilesDeleteRequest::GetExtraRequestHeaders() const {
352  std::vector<std::string> headers(
353      EntryActionRequest::GetExtraRequestHeaders());
354  headers.push_back(util::GenerateIfMatchHeader(etag_));
355  return headers;
356}
357
358//============================ FilesTrashRequest =============================
359
360FilesTrashRequest::FilesTrashRequest(
361    RequestSender* sender,
362    const DriveApiUrlGenerator& url_generator,
363    const FileResourceCallback& callback)
364    : DriveApiDataRequest<FileResource>(sender, callback),
365      url_generator_(url_generator) {
366  DCHECK(!callback.is_null());
367}
368
369FilesTrashRequest::~FilesTrashRequest() {}
370
371net::URLFetcher::RequestType FilesTrashRequest::GetRequestType() const {
372  return net::URLFetcher::POST;
373}
374
375GURL FilesTrashRequest::GetURLInternal() const {
376  return url_generator_.GetFilesTrashUrl(file_id_);
377}
378
379//============================== AboutGetRequest =============================
380
381AboutGetRequest::AboutGetRequest(
382    RequestSender* sender,
383    const DriveApiUrlGenerator& url_generator,
384    const AboutResourceCallback& callback)
385    : DriveApiDataRequest<AboutResource>(sender, callback),
386      url_generator_(url_generator) {
387  DCHECK(!callback.is_null());
388}
389
390AboutGetRequest::~AboutGetRequest() {}
391
392GURL AboutGetRequest::GetURLInternal() const {
393  return url_generator_.GetAboutGetUrl();
394}
395
396//============================ ChangesListRequest ===========================
397
398ChangesListRequest::ChangesListRequest(
399    RequestSender* sender,
400    const DriveApiUrlGenerator& url_generator,
401    const ChangeListCallback& callback)
402    : DriveApiDataRequest<ChangeList>(sender, callback),
403      url_generator_(url_generator),
404      include_deleted_(true),
405      max_results_(100),
406      start_change_id_(0) {
407  DCHECK(!callback.is_null());
408}
409
410ChangesListRequest::~ChangesListRequest() {}
411
412GURL ChangesListRequest::GetURLInternal() const {
413  return url_generator_.GetChangesListUrl(
414      include_deleted_, max_results_, page_token_, start_change_id_);
415}
416
417//======================== ChangesListNextPageRequest =========================
418
419ChangesListNextPageRequest::ChangesListNextPageRequest(
420    RequestSender* sender,
421    const ChangeListCallback& callback)
422    : DriveApiDataRequest<ChangeList>(sender, callback) {
423  DCHECK(!callback.is_null());
424}
425
426ChangesListNextPageRequest::~ChangesListNextPageRequest() {
427}
428
429GURL ChangesListNextPageRequest::GetURLInternal() const {
430  return next_link_;
431}
432
433//============================== AppsListRequest ===========================
434
435AppsListRequest::AppsListRequest(
436    RequestSender* sender,
437    const DriveApiUrlGenerator& url_generator,
438    bool use_internal_endpoint,
439    const AppListCallback& callback)
440    : DriveApiDataRequest<AppList>(sender, callback),
441      url_generator_(url_generator),
442      use_internal_endpoint_(use_internal_endpoint) {
443  DCHECK(!callback.is_null());
444}
445
446AppsListRequest::~AppsListRequest() {}
447
448GURL AppsListRequest::GetURLInternal() const {
449  return url_generator_.GetAppsListUrl(use_internal_endpoint_);
450}
451
452//============================== AppsDeleteRequest ===========================
453
454AppsDeleteRequest::AppsDeleteRequest(RequestSender* sender,
455                                     const DriveApiUrlGenerator& url_generator,
456                                     const EntryActionCallback& callback)
457    : EntryActionRequest(sender, callback),
458      url_generator_(url_generator) {
459  DCHECK(!callback.is_null());
460}
461
462AppsDeleteRequest::~AppsDeleteRequest() {}
463
464net::URLFetcher::RequestType AppsDeleteRequest::GetRequestType() const {
465  return net::URLFetcher::DELETE_REQUEST;
466}
467
468GURL AppsDeleteRequest::GetURL() const {
469  return url_generator_.GetAppsDeleteUrl(app_id_);
470}
471
472//========================== ChildrenInsertRequest ============================
473
474ChildrenInsertRequest::ChildrenInsertRequest(
475    RequestSender* sender,
476    const DriveApiUrlGenerator& url_generator,
477    const EntryActionCallback& callback)
478    : EntryActionRequest(sender, callback),
479      url_generator_(url_generator) {
480  DCHECK(!callback.is_null());
481}
482
483ChildrenInsertRequest::~ChildrenInsertRequest() {}
484
485net::URLFetcher::RequestType ChildrenInsertRequest::GetRequestType() const {
486  return net::URLFetcher::POST;
487}
488
489GURL ChildrenInsertRequest::GetURL() const {
490  return url_generator_.GetChildrenInsertUrl(folder_id_);
491}
492
493bool ChildrenInsertRequest::GetContentData(std::string* upload_content_type,
494                                           std::string* upload_content) {
495  *upload_content_type = kContentTypeApplicationJson;
496
497  base::DictionaryValue root;
498  root.SetString("id", id_);
499
500  base::JSONWriter::Write(&root, upload_content);
501  DVLOG(1) << "InsertResource data: " << *upload_content_type << ", ["
502           << *upload_content << "]";
503  return true;
504}
505
506//========================== ChildrenDeleteRequest ============================
507
508ChildrenDeleteRequest::ChildrenDeleteRequest(
509    RequestSender* sender,
510    const DriveApiUrlGenerator& url_generator,
511    const EntryActionCallback& callback)
512    : EntryActionRequest(sender, callback),
513      url_generator_(url_generator) {
514  DCHECK(!callback.is_null());
515}
516
517ChildrenDeleteRequest::~ChildrenDeleteRequest() {}
518
519net::URLFetcher::RequestType ChildrenDeleteRequest::GetRequestType() const {
520  return net::URLFetcher::DELETE_REQUEST;
521}
522
523GURL ChildrenDeleteRequest::GetURL() const {
524  return url_generator_.GetChildrenDeleteUrl(child_id_, folder_id_);
525}
526
527//======================= InitiateUploadNewFileRequest =======================
528
529InitiateUploadNewFileRequest::InitiateUploadNewFileRequest(
530    RequestSender* sender,
531    const DriveApiUrlGenerator& url_generator,
532    const std::string& content_type,
533    int64 content_length,
534    const std::string& parent_resource_id,
535    const std::string& title,
536    const InitiateUploadCallback& callback)
537    : InitiateUploadRequestBase(sender,
538                                callback,
539                                content_type,
540                                content_length),
541      url_generator_(url_generator),
542      parent_resource_id_(parent_resource_id),
543      title_(title) {
544}
545
546InitiateUploadNewFileRequest::~InitiateUploadNewFileRequest() {}
547
548GURL InitiateUploadNewFileRequest::GetURL() const {
549  return url_generator_.GetInitiateUploadNewFileUrl(!modified_date_.is_null());
550}
551
552net::URLFetcher::RequestType
553InitiateUploadNewFileRequest::GetRequestType() const {
554  return net::URLFetcher::POST;
555}
556
557bool InitiateUploadNewFileRequest::GetContentData(
558    std::string* upload_content_type,
559    std::string* upload_content) {
560  *upload_content_type = kContentTypeApplicationJson;
561
562  base::DictionaryValue root;
563  root.SetString("title", title_);
564
565  // Fill parent link.
566  scoped_ptr<base::ListValue> parents(new base::ListValue);
567  parents->Append(CreateParentValue(parent_resource_id_).release());
568  root.Set("parents", parents.release());
569
570  if (!modified_date_.is_null())
571    root.SetString("modifiedDate", util::FormatTimeAsString(modified_date_));
572
573  if (!last_viewed_by_me_date_.is_null()) {
574    root.SetString("lastViewedByMeDate",
575                   util::FormatTimeAsString(last_viewed_by_me_date_));
576  }
577
578  base::JSONWriter::Write(&root, upload_content);
579
580  DVLOG(1) << "InitiateUploadNewFile data: " << *upload_content_type << ", ["
581           << *upload_content << "]";
582  return true;
583}
584
585//===================== InitiateUploadExistingFileRequest ====================
586
587InitiateUploadExistingFileRequest::InitiateUploadExistingFileRequest(
588    RequestSender* sender,
589    const DriveApiUrlGenerator& url_generator,
590    const std::string& content_type,
591    int64 content_length,
592    const std::string& resource_id,
593    const std::string& etag,
594    const InitiateUploadCallback& callback)
595    : InitiateUploadRequestBase(sender,
596                                callback,
597                                content_type,
598                                content_length),
599      url_generator_(url_generator),
600      resource_id_(resource_id),
601      etag_(etag) {
602}
603
604InitiateUploadExistingFileRequest::~InitiateUploadExistingFileRequest() {}
605
606GURL InitiateUploadExistingFileRequest::GetURL() const {
607  return url_generator_.GetInitiateUploadExistingFileUrl(
608      resource_id_, !modified_date_.is_null());
609}
610
611net::URLFetcher::RequestType
612InitiateUploadExistingFileRequest::GetRequestType() const {
613  return net::URLFetcher::PUT;
614}
615
616std::vector<std::string>
617InitiateUploadExistingFileRequest::GetExtraRequestHeaders() const {
618  std::vector<std::string> headers(
619      InitiateUploadRequestBase::GetExtraRequestHeaders());
620  headers.push_back(util::GenerateIfMatchHeader(etag_));
621  return headers;
622}
623
624bool InitiateUploadExistingFileRequest::GetContentData(
625    std::string* upload_content_type,
626    std::string* upload_content) {
627  base::DictionaryValue root;
628  if (!parent_resource_id_.empty()) {
629    scoped_ptr<base::ListValue> parents(new base::ListValue);
630    parents->Append(CreateParentValue(parent_resource_id_).release());
631    root.Set("parents", parents.release());
632  }
633
634  if (!title_.empty())
635    root.SetString("title", title_);
636
637  if (!modified_date_.is_null())
638    root.SetString("modifiedDate", util::FormatTimeAsString(modified_date_));
639
640  if (!last_viewed_by_me_date_.is_null()) {
641    root.SetString("lastViewedByMeDate",
642                   util::FormatTimeAsString(last_viewed_by_me_date_));
643  }
644
645  if (root.empty())
646    return false;
647
648  *upload_content_type = kContentTypeApplicationJson;
649  base::JSONWriter::Write(&root, upload_content);
650  DVLOG(1) << "InitiateUploadExistingFile data: " << *upload_content_type
651           << ", [" << *upload_content << "]";
652  return true;
653}
654
655//============================ ResumeUploadRequest ===========================
656
657ResumeUploadRequest::ResumeUploadRequest(
658    RequestSender* sender,
659    const GURL& upload_location,
660    int64 start_position,
661    int64 end_position,
662    int64 content_length,
663    const std::string& content_type,
664    const base::FilePath& local_file_path,
665    const UploadRangeCallback& callback,
666    const ProgressCallback& progress_callback)
667    : ResumeUploadRequestBase(sender,
668                              upload_location,
669                              start_position,
670                              end_position,
671                              content_length,
672                              content_type,
673                              local_file_path),
674      callback_(callback),
675      progress_callback_(progress_callback) {
676  DCHECK(!callback_.is_null());
677}
678
679ResumeUploadRequest::~ResumeUploadRequest() {}
680
681void ResumeUploadRequest::OnRangeRequestComplete(
682    const UploadRangeResponse& response,
683    scoped_ptr<base::Value> value) {
684  DCHECK(CalledOnValidThread());
685  ParseFileResourceWithUploadRangeAndRun(callback_, response, value.Pass());
686}
687
688void ResumeUploadRequest::OnURLFetchUploadProgress(
689    const net::URLFetcher* source, int64 current, int64 total) {
690  if (!progress_callback_.is_null())
691    progress_callback_.Run(current, total);
692}
693
694//========================== GetUploadStatusRequest ==========================
695
696GetUploadStatusRequest::GetUploadStatusRequest(
697    RequestSender* sender,
698    const GURL& upload_url,
699    int64 content_length,
700    const UploadRangeCallback& callback)
701    : GetUploadStatusRequestBase(sender,
702                                 upload_url,
703                                 content_length),
704      callback_(callback) {
705  DCHECK(!callback.is_null());
706}
707
708GetUploadStatusRequest::~GetUploadStatusRequest() {}
709
710void GetUploadStatusRequest::OnRangeRequestComplete(
711    const UploadRangeResponse& response,
712    scoped_ptr<base::Value> value) {
713  DCHECK(CalledOnValidThread());
714  ParseFileResourceWithUploadRangeAndRun(callback_, response, value.Pass());
715}
716
717//========================== DownloadFileRequest ==========================
718
719DownloadFileRequest::DownloadFileRequest(
720    RequestSender* sender,
721    const DriveApiUrlGenerator& url_generator,
722    const std::string& resource_id,
723    const base::FilePath& output_file_path,
724    const DownloadActionCallback& download_action_callback,
725    const GetContentCallback& get_content_callback,
726    const ProgressCallback& progress_callback)
727    : DownloadFileRequestBase(
728          sender,
729          download_action_callback,
730          get_content_callback,
731          progress_callback,
732          url_generator.GenerateDownloadFileUrl(resource_id),
733          output_file_path) {
734}
735
736DownloadFileRequest::~DownloadFileRequest() {
737}
738
739//========================== PermissionsInsertRequest ==========================
740
741PermissionsInsertRequest::PermissionsInsertRequest(
742    RequestSender* sender,
743    const DriveApiUrlGenerator& url_generator,
744    const EntryActionCallback& callback)
745    : EntryActionRequest(sender, callback),
746      url_generator_(url_generator),
747      type_(PERMISSION_TYPE_USER),
748      role_(PERMISSION_ROLE_READER) {
749}
750
751PermissionsInsertRequest::~PermissionsInsertRequest() {
752}
753
754GURL PermissionsInsertRequest::GetURL() const {
755  return url_generator_.GetPermissionsInsertUrl(id_);
756}
757
758net::URLFetcher::RequestType
759PermissionsInsertRequest::GetRequestType() const {
760  return net::URLFetcher::POST;
761}
762
763bool PermissionsInsertRequest::GetContentData(std::string* upload_content_type,
764                                              std::string* upload_content) {
765  *upload_content_type = kContentTypeApplicationJson;
766
767  base::DictionaryValue root;
768  switch (type_) {
769    case PERMISSION_TYPE_ANYONE:
770      root.SetString("type", "anyone");
771      break;
772    case PERMISSION_TYPE_DOMAIN:
773      root.SetString("type", "domain");
774      break;
775    case PERMISSION_TYPE_GROUP:
776      root.SetString("type", "group");
777      break;
778    case PERMISSION_TYPE_USER:
779      root.SetString("type", "user");
780      break;
781  }
782  switch (role_) {
783    case PERMISSION_ROLE_OWNER:
784      root.SetString("role", "owner");
785      break;
786    case PERMISSION_ROLE_READER:
787      root.SetString("role", "reader");
788      break;
789    case PERMISSION_ROLE_WRITER:
790      root.SetString("role", "writer");
791      break;
792    case PERMISSION_ROLE_COMMENTER:
793      root.SetString("role", "reader");
794      {
795        base::ListValue* list = new base::ListValue;
796        list->AppendString("commenter");
797        root.Set("additionalRoles", list);
798      }
799      break;
800  }
801  root.SetString("value", value_);
802  base::JSONWriter::Write(&root, upload_content);
803  return true;
804}
805
806}  // namespace drive
807}  // namespace google_apis
808