Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(686)

Side by Side Diff: chrome/browser/chromeos/gdata/gdata_operations.cc

Issue 10920091: Move Drive API files to google_apis directory (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Reflect comments Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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 "chrome/browser/chromeos/gdata/gdata_operations.h"
6
7 #include "base/string_number_conversions.h"
8 #include "base/stringprintf.h"
9 #include "base/values.h"
10 #include "chrome/browser/chromeos/gdata/gdata_util.h"
11 #include "chrome/browser/chromeos/gdata/gdata_wapi_parser.h"
12 #include "chrome/common/net/url_util.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "net/base/escape.h"
15 #include "net/http/http_util.h"
16 #include "third_party/libxml/chromium/libxml_utils.h"
17
18 using net::URLFetcher;
19
20 namespace {
21
22 // etag matching header.
23 const char kIfMatchAllHeader[] = "If-Match: *";
24 const char kIfMatchHeaderFormat[] = "If-Match: %s";
25
26 // URL requesting documents list that belong to the authenticated user only
27 // (handled with '/-/mine' part).
28 const char kGetDocumentListURLForAllDocuments[] =
29 "https://docs.google.com/feeds/default/private/full/-/mine";
30
31 // URL requesting documents list in a particular directory specified by "%s"
32 // that belong to the authenticated user only (handled with '/-/mine' part).
33 const char kGetDocumentListURLForDirectoryFormat[] =
34 "https://docs.google.com/feeds/default/private/full/%s/contents/-/mine";
35
36 // URL requesting documents list of changes to documents collections.
37 const char kGetChangesListURL[] =
38 "https://docs.google.com/feeds/default/private/changes";
39
40 // Root document list url.
41 const char kDocumentListRootURL[] =
42 "https://docs.google.com/feeds/default/private/full";
43
44 // URL requesting single document entry whose resource id is specified by "%s".
45 const char kGetDocumentEntryURLFormat[] =
46 "https://docs.google.com/feeds/default/private/full/%s";
47
48 // Metadata feed with things like user quota.
49 const char kAccountMetadataURL[] =
50 "https://docs.google.com/feeds/metadata/default";
51
52 // URL requesting all contact groups.
53 const char kGetContactGroupsURL[] =
54 "https://www.google.com/m8/feeds/groups/default/full?alt=json";
55
56 // URL requesting all contacts.
57 // TODO(derat): Per https://goo.gl/AufHP, "The feed may not contain all of the
58 // user's contacts, because there's a default limit on the number of results
59 // returned." Decide if 10000 is reasonable or not.
60 const char kGetContactsURL[] =
61 "https://www.google.com/m8/feeds/contacts/default/full"
62 "?alt=json&showdeleted=true&max-results=10000";
63
64 // Query parameter optionally appended to |kGetContactsURL| to return contacts
65 // from a specific group (as opposed to all contacts).
66 const char kGetContactsGroupParam[] = "group";
67
68 // Query parameter optionally appended to |kGetContactsURL| to return only
69 // recently-updated contacts.
70 const char kGetContactsUpdatedMinParam[] = "updated-min";
71
72 const char kUploadContentRange[] = "Content-Range: bytes ";
73 const char kUploadContentType[] = "X-Upload-Content-Type: ";
74 const char kUploadContentLength[] = "X-Upload-Content-Length: ";
75
76 #ifndef NDEBUG
77 // Use smaller 'page' size while debugging to ensure we hit feed reload
78 // almost always. Be careful not to use something too small on account that
79 // have many items because server side 503 error might kick in.
80 const int kMaxDocumentsPerFeed = 500;
81 const int kMaxDocumentsPerSearchFeed = 50;
82 #else
83 const int kMaxDocumentsPerFeed = 500;
84 const int kMaxDocumentsPerSearchFeed = 50;
85 #endif
86
87 const char kFeedField[] = "feed";
88
89 // Templates for file uploading.
90 const char kUploadParamConvertKey[] = "convert";
91 const char kUploadParamConvertValue[] = "false";
92 const char kUploadResponseLocation[] = "location";
93 const char kUploadResponseRange[] = "range";
94
95 // Adds additional parameters for API version, output content type and to show
96 // folders in the feed are added to document feed URLs.
97 GURL AddStandardUrlParams(const GURL& url) {
98 GURL result =
99 chrome_common_net::AppendOrReplaceQueryParameter(url, "v", "3");
100 result =
101 chrome_common_net::AppendOrReplaceQueryParameter(result, "alt", "json");
102 return result;
103 }
104
105 // Adds additional parameters to metadata feed to include installed 3rd party
106 // applications.
107 GURL AddMetadataUrlParams(const GURL& url) {
108 GURL result = AddStandardUrlParams(url);
109 result = chrome_common_net::AppendOrReplaceQueryParameter(
110 result, "include-installed-apps", "true");
111 return result;
112 }
113
114 // Adds additional parameters for API version, output content type and to show
115 // folders in the feed are added to document feed URLs.
116 GURL AddFeedUrlParams(const GURL& url,
117 int num_items_to_fetch,
118 int changestamp,
119 const std::string& search_string) {
120 GURL result = AddStandardUrlParams(url);
121 result = chrome_common_net::AppendOrReplaceQueryParameter(
122 result,
123 "showfolders",
124 "true");
125 result = chrome_common_net::AppendOrReplaceQueryParameter(
126 result,
127 "max-results",
128 base::StringPrintf("%d", num_items_to_fetch));
129 result = chrome_common_net::AppendOrReplaceQueryParameter(
130 result, "include-installed-apps", "true");
131
132 if (changestamp) {
133 result = chrome_common_net::AppendQueryParameter(
134 result,
135 "start-index",
136 base::StringPrintf("%d", changestamp));
137 }
138
139 if (!search_string.empty()) {
140 result = chrome_common_net::AppendOrReplaceQueryParameter(
141 result, "q", search_string);
142 }
143 return result;
144 }
145
146 // Formats a URL for getting document list. If |directory_resource_id| is
147 // empty, returns a URL for fetching all documents. If it's given, returns a
148 // URL for fetching documents in a particular directory.
149 GURL FormatDocumentListURL(const std::string& directory_resource_id) {
150 if (directory_resource_id.empty())
151 return GURL(kGetDocumentListURLForAllDocuments);
152
153 return GURL(base::StringPrintf(kGetDocumentListURLForDirectoryFormat,
154 net::EscapePath(
155 directory_resource_id).c_str()));
156 }
157
158 } // namespace
159
160 namespace gdata {
161
162 //============================ Structs ===========================
163
164 ResumeUploadResponse::ResumeUploadResponse(GDataErrorCode code,
165 int64 start_range_received,
166 int64 end_range_received)
167 : code(code),
168 start_range_received(start_range_received),
169 end_range_received(end_range_received) {
170 }
171
172 ResumeUploadResponse::~ResumeUploadResponse() {
173 }
174
175 InitiateUploadParams::InitiateUploadParams(
176 UploadMode upload_mode,
177 const std::string& title,
178 const std::string& content_type,
179 int64 content_length,
180 const GURL& upload_location,
181 const FilePath& virtual_path)
182 : upload_mode(upload_mode),
183 title(title),
184 content_type(content_type),
185 content_length(content_length),
186 upload_location(upload_location),
187 virtual_path(virtual_path) {
188 }
189
190 InitiateUploadParams::~InitiateUploadParams() {
191 }
192
193 ResumeUploadParams::ResumeUploadParams(
194 UploadMode upload_mode,
195 int64 start_range,
196 int64 end_range,
197 int64 content_length,
198 const std::string& content_type,
199 scoped_refptr<net::IOBuffer> buf,
200 const GURL& upload_location,
201 const FilePath& virtual_path) : upload_mode(upload_mode),
202 start_range(start_range),
203 end_range(end_range),
204 content_length(content_length),
205 content_type(content_type),
206 buf(buf),
207 upload_location(upload_location),
208 virtual_path(virtual_path) {
209 }
210
211 ResumeUploadParams::~ResumeUploadParams() {
212 }
213
214 //============================ GetDocumentsOperation ===========================
215
216 GetDocumentsOperation::GetDocumentsOperation(
217 OperationRegistry* registry,
218 const GURL& url,
219 int start_changestamp,
220 const std::string& search_string,
221 const std::string& directory_resource_id,
222 const GetDataCallback& callback)
223 : GetDataOperation(registry, callback),
224 override_url_(url),
225 start_changestamp_(start_changestamp),
226 search_string_(search_string),
227 directory_resource_id_(directory_resource_id) {
228 }
229
230 GetDocumentsOperation::~GetDocumentsOperation() {}
231
232 GURL GetDocumentsOperation::GetURL() const {
233 int max_docs = search_string_.empty() ? kMaxDocumentsPerFeed :
234 kMaxDocumentsPerSearchFeed;
235
236 if (!override_url_.is_empty())
237 return AddFeedUrlParams(override_url_,
238 max_docs,
239 0,
240 search_string_);
241
242 if (start_changestamp_ == 0) {
243 return AddFeedUrlParams(FormatDocumentListURL(directory_resource_id_),
244 max_docs,
245 0,
246 search_string_);
247 }
248
249 return AddFeedUrlParams(GURL(kGetChangesListURL),
250 kMaxDocumentsPerFeed,
251 start_changestamp_,
252 std::string());
253 }
254
255 //============================ GetDocumentEntryOperation =======================
256
257 GetDocumentEntryOperation::GetDocumentEntryOperation(
258 OperationRegistry* registry,
259 const std::string& resource_id,
260 const GetDataCallback& callback)
261 : GetDataOperation(registry, callback),
262 resource_id_(resource_id) {
263 }
264
265 GetDocumentEntryOperation::~GetDocumentEntryOperation() {}
266
267 GURL GetDocumentEntryOperation::GetURL() const {
268 GURL result = GURL(base::StringPrintf(kGetDocumentEntryURLFormat,
269 net::EscapePath(resource_id_).c_str()));
270 return AddStandardUrlParams(result);
271 }
272
273 //========================= GetAccountMetadataOperation ========================
274
275 GetAccountMetadataOperation::GetAccountMetadataOperation(
276 OperationRegistry* registry,
277 const GetDataCallback& callback)
278 : GetDataOperation(registry, callback) {
279 }
280
281 GetAccountMetadataOperation::~GetAccountMetadataOperation() {}
282
283 GURL GetAccountMetadataOperation::GetURL() const {
284 return AddMetadataUrlParams(GURL(kAccountMetadataURL));
285 }
286
287 //============================ DownloadFileOperation ===========================
288
289 DownloadFileOperation::DownloadFileOperation(
290 OperationRegistry* registry,
291 const DownloadActionCallback& download_action_callback,
292 const GetContentCallback& get_content_callback,
293 const GURL& document_url,
294 const FilePath& virtual_path,
295 const FilePath& output_file_path)
296 : UrlFetchOperationBase(registry,
297 OperationRegistry::OPERATION_DOWNLOAD,
298 virtual_path),
299 download_action_callback_(download_action_callback),
300 get_content_callback_(get_content_callback),
301 document_url_(document_url) {
302 // Make sure we download the content into a temp file.
303 if (output_file_path.empty())
304 save_temp_file_ = true;
305 else
306 output_file_path_ = output_file_path;
307 }
308
309 DownloadFileOperation::~DownloadFileOperation() {}
310
311 // Overridden from UrlFetchOperationBase.
312 GURL DownloadFileOperation::GetURL() const {
313 return document_url_;
314 }
315
316 void DownloadFileOperation::OnURLFetchDownloadProgress(const URLFetcher* source,
317 int64 current,
318 int64 total) {
319 NotifyProgress(current, total);
320 }
321
322 bool DownloadFileOperation::ShouldSendDownloadData() {
323 return !get_content_callback_.is_null();
324 }
325
326 void DownloadFileOperation::OnURLFetchDownloadData(
327 const URLFetcher* source,
328 scoped_ptr<std::string> download_data) {
329 if (!get_content_callback_.is_null())
330 get_content_callback_.Run(HTTP_SUCCESS, download_data.Pass());
331 }
332
333 void DownloadFileOperation::ProcessURLFetchResults(const URLFetcher* source) {
334 GDataErrorCode code = GetErrorCode(source);
335
336 // Take over the ownership of the the downloaded temp file.
337 FilePath temp_file;
338 if (code == HTTP_SUCCESS &&
339 !source->GetResponseAsFilePath(true, // take_ownership
340 &temp_file)) {
341 code = GDATA_FILE_ERROR;
342 }
343
344 if (!download_action_callback_.is_null())
345 download_action_callback_.Run(code, document_url_, temp_file);
346 OnProcessURLFetchResultsComplete(code == HTTP_SUCCESS);
347 }
348
349 void DownloadFileOperation::RunCallbackOnPrematureFailure(GDataErrorCode code) {
350 if (!download_action_callback_.is_null())
351 download_action_callback_.Run(code, document_url_, FilePath());
352 }
353
354 //=========================== DeleteDocumentOperation ==========================
355
356 DeleteDocumentOperation::DeleteDocumentOperation(
357 OperationRegistry* registry,
358 const EntryActionCallback& callback,
359 const GURL& document_url)
360 : EntryActionOperation(registry, callback, document_url) {
361 }
362
363 DeleteDocumentOperation::~DeleteDocumentOperation() {}
364
365 GURL DeleteDocumentOperation::GetURL() const {
366 return AddStandardUrlParams(document_url());
367 }
368
369 URLFetcher::RequestType DeleteDocumentOperation::GetRequestType() const {
370 return URLFetcher::DELETE_REQUEST;
371 }
372
373 std::vector<std::string>
374 DeleteDocumentOperation::GetExtraRequestHeaders() const {
375 std::vector<std::string> headers;
376 headers.push_back(kIfMatchAllHeader);
377 return headers;
378 }
379
380 //========================== CreateDirectoryOperation ==========================
381
382 CreateDirectoryOperation::CreateDirectoryOperation(
383 OperationRegistry* registry,
384 const GetDataCallback& callback,
385 const GURL& parent_content_url,
386 const FilePath::StringType& directory_name)
387 : GetDataOperation(registry, callback),
388 parent_content_url_(parent_content_url),
389 directory_name_(directory_name) {
390 }
391
392 CreateDirectoryOperation::~CreateDirectoryOperation() {}
393
394 GURL CreateDirectoryOperation::GetURL() const {
395 if (!parent_content_url_.is_empty())
396 return AddStandardUrlParams(parent_content_url_);
397
398 return AddStandardUrlParams(GURL(kDocumentListRootURL));
399 }
400
401 URLFetcher::RequestType
402 CreateDirectoryOperation::GetRequestType() const {
403 return URLFetcher::POST;
404 }
405
406 bool CreateDirectoryOperation::GetContentData(std::string* upload_content_type,
407 std::string* upload_content) {
408 upload_content_type->assign("application/atom+xml");
409 XmlWriter xml_writer;
410 xml_writer.StartWriting();
411 xml_writer.StartElement("entry");
412 xml_writer.AddAttribute("xmlns", "http://www.w3.org/2005/Atom");
413
414 xml_writer.StartElement("category");
415 xml_writer.AddAttribute("scheme",
416 "http://schemas.google.com/g/2005#kind");
417 xml_writer.AddAttribute("term",
418 "http://schemas.google.com/docs/2007#folder");
419 xml_writer.EndElement(); // Ends "category" element.
420
421 xml_writer.WriteElement("title", FilePath(directory_name_).AsUTF8Unsafe());
422
423 xml_writer.EndElement(); // Ends "entry" element.
424 xml_writer.StopWriting();
425 upload_content->assign(xml_writer.GetWrittenString());
426 DVLOG(1) << "CreateDirectory data: " << *upload_content_type << ", ["
427 << *upload_content << "]";
428 return true;
429 }
430
431 //============================ CopyDocumentOperation ===========================
432
433 CopyDocumentOperation::CopyDocumentOperation(
434 OperationRegistry* registry,
435 const GetDataCallback& callback,
436 const std::string& resource_id,
437 const FilePath::StringType& new_name)
438 : GetDataOperation(registry, callback),
439 resource_id_(resource_id),
440 new_name_(new_name) {
441 }
442
443 CopyDocumentOperation::~CopyDocumentOperation() {}
444
445 URLFetcher::RequestType CopyDocumentOperation::GetRequestType() const {
446 return URLFetcher::POST;
447 }
448
449 GURL CopyDocumentOperation::GetURL() const {
450 return AddStandardUrlParams(GURL(kDocumentListRootURL));
451 }
452
453 bool CopyDocumentOperation::GetContentData(std::string* upload_content_type,
454 std::string* upload_content) {
455 upload_content_type->assign("application/atom+xml");
456 XmlWriter xml_writer;
457 xml_writer.StartWriting();
458 xml_writer.StartElement("entry");
459 xml_writer.AddAttribute("xmlns", "http://www.w3.org/2005/Atom");
460
461 xml_writer.WriteElement("id", resource_id_);
462 xml_writer.WriteElement("title", FilePath(new_name_).AsUTF8Unsafe());
463
464 xml_writer.EndElement(); // Ends "entry" element.
465 xml_writer.StopWriting();
466 upload_content->assign(xml_writer.GetWrittenString());
467 DVLOG(1) << "CopyDocumentOperation data: " << *upload_content_type << ", ["
468 << *upload_content << "]";
469 return true;
470 }
471
472 //=========================== RenameResourceOperation ==========================
473
474 RenameResourceOperation::RenameResourceOperation(
475 OperationRegistry* registry,
476 const EntryActionCallback& callback,
477 const GURL& document_url,
478 const FilePath::StringType& new_name)
479 : EntryActionOperation(registry, callback, document_url),
480 new_name_(new_name) {
481 }
482
483 RenameResourceOperation::~RenameResourceOperation() {}
484
485 URLFetcher::RequestType RenameResourceOperation::GetRequestType() const {
486 return URLFetcher::PUT;
487 }
488
489 std::vector<std::string>
490 RenameResourceOperation::GetExtraRequestHeaders() const {
491 std::vector<std::string> headers;
492 headers.push_back(kIfMatchAllHeader);
493 return headers;
494 }
495
496 GURL RenameResourceOperation::GetURL() const {
497 return AddStandardUrlParams(document_url());
498 }
499
500 bool RenameResourceOperation::GetContentData(std::string* upload_content_type,
501 std::string* upload_content) {
502 upload_content_type->assign("application/atom+xml");
503 XmlWriter xml_writer;
504 xml_writer.StartWriting();
505 xml_writer.StartElement("entry");
506 xml_writer.AddAttribute("xmlns", "http://www.w3.org/2005/Atom");
507
508 xml_writer.WriteElement("title", FilePath(new_name_).AsUTF8Unsafe());
509
510 xml_writer.EndElement(); // Ends "entry" element.
511 xml_writer.StopWriting();
512 upload_content->assign(xml_writer.GetWrittenString());
513 DVLOG(1) << "RenameResourceOperation data: " << *upload_content_type << ", ["
514 << *upload_content << "]";
515 return true;
516 }
517
518 //=========================== AuthorizeAppOperation ==========================
519
520 AuthorizeAppsOperation::AuthorizeAppsOperation(
521 OperationRegistry* registry,
522 const GetDataCallback& callback,
523 const GURL& document_url,
524 const std::string& app_id)
525 : GetDataOperation(registry, callback),
526 app_id_(app_id),
527 document_url_(document_url) {
528 }
529
530 AuthorizeAppsOperation::~AuthorizeAppsOperation() {}
531
532 URLFetcher::RequestType AuthorizeAppsOperation::GetRequestType() const {
533 return URLFetcher::PUT;
534 }
535
536 std::vector<std::string>
537 AuthorizeAppsOperation::GetExtraRequestHeaders() const {
538 std::vector<std::string> headers;
539 headers.push_back(kIfMatchAllHeader);
540 return headers;
541 }
542
543 void AuthorizeAppsOperation::ProcessURLFetchResults(const URLFetcher* source) {
544 std::string data;
545 source->GetResponseAsString(&data);
546 GetDataOperation::ProcessURLFetchResults(source);
547 }
548
549 bool AuthorizeAppsOperation::GetContentData(std::string* upload_content_type,
550 std::string* upload_content) {
551 upload_content_type->assign("application/atom+xml");
552 XmlWriter xml_writer;
553 xml_writer.StartWriting();
554 xml_writer.StartElement("entry");
555 xml_writer.AddAttribute("xmlns", "http://www.w3.org/2005/Atom");
556 xml_writer.AddAttribute("xmlns:docs", "http://schemas.google.com/docs/2007");
557 xml_writer.WriteElement("docs:authorizedApp", app_id_);
558
559 xml_writer.EndElement(); // Ends "entry" element.
560 xml_writer.StopWriting();
561 upload_content->assign(xml_writer.GetWrittenString());
562 DVLOG(1) << "AuthorizeAppOperation data: " << *upload_content_type << ", ["
563 << *upload_content << "]";
564 return true;
565 }
566
567 void AuthorizeAppsOperation::ParseResponse(
568 GDataErrorCode fetch_error_code,
569 const std::string& data) {
570 // Parse entry XML.
571 XmlReader xml_reader;
572 scoped_ptr<DocumentEntry> entry;
573 if (xml_reader.Load(data)) {
574 while (xml_reader.Read()) {
575 if (xml_reader.NodeName() == DocumentEntry::GetEntryNodeName()) {
576 entry.reset(DocumentEntry::CreateFromXml(&xml_reader));
577 break;
578 }
579 }
580 }
581
582 // From the response, we create a list of the links returned, since those
583 // are the only things we are interested in.
584 scoped_ptr<base::ListValue> link_list(new ListValue);
585 const ScopedVector<Link>& feed_links = entry->links();
586 for (ScopedVector<Link>::const_iterator iter = feed_links.begin();
587 iter != feed_links.end(); ++iter) {
588 if ((*iter)->type() == Link::LINK_OPEN_WITH) {
589 base::DictionaryValue* link = new DictionaryValue;
590 link->SetString(std::string("href"), (*iter)->href().spec());
591 link->SetString(std::string("mime_type"), (*iter)->mime_type());
592 link->SetString(std::string("title"), (*iter)->title());
593 link->SetString(std::string("app_id"), (*iter)->app_id());
594 link_list->Append(link);
595 }
596 }
597
598 RunCallback(fetch_error_code, link_list.PassAs<base::Value>());
599 const bool success = true;
600 OnProcessURLFetchResultsComplete(success);
601 }
602
603 GURL AuthorizeAppsOperation::GetURL() const {
604 return document_url_;
605 }
606
607 //======================= AddResourceToDirectoryOperation ======================
608
609 AddResourceToDirectoryOperation::AddResourceToDirectoryOperation(
610 OperationRegistry* registry,
611 const EntryActionCallback& callback,
612 const GURL& parent_content_url,
613 const GURL& document_url)
614 : EntryActionOperation(registry, callback, document_url),
615 parent_content_url_(parent_content_url) {
616 }
617
618 AddResourceToDirectoryOperation::~AddResourceToDirectoryOperation() {}
619
620 GURL AddResourceToDirectoryOperation::GetURL() const {
621 if (!parent_content_url_.is_empty())
622 return AddStandardUrlParams(parent_content_url_);
623
624 return AddStandardUrlParams(GURL(kDocumentListRootURL));
625 }
626
627 URLFetcher::RequestType
628 AddResourceToDirectoryOperation::GetRequestType() const {
629 return URLFetcher::POST;
630 }
631
632 bool AddResourceToDirectoryOperation::GetContentData(
633 std::string* upload_content_type, std::string* upload_content) {
634 upload_content_type->assign("application/atom+xml");
635 XmlWriter xml_writer;
636 xml_writer.StartWriting();
637 xml_writer.StartElement("entry");
638 xml_writer.AddAttribute("xmlns", "http://www.w3.org/2005/Atom");
639
640 xml_writer.WriteElement("id", document_url().spec());
641
642 xml_writer.EndElement(); // Ends "entry" element.
643 xml_writer.StopWriting();
644 upload_content->assign(xml_writer.GetWrittenString());
645 DVLOG(1) << "AddResourceToDirectoryOperation data: " << *upload_content_type
646 << ", [" << *upload_content << "]";
647 return true;
648 }
649
650 //==================== RemoveResourceFromDirectoryOperation ====================
651
652 RemoveResourceFromDirectoryOperation::RemoveResourceFromDirectoryOperation(
653 OperationRegistry* registry,
654 const EntryActionCallback& callback,
655 const GURL& parent_content_url,
656 const GURL& document_url,
657 const std::string& document_resource_id)
658 : EntryActionOperation(registry, callback, document_url),
659 resource_id_(document_resource_id),
660 parent_content_url_(parent_content_url) {
661 }
662
663 RemoveResourceFromDirectoryOperation::~RemoveResourceFromDirectoryOperation() {
664 }
665
666 GURL RemoveResourceFromDirectoryOperation::GetURL() const {
667 std::string escaped_resource_id = net::EscapePath(resource_id_);
668 GURL edit_url(base::StringPrintf("%s/%s",
669 parent_content_url_.spec().c_str(),
670 escaped_resource_id.c_str()));
671 return AddStandardUrlParams(edit_url);
672 }
673
674 URLFetcher::RequestType
675 RemoveResourceFromDirectoryOperation::GetRequestType() const {
676 return URLFetcher::DELETE_REQUEST;
677 }
678
679 std::vector<std::string>
680 RemoveResourceFromDirectoryOperation::GetExtraRequestHeaders() const {
681 std::vector<std::string> headers;
682 headers.push_back(kIfMatchAllHeader);
683 return headers;
684 }
685
686 //=========================== InitiateUploadOperation ==========================
687
688 InitiateUploadOperation::InitiateUploadOperation(
689 OperationRegistry* registry,
690 const InitiateUploadCallback& callback,
691 const InitiateUploadParams& params)
692 : UrlFetchOperationBase(registry,
693 OperationRegistry::OPERATION_UPLOAD,
694 params.virtual_path),
695 callback_(callback),
696 params_(params),
697 initiate_upload_url_(chrome_common_net::AppendOrReplaceQueryParameter(
698 params.upload_location,
699 kUploadParamConvertKey,
700 kUploadParamConvertValue)) {
701 }
702
703 InitiateUploadOperation::~InitiateUploadOperation() {}
704
705 GURL InitiateUploadOperation::GetURL() const {
706 return initiate_upload_url_;
707 }
708
709 void InitiateUploadOperation::ProcessURLFetchResults(
710 const URLFetcher* source) {
711 GDataErrorCode code = GetErrorCode(source);
712
713 std::string upload_location;
714 if (code == HTTP_SUCCESS) {
715 // Retrieve value of the first "Location" header.
716 source->GetResponseHeaders()->EnumerateHeader(NULL,
717 kUploadResponseLocation,
718 &upload_location);
719 }
720 VLOG(1) << "Got response for [" << params_.title
721 << "]: code=" << code
722 << ", location=[" << upload_location << "]";
723
724 if (!callback_.is_null())
725 callback_.Run(code, GURL(upload_location));
726 OnProcessURLFetchResultsComplete(code == HTTP_SUCCESS);
727 }
728
729 void InitiateUploadOperation::NotifySuccessToOperationRegistry() {
730 NotifySuspend();
731 }
732
733 void InitiateUploadOperation::RunCallbackOnPrematureFailure(
734 GDataErrorCode code) {
735 if (!callback_.is_null())
736 callback_.Run(code, GURL());
737 }
738
739 URLFetcher::RequestType InitiateUploadOperation::GetRequestType() const {
740 if (params_.upload_mode == UPLOAD_NEW_FILE)
741 return URLFetcher::POST;
742
743 DCHECK_EQ(UPLOAD_EXISTING_FILE, params_.upload_mode);
744 return URLFetcher::PUT;
745 }
746
747 std::vector<std::string>
748 InitiateUploadOperation::GetExtraRequestHeaders() const {
749 std::vector<std::string> headers;
750 if (!params_.content_type.empty())
751 headers.push_back(kUploadContentType + params_.content_type);
752
753 headers.push_back(
754 kUploadContentLength + base::Int64ToString(params_.content_length));
755
756 if (params_.upload_mode == UPLOAD_EXISTING_FILE)
757 headers.push_back("If-Match: *");
758
759 return headers;
760 }
761
762 bool InitiateUploadOperation::GetContentData(std::string* upload_content_type,
763 std::string* upload_content) {
764 if (params_.upload_mode == UPLOAD_EXISTING_FILE) {
765 // When uploading an existing file, the body is empty as we don't modify
766 // the metadata.
767 *upload_content = "";
768 // Even though the body is empty, Content-Type should be set to
769 // "text/plain". Otherwise, the server won't accept.
770 *upload_content_type = "text/plain";
771 return true;
772 }
773
774 DCHECK_EQ(UPLOAD_NEW_FILE, params_.upload_mode);
775 upload_content_type->assign("application/atom+xml");
776 XmlWriter xml_writer;
777 xml_writer.StartWriting();
778 xml_writer.StartElement("entry");
779 xml_writer.AddAttribute("xmlns", "http://www.w3.org/2005/Atom");
780 xml_writer.AddAttribute("xmlns:docs",
781 "http://schemas.google.com/docs/2007");
782 xml_writer.WriteElement("title", params_.title);
783 xml_writer.EndElement(); // Ends "entry" element.
784 xml_writer.StopWriting();
785 upload_content->assign(xml_writer.GetWrittenString());
786 DVLOG(1) << "Upload data: " << *upload_content_type << ", ["
787 << *upload_content << "]";
788 return true;
789 }
790
791 //============================ ResumeUploadOperation ===========================
792
793 ResumeUploadOperation::ResumeUploadOperation(
794 OperationRegistry* registry,
795 const ResumeUploadCallback& callback,
796 const ResumeUploadParams& params)
797 : UrlFetchOperationBase(registry,
798 OperationRegistry::OPERATION_UPLOAD,
799 params.virtual_path),
800 callback_(callback),
801 params_(params),
802 last_chunk_completed_(false) {
803 }
804
805 ResumeUploadOperation::~ResumeUploadOperation() {}
806
807 GURL ResumeUploadOperation::GetURL() const {
808 return params_.upload_location;
809 }
810
811 void ResumeUploadOperation::ProcessURLFetchResults(const URLFetcher* source) {
812 GDataErrorCode code = GetErrorCode(source);
813 net::HttpResponseHeaders* hdrs = source->GetResponseHeaders();
814 int64 start_range_received = -1;
815 int64 end_range_received = -1;
816 scoped_ptr<DocumentEntry> entry;
817
818 if (code == HTTP_RESUME_INCOMPLETE) {
819 // Retrieve value of the first "Range" header.
820 std::string range_received;
821 hdrs->EnumerateHeader(NULL, kUploadResponseRange, &range_received);
822 if (!range_received.empty()) { // Parse the range header.
823 std::vector<net::HttpByteRange> ranges;
824 if (net::HttpUtil::ParseRangeHeader(range_received, &ranges) &&
825 !ranges.empty() ) {
826 // We only care about the first start-end pair in the range.
827 start_range_received = ranges[0].first_byte_position();
828 end_range_received = ranges[0].last_byte_position();
829 }
830 }
831 DVLOG(1) << "Got response for [" << params_.virtual_path.value()
832 << "]: code=" << code
833 << ", range_hdr=[" << range_received
834 << "], range_parsed=" << start_range_received
835 << "," << end_range_received;
836 } else {
837 // There might be explanation of unexpected error code in response.
838 std::string response_content;
839 source->GetResponseAsString(&response_content);
840 DVLOG(1) << "Got response for [" << params_.virtual_path.value()
841 << "]: code=" << code
842 << ", content=[\n" << response_content << "\n]";
843
844 // Parse entry XML.
845 XmlReader xml_reader;
846 if (xml_reader.Load(response_content)) {
847 while (xml_reader.Read()) {
848 if (xml_reader.NodeName() == DocumentEntry::GetEntryNodeName()) {
849 entry.reset(DocumentEntry::CreateFromXml(&xml_reader));
850 break;
851 }
852 }
853 }
854 if (!entry.get())
855 LOG(WARNING) << "Invalid entry received on upload:\n" << response_content;
856 }
857
858 if (!callback_.is_null()) {
859 callback_.Run(ResumeUploadResponse(code,
860 start_range_received,
861 end_range_received),
862 entry.Pass());
863 }
864
865 // For a new file, HTTP_CREATED is returned.
866 // For an existing file, HTTP_SUCCESS is returned.
867 if ((params_.upload_mode == UPLOAD_NEW_FILE && code == HTTP_CREATED) ||
868 (params_.upload_mode == UPLOAD_EXISTING_FILE && code == HTTP_SUCCESS)) {
869 last_chunk_completed_ = true;
870 }
871
872 OnProcessURLFetchResultsComplete(
873 last_chunk_completed_ || code == HTTP_RESUME_INCOMPLETE);
874 }
875
876 void ResumeUploadOperation::NotifyStartToOperationRegistry() {
877 NotifyResume();
878 }
879
880 void ResumeUploadOperation::NotifySuccessToOperationRegistry() {
881 if (last_chunk_completed_)
882 NotifyFinish(OperationRegistry::OPERATION_COMPLETED);
883 else
884 NotifySuspend();
885 }
886
887 void ResumeUploadOperation::RunCallbackOnPrematureFailure(GDataErrorCode code) {
888 scoped_ptr<DocumentEntry> entry;
889 if (!callback_.is_null())
890 callback_.Run(ResumeUploadResponse(code, 0, 0), entry.Pass());
891 }
892
893 URLFetcher::RequestType ResumeUploadOperation::GetRequestType() const {
894 return URLFetcher::PUT;
895 }
896
897 std::vector<std::string> ResumeUploadOperation::GetExtraRequestHeaders() const {
898 if (params_.content_length == 0) {
899 // For uploading an empty document, just PUT an empty content.
900 DCHECK_EQ(params_.start_range, 0);
901 DCHECK_EQ(params_.end_range, -1);
902 return std::vector<std::string>();
903 }
904
905 // The header looks like
906 // Content-Range: bytes <start_range>-<end_range>/<content_length>
907 // for example:
908 // Content-Range: bytes 7864320-8388607/13851821
909 // Use * for unknown/streaming content length.
910 DCHECK_GE(params_.start_range, 0);
911 DCHECK_GE(params_.end_range, 0);
912 DCHECK_GE(params_.content_length, -1);
913
914 std::vector<std::string> headers;
915 headers.push_back(
916 std::string(kUploadContentRange) +
917 base::Int64ToString(params_.start_range) + "-" +
918 base::Int64ToString(params_.end_range) + "/" +
919 (params_.content_length == -1 ? "*" :
920 base::Int64ToString(params_.content_length)));
921 return headers;
922 }
923
924 bool ResumeUploadOperation::GetContentData(std::string* upload_content_type,
925 std::string* upload_content) {
926 *upload_content_type = params_.content_type;
927 *upload_content = std::string(params_.buf->data(),
928 params_.end_range - params_.start_range + 1);
929 return true;
930 }
931
932 void ResumeUploadOperation::OnURLFetchUploadProgress(
933 const URLFetcher* source, int64 current, int64 total) {
934 // Adjust the progress values according to the range currently uploaded.
935 NotifyProgress(params_.start_range + current, params_.content_length);
936 }
937
938 //========================== GetContactGroupsOperation =========================
939
940 GetContactGroupsOperation::GetContactGroupsOperation(
941 OperationRegistry* registry,
942 const GetDataCallback& callback)
943 : GetDataOperation(registry, callback) {
944 }
945
946 GetContactGroupsOperation::~GetContactGroupsOperation() {}
947
948 GURL GetContactGroupsOperation::GetURL() const {
949 return !feed_url_for_testing_.is_empty() ?
950 feed_url_for_testing_ :
951 GURL(kGetContactGroupsURL);
952 }
953
954 //============================ GetContactsOperation ============================
955
956 GetContactsOperation::GetContactsOperation(OperationRegistry* registry,
957 const std::string& group_id,
958 const base::Time& min_update_time,
959 const GetDataCallback& callback)
960 : GetDataOperation(registry, callback),
961 group_id_(group_id),
962 min_update_time_(min_update_time) {
963 }
964
965 GetContactsOperation::~GetContactsOperation() {}
966
967 GURL GetContactsOperation::GetURL() const {
968 if (!feed_url_for_testing_.is_empty())
969 return GURL(feed_url_for_testing_);
970
971 GURL url(kGetContactsURL);
972
973 if (!group_id_.empty()) {
974 url = chrome_common_net::AppendQueryParameter(
975 url, kGetContactsGroupParam, group_id_);
976 }
977 if (!min_update_time_.is_null()) {
978 std::string time_rfc3339 = util::FormatTimeAsString(min_update_time_);
979 url = chrome_common_net::AppendQueryParameter(
980 url, kGetContactsUpdatedMinParam, time_rfc3339);
981 }
982 return url;
983 }
984
985 //========================== GetContactPhotoOperation ==========================
986
987 GetContactPhotoOperation::GetContactPhotoOperation(
988 OperationRegistry* registry,
989 const GURL& photo_url,
990 const GetContentCallback& callback)
991 : UrlFetchOperationBase(registry),
992 photo_url_(photo_url),
993 callback_(callback) {
994 }
995
996 GetContactPhotoOperation::~GetContactPhotoOperation() {}
997
998 GURL GetContactPhotoOperation::GetURL() const {
999 return photo_url_;
1000 }
1001
1002 void GetContactPhotoOperation::ProcessURLFetchResults(
1003 const net::URLFetcher* source) {
1004 GDataErrorCode code = static_cast<GDataErrorCode>(source->GetResponseCode());
1005 scoped_ptr<std::string> data(new std::string);
1006 source->GetResponseAsString(data.get());
1007 callback_.Run(code, data.Pass());
1008 OnProcessURLFetchResultsComplete(code == HTTP_SUCCESS);
1009 }
1010
1011 void GetContactPhotoOperation::RunCallbackOnPrematureFailure(
1012 GDataErrorCode code) {
1013 scoped_ptr<std::string> data(new std::string);
1014 callback_.Run(code, data.Pass());
1015 }
1016
1017 } // namespace gdata
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/gdata/gdata_operations.h ('k') | chrome/browser/chromeos/gdata/gdata_operations_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698