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

Unified Diff: native_client_sdk/src/libraries/nacl_io/googledrivefs/googledrivefs_util.cc

Issue 2156503002: [NaCl SDK] Expose Google Drive to nacl_io. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: native_client_sdk/src/libraries/nacl_io/googledrivefs/googledrivefs_util.cc
diff --git a/native_client_sdk/src/libraries/nacl_io/googledrivefs/googledrivefs_util.cc b/native_client_sdk/src/libraries/nacl_io/googledrivefs/googledrivefs_util.cc
new file mode 100644
index 0000000000000000000000000000000000000000..c9efc94dbb22837052ea4e7321a84c8981ef8bf9
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/googledrivefs/googledrivefs_util.cc
@@ -0,0 +1,531 @@
+// Copyright (c) 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 "nacl_io/googledrivefs/googledrivefs_util.h"
+
+#include <stdlib.h>
+
+#include "ppapi/c/pp_completion_callback.h"
+#include "ppapi/c/pp_instance.h"
+
+#include "nacl_io/error.h"
+#include "nacl_io/filesystem.h"
+#include "nacl_io/path.h"
+#include "nacl_io/pepper_interface.h"
+#include "nacl_io/statuscode.h"
+#include "nacl_io/googledrivefs/googledrivefs.h"
+
+namespace nacl_io {
+
+void AddUrlPath(const std::string& path, std::string* out_url) {
+ *out_url += "/";
+ *out_url += path;
+}
+
+void AddUrlQAttributeValue(std::string* array,
+ int size,
+ std::string* out_q_attribute_value) {
+ *out_q_attribute_value = array[0];
+ for (int i = 1; i < size; ++i) {
+ *out_q_attribute_value += "+and+";
+ *out_q_attribute_value += array[i];
+ }
+}
+
+void AddUrlFirstQueryParameter(const std::string& attribute,
+ const std::string& value,
+ std::string* out_url) {
+ *out_url += "?";
+ *out_url += attribute;
+ *out_url += "=";
+ *out_url += value;
+}
+
+void AddUrlNextQueryParameter(const std::string& attribute,
+ const std::string& value,
+ std::string* out_url) {
+ *out_url += "&";
+ *out_url += attribute;
+ *out_url += "=";
+ *out_url += value;
+}
+
+void AddHeaders(const std::string& header_field_key,
+ const std::string& header_field_value,
+ std::string* out_headers) {
+ *out_headers += header_field_key;
+ *out_headers += ": ";
+ *out_headers += header_field_value;
+ *out_headers += "\n";
+}
+
+void AddBody(const std::string& data, std::string* out_body) {
+ *out_body += data;
+ *out_body += "\n";
+}
+
+Error FinishPreparingResponse(PepperInterface* ppapi,
+ PP_Resource url_loader_object,
+ PP_Resource* out_url_response_info_object) {
+ *out_url_response_info_object = 0;
+
+ URLLoaderInterface* url_loader_iface = ppapi->GetURLLoaderInterface();
+
+ int32_t bytes_read = url_loader_iface->FinishStreamingToFile(
+ url_loader_object, PP_BlockUntilComplete());
+ if (bytes_read < 0) {
+ return PPERROR_TO_ERRNO(bytes_read);
+ }
+
+ *out_url_response_info_object =
+ url_loader_iface->GetResponseInfo(url_loader_object);
+
+ url_loader_iface->Close(url_loader_object);
+
+ return 0;
+}
+
+Error MakeRequest(PepperInterface* ppapi,
+ PP_Resource url_loader_object,
+ PP_Resource url_request_info_object,
+ const RequestUrlParams& params) {
+ VarInterface* var_iface = ppapi->GetVarInterface();
+ URLLoaderInterface* url_loader_iface = ppapi->GetURLLoaderInterface();
+ URLRequestInfoInterface* url_request_info_iface =
+ ppapi->GetURLRequestInfoInterface();
+
+ struct PP_Var pp_var =
+ var_iface->VarFromUtf8(params.url.c_str(), params.url.size());
+ if (!url_request_info_iface->SetProperty(url_request_info_object,
chanpatorikku 2016/08/07 02:41:03 Lines 100-101 are samples of code that attempts in
+ PP_URLREQUESTPROPERTY_URL, pp_var)) {
+ return EPERM;
+ }
+
+ pp_var = var_iface->VarFromUtf8(params.method.c_str(), params.method.size());
+ if (!url_request_info_iface->SetProperty(
+ url_request_info_object, PP_URLREQUESTPROPERTY_METHOD, pp_var)) {
+ return EPERM;
+ }
+
+ pp_var =
+ var_iface->VarFromUtf8(params.headers.c_str(), params.headers.size());
+ if (!url_request_info_iface->SetProperty(
+ url_request_info_object, PP_URLREQUESTPROPERTY_HEADERS, pp_var)) {
+ return EPERM;
+ }
+
+ if (!params.body.empty() &&
+ !url_request_info_iface->AppendDataToBody(
+ url_request_info_object, params.body.data(), params.body.size())) {
+ return EPERM;
+ }
+
+ pp_var = PP_MakeBool(PP_TRUE);
+ if (!url_request_info_iface->SetProperty(
+ url_request_info_object,
+ PP_URLREQUESTPROPERTY_ALLOWCROSSORIGINREQUESTS, pp_var)) {
+ return EPERM;
+ }
+
+ pp_var = PP_MakeBool(PP_TRUE);
+ if (!url_request_info_iface->SetProperty(url_request_info_object,
+ PP_URLREQUESTPROPERTY_STREAMTOFILE,
+ pp_var)) {
+ return EPERM;
+ }
+
+ int32_t err = url_loader_iface->Open(
+ url_loader_object, url_request_info_object, PP_BlockUntilComplete());
+
+ if (err < 0) {
+ return PPERROR_TO_ERRNO(err);
+ }
+
+ return 0;
+}
+
+Error ReadResponseBody(PepperInterface* ppapi,
+ PP_Instance instance,
+ PP_Resource url_response_info_object,
+ int32_t bytes_to_read,
+ std::string* out_output) {
+ *out_output = "";
+
+ URLResponseInfoInterface* url_response_info_iface =
+ ppapi->GetURLResponseInfoInterface();
+ FileIoInterface* file_io_iface = ppapi->GetFileIoInterface();
+
+ PP_Resource file_ref_object =
+ url_response_info_iface->GetBodyAsFileRef(url_response_info_object);
+ PP_Resource file_io_object = file_io_iface->Create(instance);
+
+ Error error(0);
+ int32_t bytes_read = 0;
+ int BUFFER_SIZE = 1024;
+ // Memory is allocated in the heap but not the stack to work around
+ // https://bugs.chromium.org/p/nativeclient/issues/detail?id=4114
+ char* buffer = new char[BUFFER_SIZE];
+
+ int32_t open_result =
+ file_io_iface->Open(file_io_object, file_ref_object, PP_FILEOPENFLAG_READ,
+ PP_BlockUntilComplete());
+ if (open_result < 0) {
+ error = PPERROR_TO_ERRNO(open_result);
+ goto done;
+ }
+
+ bytes_read = file_io_iface->Read(file_io_object, 0, buffer, BUFFER_SIZE,
+ PP_BlockUntilComplete());
+
+ while (bytes_read > 0) {
+ *out_output += std::string(buffer, bytes_read);
+
+ bytes_read = file_io_iface->Read(file_io_object, out_output->size(), buffer,
+ BUFFER_SIZE, PP_BlockUntilComplete());
+ }
+
+ if (bytes_read < 0) {
+ error = PPERROR_TO_ERRNO(bytes_read);
+ goto done;
+ }
+
+ out_output->resize(std::min(out_output->size(), (size_t)bytes_to_read));
+
+done:
+ if (file_ref_object) {
+ ppapi->ReleaseResource(file_ref_object);
+ }
+ if (file_io_object) {
+ file_io_iface->Close(file_io_object);
+
+ ppapi->ReleaseResource(file_io_object);
+ }
+
+ delete[] buffer;
+
+ return error;
+}
+
+int32_t ReadStatusCode(PepperInterface* ppapi,
+ PP_Resource url_response_info_object) {
+ URLResponseInfoInterface* url_response_info_iface =
+ ppapi->GetURLResponseInfoInterface();
+
+ struct PP_Var status_code_var = url_response_info_iface->GetProperty(
+ url_response_info_object, PP_URLRESPONSEPROPERTY_STATUSCODE);
+
+ return status_code_var.value.as_int;
+}
+
+void GetValue(const std::string& json,
+ const std::string& key,
+ int find_pos,
+ std::string* out_value,
+ int* out_value_char_pos) {
+ // All keys parsed in the response format in GoogleDriveFs are unique.
+ // Suppose keys of the API response stay unchanged.
+ // Without parsing Json, use substring search to get the key's value.
+
+ *out_value = "";
+ *out_value_char_pos = -1;
+
+ size_t key_location = json.find("\"" + key + "\": \"", find_pos);
+ if (key_location == std::string::npos) {
+ return;
binji 2016/08/22 19:21:53 This should be an error.
chanpatorikku 2016/08/29 17:14:03 Done. The function is redesigned to return an erro
+ }
+
+ size_t start_value_index = key_location + key.size() + 5;
binji 2016/08/22 19:21:53 Why 5?
chanpatorikku 2016/08/29 17:14:03 From your other comments, you already figured out
+ // GetValue is called when STATUSCODE_OK responses are received.
+ // The responses are assumed to always be completely received.
+ size_t end_value_index = json.find("\"", start_value_index);
binji 2016/08/22 19:21:53 If GetValue is always returning a string, you may
chanpatorikku 2016/08/29 17:14:03 GetValue(..) is renamed to GetValueStringAndValueP
+
+ *out_value =
+ json.substr(start_value_index, end_value_index - start_value_index);
+ *out_value_char_pos = start_value_index;
+}
+
+// A Google Drive item is a file or a directory.
+// RequestDirId requests to see if a directory with dir_name
+// and a parent with ID parent_dir_id is there.
+// If it is, dir_id is set.
+// RequestDirId returns ENOENT when a file with dir_name is there
+// but a directory with dir_name is not.
+Error RequestDirId(const std::string& parent_dir_id,
+ const std::string& dir_name,
+ Filesystem* filesystem,
+ std::string* out_dir_id) {
+ *out_dir_id = "";
+
+ GoogleDriveFs* googledrivefs = static_cast<GoogleDriveFs*>(filesystem);
+
+ URLLoaderInterface* url_loader_iface =
+ googledrivefs->ppapi()->GetURLLoaderInterface();
+ PP_Resource url_loader_object =
+ url_loader_iface->Create(googledrivefs->instance());
+ URLRequestInfoInterface* url_request_info_iface =
+ googledrivefs->ppapi()->GetURLRequestInfoInterface();
+ PP_Resource url_request_info_object =
+ url_request_info_iface->Create(googledrivefs->instance());
+ PP_Resource url_response_info_object = 0;
+ Error error(0);
+ std::string output;
+ int id_index;
+
+ static const char base_url[] = "https://www.googleapis.com/drive/v3/files";
+
+ RequestUrlParams p;
+
+ p.url = base_url;
+
+ std::string q_attribute_value = "";
+
+ std::string attribute_values[] = {
+ "%27" + parent_dir_id + "%27+in+parents",
+ "mimeType+=+%27application/vnd.google-apps.folder%27",
+ "name+=+%27" + dir_name + "%27"};
+
+ AddUrlQAttributeValue(attribute_values, 3, &q_attribute_value);
+ AddUrlFirstQueryParameter("q", q_attribute_value, &p.url);
+
+ p.method = "GET";
+
+ p.headers = "";
+
+ AddHeaders("Content-type", "application/json", &p.headers);
+ AddHeaders("Authorization", "Bearer " + googledrivefs->token(), &p.headers);
+
+ error = MakeRequest(googledrivefs->ppapi(), url_loader_object,
+ url_request_info_object, p);
+
+ if (error) {
+ goto done;
+ }
+
+ error = FinishPreparingResponse(googledrivefs->ppapi(), url_loader_object,
+ &url_response_info_object);
+
+ if (error) {
+ goto done;
+ }
+
+ if (ReadStatusCode(googledrivefs->ppapi(), url_response_info_object) !=
+ STATUSCODE_OK) {
+ error = EPERM;
+ goto done;
+ }
+
+ error = ReadResponseBody(googledrivefs->ppapi(), googledrivefs->instance(),
+ url_response_info_object, INT_MAX, &output);
+
+ if (error) {
+ goto done;
+ }
+
+ GetValue(output, "id", 0, out_dir_id, &id_index);
+ if (id_index == -1) {
+ error = ENOENT;
+ goto done;
+ }
+
+done:
+ if (url_loader_object) {
+ googledrivefs->ppapi()->ReleaseResource(url_loader_object);
+ }
+ if (url_request_info_object) {
+ googledrivefs->ppapi()->ReleaseResource(url_request_info_object);
+ }
+ if (url_response_info_object) {
+ googledrivefs->ppapi()->ReleaseResource(url_response_info_object);
+ }
+
+ return error;
+}
+
+// A Google Drive item is a file or a directory.
+// RequestItemId requests to see if either a file with item_name
+// or a directory with item_name is there.
+// If it is, item_id is set.
+Error RequestItemId(const std::string& parent_dir_id,
+ const std::string& item_name,
+ Filesystem* filesystem,
+ std::string* out_item_id) {
+ *out_item_id = "";
+
+ GoogleDriveFs* googledrivefs = static_cast<GoogleDriveFs*>(filesystem);
+
+ URLLoaderInterface* url_loader_iface =
+ googledrivefs->ppapi()->GetURLLoaderInterface();
+ PP_Resource url_loader_object =
+ url_loader_iface->Create(googledrivefs->instance());
+ URLRequestInfoInterface* url_request_info_iface =
+ googledrivefs->ppapi()->GetURLRequestInfoInterface();
+ PP_Resource url_request_info_object =
+ url_request_info_iface->Create(googledrivefs->instance());
+ PP_Resource url_response_info_object = 0;
+ Error error(0);
+ std::string output;
+ int id_index;
+
+ static const char base_url[] = "https://www.googleapis.com/drive/v3/files";
+
+ RequestUrlParams p;
+
+ p.url = base_url;
+ std::string q_attribute_value = "";
+ std::string attribute_values[] = {"%27" + parent_dir_id + "%27+in+parents",
+ "name+=+%27" + item_name + "%27"};
+ AddUrlQAttributeValue(attribute_values, 2, &q_attribute_value);
+ AddUrlFirstQueryParameter("q", q_attribute_value, &p.url);
+
+ p.method = "GET";
+
+ p.headers = "";
+
+ AddHeaders("Content-type", "application/json", &p.headers);
+ AddHeaders("Authorization", "Bearer " + googledrivefs->token(), &p.headers);
+
+ error = MakeRequest(googledrivefs->ppapi(), url_loader_object,
+ url_request_info_object, p);
+
+ if (error) {
+ goto done;
+ }
+
+ error = FinishPreparingResponse(googledrivefs->ppapi(), url_loader_object,
+ &url_response_info_object);
+
+ if (error) {
+ goto done;
+ }
+
+ if (ReadStatusCode(googledrivefs->ppapi(), url_response_info_object) !=
+ STATUSCODE_OK) {
+ error = EPERM;
+ goto done;
+ }
+
+ error = ReadResponseBody(googledrivefs->ppapi(), googledrivefs->instance(),
+ url_response_info_object, INT_MAX, &output);
+
+ if (error) {
+ goto done;
+ }
+
+ GetValue(output, "id", 0, out_item_id, &id_index);
+ if (id_index == -1) {
+ error = ENOENT;
+ goto done;
+ }
+
+done:
+ if (url_loader_object) {
+ googledrivefs->ppapi()->ReleaseResource(url_loader_object);
+ }
+ if (url_request_info_object) {
+ googledrivefs->ppapi()->ReleaseResource(url_request_info_object);
+ }
+ if (url_response_info_object) {
+ googledrivefs->ppapi()->ReleaseResource(url_response_info_object);
+ }
+
+ return error;
+}
+
+Error RequestParentDirId(const Path& path,
+ Filesystem* filesystem,
+ std::string* out_parent_dir_id) {
+ *out_parent_dir_id = "";
+
+ if (path.Size() < 2) {
+ return EINVAL;
+ }
+
+ std::string helper_parent_dir_id = "root";
+
+ for (unsigned int i = 1; i < path.Size() - 1; ++i) {
+ std::string dir_name = path.Range(i, i + 1);
+
+ std::string dir_id = "";
+ Error error =
+ RequestDirId(helper_parent_dir_id, dir_name, filesystem, &dir_id);
+ if (error) {
+ return error;
+ }
+
+ helper_parent_dir_id = dir_id;
+ }
+ *out_parent_dir_id = helper_parent_dir_id;
+
+ return 0;
+}
+
+Error GetListFileResponseBody(const std::string& url,
binji 2016/08/22 19:21:53 These last few functions look very similar with a
chanpatorikku 2016/08/29 17:14:03 Some combination has been done. RequestDirent(..)
+ Filesystem* filesystem,
+ std::string* out_response_body) {
+ GoogleDriveFs* googledrivefs = static_cast<GoogleDriveFs*>(filesystem);
+
+ URLLoaderInterface* url_loader_iface =
+ googledrivefs->ppapi()->GetURLLoaderInterface();
+ PP_Resource url_loader_object =
+ url_loader_iface->Create(googledrivefs->instance());
+ URLRequestInfoInterface* url_request_info_iface =
+ googledrivefs->ppapi()->GetURLRequestInfoInterface();
+ PP_Resource url_request_info_object =
+ url_request_info_iface->Create(googledrivefs->instance());
+ PP_Resource url_response_info_object = 0;
+ Error error(0);
+
+ RequestUrlParams p;
+
+ p.url = url;
+
+ p.method = "GET";
+
+ p.headers = "";
+
+ AddHeaders("Content-type", "application/json", &p.headers);
+ AddHeaders("Authorization", "Bearer " + googledrivefs->token(), &p.headers);
+
+ error = MakeRequest(googledrivefs->ppapi(), url_loader_object,
+ url_request_info_object, p);
+
+ if (error) {
+ goto done;
+ }
+
+ error = FinishPreparingResponse(googledrivefs->ppapi(), url_loader_object,
+ &url_response_info_object);
+
+ if (error) {
+ goto done;
+ }
+
+ if (ReadStatusCode(googledrivefs->ppapi(), url_response_info_object) !=
+ STATUSCODE_OK) {
+ error = EPERM;
+ goto done;
+ }
+
+ error =
+ ReadResponseBody(googledrivefs->ppapi(), googledrivefs->instance(),
+ url_response_info_object, INT_MAX, out_response_body);
+ if (error) {
+ goto done;
+ }
+
+done:
+ if (url_loader_object) {
+ googledrivefs->ppapi()->ReleaseResource(url_loader_object);
+ }
+ if (url_request_info_object) {
+ googledrivefs->ppapi()->ReleaseResource(url_request_info_object);
+ }
+ if (url_response_info_object) {
+ googledrivefs->ppapi()->ReleaseResource(url_response_info_object);
+ }
+
+ return error;
+}
+
+} // namespace nacl_io

Powered by Google App Engine
This is Rietveld 408576698