 Chromium Code Reviews
 Chromium Code Reviews Issue 2156503002:
  [NaCl SDK] Expose Google Drive to nacl_io.  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master
    
  
    Issue 2156503002:
  [NaCl SDK] Expose Google Drive to nacl_io.  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master| Index: native_client_sdk/src/tests/nacl_io_test/fake_ppapi/fake_pepper_interface_googledrivefs.cc | 
| diff --git a/native_client_sdk/src/tests/nacl_io_test/fake_ppapi/fake_pepper_interface_googledrivefs.cc b/native_client_sdk/src/tests/nacl_io_test/fake_ppapi/fake_pepper_interface_googledrivefs.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..ea2ae71a9a4509f40868a3e8f083d8d1d0ef8604 | 
| --- /dev/null | 
| +++ b/native_client_sdk/src/tests/nacl_io_test/fake_ppapi/fake_pepper_interface_googledrivefs.cc | 
| @@ -0,0 +1,831 @@ | 
| +// Copyright 2016 The Chromium Authors. All rights reserved. | 
| +// Use of this source code is governed by a BSD-style license that can be | 
| +// found in the LICENSE file. | 
| + | 
| +#include "fake_ppapi/fake_pepper_interface_googledrivefs.h" | 
| + | 
| +#include <algorithm> | 
| +#include <sstream> | 
| + | 
| +#include <ppapi/c/pp_completion_callback.h> | 
| +#include <ppapi/c/pp_errors.h> | 
| + | 
| +#include "gtest/gtest.h" | 
| + | 
| +#include "nacl_io/osinttypes.h" | 
| + | 
| +#include "fake_ppapi/fake_core_interface.h" | 
| +#include "fake_ppapi/fake_file_io_interface.h" | 
| +#include "fake_ppapi/fake_pepper_interface_url_loader.h" | 
| +#include "fake_ppapi/fake_util.h" | 
| +#include "fake_ppapi/fake_var_interface.h" | 
| + | 
| +class FakeGoogleDriveInstanceResource : public FakeResource { | 
| + public: | 
| + FakeGoogleDriveInstanceResource() : server_template(NULL) {} | 
| + static const char* classname() { return "FakeGoogleDriveInstanceResource"; } | 
| + | 
| + FakeGoogleDriveServer* server_template; | 
| +}; | 
| + | 
| +class FakeGoogleDriveURLLoaderResource : public FakeResource { | 
| + public: | 
| + FakeGoogleDriveURLLoaderResource() | 
| + : server(NULL), response_resource(0), response_body("") {} | 
| + | 
| + static const char* classname() { return "FakeGoogleDriveURLLoaderResource"; } | 
| + | 
| + FakeGoogleDriveServer* server; | 
| + PP_Resource response_resource; | 
| + std::string response_body; | 
| +}; | 
| + | 
| +int FakeGoogleDriveServer::FILES_PER_PAGE = 100; | 
| + | 
| +FakeGoogleDriveServer::FakeGoogleDriveServer() { | 
| + token_id_ = 0; | 
| + item_id_ = 0; | 
| + | 
| + ItemMetadata metadata("root", "root_directory", "", | 
| + "2016-07-24T08:21:28.940Z", true); | 
| + item_id_to_metadata["root"] = metadata; | 
| + dir_id_to_file_list["root"] = std::vector<ItemMetadata*>(); | 
| +} | 
| + | 
| +void FakeGoogleDriveServer::AddBody(const std::string& data, | 
| + std::string* out_body) { | 
| + *out_body += data; | 
| + *out_body += "\n"; | 
| +} | 
| + | 
| +std::string FakeGoogleDriveServer::GetIdFromUrlPath(const std::string& url) { | 
| + int end_id_index = url.find("?", 0); | 
| + int start_id_index = url.rfind("/", end_id_index) + 1; | 
| + | 
| + return url.substr(start_id_index, end_id_index - start_id_index); | 
| +} | 
| + | 
| +std::string FakeGoogleDriveServer::GetParentDirIdFromUrlQuery( | 
| + const std::string& url) { | 
| + int end_id_index = url.find("%27+in+parents", 0); | 
| + int start_id_index = url.rfind("%27", end_id_index - 1) + 3; | 
| + return url.substr(start_id_index, end_id_index - start_id_index); | 
| +} | 
| + | 
| +std::string FakeGoogleDriveServer::GetNameFromUrlQuery(const std::string& url) { | 
| + int start_name_index = url.find("name", 0) + 10; | 
| + int end_name_index = url.find("%27", start_name_index); | 
| + return url.substr(start_name_index, end_name_index - start_name_index); | 
| +} | 
| + | 
| +void FakeGoogleDriveServer::MakeIdExistResponse(const std::string& id, | 
| + const std::string& name, | 
| + std::string* out_body) { | 
| + AddBody("{", out_body); | 
| + AddBody(" \"files\": [", out_body); | 
| + AddBody(" {", out_body); | 
| + AddBody(" \"mimeType\": \"mimeType instance\",", out_body); | 
| + AddBody(" \"kind\": \"drive#file\",", out_body); | 
| + AddBody(" \"id\": \"" + id + "\",", out_body); | 
| + AddBody(" \"name\": \"" + name + "\"", out_body); | 
| + AddBody(" }", out_body); | 
| + AddBody(" ],", out_body); | 
| + AddBody(" \"kind\": \"drive#fileList\"", out_body); | 
| + AddBody("}", out_body); | 
| +} | 
| + | 
| +void FakeGoogleDriveServer::MakeIdNotExistResponse(std::string* out_body) { | 
| + AddBody("{", out_body); | 
| + AddBody(" \"files\": [],", out_body); | 
| + AddBody(" \"kind\": \"drive#fileList\"", out_body); | 
| + AddBody("}", out_body); | 
| +} | 
| + | 
| +void FakeGoogleDriveServer::AddItemArray(const std::string& parent_dir_id, | 
| + int file_list_start_index, | 
| + std::string* out_body) { | 
| + AddBody(" \"files\": [", out_body); | 
| + | 
| + int bound = std::min(((size_t)file_list_start_index + FILES_PER_PAGE), | 
| + dir_id_to_file_list[parent_dir_id].size()); | 
| + for (int i = file_list_start_index; i < bound; ++i) { | 
| + AddBody(" {", out_body); | 
| + AddBody(" \"mimeType\": \"mimeType instance\",", out_body); | 
| + AddBody(" \"kind\": \"drive#file\",", out_body); | 
| + AddBody(" \"id\": \"" + dir_id_to_file_list[parent_dir_id][i]->id() + | 
| + "\",", | 
| + out_body); | 
| + AddBody(" \"name\": \"" + | 
| + dir_id_to_file_list[parent_dir_id][i]->name() + "\"", | 
| + out_body); | 
| + if (i == bound - 1) { | 
| + AddBody(" }", out_body); | 
| + } else { | 
| + AddBody(" },", out_body); | 
| + } | 
| + } | 
| + AddBody(" ],", out_body); | 
| +} | 
| + | 
| +std::string FakeGoogleDriveServer::GetPageTokenFromUrlQuery( | 
| + const std::string& url) { | 
| + int start_page_token_index = url.find("pageToken", 0) + 10; | 
| 
binji
2016/08/22 19:21:53
better to do something like:
const char s_page_to
 
chanpatorikku
2016/08/29 17:14:03
The function is redesigned to return a pp error if
 | 
| + int end_page_token_index = url.find("&", start_page_token_index); | 
| + if (end_page_token_index == -1) { | 
| + end_page_token_index = url.size(); | 
| + } | 
| + return url.substr(start_page_token_index, | 
| + end_page_token_index - start_page_token_index); | 
| +} | 
| + | 
| +std::string FakeGoogleDriveServer::GetNameFromBody(const std::string& body) { | 
| + int start_name_index = body.find("\"name\": \"", 0) + 9; | 
| + int end_name_index = body.find("\"", start_name_index); | 
| + return body.substr(start_name_index, end_name_index - start_name_index); | 
| +} | 
| + | 
| +std::string FakeGoogleDriveServer::GetParentDirIdFromBody( | 
| + const std::string& body) { | 
| + int end_parent_key_index = body.find("\"parents\"", 0) + 9; | 
| + int start_parent_dir_id_index = body.find("\"", end_parent_key_index) + 1; | 
| + int end_parent_dir_id_index = body.find("\"", start_parent_dir_id_index); | 
| + return body.substr(start_parent_dir_id_index, | 
| + end_parent_dir_id_index - start_parent_dir_id_index); | 
| +} | 
| + | 
| +Response FakeGoogleDriveServer::RespondItemModifiedTime( | 
| + const std::string& url) { | 
| + // url string: | 
| + // https://www.googleapis.com/drive/v3/files/<itemid>?fields=modifiedTime | 
| + | 
| + Response response; | 
| + | 
| + std::string id = GetIdFromUrlPath(url); | 
| + if (item_id_to_metadata.find(id) == item_id_to_metadata.end()) { | 
| + response.status_code = STATUSCODE_NOT_FOUND; | 
| + | 
| + return response; | 
| + } | 
| + | 
| + response.status_code = STATUSCODE_OK; | 
| + | 
| + AddBody("{", &response.body); | 
| + AddBody( | 
| + " \"modifiedTime\": \"" + item_id_to_metadata[id].modified_time() + "\"", | 
| + &response.body); | 
| + AddBody("}", &response.body); | 
| + | 
| + return response; | 
| +} | 
| + | 
| +Response FakeGoogleDriveServer::RespondItemSize(const std::string& url) { | 
| + // url string: | 
| + // https://www.googleapis.com/drive/v3/files/<itemid>?fields=size | 
| + | 
| + Response response; | 
| + | 
| + std::string id = GetIdFromUrlPath(url); | 
| + if (item_id_to_metadata.find(id) == item_id_to_metadata.end()) { | 
| + response.status_code = STATUSCODE_NOT_FOUND; | 
| + | 
| + return response; | 
| + } | 
| + | 
| + if (item_id_to_metadata[id].is_dir()) { | 
| + response.status_code = STATUSCODE_OK; | 
| + | 
| + response.body = "{}"; | 
| + | 
| + return response; | 
| + } | 
| + | 
| + char buffer[33]; | 
| + int char_written = | 
| + sprintf(buffer, "%i", item_id_to_metadata[id].contents().size()); | 
| + if (char_written < 0) { | 
| + response.status_code = STATUSCODE_INTERNAL_SERVER_ERROR; | 
| + | 
| + return response; | 
| + } | 
| + std::string size(buffer); | 
| + | 
| + response.status_code = STATUSCODE_OK; | 
| + | 
| + AddBody("{", &response.body); | 
| + AddBody(" \"size\": \"" + size + "\"", &response.body); | 
| + AddBody("}", &response.body); | 
| + | 
| + return response; | 
| +} | 
| + | 
| +Response FakeGoogleDriveServer::RespondDirId(const std::string& url) { | 
| + // url string: | 
| + // https://www.googleapis.com/drive/v3/files | 
| + // ?q=%27<itemid>%27+in+parents | 
| + // +and+mimeType+=+%27application/vnd.google-apps.folder%27 | 
| + // +and+name+=+%27<name>%27 | 
| + | 
| + Response response; | 
| + | 
| + std::string parent_dir_id = GetParentDirIdFromUrlQuery(url); | 
| + | 
| + if (dir_id_to_file_list.find(parent_dir_id) == dir_id_to_file_list.end()) { | 
| + response.status_code = STATUSCODE_NOT_FOUND; | 
| + | 
| + return response; | 
| + } | 
| + | 
| + std::string name = GetNameFromUrlQuery(url); | 
| + | 
| + for (int i = 0; i < dir_id_to_file_list[parent_dir_id].size(); ++i) { | 
| + if (dir_id_to_file_list[parent_dir_id][i]->is_dir() && | 
| + dir_id_to_file_list[parent_dir_id][i]->name() == name) { | 
| + response.status_code = STATUSCODE_OK; | 
| + | 
| + MakeIdExistResponse(dir_id_to_file_list[parent_dir_id][i]->id(), | 
| + dir_id_to_file_list[parent_dir_id][i]->name(), | 
| + &response.body); | 
| + | 
| + return response; | 
| + } | 
| + } | 
| + | 
| + response.status_code = STATUSCODE_OK; | 
| + | 
| + MakeIdNotExistResponse(&response.body); | 
| + | 
| + return response; | 
| +} | 
| + | 
| +Response FakeGoogleDriveServer::RespondItemId(const std::string& url) { | 
| + // url string: | 
| + // https://www.googleapis.com/drive/v3/files | 
| + // ?q=%27<itemid>%27+in+parents+and+name+=+%27<name>%27 | 
| + | 
| + Response response; | 
| + | 
| + std::string parent_dir_id = GetParentDirIdFromUrlQuery(url); | 
| + | 
| + if (dir_id_to_file_list.find(parent_dir_id) == dir_id_to_file_list.end()) { | 
| + response.status_code = STATUSCODE_NOT_FOUND; | 
| + | 
| + return response; | 
| + } | 
| + | 
| + std::string name = GetNameFromUrlQuery(url); | 
| + | 
| + for (int i = 0; i < dir_id_to_file_list[parent_dir_id].size(); ++i) { | 
| + if (dir_id_to_file_list[parent_dir_id][i]->name() == name) { | 
| + response.status_code = STATUSCODE_OK; | 
| + | 
| + MakeIdExistResponse(dir_id_to_file_list[parent_dir_id][i]->id(), | 
| + dir_id_to_file_list[parent_dir_id][i]->name(), | 
| + &response.body); | 
| + | 
| + return response; | 
| + } | 
| + } | 
| + | 
| + response.status_code = STATUSCODE_OK; | 
| + | 
| + MakeIdNotExistResponse(&response.body); | 
| + | 
| + return response; | 
| +} | 
| + | 
| +Response FakeGoogleDriveServer::RespondDirent(const std::string& url) { | 
| + // url string: | 
| + // https://www.googleapis.com/drive/v3/files | 
| + // ?q=%27<itemid>%27+in+parents | 
| + Response response; | 
| + | 
| + std::string parent_dir_id = GetParentDirIdFromUrlQuery(url); | 
| + | 
| + if (dir_id_to_file_list.find(parent_dir_id) == dir_id_to_file_list.end()) { | 
| + response.status_code = STATUSCODE_NOT_FOUND; | 
| + | 
| + return response; | 
| + } | 
| + | 
| + if (dir_id_to_file_list[parent_dir_id].size() == 0) { | 
| + response.status_code = STATUSCODE_OK; | 
| + | 
| + MakeIdNotExistResponse(&response.body); | 
| + | 
| + return response; | 
| + } | 
| + | 
| + response.status_code = STATUSCODE_OK; | 
| + | 
| + AddBody("{", &response.body); | 
| + | 
| + if (dir_id_to_file_list[parent_dir_id].size() > FILES_PER_PAGE) { | 
| + char buffer[33]; | 
| + int char_written = sprintf(buffer, "%i", token_id_); | 
| + if (char_written < 0) { | 
| + response.status_code = STATUSCODE_INTERNAL_SERVER_ERROR; | 
| + | 
| + return response; | 
| + } | 
| + std::string next_page_token(buffer); | 
| + token_id_++; | 
| + | 
| + AddBody(" \"nextPageToken\": \"" + next_page_token + "\",", | 
| + &response.body); | 
| + | 
| + token_to_next_entry[next_page_token] = | 
| + NextEntry(parent_dir_id, FILES_PER_PAGE); | 
| + } | 
| + | 
| + AddItemArray(parent_dir_id, 0, &response.body); | 
| + | 
| + AddBody(" \"kind\": \"drive#fileList\"", &response.body); | 
| + AddBody("}", &response.body); | 
| + | 
| + return response; | 
| +} | 
| + | 
| +Response FakeGoogleDriveServer::RespondDirentNextPage(const std::string& url) { | 
| + // url string: | 
| + // https://www.googleapis.com/drive/v3/files?pageToken=<pagetoken>&q=%27<id>%27+in+parents | 
| + | 
| + Response response; | 
| + | 
| + std::string parent_dir_id = GetParentDirIdFromUrlQuery(url); | 
| + std::string page_token = GetPageTokenFromUrlQuery(url); | 
| + | 
| + NextEntry entry = token_to_next_entry[page_token]; | 
| + | 
| + if (entry.parent_dir_id() != parent_dir_id) { | 
| + // When <id> in <id>+in+parents is not equal to the id of the | 
| + // parent directory that the page token is related to, Google | 
| + // Drive API v3 returns a status code 200 but a list of files | 
| + // that does not make sense. Return the status code 500 for | 
| + // the error of returning a list of files that does not make | 
| + // sense. | 
| + response.status_code = STATUSCODE_INTERNAL_SERVER_ERROR; | 
| + | 
| + return response; | 
| + } | 
| + | 
| + response.status_code = STATUSCODE_OK; | 
| + | 
| + AddBody("{", &response.body); | 
| + | 
| + if (dir_id_to_file_list[parent_dir_id].size() > | 
| + entry.index() + FILES_PER_PAGE) { | 
| + char buffer[33]; | 
| + int char_written = sprintf(buffer, "%i", token_id_); | 
| + if (char_written < 0) { | 
| + response.status_code = STATUSCODE_INTERNAL_SERVER_ERROR; | 
| + | 
| + return response; | 
| + } | 
| + std::string next_page_token(buffer); | 
| + token_id_++; | 
| + | 
| + AddBody(" \"nextPageToken\": \"" + next_page_token + "\",", | 
| + &response.body); | 
| + | 
| + token_to_next_entry[next_page_token] = | 
| + NextEntry(parent_dir_id, entry.index() + FILES_PER_PAGE); | 
| + } | 
| + | 
| + AddItemArray(parent_dir_id, entry.index(), &response.body); | 
| + | 
| + AddBody(" \"kind\": \"drive#fileList\"", &response.body); | 
| + AddBody("}", &response.body); | 
| + | 
| + return response; | 
| +} | 
| + | 
| +Response FakeGoogleDriveServer::RespondFileWriteRequest( | 
| + const std::string& url, | 
| + const std::string& body) { | 
| + // url string: | 
| + // https://www.googleapis.com/upload/drive/v3/files/<itemid>?uploadType=media | 
| + | 
| + Response response; | 
| + | 
| + std::string id = GetIdFromUrlPath(url); | 
| + | 
| + if (item_id_to_metadata.find(id) == item_id_to_metadata.end()) { | 
| + response.status_code = STATUSCODE_NOT_FOUND; | 
| + | 
| + return response; | 
| + } | 
| + | 
| + response.status_code = STATUSCODE_OK; | 
| + | 
| + item_id_to_metadata[id].set_contents(body); | 
| + | 
| + return response; | 
| +} | 
| + | 
| +Response FakeGoogleDriveServer::RespondFileCreationRequest( | 
| + const std::string& url, | 
| + const std::string& body) { | 
| + // url string: | 
| + // https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart | 
| + | 
| + // body string: | 
| + // --foo_bar_baz | 
| + // Content-Type: application/json; charset=UTF-8 | 
| + // | 
| + // { | 
| + // "name": "<itemname>", | 
| + // "parents": [ | 
| + // "<parentdirid>" | 
| + // ] | 
| + // } | 
| + // | 
| + // --foo_bar_baz | 
| + // Content-Type: text/plain | 
| + // | 
| + // | 
| + // --foo_bar_baz-- | 
| + Response response; | 
| + | 
| + std::string name = GetNameFromBody(body); | 
| + std::string parent_dir_id = GetParentDirIdFromBody(body); | 
| + | 
| + if (dir_id_to_file_list.find(parent_dir_id) == dir_id_to_file_list.end()) { | 
| + response.status_code = STATUSCODE_NOT_FOUND; | 
| + | 
| + return response; | 
| + } | 
| + | 
| + char buffer[33]; | 
| + int char_written = sprintf(buffer, "%i", item_id_); | 
| + if (char_written < 0) { | 
| + response.status_code = STATUSCODE_INTERNAL_SERVER_ERROR; | 
| + | 
| + return response; | 
| + } | 
| + std::string file_id(buffer); | 
| + item_id_++; | 
| + | 
| + response.status_code = STATUSCODE_OK; | 
| + | 
| + ItemMetadata metadata(file_id, name, "", "2016-07-24T08:21:28.940Z", false); | 
| + | 
| + item_id_to_metadata[file_id] = metadata; | 
| + dir_id_to_file_list[parent_dir_id].push_back(&item_id_to_metadata[file_id]); | 
| + | 
| + return response; | 
| +} | 
| + | 
| +Response FakeGoogleDriveServer::RespondFileReadRequest( | 
| + const std::string& url, | 
| + const std::string& headers) { | 
| + // url string: | 
| + // https://www.googleapis.com/download/drive/v3/files/<itemid>?alt=media | 
| + Response response; | 
| + | 
| + std::string id = GetIdFromUrlPath(url); | 
| + | 
| + if (item_id_to_metadata.find(id) == item_id_to_metadata.end()) { | 
| + response.status_code = STATUSCODE_INTERNAL_SERVER_ERROR; | 
| + | 
| + return response; | 
| + } | 
| + | 
| + std::string range; | 
| + if (!GetHeaderValue(headers, "Range", &range)) { | 
| + response.status_code = STATUSCODE_OK; | 
| + | 
| + response.body = item_id_to_metadata[id].contents(); | 
| + | 
| + return response; | 
| + } | 
| + | 
| + // We don't support all range requests, just bytes=<num>-<num> | 
| + off_t lo; | 
| + off_t hi; | 
| + if (sscanf(range.c_str(), "bytes=%" SCNi64 "-%" SCNi64, &lo, &hi) != 2) { | 
| + // Couldn't parse the range value. | 
| + response.status_code = STATUSCODE_INTERNAL_SERVER_ERROR; | 
| + | 
| + return response; | 
| + } | 
| + | 
| + off_t content_length = item_id_to_metadata[id].contents().size(); | 
| + if (lo >= content_length) { | 
| + // Trying to start reading past the end of the file contents is | 
| + // unsatisfiable. | 
| + response.status_code = | 
| + STATUSCODE_REQUESTED_RANGE_NOT_SATISFIABLE; // Request range not | 
| + // satisfiable. | 
| + | 
| + return response; | 
| + } | 
| + | 
| + // Clamp the hi value to the content length. | 
| + if (hi >= content_length) { | 
| + hi = content_length - 1; | 
| + } | 
| + | 
| + if (lo > hi) { | 
| + response.status_code = STATUSCODE_OK; | 
| + | 
| + response.body = item_id_to_metadata[id].contents(); | 
| + | 
| + return response; | 
| + } | 
| + | 
| + response.status_code = STATUSCODE_PARTIAL_CONTENT; | 
| + | 
| + response.body = item_id_to_metadata[id].contents().substr(lo, hi - lo + 1); | 
| + | 
| + return response; | 
| +} | 
| + | 
| +Response FakeGoogleDriveServer::RespondRemoveDirRequest( | 
| + const std::string& url) { | 
| + // url string: | 
| + // https://www.googleapis.com/drive/v3/files/<dirid> | 
| + Response response; | 
| + | 
| + int start_id_index = url.rfind("/", url.size() - 1) + 1; | 
| + std::string id = url.substr(start_id_index, url.size() - start_id_index); | 
| + | 
| + std::map<std::string, std::vector<ItemMetadata*> >::const_iterator | 
| + dir_id_to_file_list_iter = dir_id_to_file_list.find(id); | 
| + | 
| + if (dir_id_to_file_list_iter == dir_id_to_file_list.end()) { | 
| + response.status_code = STATUSCODE_NOT_FOUND; | 
| + | 
| + return response; | 
| + } | 
| + | 
| + if (dir_id_to_file_list[id].size() > 0) { | 
| + // Posix rmdir(3) is supposed to remove a directory when the directory is | 
| + // empty. Return a client error when the client requests to remove a | 
| + // directory that has items. | 
| + response.status_code = STATUSCODE_BAD_REQUEST; | 
| + | 
| + return response; | 
| + } | 
| + | 
| + dir_id_to_file_list.erase(dir_id_to_file_list_iter); | 
| + | 
| + std::map<std::string, ItemMetadata>::const_iterator item_id_to_metadata_iter = | 
| + item_id_to_metadata.find(id); | 
| + | 
| + // id in dir_id_to_file_list also is in item_id_to_metadata. | 
| + // Do not check to see if iterator == item_id_to_metadata.end(). | 
| + item_id_to_metadata.erase(item_id_to_metadata_iter); | 
| + | 
| + response.status_code = STATUSCODE_NO_CONTENT; | 
| + | 
| + return response; | 
| +} | 
| + | 
| +Response FakeGoogleDriveServer::RespondMakeDirRequest(const std::string& url, | 
| + const std::string& body) { | 
| + // url string: | 
| + // https://www.googleapis.com/drive/v3/files | 
| + | 
| + // body string: | 
| + // { | 
| + // "name": "<dirname>", | 
| + // "mimeType": "application/vnd.google-apps.folder" | 
| + // "parents": [ | 
| + // "<parentdirid>" | 
| + // ] | 
| + // } | 
| + Response response; | 
| + | 
| + std::string name = GetNameFromBody(body); | 
| + std::string parent_dir_id = GetParentDirIdFromBody(body); | 
| + | 
| + if (dir_id_to_file_list.find(parent_dir_id) == dir_id_to_file_list.end()) { | 
| + response.status_code = STATUSCODE_UNAUTHORIZED; | 
| + | 
| + return response; | 
| + } | 
| + | 
| + char buffer[33]; | 
| + | 
| + int char_written = sprintf(buffer, "%i", item_id_); | 
| + | 
| + if (char_written < 0) { | 
| + response.status_code = STATUSCODE_INTERNAL_SERVER_ERROR; | 
| + | 
| + return response; | 
| + } | 
| + std::string dir_id(buffer); | 
| + item_id_++; | 
| + | 
| + response.status_code = STATUSCODE_OK; | 
| + | 
| + ItemMetadata metadata(dir_id, name, "", "2016-07-24T08:21:28.940Z", true); | 
| + | 
| + item_id_to_metadata[dir_id] = metadata; | 
| + dir_id_to_file_list[dir_id] = std::vector<ItemMetadata*>(); | 
| + dir_id_to_file_list[parent_dir_id].push_back(&item_id_to_metadata[dir_id]); | 
| + | 
| + return response; | 
| +} | 
| + | 
| +Response FakeGoogleDriveServer::Respond(const std::string& url, | 
| + const std::string& headers, | 
| + const std::string& method, | 
| + const std::string& body) { | 
| + if (url.find("size", 0) != -1) { | 
| + return RespondItemSize(url); | 
| + } else if (url.find("modifiedTime", 0) != -1) { | 
| + return RespondItemModifiedTime(url); | 
| + } else if (url.find("+in+parents", 0) != -1 && | 
| + url.find("mimeType+=+%27application/vnd.google-apps.folder%27", | 
| + 0) != -1 && | 
| + url.find("name", 0) != -1) { | 
| + return RespondDirId(url); | 
| + } else if (url.find("name", 0) != -1 && url.find("+in+parents", 0) != -1) { | 
| + return RespondItemId(url); | 
| + } else if (url.find("pageToken", 0) != -1 && | 
| + url.find("+in+parents", 0) != -1) { | 
| + return RespondDirentNextPage(url); | 
| + } else if (url.find("+in+parents", 0) != -1) { | 
| + return RespondDirent(url); | 
| + } else if (url.find("uploadType=media", 0) != -1) { | 
| + return RespondFileWriteRequest(url, body); | 
| + } else if (url.find("uploadType=multipart", 0) != -1) { | 
| + return RespondFileCreationRequest(url, body); | 
| + } else if (url.find("download/drive", 0) != -1) { | 
| + return RespondFileReadRequest(url, headers); | 
| + } else if (method == "DELETE") { | 
| + return RespondRemoveDirRequest(url); | 
| + } else if (body.find("\"name\"", 0) != -1 && | 
| + body.find("\"mimeType\": \"application/vnd.google-apps.folder\"", | 
| + 0) != -1 && | 
| + body.find("\"parents\"", 0) != -1) { | 
| + return RespondMakeDirRequest(url, body); | 
| + } | 
| + Response response; | 
| + | 
| + response.status_code = STATUSCODE_NOT_IMPLEMENTED; | 
| + | 
| + return response; | 
| +} | 
| + | 
| +FakeGoogleDriveURLLoaderInterface::FakeGoogleDriveURLLoaderInterface( | 
| + FakeCoreInterface* core_interface) | 
| + : FakeURLLoaderInterface(core_interface) {} | 
| + | 
| +PP_Resource FakeGoogleDriveURLLoaderInterface::Create(PP_Instance instance) { | 
| + FakeGoogleDriveInstanceResource* instance_resource = | 
| + core_interface_->resource_manager()->Get<FakeGoogleDriveInstanceResource>( | 
| + instance); | 
| + if (instance_resource == NULL) | 
| + return PP_ERROR_BADRESOURCE; | 
| + | 
| + FakeGoogleDriveURLLoaderResource* loader_resource = | 
| + new FakeGoogleDriveURLLoaderResource; | 
| + loader_resource->server = instance_resource->server_template; | 
| + | 
| + return CREATE_RESOURCE(core_interface_->resource_manager(), | 
| + FakeGoogleDriveURLLoaderResource, loader_resource); | 
| +} | 
| + | 
| +int32_t FakeGoogleDriveURLLoaderInterface::Open( | 
| + PP_Resource loader, | 
| + PP_Resource request, | 
| + PP_CompletionCallback callback) { | 
| + FakeGoogleDriveURLLoaderResource* loader_resource = | 
| + core_interface_->resource_manager() | 
| + ->Get<FakeGoogleDriveURLLoaderResource>(loader); | 
| + if (loader_resource == NULL) | 
| + return PP_ERROR_BADRESOURCE; | 
| + | 
| + FakeURLRequestInfoResource* request_resource = | 
| + core_interface_->resource_manager()->Get<FakeURLRequestInfoResource>( | 
| + request); | 
| + if (request_resource == NULL) | 
| + return PP_ERROR_BADRESOURCE; | 
| + | 
| + // Create a response resource. | 
| + FakeURLResponseInfoResource* response_resource = | 
| + new FakeURLResponseInfoResource; | 
| + loader_resource->response_resource = | 
| + CREATE_RESOURCE(core_interface_->resource_manager(), | 
| + FakeURLResponseInfoResource, response_resource); | 
| + | 
| + Response response = loader_resource->server->Respond( | 
| + request_resource->url, request_resource->headers, | 
| + request_resource->method, request_resource->body); | 
| + | 
| + response_resource->status_code = response.status_code; | 
| + loader_resource->response_body = response.body; | 
| + | 
| + // Call the callback. | 
| + return RunCompletionCallback(&callback, PP_OK); | 
| +} | 
| + | 
| +PP_Resource FakeGoogleDriveURLLoaderInterface::GetResponseInfo( | 
| + PP_Resource loader) { | 
| + FakeGoogleDriveURLLoaderResource* loader_resource = | 
| + core_interface_->resource_manager() | 
| + ->Get<FakeGoogleDriveURLLoaderResource>(loader); | 
| + if (loader_resource == NULL) | 
| + return 0; | 
| + | 
| + // Returned resources have an implicit AddRef. | 
| + core_interface_->resource_manager()->AddRef( | 
| + loader_resource->response_resource); | 
| + return loader_resource->response_resource; | 
| +} | 
| + | 
| +int32_t FakeGoogleDriveURLLoaderInterface::FinishStreamingToFile( | 
| + PP_Resource loader, | 
| + PP_CompletionCallback callback) { | 
| + FakeGoogleDriveURLLoaderResource* loader_resource = | 
| + core_interface_->resource_manager() | 
| + ->Get<FakeGoogleDriveURLLoaderResource>(loader); | 
| + if (loader_resource == NULL) | 
| + return PP_ERROR_BADRESOURCE; | 
| + | 
| + FakeURLResponseInfoResource* response_resource = | 
| + core_interface_->resource_manager()->Get<FakeURLResponseInfoResource>( | 
| + loader_resource->response_resource); | 
| + if (response_resource == NULL) | 
| + return PP_ERROR_BADRESOURCE; | 
| + | 
| + response_resource->body = loader_resource->response_body; | 
| + | 
| + return response_resource->body.size(); | 
| +} | 
| + | 
| +void FakeGoogleDriveURLLoaderInterface::Close(PP_Resource loader) { | 
| + FakeGoogleDriveURLLoaderResource* loader_resource = | 
| + core_interface_->resource_manager() | 
| + ->Get<FakeGoogleDriveURLLoaderResource>(loader); | 
| + if (loader_resource == NULL) | 
| + return; | 
| + | 
| + core_interface_->resource_manager()->Release( | 
| + loader_resource->response_resource); | 
| + | 
| + loader_resource->server = NULL; | 
| + loader_resource->response_resource = 0; | 
| +} | 
| + | 
| +FakePepperInterfaceGoogleDriveFs::FakePepperInterfaceGoogleDriveFs() | 
| + : core_interface_(&resource_manager_), | 
| + var_interface_(&var_manager_), | 
| + file_io_interface_(&core_interface_), | 
| + file_ref_interface_(&core_interface_, &var_interface_), | 
| + google_drive_url_loader_interface_(&core_interface_), | 
| + url_request_info_interface_(&core_interface_, &var_interface_), | 
| + url_response_info_interface_(&core_interface_, | 
| + &var_interface_, | 
| + &file_ref_interface_) { | 
| + Init(); | 
| +} | 
| + | 
| +void FakePepperInterfaceGoogleDriveFs::Init() { | 
| + FakeGoogleDriveInstanceResource* instance_resource = | 
| + new FakeGoogleDriveInstanceResource; | 
| + instance_resource->server_template = &google_drive_server_template_; | 
| + | 
| + instance_ = | 
| + CREATE_RESOURCE(core_interface_.resource_manager(), | 
| + FakeGoogleDriveInstanceResource, instance_resource); | 
| +} | 
| + | 
| +FakePepperInterfaceGoogleDriveFs::~FakePepperInterfaceGoogleDriveFs() { | 
| + core_interface_.ReleaseResource(instance_); | 
| +} | 
| + | 
| +nacl_io::CoreInterface* FakePepperInterfaceGoogleDriveFs::GetCoreInterface() { | 
| + return &core_interface_; | 
| +} | 
| + | 
| +nacl_io::FileRefInterface* | 
| +FakePepperInterfaceGoogleDriveFs::GetFileRefInterface() { | 
| + return &file_ref_interface_; | 
| +} | 
| + | 
| +nacl_io::FileIoInterface* | 
| +FakePepperInterfaceGoogleDriveFs::GetFileIoInterface() { | 
| + return &file_io_interface_; | 
| +} | 
| + | 
| +nacl_io::URLLoaderInterface* | 
| +FakePepperInterfaceGoogleDriveFs::GetURLLoaderInterface() { | 
| + return &google_drive_url_loader_interface_; | 
| +} | 
| + | 
| +nacl_io::URLRequestInfoInterface* | 
| +FakePepperInterfaceGoogleDriveFs::GetURLRequestInfoInterface() { | 
| + return &url_request_info_interface_; | 
| +} | 
| + | 
| +nacl_io::URLResponseInfoInterface* | 
| +FakePepperInterfaceGoogleDriveFs::GetURLResponseInfoInterface() { | 
| + return &url_response_info_interface_; | 
| +} | 
| + | 
| +nacl_io::VarInterface* FakePepperInterfaceGoogleDriveFs::GetVarInterface() { | 
| + return &var_interface_; | 
| +} |