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_operations.h"
7 #include "base/stringprintf.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/task_runner_util.h"
10 #include "base/threading/sequenced_worker_pool.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/operation_util.h"
15 #include "chrome/browser/google_apis/time_util.h"
16 #include "content/public/browser/browser_thread.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 content::BrowserThread
;
22 using net::URLFetcher
;
24 namespace google_apis
{
29 const char kUploadContentRange
[] = "Content-Range: bytes ";
31 const char kFeedField
[] = "feed";
33 // Templates for file uploading.
34 const char kUploadResponseRange
[] = "range";
36 // Parses the JSON value to ResourceList.
37 scoped_ptr
<ResourceList
> ParseResourceListOnBlockingPool(
38 scoped_ptr
<base::Value
> value
) {
39 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI
));
42 return ResourceList::ExtractAndParse(*value
);
45 // Runs |callback| with |error| and |value|, but replace the error code with
46 // GDATA_PARSE_ERROR, if there was a parsing error.
47 void DidParseResourceListOnBlockingPool(
48 const GetResourceListCallback
& callback
,
50 scoped_ptr
<ResourceList
> resource_list
) {
51 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
52 DCHECK(!callback
.is_null());
54 // resource_list being NULL indicates there was a parsing error.
56 error
= GDATA_PARSE_ERROR
;
58 callback
.Run(error
, resource_list
.Pass());
61 // Parses the JSON value to ResourceList on the blocking pool and runs
62 // |callback| on the UI thread once parsing is done.
63 void ParseResourceListAndRun(const GetResourceListCallback
& callback
,
65 scoped_ptr
<base::Value
> value
) {
66 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
67 DCHECK(!callback
.is_null());
70 callback
.Run(error
, scoped_ptr
<ResourceList
>());
74 base::PostTaskAndReplyWithResult(
75 BrowserThread::GetBlockingPool(),
77 base::Bind(&ParseResourceListOnBlockingPool
, base::Passed(&value
)),
78 base::Bind(&DidParseResourceListOnBlockingPool
, callback
, error
));
81 // Parses the JSON value to AccountMetadata and runs |callback| on the UI
82 // thread once parsing is done.
83 void ParseAccounetMetadataAndRun(const GetAccountMetadataCallback
& callback
,
85 scoped_ptr
<base::Value
> value
) {
86 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
87 DCHECK(!callback
.is_null());
90 callback
.Run(error
, scoped_ptr
<AccountMetadata
>());
94 // Parsing AccountMetadata is cheap enough to do on UI thread.
95 scoped_ptr
<AccountMetadata
> entry
=
96 google_apis::AccountMetadata::CreateFrom(*value
);
98 callback
.Run(GDATA_PARSE_ERROR
, scoped_ptr
<AccountMetadata
>());
102 callback
.Run(error
, entry
.Pass());
105 // Parses the |value| to ResourceEntry with error handling.
106 // This is designed to be used for ResumeUploadOperation and
107 // GetUploadStatusOperation.
108 scoped_ptr
<ResourceEntry
> ParseResourceEntry(scoped_ptr
<base::Value
> value
) {
109 scoped_ptr
<ResourceEntry
> entry
;
111 entry
= ResourceEntry::ExtractAndParse(*value
);
113 // Note: |value| may be NULL, in particular if the callback is for a
116 LOG(WARNING
) << "Invalid entry received on upload.";
122 // Extracts the open link url from the JSON Feed. Used by AuthorizeApp().
123 void ParseOpenLinkAndRun(const std::string
& app_id
,
124 const AuthorizeAppCallback
& callback
,
125 GDataErrorCode error
,
126 scoped_ptr
<base::Value
> value
) {
127 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
128 DCHECK(!callback
.is_null());
131 callback
.Run(error
, GURL());
135 // Parsing ResourceEntry is cheap enough to do on UI thread.
136 scoped_ptr
<ResourceEntry
> resource_entry
= ParseResourceEntry(value
.Pass());
137 if (!resource_entry
) {
138 callback
.Run(GDATA_PARSE_ERROR
, GURL());
142 // Look for the link to open the file with the app with |app_id|.
143 const ScopedVector
<Link
>& resource_links
= resource_entry
->links();
145 for (size_t i
= 0; i
< resource_links
.size(); ++i
) {
146 const Link
& link
= *resource_links
[i
];
147 if (link
.type() == google_apis::Link::LINK_OPEN_WITH
&&
148 link
.app_id() == app_id
) {
149 open_link
= link
.href();
154 callback
.Run(error
, open_link
);
159 //============================ GetResourceListOperation ========================
161 GetResourceListOperation::GetResourceListOperation(
162 OperationRegistry
* registry
,
163 net::URLRequestContextGetter
* url_request_context_getter
,
164 const GDataWapiUrlGenerator
& url_generator
,
165 const GURL
& override_url
,
166 int start_changestamp
,
167 const std::string
& search_string
,
168 const std::string
& directory_resource_id
,
169 const GetResourceListCallback
& callback
)
170 : GetDataOperation(registry
, url_request_context_getter
,
171 base::Bind(&ParseResourceListAndRun
, callback
)),
172 url_generator_(url_generator
),
173 override_url_(override_url
),
174 start_changestamp_(start_changestamp
),
175 search_string_(search_string
),
176 directory_resource_id_(directory_resource_id
) {
177 DCHECK(!callback
.is_null());
180 GetResourceListOperation::~GetResourceListOperation() {}
182 GURL
GetResourceListOperation::GetURL() const {
183 return url_generator_
.GenerateResourceListUrl(override_url_
,
186 directory_resource_id_
);
189 //============================ GetResourceEntryOperation =======================
191 GetResourceEntryOperation::GetResourceEntryOperation(
192 OperationRegistry
* registry
,
193 net::URLRequestContextGetter
* url_request_context_getter
,
194 const GDataWapiUrlGenerator
& url_generator
,
195 const std::string
& resource_id
,
196 const GetDataCallback
& callback
)
197 : GetDataOperation(registry
, url_request_context_getter
, callback
),
198 url_generator_(url_generator
),
199 resource_id_(resource_id
) {
200 DCHECK(!callback
.is_null());
203 GetResourceEntryOperation::~GetResourceEntryOperation() {}
205 GURL
GetResourceEntryOperation::GetURL() const {
206 return url_generator_
.GenerateEditUrl(resource_id_
);
209 //========================= GetAccountMetadataOperation ========================
211 GetAccountMetadataOperation::GetAccountMetadataOperation(
212 OperationRegistry
* registry
,
213 net::URLRequestContextGetter
* url_request_context_getter
,
214 const GDataWapiUrlGenerator
& url_generator
,
215 const GetAccountMetadataCallback
& callback
,
216 bool include_installed_apps
)
217 : GetDataOperation(registry
, url_request_context_getter
,
218 base::Bind(&ParseAccounetMetadataAndRun
, callback
)),
219 url_generator_(url_generator
),
220 include_installed_apps_(include_installed_apps
) {
221 DCHECK(!callback
.is_null());
224 GetAccountMetadataOperation::~GetAccountMetadataOperation() {}
226 GURL
GetAccountMetadataOperation::GetURL() const {
227 return url_generator_
.GenerateAccountMetadataUrl(include_installed_apps_
);
230 //=========================== DeleteResourceOperation ==========================
232 DeleteResourceOperation::DeleteResourceOperation(
233 OperationRegistry
* registry
,
234 net::URLRequestContextGetter
* url_request_context_getter
,
235 const GDataWapiUrlGenerator
& url_generator
,
236 const EntryActionCallback
& callback
,
237 const std::string
& resource_id
,
238 const std::string
& etag
)
239 : EntryActionOperation(registry
, url_request_context_getter
, callback
),
240 url_generator_(url_generator
),
241 resource_id_(resource_id
),
243 DCHECK(!callback
.is_null());
246 DeleteResourceOperation::~DeleteResourceOperation() {}
248 GURL
DeleteResourceOperation::GetURL() const {
249 return url_generator_
.GenerateEditUrl(resource_id_
);
252 URLFetcher::RequestType
DeleteResourceOperation::GetRequestType() const {
253 return URLFetcher::DELETE_REQUEST
;
256 std::vector
<std::string
>
257 DeleteResourceOperation::GetExtraRequestHeaders() const {
258 std::vector
<std::string
> headers
;
259 headers
.push_back(util::GenerateIfMatchHeader(etag_
));
263 //========================== CreateDirectoryOperation ==========================
265 CreateDirectoryOperation::CreateDirectoryOperation(
266 OperationRegistry
* registry
,
267 net::URLRequestContextGetter
* url_request_context_getter
,
268 const GDataWapiUrlGenerator
& url_generator
,
269 const GetDataCallback
& callback
,
270 const std::string
& parent_resource_id
,
271 const std::string
& directory_name
)
272 : GetDataOperation(registry
, url_request_context_getter
, callback
),
273 url_generator_(url_generator
),
274 parent_resource_id_(parent_resource_id
),
275 directory_name_(directory_name
) {
276 DCHECK(!callback
.is_null());
279 CreateDirectoryOperation::~CreateDirectoryOperation() {}
281 GURL
CreateDirectoryOperation::GetURL() const {
282 return url_generator_
.GenerateContentUrl(parent_resource_id_
);
285 URLFetcher::RequestType
286 CreateDirectoryOperation::GetRequestType() const {
287 return URLFetcher::POST
;
290 bool CreateDirectoryOperation::GetContentData(std::string
* upload_content_type
,
291 std::string
* upload_content
) {
292 upload_content_type
->assign("application/atom+xml");
293 XmlWriter xml_writer
;
294 xml_writer
.StartWriting();
295 xml_writer
.StartElement("entry");
296 xml_writer
.AddAttribute("xmlns", "http://www.w3.org/2005/Atom");
298 xml_writer
.StartElement("category");
299 xml_writer
.AddAttribute("scheme",
300 "http://schemas.google.com/g/2005#kind");
301 xml_writer
.AddAttribute("term",
302 "http://schemas.google.com/docs/2007#folder");
303 xml_writer
.EndElement(); // Ends "category" element.
305 xml_writer
.WriteElement("title", directory_name_
);
307 xml_writer
.EndElement(); // Ends "entry" element.
308 xml_writer
.StopWriting();
309 upload_content
->assign(xml_writer
.GetWrittenString());
310 DVLOG(1) << "CreateDirectory data: " << *upload_content_type
<< ", ["
311 << *upload_content
<< "]";
315 //============================ CopyHostedDocumentOperation =====================
317 CopyHostedDocumentOperation::CopyHostedDocumentOperation(
318 OperationRegistry
* registry
,
319 net::URLRequestContextGetter
* url_request_context_getter
,
320 const GDataWapiUrlGenerator
& url_generator
,
321 const GetDataCallback
& callback
,
322 const std::string
& resource_id
,
323 const std::string
& new_name
)
324 : GetDataOperation(registry
, url_request_context_getter
, callback
),
325 url_generator_(url_generator
),
326 resource_id_(resource_id
),
327 new_name_(new_name
) {
328 DCHECK(!callback
.is_null());
331 CopyHostedDocumentOperation::~CopyHostedDocumentOperation() {}
333 URLFetcher::RequestType
CopyHostedDocumentOperation::GetRequestType() const {
334 return URLFetcher::POST
;
337 GURL
CopyHostedDocumentOperation::GetURL() const {
338 return url_generator_
.GenerateResourceListRootUrl();
341 bool CopyHostedDocumentOperation::GetContentData(
342 std::string
* upload_content_type
,
343 std::string
* upload_content
) {
344 upload_content_type
->assign("application/atom+xml");
345 XmlWriter xml_writer
;
346 xml_writer
.StartWriting();
347 xml_writer
.StartElement("entry");
348 xml_writer
.AddAttribute("xmlns", "http://www.w3.org/2005/Atom");
350 xml_writer
.WriteElement("id", resource_id_
);
351 xml_writer
.WriteElement("title", new_name_
);
353 xml_writer
.EndElement(); // Ends "entry" element.
354 xml_writer
.StopWriting();
355 upload_content
->assign(xml_writer
.GetWrittenString());
356 DVLOG(1) << "CopyHostedDocumentOperation data: " << *upload_content_type
357 << ", [" << *upload_content
<< "]";
361 //=========================== RenameResourceOperation ==========================
363 RenameResourceOperation::RenameResourceOperation(
364 OperationRegistry
* registry
,
365 net::URLRequestContextGetter
* url_request_context_getter
,
366 const GDataWapiUrlGenerator
& url_generator
,
367 const EntryActionCallback
& callback
,
368 const std::string
& resource_id
,
369 const std::string
& new_name
)
370 : EntryActionOperation(registry
, url_request_context_getter
, callback
),
371 url_generator_(url_generator
),
372 resource_id_(resource_id
),
373 new_name_(new_name
) {
374 DCHECK(!callback
.is_null());
377 RenameResourceOperation::~RenameResourceOperation() {}
379 URLFetcher::RequestType
RenameResourceOperation::GetRequestType() const {
380 return URLFetcher::PUT
;
383 std::vector
<std::string
>
384 RenameResourceOperation::GetExtraRequestHeaders() const {
385 std::vector
<std::string
> headers
;
386 headers
.push_back(util::kIfMatchAllHeader
);
390 GURL
RenameResourceOperation::GetURL() const {
391 return url_generator_
.GenerateEditUrl(resource_id_
);
394 bool RenameResourceOperation::GetContentData(std::string
* upload_content_type
,
395 std::string
* upload_content
) {
396 upload_content_type
->assign("application/atom+xml");
397 XmlWriter xml_writer
;
398 xml_writer
.StartWriting();
399 xml_writer
.StartElement("entry");
400 xml_writer
.AddAttribute("xmlns", "http://www.w3.org/2005/Atom");
402 xml_writer
.WriteElement("title", new_name_
);
404 xml_writer
.EndElement(); // Ends "entry" element.
405 xml_writer
.StopWriting();
406 upload_content
->assign(xml_writer
.GetWrittenString());
407 DVLOG(1) << "RenameResourceOperation data: " << *upload_content_type
<< ", ["
408 << *upload_content
<< "]";
412 //=========================== AuthorizeAppOperation ==========================
414 AuthorizeAppOperation::AuthorizeAppOperation(
415 OperationRegistry
* registry
,
416 net::URLRequestContextGetter
* url_request_context_getter
,
417 const GDataWapiUrlGenerator
& url_generator
,
418 const AuthorizeAppCallback
& callback
,
419 const std::string
& resource_id
,
420 const std::string
& app_id
)
421 : GetDataOperation(registry
, url_request_context_getter
,
422 base::Bind(&ParseOpenLinkAndRun
, app_id
, callback
)),
423 url_generator_(url_generator
),
424 resource_id_(resource_id
),
426 DCHECK(!callback
.is_null());
429 AuthorizeAppOperation::~AuthorizeAppOperation() {}
431 URLFetcher::RequestType
AuthorizeAppOperation::GetRequestType() const {
432 return URLFetcher::PUT
;
435 std::vector
<std::string
>
436 AuthorizeAppOperation::GetExtraRequestHeaders() const {
437 std::vector
<std::string
> headers
;
438 headers
.push_back(util::kIfMatchAllHeader
);
442 bool AuthorizeAppOperation::GetContentData(std::string
* upload_content_type
,
443 std::string
* upload_content
) {
444 upload_content_type
->assign("application/atom+xml");
445 XmlWriter xml_writer
;
446 xml_writer
.StartWriting();
447 xml_writer
.StartElement("entry");
448 xml_writer
.AddAttribute("xmlns", "http://www.w3.org/2005/Atom");
449 xml_writer
.AddAttribute("xmlns:docs", "http://schemas.google.com/docs/2007");
450 xml_writer
.WriteElement("docs:authorizedApp", app_id_
);
452 xml_writer
.EndElement(); // Ends "entry" element.
453 xml_writer
.StopWriting();
454 upload_content
->assign(xml_writer
.GetWrittenString());
455 DVLOG(1) << "AuthorizeAppOperation data: " << *upload_content_type
<< ", ["
456 << *upload_content
<< "]";
460 GURL
AuthorizeAppOperation::GetURL() const {
461 return url_generator_
.GenerateEditUrl(resource_id_
);
464 //======================= AddResourceToDirectoryOperation ======================
466 AddResourceToDirectoryOperation::AddResourceToDirectoryOperation(
467 OperationRegistry
* registry
,
468 net::URLRequestContextGetter
* url_request_context_getter
,
469 const GDataWapiUrlGenerator
& url_generator
,
470 const EntryActionCallback
& callback
,
471 const std::string
& parent_resource_id
,
472 const std::string
& resource_id
)
473 : EntryActionOperation(registry
, url_request_context_getter
, callback
),
474 url_generator_(url_generator
),
475 parent_resource_id_(parent_resource_id
),
476 resource_id_(resource_id
) {
477 DCHECK(!callback
.is_null());
480 AddResourceToDirectoryOperation::~AddResourceToDirectoryOperation() {}
482 GURL
AddResourceToDirectoryOperation::GetURL() const {
483 return url_generator_
.GenerateContentUrl(parent_resource_id_
);
486 URLFetcher::RequestType
487 AddResourceToDirectoryOperation::GetRequestType() const {
488 return URLFetcher::POST
;
491 bool AddResourceToDirectoryOperation::GetContentData(
492 std::string
* upload_content_type
, std::string
* upload_content
) {
493 upload_content_type
->assign("application/atom+xml");
494 XmlWriter xml_writer
;
495 xml_writer
.StartWriting();
496 xml_writer
.StartElement("entry");
497 xml_writer
.AddAttribute("xmlns", "http://www.w3.org/2005/Atom");
499 xml_writer
.WriteElement(
500 "id", url_generator_
.GenerateEditUrlWithoutParams(resource_id_
).spec());
502 xml_writer
.EndElement(); // Ends "entry" element.
503 xml_writer
.StopWriting();
504 upload_content
->assign(xml_writer
.GetWrittenString());
505 DVLOG(1) << "AddResourceToDirectoryOperation data: " << *upload_content_type
506 << ", [" << *upload_content
<< "]";
510 //==================== RemoveResourceFromDirectoryOperation ====================
512 RemoveResourceFromDirectoryOperation::RemoveResourceFromDirectoryOperation(
513 OperationRegistry
* registry
,
514 net::URLRequestContextGetter
* url_request_context_getter
,
515 const GDataWapiUrlGenerator
& url_generator
,
516 const EntryActionCallback
& callback
,
517 const std::string
& parent_resource_id
,
518 const std::string
& document_resource_id
)
519 : EntryActionOperation(registry
, url_request_context_getter
, callback
),
520 url_generator_(url_generator
),
521 resource_id_(document_resource_id
),
522 parent_resource_id_(parent_resource_id
) {
523 DCHECK(!callback
.is_null());
526 RemoveResourceFromDirectoryOperation::~RemoveResourceFromDirectoryOperation() {
529 GURL
RemoveResourceFromDirectoryOperation::GetURL() const {
530 return url_generator_
.GenerateResourceUrlForRemoval(
531 parent_resource_id_
, resource_id_
);
534 URLFetcher::RequestType
535 RemoveResourceFromDirectoryOperation::GetRequestType() const {
536 return URLFetcher::DELETE_REQUEST
;
539 std::vector
<std::string
>
540 RemoveResourceFromDirectoryOperation::GetExtraRequestHeaders() const {
541 std::vector
<std::string
> headers
;
542 headers
.push_back(util::kIfMatchAllHeader
);
546 //======================= InitiateUploadNewFileOperation =======================
548 InitiateUploadNewFileOperation::InitiateUploadNewFileOperation(
549 OperationRegistry
* registry
,
550 net::URLRequestContextGetter
* url_request_context_getter
,
551 const GDataWapiUrlGenerator
& url_generator
,
552 const InitiateUploadCallback
& callback
,
553 const base::FilePath
& drive_file_path
,
554 const std::string
& content_type
,
555 int64 content_length
,
556 const std::string
& parent_resource_id
,
557 const std::string
& title
)
558 : InitiateUploadOperationBase(registry
,
559 url_request_context_getter
,
564 url_generator_(url_generator
),
565 parent_resource_id_(parent_resource_id
),
569 InitiateUploadNewFileOperation::~InitiateUploadNewFileOperation() {}
571 GURL
InitiateUploadNewFileOperation::GetURL() const {
572 return url_generator_
.GenerateInitiateUploadNewFileUrl(parent_resource_id_
);
575 net::URLFetcher::RequestType
576 InitiateUploadNewFileOperation::GetRequestType() const {
577 return net::URLFetcher::POST
;
580 bool InitiateUploadNewFileOperation::GetContentData(
581 std::string
* upload_content_type
,
582 std::string
* upload_content
) {
583 upload_content_type
->assign("application/atom+xml");
584 XmlWriter xml_writer
;
585 xml_writer
.StartWriting();
586 xml_writer
.StartElement("entry");
587 xml_writer
.AddAttribute("xmlns", "http://www.w3.org/2005/Atom");
588 xml_writer
.AddAttribute("xmlns:docs",
589 "http://schemas.google.com/docs/2007");
590 xml_writer
.WriteElement("title", title_
);
591 xml_writer
.EndElement(); // Ends "entry" element.
592 xml_writer
.StopWriting();
593 upload_content
->assign(xml_writer
.GetWrittenString());
594 DVLOG(1) << "InitiateUploadNewFile: " << *upload_content_type
<< ", ["
595 << *upload_content
<< "]";
599 //===================== InitiateUploadExistingFileOperation ====================
601 InitiateUploadExistingFileOperation::InitiateUploadExistingFileOperation(
602 OperationRegistry
* registry
,
603 net::URLRequestContextGetter
* url_request_context_getter
,
604 const GDataWapiUrlGenerator
& url_generator
,
605 const InitiateUploadCallback
& callback
,
606 const base::FilePath
& drive_file_path
,
607 const std::string
& content_type
,
608 int64 content_length
,
609 const std::string
& resource_id
,
610 const std::string
& etag
)
611 : InitiateUploadOperationBase(registry
,
612 url_request_context_getter
,
617 url_generator_(url_generator
),
618 resource_id_(resource_id
),
622 InitiateUploadExistingFileOperation::~InitiateUploadExistingFileOperation() {}
624 GURL
InitiateUploadExistingFileOperation::GetURL() const {
625 return url_generator_
.GenerateInitiateUploadExistingFileUrl(resource_id_
);
628 net::URLFetcher::RequestType
629 InitiateUploadExistingFileOperation::GetRequestType() const {
630 return net::URLFetcher::PUT
;
633 bool InitiateUploadExistingFileOperation::GetContentData(
634 std::string
* upload_content_type
,
635 std::string
* upload_content
) {
636 // According to the document there is no need to send the content-type.
637 // However, the server would return 500 server error without the
639 // As its workaround, send "text/plain" content-type here.
640 *upload_content_type
= "text/plain";
641 *upload_content
= "";
645 std::vector
<std::string
>
646 InitiateUploadExistingFileOperation::GetExtraRequestHeaders() const {
647 std::vector
<std::string
> headers(
648 InitiateUploadOperationBase::GetExtraRequestHeaders());
649 headers
.push_back(util::GenerateIfMatchHeader(etag_
));
653 //============================ ResumeUploadOperation ===========================
655 ResumeUploadOperation::ResumeUploadOperation(
656 OperationRegistry
* registry
,
657 net::URLRequestContextGetter
* url_request_context_getter
,
658 const UploadRangeCallback
& callback
,
659 const ProgressCallback
& progress_callback
,
660 UploadMode upload_mode
,
661 const base::FilePath
& drive_file_path
,
662 const GURL
& upload_location
,
663 int64 start_position
,
665 int64 content_length
,
666 const std::string
& content_type
,
667 const scoped_refptr
<net::IOBuffer
>& buf
)
668 : ResumeUploadOperationBase(registry
,
669 url_request_context_getter
,
679 progress_callback_(progress_callback
) {
680 DCHECK(!callback_
.is_null());
683 ResumeUploadOperation::~ResumeUploadOperation() {}
685 void ResumeUploadOperation::OnRangeOperationComplete(
686 const UploadRangeResponse
& response
, scoped_ptr
<base::Value
> value
) {
687 callback_
.Run(response
, ParseResourceEntry(value
.Pass()));
690 void ResumeUploadOperation::OnURLFetchUploadProgress(
691 const URLFetcher
* source
, int64 current
, int64 total
) {
692 ResumeUploadOperationBase::OnURLFetchUploadProgress(source
, current
, total
);
693 if (!progress_callback_
.is_null())
694 progress_callback_
.Run(current
, total
);
697 //========================== GetUploadStatusOperation ==========================
699 GetUploadStatusOperation::GetUploadStatusOperation(
700 OperationRegistry
* registry
,
701 net::URLRequestContextGetter
* url_request_context_getter
,
702 const UploadRangeCallback
& callback
,
703 UploadMode upload_mode
,
704 const base::FilePath
& drive_file_path
,
705 const GURL
& upload_url
,
706 int64 content_length
)
707 : UploadRangeOperationBase(registry
,
708 url_request_context_getter
,
713 content_length_(content_length
) {}
715 GetUploadStatusOperation::~GetUploadStatusOperation() {}
717 std::vector
<std::string
>
718 GetUploadStatusOperation::GetExtraRequestHeaders() const {
719 // The header looks like
720 // Content-Range: bytes */<content_length>
722 // Content-Range: bytes */13851821
723 DCHECK_GE(content_length_
, 0);
725 std::vector
<std::string
> headers
;
727 std::string(kUploadContentRange
) + "*/" +
728 base::Int64ToString(content_length_
));
732 void GetUploadStatusOperation::OnRangeOperationComplete(
733 const UploadRangeResponse
& response
, scoped_ptr
<base::Value
> value
) {
734 callback_
.Run(response
, ParseResourceEntry(value
.Pass()));
737 } // namespace google_apis