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