190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved. 290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// found in the LICENSE file. 490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <ctype.h> 690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <stdarg.h> 790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <stdio.h> 890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <string.h> 990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 1090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <string> 1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <vector> 1290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 1390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "json/reader.h" 1490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "json/writer.h" 1590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ppapi/c/pp_errors.h" 1690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ppapi/cpp/completion_callback.h" 1790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ppapi/cpp/instance.h" 1890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ppapi/cpp/module.h" 1990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ppapi/cpp/url_loader.h" 2090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ppapi/cpp/url_request_info.h" 2190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ppapi/cpp/url_response_info.h" 2290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ppapi/cpp/var.h" 2390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ppapi/utility/completion_callback_factory.h" 2490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ppapi/utility/threading/simple_thread.h" 2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace { 2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 2890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// When we upload files, we also upload the metadata at the same time. To do so, 2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// we use the mimetype multipart/related. This mimetype requires specifying a 3090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// boundary between the JSON metadata and the file content. 3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const char kBoundary[] = "NACL_BOUNDARY_600673"; 3290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// This is a simple implementation of JavaScript's encodeUriComponent. We 3490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// assume the data is already UTF-8. See 3590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/encodeURIComponent. 3690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)std::string EncodeUriComponent(const std::string& s) { 3790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) char hex[] = "0123456789ABCDEF"; 3890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string result; 3990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) for (size_t i = 0; i < s.length(); ++i) { 4090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) char c = s[i]; 4190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (isalpha(c) || isdigit(c) || strchr("-_.!~*'()", c)) { 4290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) result += c; 4390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } else { 4490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) result += '%'; 4590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) result += hex[(c >> 4) & 0xf]; 4690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) result += hex[c & 0xf]; 4790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 4890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 4990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return result; 5090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 5190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 5290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)std::string IntToString(int x) { 5390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) char buffer[32]; 5490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) snprintf(&buffer[0], 32, "%d", x); 5590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return &buffer[0]; 5690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 5790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 5890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void AddQueryParameter(std::string* s, 5990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const std::string& key, 6090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const std::string& value, 6190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) bool first) { 6290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *s += first ? '?' : '&'; 6390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *s += EncodeUriComponent(key); 6490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *s += '='; 6590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *s += EncodeUriComponent(value); 6690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 6790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 6890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void AddQueryParameter(std::string* s, 6990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const std::string& key, 7090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int value, 7190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) bool first) { 7290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) AddQueryParameter(s, key, IntToString(value), first); 7390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 7490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void AddAuthTokenHeader(std::string* s, const std::string& auth_token) { 7690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *s += "Authorization: Bearer "; 7790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *s += auth_token; 7890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *s += "\n"; 7990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 8090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 8190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void AddHeader(std::string* s, const char* key, const std::string& value) { 8290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *s += key; 8390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *s += ": "; 8490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *s += value; 8590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *s += "\n"; 8690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 8790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 8890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} // namespace 8990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 9090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// 9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// ReadUrl 9290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// 9390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)struct ReadUrlParams { 9490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string url; 9590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string method; 9690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string request_headers; 9790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string request_body; 9890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}; 9990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 10090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// This function blocks so it needs to be called off the main thread. 10190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)int32_t ReadUrl(pp::Instance* instance, 10290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const ReadUrlParams& params, 10390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string* output) { 10490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) pp::URLRequestInfo url_request(instance); 10590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) pp::URLLoader url_loader(instance); 10690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 10790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) url_request.SetURL(params.url); 10890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) url_request.SetMethod(params.method); 10990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) url_request.SetHeaders(params.request_headers); 11090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) url_request.SetRecordDownloadProgress(true); 11190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (params.request_body.size()) { 11290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) url_request.AppendDataToBody(params.request_body.data(), 11390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) params.request_body.size()); 11490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 11590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 11690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int32_t result = url_loader.Open(url_request, pp::BlockUntilComplete()); 11790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (result != PP_OK) { 11890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return result; 11990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 12090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 12190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) pp::URLResponseInfo url_response = url_loader.GetResponseInfo(); 12290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (url_response.GetStatusCode() != 200) 12390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return PP_ERROR_FAILED; 12490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 12590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) output->clear(); 12690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 12790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int64_t bytes_received = 0; 12890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int64_t total_bytes_to_be_received = 0; 12990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (url_loader.GetDownloadProgress(&bytes_received, 13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) &total_bytes_to_be_received)) { 13190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (total_bytes_to_be_received > 0) { 13290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) output->reserve(total_bytes_to_be_received); 13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 13490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 13590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 13690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) url_request.SetRecordDownloadProgress(false); 13790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 138ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch const int32_t kReadBufferSize = 16 * 1024; 13990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) uint8_t* buffer_ = new uint8_t[kReadBufferSize]; 14090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 14190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) do { 14290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) result = url_loader.ReadResponseBody( 14390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) buffer_, kReadBufferSize, pp::BlockUntilComplete()); 14490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (result > 0) { 14590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) assert(result <= kReadBufferSize); 14690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) size_t num_bytes = result; 14790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) output->insert(output->end(), buffer_, buffer_ + num_bytes); 14890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 14990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } while (result > 0); 15090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 15190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) delete[] buffer_; 15290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 15390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return result; 15490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 15590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 15690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// 15790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// ListFiles 15890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// 15990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// This is a simplistic implementation of the files.list method defined here: 16090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// https://developers.google.com/drive/v2/reference/files/list 16190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// 16290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)struct ListFilesParams { 16390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int max_results; 16490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string page_token; 16590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string query; 16690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}; 16790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 16890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)int32_t ListFiles(pp::Instance* instance, 16990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const std::string& auth_token, 17090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const ListFilesParams& params, 17190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Json::Value* root) { 17290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) static const char base_url[] = "https://www.googleapis.com/drive/v2/files"; 17390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 17490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) ReadUrlParams p; 17590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) p.method = "GET"; 17690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) p.url = base_url; 17790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) AddQueryParameter(&p.url, "maxResults", params.max_results, true); 17890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (params.page_token.length()) 17990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) AddQueryParameter(&p.url, "pageToken", params.page_token, false); 18090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) AddQueryParameter(&p.url, "q", params.query, false); 18190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Request a "partial response". See 18290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // https://developers.google.com/drive/performance#partial for more 18390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // information. 18490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) AddQueryParameter(&p.url, "fields", "items(id,downloadUrl)", false); 18590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) AddAuthTokenHeader(&p.request_headers, auth_token); 18690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 18790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string output; 18890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int32_t result = ReadUrl(instance, p, &output); 18990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (result != PP_OK) { 19090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return result; 19190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 19290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 19390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Json::Reader reader(Json::Features::strictMode()); 19490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!reader.parse(output, *root, false)) { 19590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return PP_ERROR_FAILED; 19690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 19790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 19890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return PP_OK; 19990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 20090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 20190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// 20290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// InsertFile 20390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// 20490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// This is a simplistic implementation of the files.update and files.insert 20590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// methods defined here: 20690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// https://developers.google.com/drive/v2/reference/files/insert 20790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// https://developers.google.com/drive/v2/reference/files/update 20890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// 20990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)struct InsertFileParams { 21090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // If file_id is empty, create a new file (files.insert). If file_id is not 21190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // empty, update that file (files.update) 21290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string file_id; 21390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string content; 21490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string description; 21590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string mime_type; 21690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string title; 21790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}; 21890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 21990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)std::string BuildRequestBody(const InsertFileParams& params) { 22090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // This generates the multipart-upload request body for InsertFile. See 22190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // https://developers.google.com/drive/manage-uploads#multipart for more 22290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // information. 22390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string result; 22490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) result += "--"; 22590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) result += kBoundary; 22690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) result += "\nContent-Type: application/json; charset=UTF-8\n\n"; 22790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 22890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Json::Value value(Json::objectValue); 22990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!params.description.empty()) 23090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) value["description"] = Json::Value(params.description); 23190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 23290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!params.mime_type.empty()) 23390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) value["mimeType"] = Json::Value(params.mime_type); 23490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 23590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!params.title.empty()) 23690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) value["title"] = Json::Value(params.title); 23790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 23890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Json::FastWriter writer; 23990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string metadata = writer.write(value); 24090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 24190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) result += metadata; 24290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) result += "--"; 24390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) result += kBoundary; 24490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) result += "\nContent-Type: "; 24590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) result += params.mime_type; 24690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) result += "\n\n"; 24790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) result += params.content; 24890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) result += "\n--"; 24990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) result += kBoundary; 25090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) result += "--"; 25190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return result; 25290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 25390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 25490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)int32_t InsertFile(pp::Instance* instance, 25590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const std::string& auth_token, 25690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const InsertFileParams& params, 25790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Json::Value* root) { 25890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) static const char base_url[] = 25990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) "https://www.googleapis.com/upload/drive/v2/files"; 26090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 26190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) ReadUrlParams p; 26290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) p.url = base_url; 26390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 26490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // If file_id is defined, we are actually updating an existing file. 26590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!params.file_id.empty()) { 26690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) p.url += "/"; 26790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) p.url += params.file_id; 26890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) p.method = "PUT"; 26990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } else { 27090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) p.method = "POST"; 27190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 27290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 27390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // We always use the multipart upload interface, but see 27490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // https://developers.google.com/drive/manage-uploads for other 27590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // options. 27690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) AddQueryParameter(&p.url, "uploadType", "multipart", true); 27790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Request a "partial response". See 27890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // https://developers.google.com/drive/performance#partial for more 27990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // information. 28090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) AddQueryParameter(&p.url, "fields", "id,downloadUrl", false); 28190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) AddAuthTokenHeader(&p.request_headers, auth_token); 28290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) AddHeader(&p.request_headers, 28390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) "Content-Type", 28490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string("multipart/related; boundary=") + kBoundary + "\n"); 28590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) p.request_body = BuildRequestBody(params); 28690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 28790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string output; 28890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int32_t result = ReadUrl(instance, p, &output); 28990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (result != PP_OK) { 29090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return result; 29190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 29290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 29390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Json::Reader reader(Json::Features::strictMode()); 29490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!reader.parse(output, *root, false)) { 29590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return PP_ERROR_FAILED; 29690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 29790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 29890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return PP_OK; 29990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 30090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 30190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// 30290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Instance 30390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// 30490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)class Instance : public pp::Instance { 30590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) public: 30690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Instance(PP_Instance instance); 30790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]); 30890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) virtual void HandleMessage(const pp::Var& var_message); 30990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 31090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) void PostMessagef(const char* format, ...); 31190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 31290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) private: 31390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) void ThreadSetAuthToken(int32_t, const std::string& auth_token); 31490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) void ThreadRequestThunk(int32_t); 31590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) bool ThreadRequest(); 31690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) bool ThreadGetFileMetadata(const char* title, Json::Value* metadata); 31790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) bool ThreadCreateFile(const char* title, 31890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const char* description, 31990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const char* content, 32090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Json::Value* metadata); 32190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) bool ThreadUpdateFile(const std::string& file_id, 32290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const std::string& content, 32390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Json::Value* metadata); 32490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) bool ThreadDownloadFile(const Json::Value& metadata, std::string* output); 32590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) bool GetMetadataKey(const Json::Value& metadata, 32690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const char* key, 32790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string* output); 32890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 32990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) pp::SimpleThread worker_thread_; 33090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) pp::CompletionCallbackFactory<Instance> callback_factory_; 33190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string auth_token_; 33290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) bool is_processing_request_; 33390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}; 33490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 33590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)Instance::Instance(PP_Instance instance) 33690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) : pp::Instance(instance), 33790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) worker_thread_(this), 338ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch callback_factory_(this), 33990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) is_processing_request_(false) {} 34090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 34190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool Instance::Init(uint32_t /*argc*/, 34290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const char * [] /*argn*/, 34390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const char * [] /*argv*/) { 34490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) worker_thread_.Start(); 34590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return true; 34690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 34790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 34890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void Instance::HandleMessage(const pp::Var& var_message) { 34990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const char kTokenMessage[] = "token:"; 35090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const size_t kTokenMessageLen = strlen(kTokenMessage); 35190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const char kGetFileMessage[] = "getFile"; 35290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 35390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!var_message.is_string()) { 35490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return; 35590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 35690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 35790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string message = var_message.AsString(); 35890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) printf("Got message: \"%s\"\n", message.c_str()); 35990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (message.compare(0, kTokenMessageLen, kTokenMessage) == 0) { 36090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Auth token 36190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string auth_token = message.substr(kTokenMessageLen); 36290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) worker_thread_.message_loop().PostWork(callback_factory_.NewCallback( 36390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) &Instance::ThreadSetAuthToken, auth_token)); 36490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } else if (message == kGetFileMessage) { 36590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Request 36690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!is_processing_request_) { 36790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) is_processing_request_ = true; 36890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) worker_thread_.message_loop().PostWork( 36990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) callback_factory_.NewCallback(&Instance::ThreadRequestThunk)); 37090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 37190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 37290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 37390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 37490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void Instance::PostMessagef(const char* format, ...) { 37590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const size_t kBufferSize = 1024; 37690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) char buffer[kBufferSize]; 37790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) va_list args; 37890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) va_start(args, format); 37990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) vsnprintf(&buffer[0], kBufferSize, format, args); 38090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 38190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) PostMessage(buffer); 38290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 38390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 38490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void Instance::ThreadSetAuthToken(int32_t /*result*/, 38590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const std::string& auth_token) { 38690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) printf("Got auth token: %s\n", auth_token.c_str()); 38790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) auth_token_ = auth_token; 38890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 38990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 39090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void Instance::ThreadRequestThunk(int32_t /*result*/) { 39190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) ThreadRequest(); 39290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) is_processing_request_ = false; 39390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 39490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 39590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool Instance::ThreadRequest() { 39690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) static int request_count = 0; 39790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) static const char kTitle[] = "hello nacl.txt"; 39890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Json::Value metadata; 39990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string output; 40090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 40190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) PostMessagef("log:\n Got request (#%d).\n", ++request_count); 40290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) PostMessagef("log: Looking for file: \"%s\".\n", kTitle); 40390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 40490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!ThreadGetFileMetadata(kTitle, &metadata)) { 40590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) PostMessage("log: Not found! Creating a new file...\n"); 40690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // No data found, write a new file. 40790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) static const char kDescription[] = "A file generated by NaCl!"; 40890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) static const char kInitialContent[] = "Hello, Google Drive!"; 40990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 41090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!ThreadCreateFile(kTitle, kDescription, kInitialContent, &metadata)) { 41190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) PostMessage("log: Creating the new file failed...\n"); 41290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return false; 41390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 41490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } else { 41590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) PostMessage("log: Found it! Downloading the file...\n"); 41690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Found the file, download it's data. 41790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!ThreadDownloadFile(metadata, &output)) { 41890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) PostMessage("log: Downloading the file failed...\n"); 41990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return false; 42090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 42190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 42290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Modify it. 42390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) output += "\nHello, again Google Drive!"; 42490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 42590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string file_id; 42690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!GetMetadataKey(metadata, "id", &file_id)) { 42790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) PostMessage("log: Couldn't find the file id...\n"); 42890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return false; 42990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 43090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 43190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) PostMessage("log: Updating the file...\n"); 43290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!ThreadUpdateFile(file_id, output, &metadata)) { 43390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) PostMessage("log: Failed to update the file...\n"); 43490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return false; 43590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 43690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 43790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 43890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) PostMessage("log: Done!\n"); 43990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) PostMessage("log: Downloading the newly written file...\n"); 44090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!ThreadDownloadFile(metadata, &output)) { 44190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) PostMessage("log: Downloading the file failed...\n"); 44290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return false; 44390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 44490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 44590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) PostMessage("log: Done!\n"); 44690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) PostMessage(output); 44790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return true; 44890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 44990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 45090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool Instance::ThreadGetFileMetadata(const char* title, Json::Value* metadata) { 45190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) ListFilesParams p; 45290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) p.max_results = 1; 45390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) p.query = "title = \'"; 45490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) p.query += title; 45590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) p.query += "\'"; 45690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 45790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Json::Value root; 45890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int32_t result = ListFiles(this, auth_token_, p, &root); 45990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (result != PP_OK) { 46090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) PostMessagef("log: ListFiles failed with result %d\n", result); 46190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return false; 46290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 46390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 46490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Extract the first item's metadata. 46590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!root.isMember("items")) { 46690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) PostMessage("log: ListFiles returned no items...\n"); 46790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return false; 46890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 46990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 47090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Json::Value items = root["items"]; 47190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!items.isValidIndex(0)) { 47290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) PostMessage("log: Expected items[0] to be valid.\n"); 47390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return false; 47490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 47590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 47690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *metadata = items[0U]; 47790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return true; 47890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 47990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 48090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool Instance::ThreadCreateFile(const char* title, 48190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const char* description, 48290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const char* content, 48390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Json::Value* metadata) { 48490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) InsertFileParams p; 48590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) p.content = content; 48690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) p.description = description; 48790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) p.mime_type = "text/plain"; 48890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) p.title = title; 48990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 49090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int32_t result = InsertFile(this, auth_token_, p, metadata); 49190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (result != PP_OK) { 49290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) PostMessagef("log: Creating file failed with result %d\n", result); 49390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return false; 49490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 49590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 49690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return true; 49790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 49890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 49990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool Instance::ThreadUpdateFile(const std::string& file_id, 50090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const std::string& content, 50190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Json::Value* metadata) { 50290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) InsertFileParams p; 50390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) p.file_id = file_id; 50490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) p.content = content; 50590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) p.mime_type = "text/plain"; 50690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 50790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int32_t result = InsertFile(this, auth_token_, p, metadata); 50890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (result != PP_OK) { 50990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) PostMessagef("log: Updating file failed with result %d\n", result); 51090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return false; 51190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 51290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 51390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return true; 51490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 51590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 51690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool Instance::ThreadDownloadFile(const Json::Value& metadata, 51790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string* output) { 51890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) ReadUrlParams p; 51990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) p.method = "GET"; 52090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 52190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!GetMetadataKey(metadata, "downloadUrl", &p.url)) { 52290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return false; 52390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 52490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 52590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) AddAuthTokenHeader(&p.request_headers, auth_token_); 52690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 52790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int32_t result = ReadUrl(this, p, output); 52890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (result != PP_OK) { 52990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) PostMessagef("log: Downloading failed with result %d\n", result); 53090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return false; 53190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 53290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 53390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return true; 53490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 53590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 53690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool Instance::GetMetadataKey(const Json::Value& metadata, 53790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const char* key, 53890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string* output) { 53990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Json::Value value = metadata[key]; 54090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!value.isString()) { 54190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) PostMessagef("log: Expected metadata.%s to be a string.\n", key); 54290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return false; 54390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 54490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 54590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *output = value.asString(); 54690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return true; 54790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 54890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 54990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)class Module : public pp::Module { 55090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) public: 55190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Module() : pp::Module() {} 55290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) virtual ~Module() {} 55390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 55490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) virtual pp::Instance* CreateInstance(PP_Instance instance) { 55590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return new Instance(instance); 55690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 55790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}; 55890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 55990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace pp { 56090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 56190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)Module* CreateModule() { return new ::Module(); } 56290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 56390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} // namespace pp 564