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 "chrome/browser/google_apis/gdata_wapi_requests.h"
7 #include "base/location.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/strings/stringprintf.h"
10 #include "base/task_runner_util.h"
11 #include "base/values.h"
12 #include "chrome/browser/google_apis/gdata_wapi_parser.h"
13 #include "chrome/browser/google_apis/gdata_wapi_url_generator.h"
14 #include "chrome/browser/google_apis/request_sender.h"
15 #include "chrome/browser/google_apis/request_util.h"
16 #include "chrome/browser/google_apis/time_util.h"
17 #include "net/base/escape.h"
18 #include "net/base/url_util.h"
19 #include "third_party/libxml/chromium/libxml_utils.h"
21 using net::URLFetcher
;
23 namespace google_apis
{
27 // Parses the JSON value to ResourceList.
28 scoped_ptr
<ResourceList
> ParseResourceListOnBlockingPool(
29 scoped_ptr
<base::Value
> value
) {
32 return ResourceList::ExtractAndParse(*value
);
35 // Runs |callback| with |error| and |resource_list|, but replace the error code
36 // with GDATA_PARSE_ERROR, if there was a parsing error.
37 void DidParseResourceListOnBlockingPool(
38 const GetResourceListCallback
& callback
,
40 scoped_ptr
<ResourceList
> resource_list
) {
41 DCHECK(!callback
.is_null());
43 // resource_list being NULL indicates there was a parsing error.
45 error
= GDATA_PARSE_ERROR
;
47 callback
.Run(error
, resource_list
.Pass());
50 // Parses the JSON value to ResourceList on the blocking pool and runs
51 // |callback| on the UI thread once parsing is done.
52 void ParseResourceListAndRun(
53 scoped_refptr
<base::TaskRunner
> blocking_task_runner
,
54 const GetResourceListCallback
& callback
,
56 scoped_ptr
<base::Value
> value
) {
57 DCHECK(!callback
.is_null());
60 callback
.Run(error
, scoped_ptr
<ResourceList
>());
64 base::PostTaskAndReplyWithResult(
67 base::Bind(&ParseResourceListOnBlockingPool
, base::Passed(&value
)),
68 base::Bind(&DidParseResourceListOnBlockingPool
, callback
, error
));
71 // Parses the JSON value to AccountMetadata and runs |callback| on the UI
72 // thread once parsing is done.
73 void ParseAccounetMetadataAndRun(const GetAccountMetadataCallback
& callback
,
75 scoped_ptr
<base::Value
> value
) {
76 DCHECK(!callback
.is_null());
79 callback
.Run(error
, scoped_ptr
<AccountMetadata
>());
83 // Parsing AccountMetadata is cheap enough to do on UI thread.
84 scoped_ptr
<AccountMetadata
> entry
=
85 google_apis::AccountMetadata::CreateFrom(*value
);
87 callback
.Run(GDATA_PARSE_ERROR
, scoped_ptr
<AccountMetadata
>());
91 callback
.Run(error
, entry
.Pass());
94 // Parses the |value| to ResourceEntry with error handling.
95 // This is designed to be used for ResumeUploadRequest and
96 // GetUploadStatusRequest.
97 scoped_ptr
<ResourceEntry
> ParseResourceEntry(scoped_ptr
<base::Value
> value
) {
98 scoped_ptr
<ResourceEntry
> entry
;
100 entry
= ResourceEntry::ExtractAndParse(*value
);
102 // Note: |value| may be NULL, in particular if the callback is for a
105 LOG(WARNING
) << "Invalid entry received on upload.";
111 // Extracts the open link url from the JSON Feed. Used by AuthorizeApp().
112 void ParseOpenLinkAndRun(const std::string
& app_id
,
113 const AuthorizeAppCallback
& callback
,
114 GDataErrorCode error
,
115 scoped_ptr
<base::Value
> value
) {
116 DCHECK(!callback
.is_null());
119 callback
.Run(error
, GURL());
123 // Parsing ResourceEntry is cheap enough to do on UI thread.
124 scoped_ptr
<ResourceEntry
> resource_entry
= ParseResourceEntry(value
.Pass());
125 if (!resource_entry
) {
126 callback
.Run(GDATA_PARSE_ERROR
, GURL());
130 // Look for the link to open the file with the app with |app_id|.
131 const ScopedVector
<Link
>& resource_links
= resource_entry
->links();
133 for (size_t i
= 0; i
< resource_links
.size(); ++i
) {
134 const Link
& link
= *resource_links
[i
];
135 if (link
.type() == Link::LINK_OPEN_WITH
&& link
.app_id() == app_id
) {
136 open_link
= link
.href();
141 if (open_link
.is_empty())
142 error
= GDATA_OTHER_ERROR
;
144 callback
.Run(error
, open_link
);
149 //============================ GetResourceListRequest ========================
151 GetResourceListRequest::GetResourceListRequest(
152 RequestSender
* sender
,
153 const GDataWapiUrlGenerator
& url_generator
,
154 const GURL
& override_url
,
155 int64 start_changestamp
,
156 const std::string
& search_string
,
157 const std::string
& directory_resource_id
,
158 const GetResourceListCallback
& callback
)
161 base::Bind(&ParseResourceListAndRun
,
162 make_scoped_refptr(sender
->blocking_task_runner()),
164 url_generator_(url_generator
),
165 override_url_(override_url
),
166 start_changestamp_(start_changestamp
),
167 search_string_(search_string
),
168 directory_resource_id_(directory_resource_id
) {
169 DCHECK(!callback
.is_null());
172 GetResourceListRequest::~GetResourceListRequest() {}
174 GURL
GetResourceListRequest::GetURL() const {
175 return url_generator_
.GenerateResourceListUrl(override_url_
,
178 directory_resource_id_
);
181 //============================ SearchByTitleRequest ==========================
183 SearchByTitleRequest::SearchByTitleRequest(
184 RequestSender
* sender
,
185 const GDataWapiUrlGenerator
& url_generator
,
186 const std::string
& title
,
187 const std::string
& directory_resource_id
,
188 const GetResourceListCallback
& callback
)
191 base::Bind(&ParseResourceListAndRun
,
192 make_scoped_refptr(sender
->blocking_task_runner()),
194 url_generator_(url_generator
),
196 directory_resource_id_(directory_resource_id
) {
197 DCHECK(!callback
.is_null());
200 SearchByTitleRequest::~SearchByTitleRequest() {}
202 GURL
SearchByTitleRequest::GetURL() const {
203 return url_generator_
.GenerateSearchByTitleUrl(
204 title_
, directory_resource_id_
);
207 //============================ GetResourceEntryRequest =======================
209 GetResourceEntryRequest::GetResourceEntryRequest(
210 RequestSender
* sender
,
211 const GDataWapiUrlGenerator
& url_generator
,
212 const std::string
& resource_id
,
213 const GURL
& embed_origin
,
214 const GetDataCallback
& callback
)
215 : GetDataRequest(sender
, callback
),
216 url_generator_(url_generator
),
217 resource_id_(resource_id
),
218 embed_origin_(embed_origin
) {
219 DCHECK(!callback
.is_null());
222 GetResourceEntryRequest::~GetResourceEntryRequest() {}
224 GURL
GetResourceEntryRequest::GetURL() const {
225 return url_generator_
.GenerateEditUrlWithEmbedOrigin(
226 resource_id_
, embed_origin_
);
229 //========================= GetAccountMetadataRequest ========================
231 GetAccountMetadataRequest::GetAccountMetadataRequest(
232 RequestSender
* sender
,
233 const GDataWapiUrlGenerator
& url_generator
,
234 const GetAccountMetadataCallback
& callback
,
235 bool include_installed_apps
)
236 : GetDataRequest(sender
,
237 base::Bind(&ParseAccounetMetadataAndRun
, callback
)),
238 url_generator_(url_generator
),
239 include_installed_apps_(include_installed_apps
) {
240 DCHECK(!callback
.is_null());
243 GetAccountMetadataRequest::~GetAccountMetadataRequest() {}
245 GURL
GetAccountMetadataRequest::GetURL() const {
246 return url_generator_
.GenerateAccountMetadataUrl(include_installed_apps_
);
249 //=========================== DeleteResourceRequest ==========================
251 DeleteResourceRequest::DeleteResourceRequest(
252 RequestSender
* sender
,
253 const GDataWapiUrlGenerator
& url_generator
,
254 const EntryActionCallback
& callback
,
255 const std::string
& resource_id
,
256 const std::string
& etag
)
257 : EntryActionRequest(sender
, callback
),
258 url_generator_(url_generator
),
259 resource_id_(resource_id
),
261 DCHECK(!callback
.is_null());
264 DeleteResourceRequest::~DeleteResourceRequest() {}
266 GURL
DeleteResourceRequest::GetURL() const {
267 return url_generator_
.GenerateEditUrl(resource_id_
);
270 URLFetcher::RequestType
DeleteResourceRequest::GetRequestType() const {
271 return URLFetcher::DELETE_REQUEST
;
274 std::vector
<std::string
>
275 DeleteResourceRequest::GetExtraRequestHeaders() const {
276 std::vector
<std::string
> headers
;
277 headers
.push_back(util::GenerateIfMatchHeader(etag_
));
281 //========================== CreateDirectoryRequest ==========================
283 CreateDirectoryRequest::CreateDirectoryRequest(
284 RequestSender
* sender
,
285 const GDataWapiUrlGenerator
& url_generator
,
286 const GetDataCallback
& callback
,
287 const std::string
& parent_resource_id
,
288 const std::string
& directory_title
)
289 : GetDataRequest(sender
, callback
),
290 url_generator_(url_generator
),
291 parent_resource_id_(parent_resource_id
),
292 directory_title_(directory_title
) {
293 DCHECK(!callback
.is_null());
296 CreateDirectoryRequest::~CreateDirectoryRequest() {}
298 GURL
CreateDirectoryRequest::GetURL() const {
299 return url_generator_
.GenerateContentUrl(parent_resource_id_
);
302 URLFetcher::RequestType
303 CreateDirectoryRequest::GetRequestType() const {
304 return URLFetcher::POST
;
307 bool CreateDirectoryRequest::GetContentData(std::string
* upload_content_type
,
308 std::string
* upload_content
) {
309 upload_content_type
->assign("application/atom+xml");
310 XmlWriter xml_writer
;
311 xml_writer
.StartWriting();
312 xml_writer
.StartElement("entry");
313 xml_writer
.AddAttribute("xmlns", "http://www.w3.org/2005/Atom");
315 xml_writer
.StartElement("category");
316 xml_writer
.AddAttribute("scheme",
317 "http://schemas.google.com/g/2005#kind");
318 xml_writer
.AddAttribute("term",
319 "http://schemas.google.com/docs/2007#folder");
320 xml_writer
.EndElement(); // Ends "category" element.
322 xml_writer
.WriteElement("title", directory_title_
);
324 xml_writer
.EndElement(); // Ends "entry" element.
325 xml_writer
.StopWriting();
326 upload_content
->assign(xml_writer
.GetWrittenString());
327 DVLOG(1) << "CreateDirectory data: " << *upload_content_type
<< ", ["
328 << *upload_content
<< "]";
332 //============================ CopyHostedDocumentRequest =====================
334 CopyHostedDocumentRequest::CopyHostedDocumentRequest(
335 RequestSender
* sender
,
336 const GDataWapiUrlGenerator
& url_generator
,
337 const GetDataCallback
& callback
,
338 const std::string
& resource_id
,
339 const std::string
& new_title
)
340 : GetDataRequest(sender
, callback
),
341 url_generator_(url_generator
),
342 resource_id_(resource_id
),
343 new_title_(new_title
) {
344 DCHECK(!callback
.is_null());
347 CopyHostedDocumentRequest::~CopyHostedDocumentRequest() {}
349 URLFetcher::RequestType
CopyHostedDocumentRequest::GetRequestType() const {
350 return URLFetcher::POST
;
353 GURL
CopyHostedDocumentRequest::GetURL() const {
354 return url_generator_
.GenerateResourceListRootUrl();
357 bool CopyHostedDocumentRequest::GetContentData(
358 std::string
* upload_content_type
,
359 std::string
* upload_content
) {
360 upload_content_type
->assign("application/atom+xml");
361 XmlWriter xml_writer
;
362 xml_writer
.StartWriting();
363 xml_writer
.StartElement("entry");
364 xml_writer
.AddAttribute("xmlns", "http://www.w3.org/2005/Atom");
366 xml_writer
.WriteElement("id", resource_id_
);
367 xml_writer
.WriteElement("title", new_title_
);
369 xml_writer
.EndElement(); // Ends "entry" element.
370 xml_writer
.StopWriting();
371 upload_content
->assign(xml_writer
.GetWrittenString());
372 DVLOG(1) << "CopyHostedDocumentRequest data: " << *upload_content_type
373 << ", [" << *upload_content
<< "]";
377 //=========================== RenameResourceRequest ==========================
379 RenameResourceRequest::RenameResourceRequest(
380 RequestSender
* sender
,
381 const GDataWapiUrlGenerator
& url_generator
,
382 const EntryActionCallback
& callback
,
383 const std::string
& resource_id
,
384 const std::string
& new_title
)
385 : EntryActionRequest(sender
, callback
),
386 url_generator_(url_generator
),
387 resource_id_(resource_id
),
388 new_title_(new_title
) {
389 DCHECK(!callback
.is_null());
392 RenameResourceRequest::~RenameResourceRequest() {}
394 URLFetcher::RequestType
RenameResourceRequest::GetRequestType() const {
395 return URLFetcher::PUT
;
398 std::vector
<std::string
>
399 RenameResourceRequest::GetExtraRequestHeaders() const {
400 std::vector
<std::string
> headers
;
401 headers
.push_back(util::kIfMatchAllHeader
);
405 GURL
RenameResourceRequest::GetURL() const {
406 return url_generator_
.GenerateEditUrl(resource_id_
);
409 bool RenameResourceRequest::GetContentData(std::string
* upload_content_type
,
410 std::string
* upload_content
) {
411 upload_content_type
->assign("application/atom+xml");
412 XmlWriter xml_writer
;
413 xml_writer
.StartWriting();
414 xml_writer
.StartElement("entry");
415 xml_writer
.AddAttribute("xmlns", "http://www.w3.org/2005/Atom");
417 xml_writer
.WriteElement("title", new_title_
);
419 xml_writer
.EndElement(); // Ends "entry" element.
420 xml_writer
.StopWriting();
421 upload_content
->assign(xml_writer
.GetWrittenString());
422 DVLOG(1) << "RenameResourceRequest data: " << *upload_content_type
<< ", ["
423 << *upload_content
<< "]";
427 //=========================== AuthorizeAppRequest ==========================
429 AuthorizeAppRequest::AuthorizeAppRequest(
430 RequestSender
* sender
,
431 const GDataWapiUrlGenerator
& url_generator
,
432 const AuthorizeAppCallback
& callback
,
433 const std::string
& resource_id
,
434 const std::string
& app_id
)
435 : GetDataRequest(sender
,
436 base::Bind(&ParseOpenLinkAndRun
, app_id
, callback
)),
437 url_generator_(url_generator
),
438 resource_id_(resource_id
),
440 DCHECK(!callback
.is_null());
443 AuthorizeAppRequest::~AuthorizeAppRequest() {}
445 URLFetcher::RequestType
AuthorizeAppRequest::GetRequestType() const {
446 return URLFetcher::PUT
;
449 std::vector
<std::string
>
450 AuthorizeAppRequest::GetExtraRequestHeaders() const {
451 std::vector
<std::string
> headers
;
452 headers
.push_back(util::kIfMatchAllHeader
);
456 bool AuthorizeAppRequest::GetContentData(std::string
* upload_content_type
,
457 std::string
* upload_content
) {
458 upload_content_type
->assign("application/atom+xml");
459 XmlWriter xml_writer
;
460 xml_writer
.StartWriting();
461 xml_writer
.StartElement("entry");
462 xml_writer
.AddAttribute("xmlns", "http://www.w3.org/2005/Atom");
463 xml_writer
.AddAttribute("xmlns:docs", "http://schemas.google.com/docs/2007");
464 xml_writer
.WriteElement("docs:authorizedApp", app_id_
);
466 xml_writer
.EndElement(); // Ends "entry" element.
467 xml_writer
.StopWriting();
468 upload_content
->assign(xml_writer
.GetWrittenString());
469 DVLOG(1) << "AuthorizeAppRequest data: " << *upload_content_type
<< ", ["
470 << *upload_content
<< "]";
474 GURL
AuthorizeAppRequest::GetURL() const {
475 return url_generator_
.GenerateEditUrl(resource_id_
);
478 //======================= AddResourceToDirectoryRequest ======================
480 AddResourceToDirectoryRequest::AddResourceToDirectoryRequest(
481 RequestSender
* sender
,
482 const GDataWapiUrlGenerator
& url_generator
,
483 const EntryActionCallback
& callback
,
484 const std::string
& parent_resource_id
,
485 const std::string
& resource_id
)
486 : EntryActionRequest(sender
, callback
),
487 url_generator_(url_generator
),
488 parent_resource_id_(parent_resource_id
),
489 resource_id_(resource_id
) {
490 DCHECK(!callback
.is_null());
493 AddResourceToDirectoryRequest::~AddResourceToDirectoryRequest() {}
495 GURL
AddResourceToDirectoryRequest::GetURL() const {
496 return url_generator_
.GenerateContentUrl(parent_resource_id_
);
499 URLFetcher::RequestType
500 AddResourceToDirectoryRequest::GetRequestType() const {
501 return URLFetcher::POST
;
504 bool AddResourceToDirectoryRequest::GetContentData(
505 std::string
* upload_content_type
, std::string
* upload_content
) {
506 upload_content_type
->assign("application/atom+xml");
507 XmlWriter xml_writer
;
508 xml_writer
.StartWriting();
509 xml_writer
.StartElement("entry");
510 xml_writer
.AddAttribute("xmlns", "http://www.w3.org/2005/Atom");
512 xml_writer
.WriteElement(
513 "id", url_generator_
.GenerateEditUrlWithoutParams(resource_id_
).spec());
515 xml_writer
.EndElement(); // Ends "entry" element.
516 xml_writer
.StopWriting();
517 upload_content
->assign(xml_writer
.GetWrittenString());
518 DVLOG(1) << "AddResourceToDirectoryRequest data: " << *upload_content_type
519 << ", [" << *upload_content
<< "]";
523 //==================== RemoveResourceFromDirectoryRequest ====================
525 RemoveResourceFromDirectoryRequest::RemoveResourceFromDirectoryRequest(
526 RequestSender
* sender
,
527 const GDataWapiUrlGenerator
& url_generator
,
528 const EntryActionCallback
& callback
,
529 const std::string
& parent_resource_id
,
530 const std::string
& document_resource_id
)
531 : EntryActionRequest(sender
, callback
),
532 url_generator_(url_generator
),
533 resource_id_(document_resource_id
),
534 parent_resource_id_(parent_resource_id
) {
535 DCHECK(!callback
.is_null());
538 RemoveResourceFromDirectoryRequest::~RemoveResourceFromDirectoryRequest() {
541 GURL
RemoveResourceFromDirectoryRequest::GetURL() const {
542 return url_generator_
.GenerateResourceUrlForRemoval(
543 parent_resource_id_
, resource_id_
);
546 URLFetcher::RequestType
547 RemoveResourceFromDirectoryRequest::GetRequestType() const {
548 return URLFetcher::DELETE_REQUEST
;
551 std::vector
<std::string
>
552 RemoveResourceFromDirectoryRequest::GetExtraRequestHeaders() const {
553 std::vector
<std::string
> headers
;
554 headers
.push_back(util::kIfMatchAllHeader
);
558 //======================= InitiateUploadNewFileRequest =======================
560 InitiateUploadNewFileRequest::InitiateUploadNewFileRequest(
561 RequestSender
* sender
,
562 const GDataWapiUrlGenerator
& url_generator
,
563 const InitiateUploadCallback
& callback
,
564 const std::string
& content_type
,
565 int64 content_length
,
566 const std::string
& parent_resource_id
,
567 const std::string
& title
)
568 : InitiateUploadRequestBase(sender
,
572 url_generator_(url_generator
),
573 parent_resource_id_(parent_resource_id
),
577 InitiateUploadNewFileRequest::~InitiateUploadNewFileRequest() {}
579 GURL
InitiateUploadNewFileRequest::GetURL() const {
580 return url_generator_
.GenerateInitiateUploadNewFileUrl(parent_resource_id_
);
583 net::URLFetcher::RequestType
584 InitiateUploadNewFileRequest::GetRequestType() const {
585 return net::URLFetcher::POST
;
588 bool InitiateUploadNewFileRequest::GetContentData(
589 std::string
* upload_content_type
,
590 std::string
* upload_content
) {
591 upload_content_type
->assign("application/atom+xml");
592 XmlWriter xml_writer
;
593 xml_writer
.StartWriting();
594 xml_writer
.StartElement("entry");
595 xml_writer
.AddAttribute("xmlns", "http://www.w3.org/2005/Atom");
596 xml_writer
.AddAttribute("xmlns:docs",
597 "http://schemas.google.com/docs/2007");
598 xml_writer
.WriteElement("title", title_
);
599 xml_writer
.EndElement(); // Ends "entry" element.
600 xml_writer
.StopWriting();
601 upload_content
->assign(xml_writer
.GetWrittenString());
602 DVLOG(1) << "InitiateUploadNewFile: " << *upload_content_type
<< ", ["
603 << *upload_content
<< "]";
607 //===================== InitiateUploadExistingFileRequest ====================
609 InitiateUploadExistingFileRequest::InitiateUploadExistingFileRequest(
610 RequestSender
* sender
,
611 const GDataWapiUrlGenerator
& url_generator
,
612 const InitiateUploadCallback
& callback
,
613 const std::string
& content_type
,
614 int64 content_length
,
615 const std::string
& resource_id
,
616 const std::string
& etag
)
617 : InitiateUploadRequestBase(sender
,
621 url_generator_(url_generator
),
622 resource_id_(resource_id
),
626 InitiateUploadExistingFileRequest::~InitiateUploadExistingFileRequest() {}
628 GURL
InitiateUploadExistingFileRequest::GetURL() const {
629 return url_generator_
.GenerateInitiateUploadExistingFileUrl(resource_id_
);
632 net::URLFetcher::RequestType
633 InitiateUploadExistingFileRequest::GetRequestType() const {
634 return net::URLFetcher::PUT
;
637 bool InitiateUploadExistingFileRequest::GetContentData(
638 std::string
* upload_content_type
,
639 std::string
* upload_content
) {
640 // According to the document there is no need to send the content-type.
641 // However, the server would return 500 server error without the
643 // As its workaround, send "text/plain" content-type here.
644 *upload_content_type
= "text/plain";
645 *upload_content
= "";
649 std::vector
<std::string
>
650 InitiateUploadExistingFileRequest::GetExtraRequestHeaders() const {
651 std::vector
<std::string
> headers(
652 InitiateUploadRequestBase::GetExtraRequestHeaders());
653 headers
.push_back(util::GenerateIfMatchHeader(etag_
));
657 //============================ ResumeUploadRequest ===========================
659 ResumeUploadRequest::ResumeUploadRequest(
660 RequestSender
* sender
,
661 const UploadRangeCallback
& callback
,
662 const ProgressCallback
& progress_callback
,
663 const GURL
& upload_location
,
664 int64 start_position
,
666 int64 content_length
,
667 const std::string
& content_type
,
668 const base::FilePath
& local_file_path
)
669 : ResumeUploadRequestBase(sender
,
677 progress_callback_(progress_callback
) {
678 DCHECK(!callback_
.is_null());
681 ResumeUploadRequest::~ResumeUploadRequest() {}
683 void ResumeUploadRequest::OnRangeRequestComplete(
684 const UploadRangeResponse
& response
, scoped_ptr
<base::Value
> value
) {
685 callback_
.Run(response
, ParseResourceEntry(value
.Pass()));
688 void ResumeUploadRequest::OnURLFetchUploadProgress(
689 const URLFetcher
* source
, int64 current
, int64 total
) {
690 if (!progress_callback_
.is_null())
691 progress_callback_
.Run(current
, total
);
694 //========================== GetUploadStatusRequest ==========================
696 GetUploadStatusRequest::GetUploadStatusRequest(
697 RequestSender
* sender
,
698 const UploadRangeCallback
& callback
,
699 const GURL
& upload_url
,
700 int64 content_length
)
701 : GetUploadStatusRequestBase(sender
, upload_url
, content_length
),
702 callback_(callback
) {
703 DCHECK(!callback
.is_null());
706 GetUploadStatusRequest::~GetUploadStatusRequest() {}
708 void GetUploadStatusRequest::OnRangeRequestComplete(
709 const UploadRangeResponse
& response
, scoped_ptr
<base::Value
> value
) {
710 callback_
.Run(response
, ParseResourceEntry(value
.Pass()));
714 //========================== DownloadFileRequest ==========================
716 DownloadFileRequest::DownloadFileRequest(
717 RequestSender
* sender
,
718 const GDataWapiUrlGenerator
& url_generator
,
719 const DownloadActionCallback
& download_action_callback
,
720 const GetContentCallback
& get_content_callback
,
721 const ProgressCallback
& progress_callback
,
722 const std::string
& resource_id
,
723 const base::FilePath
& output_file_path
)
724 : DownloadFileRequestBase(
726 download_action_callback
,
727 get_content_callback
,
729 url_generator
.GenerateDownloadFileUrl(resource_id
),
733 DownloadFileRequest::~DownloadFileRequest() {
736 } // namespace google_apis