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

Side by Side Diff: native_client_sdk/src/examples/demo/drive/drive.cc

Issue 14500010: [NaCl SDK] Google Drive example (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 7 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) 2013 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 <ctype.h>
6 #include <stdio.h>
7 #include <string.h>
8
9 #include <string>
10 #include <vector>
11
12 #include "ppapi/c/pp_errors.h"
13 #include "ppapi/cpp/completion_callback.h"
14 #include "ppapi/cpp/instance.h"
15 #include "ppapi/cpp/module.h"
16 #include "ppapi/cpp/url_loader.h"
17 #include "ppapi/cpp/url_request_info.h"
18 #include "ppapi/cpp/url_response_info.h"
19 #include "ppapi/cpp/var.h"
20 #include "ppapi/utility/completion_callback_factory.h"
21
22 #include "json/reader.h"
23 #include "json/writer.h"
24
25 static const char kTokenMessage[] = "token:";
26 static const char kGetFileMessage[] = "getFile";
27 static const char kBoundary[] = "NACL_BOUNDARY_600673";
28
29
30 static std::string EncodeUriComponent(const std::string& s) {
31 char hex[] = "0123456789ABCDEF";
32 std::string result;
33 for (size_t i = 0; i < s.length(); ++i) {
34 char c = s[i];
35 if (isalpha(c) || isdigit(c) || strchr("-_.!~*'()", c)) {
36 result += c;
37 } else {
38 result += '%';
39 result += hex[(c >> 4) & 0xf];
40 result += hex[c & 0xf];
41 }
42 }
43 return result;
44 }
45
46 static std::string IntToString(int x) {
47 char buffer[32];
48 snprintf(&buffer[0], 32, "%d", x);
49 return &buffer[0];
50 }
51
52 static void AddQueryParameter(std::string* s,
53 const std::string& key,
54 const std::string& value,
55 bool first) {
56 *s += first ? '?' : '&';
57 *s += EncodeUriComponent(key);
58 *s += '=';
59 *s += EncodeUriComponent(value);
60 }
61
62 static void AddQueryParameter(std::string* s,
63 const std::string& key,
64 int value,
65 bool first) {
66 AddQueryParameter(s, key, IntToString(value), first);
67 }
68
69 static void AddAuthTokenHeader(std::string* s, const std::string& auth_token) {
70 *s += "Authorization: Bearer ";
71 *s += auth_token;
72 *s += "\n";
73 }
74
75 static void AddHeader(std::string* s,
76 const char* key,
77 const std::string& value) {
78 *s += key;
79 *s += ": ";
80 *s += value;
81 *s += "\n";
82 }
83
84 //
85 // UrlReader
86 //
87 struct UrlReaderParams {
88 std::string url;
89 std::string method;
90 std::string request_headers;
91 std::string request_body;
92 };
93
94 class UrlReaderDelegate {
95 public:
96 virtual void OnReadSucceeded(const std::string& output) = 0;
97 virtual void OnReadFailed(int32_t result) = 0;
98 };
99
100 class UrlReader {
101 public:
102 static UrlReader* Create(pp::Instance* instance,
103 const UrlReaderParams& params,
104 UrlReaderDelegate* delegate);
105 ~UrlReader();
106
107 void Run();
108
109 private:
110 UrlReader(pp::Instance* instance,
111 const UrlReaderParams& params,
112 UrlReaderDelegate* delegate);
113
114 static const int32_t kReadBufferSize = 16 * 1024;
115
116 void InitRequestInfo();
117 void OnOpen(int32_t result);
118 void ReadBody();
119 void OnRead(int32_t result);
120 void AppendDataBytes(int32_t num_bytes);
121
122 void Success();
123 void Failure(int32_t result);
124
125 pp::Instance* instance_; // Weak pointer.
126 pp::URLRequestInfo url_request_;
127 pp::URLLoader url_loader_;
128 pp::CompletionCallbackFactory<UrlReader> cc_factory_;
129 UrlReaderParams params_;
130 UrlReaderDelegate* delegate_; // Weak pointer.
131
132 uint8_t* buffer_;
133 std::string response_body_;
134 };
135
136 // static
137 UrlReader* UrlReader::Create(pp::Instance* instance,
138 const UrlReaderParams& params,
139 UrlReaderDelegate* delegate) {
140 return new UrlReader(instance, params, delegate);
141 }
142
143 UrlReader::UrlReader(pp::Instance* instance,
144 const UrlReaderParams& params,
145 UrlReaderDelegate* delegate)
146 : instance_(instance),
147 url_request_(instance),
148 url_loader_(instance),
149 cc_factory_(this),
150 params_(params),
151 delegate_(delegate),
152 buffer_(new uint8_t[kReadBufferSize]) {}
153
154 UrlReader::~UrlReader() { delete[] buffer_; }
155
156 void UrlReader::Run() {
157 InitRequestInfo();
158 pp::CompletionCallback cc = cc_factory_.NewCallback(&UrlReader::OnOpen);
159 url_loader_.Open(url_request_, cc);
160 }
161
162 void UrlReader::InitRequestInfo() {
163 url_request_.SetURL(params_.url);
164 url_request_.SetMethod(params_.method);
165 url_request_.SetHeaders(params_.request_headers);
166 url_request_.SetRecordDownloadProgress(true);
167 if (params_.request_body.size()) {
168 url_request_.AppendDataToBody(params_.request_body.data(),
169 params_.request_body.size());
170 }
171 }
172
173 void UrlReader::OnOpen(int32_t result) {
174 if (result != PP_OK)
175 return Failure(result);
176
177 pp::URLResponseInfo url_response = url_loader_.GetResponseInfo();
178 if (url_response.GetStatusCode() != 200)
179 return Failure(PP_ERROR_FAILED);
180
181 int64_t bytes_received = 0;
182 int64_t total_bytes_to_be_received = 0;
183 if (url_loader_.GetDownloadProgress(&bytes_received,
184 &total_bytes_to_be_received)) {
185 if (total_bytes_to_be_received > 0) {
186 response_body_.reserve(total_bytes_to_be_received);
187 }
188 }
189
190 url_request_.SetRecordDownloadProgress(false);
191 ReadBody();
192 }
193
194 void UrlReader::ReadBody() {
195 pp::CompletionCallback cc =
196 cc_factory_.NewOptionalCallback(&UrlReader::OnRead);
197 int32_t result = PP_OK;
198 do {
199 result = url_loader_.ReadResponseBody(buffer_, kReadBufferSize, cc);
200 if (result > 0) {
201 AppendDataBytes(result);
202 }
203 } while (result > 0);
204
205 if (result != PP_OK_COMPLETIONPENDING) {
206 cc.Run(result);
207 }
208 }
209
210 void UrlReader::OnRead(int32_t result) {
211 if (result < 0)
212 return Failure(result);
213
214 if (result == 0) {
215 Success();
216 } else if (result > 0) {
217 AppendDataBytes(result);
218 ReadBody();
219 }
220 }
221
222 void UrlReader::AppendDataBytes(int32_t num_bytes) {
223 num_bytes = num_bytes > kReadBufferSize ? kReadBufferSize : num_bytes;
224 response_body_.insert(response_body_.end(), buffer_, buffer_ + num_bytes);
225 }
226
227 void UrlReader::Success() {
228 delegate_->OnReadSucceeded(response_body_);
229 delete this;
230 }
231
232 void UrlReader::Failure(int32_t result) {
233 delegate_->OnReadFailed(result);
234 delete this;
235 }
236
237 //
238 // FilesList
239 //
240 struct FilesListParams {
241 int max_results;
242 std::string page_token;
243 std::string q;
244 };
245
246 class FilesListDelegate {
247 public:
248 virtual void OnFilesListSucceeded(const Json::Value& url) = 0;
249 virtual void OnFilesListFailed(int32_t result) = 0;
250 };
251
252 class FilesList : public UrlReaderDelegate {
253 public:
254 static FilesList* Create(pp::Instance* instance,
255 const std::string& auth_token,
256 const FilesListParams& params,
257 FilesListDelegate* delegate);
258 ~FilesList();
259
260 void Run();
261 virtual void OnReadSucceeded(const std::string& output);
262 virtual void OnReadFailed(int32_t result);
263
264 private:
265 FilesList(pp::Instance* instance,
266 const std::string& auth_token,
267 const FilesListParams& params,
268 FilesListDelegate* delegate);
269
270 pp::Instance* instance_; // Weak pointer.
271 std::string auth_token_;
272 FilesListParams params_;
273 FilesListDelegate* delegate_; // Weak pointer.
274 };
275
276 // static
277 FilesList* FilesList::Create(pp::Instance* instance,
278 const std::string& auth_token,
279 const FilesListParams& params,
280 FilesListDelegate* delegate) {
281 return new FilesList(instance, auth_token, params, delegate);
282 }
283
284 FilesList::FilesList(pp::Instance* instance,
285 const std::string& auth_token,
286 const FilesListParams& params,
287 FilesListDelegate* delegate)
288 : instance_(instance),
289 auth_token_(auth_token),
290 params_(params),
291 delegate_(delegate) {}
292
293 FilesList::~FilesList() {}
294
295 void FilesList::Run() {
296 static const char base_url[] = "https://www.googleapis.com/drive/v2/files";
297
298 UrlReaderParams p;
299 p.method = "GET";
300 p.url = base_url;
301 AddQueryParameter(&p.url, "maxResults", params_.max_results, true);
302 if (params_.page_token.length())
303 AddQueryParameter(&p.url, "pageToken", params_.page_token, false);
304 AddQueryParameter(&p.url, "q", params_.q, false);
305 AddAuthTokenHeader(&p.request_headers, auth_token_);
306 UrlReader* url_reader = UrlReader::Create(instance_, p, this);
307 url_reader->Run();
308 }
309
310 void FilesList::OnReadSucceeded(const std::string& output) {
311 Json::Reader reader(Json::Features::strictMode());
312 Json::Value value;
313 if (!reader.parse(output, value, false)) {
314 printf("Couldn't parse JSON!\n");
315 delegate_->OnFilesListFailed(PP_ERROR_FAILED);
316 delete this;
317 }
318
319 delegate_->OnFilesListSucceeded(value);
320 delete this;
321 }
322
323 void FilesList::OnReadFailed(int32_t result) {
324 delegate_->OnFilesListFailed(result);
325 delete this;
326 }
327
328 //
329 // FilesInsert
330 //
331 struct FilesInsertParams {
332 std::string file_id;
333 std::string content;
334 std::string description;
335 std::string mime_type;
336 std::string title;
337 };
338
339 class FilesInsertDelegate {
340 public:
341 virtual void OnFilesInsertSucceeded(const Json::Value& url) = 0;
342 virtual void OnFilesInsertFailed(int32_t result) = 0;
343 };
344
345 class FilesInsert : public UrlReaderDelegate {
346 public:
347 static FilesInsert* Create(pp::Instance* instance,
348 const std::string& auth_token,
349 const FilesInsertParams& params,
350 FilesInsertDelegate* delegate);
351 ~FilesInsert();
352
353 void Run();
354 virtual void OnReadSucceeded(const std::string& output);
355 virtual void OnReadFailed(int32_t result);
356
357 private:
358 FilesInsert(pp::Instance* instance,
359 const std::string& auth_token,
360 const FilesInsertParams& params,
361 FilesInsertDelegate* delegate);
362
363 std::string BuildRequestBody();
364
365 pp::Instance* instance_; // Weak pointer.
366 std::string auth_token_;
367 FilesInsertParams params_;
368 FilesInsertDelegate* delegate_; // Weak pointer.
369 };
370
371 // static
372 FilesInsert* FilesInsert::Create(pp::Instance* instance,
373 const std::string& auth_token,
374 const FilesInsertParams& params,
375 FilesInsertDelegate* delegate) {
376 return new FilesInsert(instance, auth_token, params, delegate);
377 }
378
379 FilesInsert::FilesInsert(pp::Instance* instance,
380 const std::string& auth_token,
381 const FilesInsertParams& params,
382 FilesInsertDelegate* delegate)
383 : instance_(instance),
384 auth_token_(auth_token),
385 params_(params),
386 delegate_(delegate) {}
387
388 FilesInsert::~FilesInsert() {}
389
390 void FilesInsert::Run() {
391 static const char base_url[] =
392 "https://www.googleapis.com/upload/drive/v2/files";
393 const char* method = "POST";
394
395 UrlReaderParams p;
396 p.url = base_url;
397
398 // If file_id is defined, we are actually updating an existing file.
399 if (!params_.file_id.empty()) {
400 p.url += "/";
401 p.url += params_.file_id;
402 p.method = "PUT";
403 } else {
404 p.method = "POST";
405 }
406
407 AddQueryParameter(&p.url, "uploadType", "multipart", true);
408 AddAuthTokenHeader(&p.request_headers, auth_token_);
409 AddHeader(&p.request_headers,
410 "Content-Type",
411 std::string("multipart/related; boundary=") + kBoundary + "\n");
412 p.request_body = BuildRequestBody();
413 UrlReader* url_reader = UrlReader::Create(instance_, p, this);
414 url_reader->Run();
415 }
416
417 void FilesInsert::OnReadSucceeded(const std::string& output) {
418 Json::Reader reader(Json::Features::strictMode());
419 Json::Value value;
420 if (!reader.parse(output, value, false)) {
421 printf("Couldn't parse JSON!\n");
422 delegate_->OnFilesInsertFailed(PP_ERROR_FAILED);
423 delete this;
424 }
425
426 delegate_->OnFilesInsertSucceeded(value);
427 delete this;
428 }
429
430 void FilesInsert::OnReadFailed(int32_t result) {
431 delegate_->OnFilesInsertFailed(result);
432 delete this;
433 }
434
435 std::string FilesInsert::BuildRequestBody() {
436 std::string result;
437 result += "--";
438 result += kBoundary;
439 result += "\nContent-Type: application/json; charset=UTF-8\n\n";
440
441 Json::Value value(Json::objectValue);
442 value["description"] = Json::Value(params_.description);
443 value["mimeType"] = Json::Value(params_.mime_type);
444 value["title"] = Json::Value(params_.title);
445 Json::FastWriter writer;
446 std::string metadata = writer.write(value);
447
448 result += metadata;
449 result += "--";
450 result += kBoundary;
451 result += "\nContent-Type: ";
452 result += params_.mime_type;
453 result += "\n\n";
454 result += params_.content;
455 result += "\n--";
456 result += kBoundary;
457 result += "--";
458 return result;
459 }
460
461 //
462 // Instance
463 //
464 class Instance : public pp::Instance,
465 public UrlReaderDelegate,
466 public FilesListDelegate,
467 public FilesInsertDelegate {
468 public:
469 explicit Instance(PP_Instance instance);
470 virtual ~Instance();
471 virtual void HandleMessage(const pp::Var& var_message);
472
473 virtual void OnFilesListSucceeded(const Json::Value& root);
474 virtual void OnFilesListFailed(int32_t result);
475
476 virtual void OnReadSucceeded(const std::string& output);
477 virtual void OnReadFailed(int32_t result);
478
479 virtual void OnFilesInsertSucceeded(const Json::Value& root);
480 virtual void OnFilesInsertFailed(int32_t result);
481
482 private:
483 bool GetFirstItemStringValue(const Json::Value& root,
484 const char* key,
485 std::string* out);
486 void GetFileMetadata(const char* title);
487 void DownloadFile(const std::string& download_url);
488 void InsertFile(const char* title,
489 const char* description,
490 const char* content);
491
492 std::string auth_token_;
493 };
494
495 Instance::Instance(PP_Instance instance) : pp::Instance(instance) {}
496
497 Instance::~Instance() {}
498
499 void Instance::HandleMessage(const pp::Var& var_message) {
500 if (!var_message.is_string()) {
501 return;
502 }
503
504 std::string message = var_message.AsString();
505 if (!strncmp(message.c_str(), kTokenMessage, strlen(kTokenMessage))) {
506 // Auth token
507 auth_token_ = message.c_str() + strlen(kTokenMessage);
508 printf("Auth token: %s\n", auth_token_.c_str());
509 } else if (!strncmp(
510 message.c_str(), kGetFileMessage, strlen(kGetFileMessage))) {
511 // getFile
512 printf("Getting file...\n");
513 GetFileMetadata("hello nacl.txt");
514 }
515 }
516
517 void Instance::OnFilesListSucceeded(const Json::Value& root) {
518 // Extract the download URL...
519 std::string download_url;
520 if (GetFirstItemStringValue(root, "downloadUrl", &download_url)) {
521 // Read the file...
522 printf("got a download url: %s\n", download_url.c_str());
523 DownloadFile(download_url);
524 } else {
525 // Insert a new file instead!
526 InsertFile(
527 "hello nacl.txt", "A file generated by NaCl!", "Hello, Google Drive!");
528 }
529 }
530
531 void Instance::OnFilesListFailed(int32_t result) {
532 printf("drive.files.list failed with result %d\n", result);
533 }
534
535 void Instance::OnReadSucceeded(const std::string& output) {
536 PostMessage(output);
537 }
538
539 void Instance::OnReadFailed(int32_t result) {
540 printf("Reading download URL failed with result %d\n", result);
541 }
542
543 void Instance::OnFilesInsertSucceeded(const Json::Value& root) {
544 // Extract the download URL...
545 std::string download_url;
546 if (GetFirstItemStringValue(root, "downloadUrl", &download_url)) {
547 // Read the file...
548 printf("got a download url: %s\n", download_url.c_str());
549 DownloadFile(download_url);
550 } else {
551 printf("Inserted a file, but it doesn't have a downloadUrl?\n");
552 }
553 }
554
555 void Instance::OnFilesInsertFailed(int32_t result) {
556 printf("Inserting file failed with result %d\n", result);
557 }
558
559 bool Instance::GetFirstItemStringValue(const Json::Value& root,
560 const char* key,
561 std::string* out) {
562 if (!root.isMember("items")) {
563 printf("No items...\n");
564 return false;
565 }
566
567 Json::Value items = root["items"];
568 if (!items.isValidIndex(0)) {
569 printf("Expected items[0] to be valid.\n");
570 return false;
571 }
572
573 Json::Value first_item = items[0U];
574 if (!first_item.isMember(key)) {
575 printf("Expected items[0].%s to be valid.\n", key);
576 return false;
577 }
578
579 Json::Value value = first_item[key];
580 if (!value.isString()) {
581 printf("Expected items[0].%s to be a string.\n", key);
582 return false;
583 }
584
585 *out = value.asString();
586 return true;
587 }
588
589 void Instance::GetFileMetadata(const char* filename) {
590 FilesListParams p;
591 p.max_results = 1;
592 p.q = "title = \'";
593 p.q += filename;
594 p.q += "\'";
595 FilesList* func = FilesList::Create(this, auth_token_, p, this);
596 func->Run();
597 }
598
599 void Instance::InsertFile(const char* title,
600 const char* description,
601 const char* content) {
602 FilesInsertParams p;
603 p.content = content;
604 p.description = description;
605 p.mime_type = "text/plain";
606 p.title = title;
607 FilesInsert* func = FilesInsert::Create(this, auth_token_, p, this);
608 func->Run();
609 }
610
611 void Instance::DownloadFile(const std::string& download_url) {
612 UrlReaderParams p;
613 p.method = "GET";
614 p.url = download_url;
615 AddAuthTokenHeader(&p.request_headers, auth_token_);
616 UrlReader* url_reader = UrlReader::Create(this, p, this);
617 url_reader->Run();
618 }
619
620 class Module : public pp::Module {
621 public:
622 Module() : pp::Module() {}
623 virtual ~Module() {}
624
625 virtual pp::Instance* CreateInstance(PP_Instance instance) {
626 return new Instance(instance);
627 }
628 };
629
630 namespace pp {
631
632 Module* CreateModule() { return new ::Module(); }
633
634 } // namespace pp
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698