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 |