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

Side by Side 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "nacl_io/googledrivefs/googledrivefs_util.h"
6
7 #include <stdlib.h>
8
9 #include "ppapi/c/pp_completion_callback.h"
10 #include "ppapi/c/pp_instance.h"
11
12 #include "nacl_io/error.h"
13 #include "nacl_io/filesystem.h"
14 #include "nacl_io/path.h"
15 #include "nacl_io/pepper_interface.h"
16 #include "nacl_io/statuscode.h"
17 #include "nacl_io/googledrivefs/googledrivefs.h"
18
19 namespace nacl_io {
20
21 void AddUrlPath(const std::string& path, std::string* out_url) {
22 *out_url += "/";
23 *out_url += path;
24 }
25
26 void AddUrlQAttributeValue(std::string* array,
27 int size,
28 std::string* out_q_attribute_value) {
29 *out_q_attribute_value = array[0];
30 for (int i = 1; i < size; ++i) {
31 *out_q_attribute_value += "+and+";
32 *out_q_attribute_value += array[i];
33 }
34 }
35
36 void AddUrlFirstQueryParameter(const std::string& attribute,
37 const std::string& value,
38 std::string* out_url) {
39 *out_url += "?";
40 *out_url += attribute;
41 *out_url += "=";
42 *out_url += value;
43 }
44
45 void AddUrlNextQueryParameter(const std::string& attribute,
46 const std::string& value,
47 std::string* out_url) {
48 *out_url += "&";
49 *out_url += attribute;
50 *out_url += "=";
51 *out_url += value;
52 }
53
54 void AddHeaders(const std::string& header_field_key,
55 const std::string& header_field_value,
56 std::string* out_headers) {
57 *out_headers += header_field_key;
58 *out_headers += ": ";
59 *out_headers += header_field_value;
60 *out_headers += "\n";
61 }
62
63 void AddBody(const std::string& data, std::string* out_body) {
64 *out_body += data;
65 *out_body += "\n";
66 }
67
68 Error FinishPreparingResponse(PepperInterface* ppapi,
69 PP_Resource url_loader_object,
70 PP_Resource* out_url_response_info_object) {
71 *out_url_response_info_object = 0;
72
73 URLLoaderInterface* url_loader_iface = ppapi->GetURLLoaderInterface();
74
75 int32_t bytes_read = url_loader_iface->FinishStreamingToFile(
76 url_loader_object, PP_BlockUntilComplete());
77 if (bytes_read < 0) {
78 return PPERROR_TO_ERRNO(bytes_read);
79 }
80
81 *out_url_response_info_object =
82 url_loader_iface->GetResponseInfo(url_loader_object);
83
84 url_loader_iface->Close(url_loader_object);
85
86 return 0;
87 }
88
89 Error MakeRequest(PepperInterface* ppapi,
90 PP_Resource url_loader_object,
91 PP_Resource url_request_info_object,
92 const RequestUrlParams& params) {
93 VarInterface* var_iface = ppapi->GetVarInterface();
94 URLLoaderInterface* url_loader_iface = ppapi->GetURLLoaderInterface();
95 URLRequestInfoInterface* url_request_info_iface =
96 ppapi->GetURLRequestInfoInterface();
97
98 struct PP_Var pp_var =
99 var_iface->VarFromUtf8(params.url.c_str(), params.url.size());
100 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
101 PP_URLREQUESTPROPERTY_URL, pp_var)) {
102 return EPERM;
103 }
104
105 pp_var = var_iface->VarFromUtf8(params.method.c_str(), params.method.size());
106 if (!url_request_info_iface->SetProperty(
107 url_request_info_object, PP_URLREQUESTPROPERTY_METHOD, pp_var)) {
108 return EPERM;
109 }
110
111 pp_var =
112 var_iface->VarFromUtf8(params.headers.c_str(), params.headers.size());
113 if (!url_request_info_iface->SetProperty(
114 url_request_info_object, PP_URLREQUESTPROPERTY_HEADERS, pp_var)) {
115 return EPERM;
116 }
117
118 if (!params.body.empty() &&
119 !url_request_info_iface->AppendDataToBody(
120 url_request_info_object, params.body.data(), params.body.size())) {
121 return EPERM;
122 }
123
124 pp_var = PP_MakeBool(PP_TRUE);
125 if (!url_request_info_iface->SetProperty(
126 url_request_info_object,
127 PP_URLREQUESTPROPERTY_ALLOWCROSSORIGINREQUESTS, pp_var)) {
128 return EPERM;
129 }
130
131 pp_var = PP_MakeBool(PP_TRUE);
132 if (!url_request_info_iface->SetProperty(url_request_info_object,
133 PP_URLREQUESTPROPERTY_STREAMTOFILE,
134 pp_var)) {
135 return EPERM;
136 }
137
138 int32_t err = url_loader_iface->Open(
139 url_loader_object, url_request_info_object, PP_BlockUntilComplete());
140
141 if (err < 0) {
142 return PPERROR_TO_ERRNO(err);
143 }
144
145 return 0;
146 }
147
148 Error ReadResponseBody(PepperInterface* ppapi,
149 PP_Instance instance,
150 PP_Resource url_response_info_object,
151 int32_t bytes_to_read,
152 std::string* out_output) {
153 *out_output = "";
154
155 URLResponseInfoInterface* url_response_info_iface =
156 ppapi->GetURLResponseInfoInterface();
157 FileIoInterface* file_io_iface = ppapi->GetFileIoInterface();
158
159 PP_Resource file_ref_object =
160 url_response_info_iface->GetBodyAsFileRef(url_response_info_object);
161 PP_Resource file_io_object = file_io_iface->Create(instance);
162
163 Error error(0);
164 int32_t bytes_read = 0;
165 int BUFFER_SIZE = 1024;
166 // Memory is allocated in the heap but not the stack to work around
167 // https://bugs.chromium.org/p/nativeclient/issues/detail?id=4114
168 char* buffer = new char[BUFFER_SIZE];
169
170 int32_t open_result =
171 file_io_iface->Open(file_io_object, file_ref_object, PP_FILEOPENFLAG_READ,
172 PP_BlockUntilComplete());
173 if (open_result < 0) {
174 error = PPERROR_TO_ERRNO(open_result);
175 goto done;
176 }
177
178 bytes_read = file_io_iface->Read(file_io_object, 0, buffer, BUFFER_SIZE,
179 PP_BlockUntilComplete());
180
181 while (bytes_read > 0) {
182 *out_output += std::string(buffer, bytes_read);
183
184 bytes_read = file_io_iface->Read(file_io_object, out_output->size(), buffer,
185 BUFFER_SIZE, PP_BlockUntilComplete());
186 }
187
188 if (bytes_read < 0) {
189 error = PPERROR_TO_ERRNO(bytes_read);
190 goto done;
191 }
192
193 out_output->resize(std::min(out_output->size(), (size_t)bytes_to_read));
194
195 done:
196 if (file_ref_object) {
197 ppapi->ReleaseResource(file_ref_object);
198 }
199 if (file_io_object) {
200 file_io_iface->Close(file_io_object);
201
202 ppapi->ReleaseResource(file_io_object);
203 }
204
205 delete[] buffer;
206
207 return error;
208 }
209
210 int32_t ReadStatusCode(PepperInterface* ppapi,
211 PP_Resource url_response_info_object) {
212 URLResponseInfoInterface* url_response_info_iface =
213 ppapi->GetURLResponseInfoInterface();
214
215 struct PP_Var status_code_var = url_response_info_iface->GetProperty(
216 url_response_info_object, PP_URLRESPONSEPROPERTY_STATUSCODE);
217
218 return status_code_var.value.as_int;
219 }
220
221 void GetValue(const std::string& json,
222 const std::string& key,
223 int find_pos,
224 std::string* out_value,
225 int* out_value_char_pos) {
226 // All keys parsed in the response format in GoogleDriveFs are unique.
227 // Suppose keys of the API response stay unchanged.
228 // Without parsing Json, use substring search to get the key's value.
229
230 *out_value = "";
231 *out_value_char_pos = -1;
232
233 size_t key_location = json.find("\"" + key + "\": \"", find_pos);
234 if (key_location == std::string::npos) {
235 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
236 }
237
238 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
239 // GetValue is called when STATUSCODE_OK responses are received.
240 // The responses are assumed to always be completely received.
241 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
242
243 *out_value =
244 json.substr(start_value_index, end_value_index - start_value_index);
245 *out_value_char_pos = start_value_index;
246 }
247
248 // A Google Drive item is a file or a directory.
249 // RequestDirId requests to see if a directory with dir_name
250 // and a parent with ID parent_dir_id is there.
251 // If it is, dir_id is set.
252 // RequestDirId returns ENOENT when a file with dir_name is there
253 // but a directory with dir_name is not.
254 Error RequestDirId(const std::string& parent_dir_id,
255 const std::string& dir_name,
256 Filesystem* filesystem,
257 std::string* out_dir_id) {
258 *out_dir_id = "";
259
260 GoogleDriveFs* googledrivefs = static_cast<GoogleDriveFs*>(filesystem);
261
262 URLLoaderInterface* url_loader_iface =
263 googledrivefs->ppapi()->GetURLLoaderInterface();
264 PP_Resource url_loader_object =
265 url_loader_iface->Create(googledrivefs->instance());
266 URLRequestInfoInterface* url_request_info_iface =
267 googledrivefs->ppapi()->GetURLRequestInfoInterface();
268 PP_Resource url_request_info_object =
269 url_request_info_iface->Create(googledrivefs->instance());
270 PP_Resource url_response_info_object = 0;
271 Error error(0);
272 std::string output;
273 int id_index;
274
275 static const char base_url[] = "https://www.googleapis.com/drive/v3/files";
276
277 RequestUrlParams p;
278
279 p.url = base_url;
280
281 std::string q_attribute_value = "";
282
283 std::string attribute_values[] = {
284 "%27" + parent_dir_id + "%27+in+parents",
285 "mimeType+=+%27application/vnd.google-apps.folder%27",
286 "name+=+%27" + dir_name + "%27"};
287
288 AddUrlQAttributeValue(attribute_values, 3, &q_attribute_value);
289 AddUrlFirstQueryParameter("q", q_attribute_value, &p.url);
290
291 p.method = "GET";
292
293 p.headers = "";
294
295 AddHeaders("Content-type", "application/json", &p.headers);
296 AddHeaders("Authorization", "Bearer " + googledrivefs->token(), &p.headers);
297
298 error = MakeRequest(googledrivefs->ppapi(), url_loader_object,
299 url_request_info_object, p);
300
301 if (error) {
302 goto done;
303 }
304
305 error = FinishPreparingResponse(googledrivefs->ppapi(), url_loader_object,
306 &url_response_info_object);
307
308 if (error) {
309 goto done;
310 }
311
312 if (ReadStatusCode(googledrivefs->ppapi(), url_response_info_object) !=
313 STATUSCODE_OK) {
314 error = EPERM;
315 goto done;
316 }
317
318 error = ReadResponseBody(googledrivefs->ppapi(), googledrivefs->instance(),
319 url_response_info_object, INT_MAX, &output);
320
321 if (error) {
322 goto done;
323 }
324
325 GetValue(output, "id", 0, out_dir_id, &id_index);
326 if (id_index == -1) {
327 error = ENOENT;
328 goto done;
329 }
330
331 done:
332 if (url_loader_object) {
333 googledrivefs->ppapi()->ReleaseResource(url_loader_object);
334 }
335 if (url_request_info_object) {
336 googledrivefs->ppapi()->ReleaseResource(url_request_info_object);
337 }
338 if (url_response_info_object) {
339 googledrivefs->ppapi()->ReleaseResource(url_response_info_object);
340 }
341
342 return error;
343 }
344
345 // A Google Drive item is a file or a directory.
346 // RequestItemId requests to see if either a file with item_name
347 // or a directory with item_name is there.
348 // If it is, item_id is set.
349 Error RequestItemId(const std::string& parent_dir_id,
350 const std::string& item_name,
351 Filesystem* filesystem,
352 std::string* out_item_id) {
353 *out_item_id = "";
354
355 GoogleDriveFs* googledrivefs = static_cast<GoogleDriveFs*>(filesystem);
356
357 URLLoaderInterface* url_loader_iface =
358 googledrivefs->ppapi()->GetURLLoaderInterface();
359 PP_Resource url_loader_object =
360 url_loader_iface->Create(googledrivefs->instance());
361 URLRequestInfoInterface* url_request_info_iface =
362 googledrivefs->ppapi()->GetURLRequestInfoInterface();
363 PP_Resource url_request_info_object =
364 url_request_info_iface->Create(googledrivefs->instance());
365 PP_Resource url_response_info_object = 0;
366 Error error(0);
367 std::string output;
368 int id_index;
369
370 static const char base_url[] = "https://www.googleapis.com/drive/v3/files";
371
372 RequestUrlParams p;
373
374 p.url = base_url;
375 std::string q_attribute_value = "";
376 std::string attribute_values[] = {"%27" + parent_dir_id + "%27+in+parents",
377 "name+=+%27" + item_name + "%27"};
378 AddUrlQAttributeValue(attribute_values, 2, &q_attribute_value);
379 AddUrlFirstQueryParameter("q", q_attribute_value, &p.url);
380
381 p.method = "GET";
382
383 p.headers = "";
384
385 AddHeaders("Content-type", "application/json", &p.headers);
386 AddHeaders("Authorization", "Bearer " + googledrivefs->token(), &p.headers);
387
388 error = MakeRequest(googledrivefs->ppapi(), url_loader_object,
389 url_request_info_object, p);
390
391 if (error) {
392 goto done;
393 }
394
395 error = FinishPreparingResponse(googledrivefs->ppapi(), url_loader_object,
396 &url_response_info_object);
397
398 if (error) {
399 goto done;
400 }
401
402 if (ReadStatusCode(googledrivefs->ppapi(), url_response_info_object) !=
403 STATUSCODE_OK) {
404 error = EPERM;
405 goto done;
406 }
407
408 error = ReadResponseBody(googledrivefs->ppapi(), googledrivefs->instance(),
409 url_response_info_object, INT_MAX, &output);
410
411 if (error) {
412 goto done;
413 }
414
415 GetValue(output, "id", 0, out_item_id, &id_index);
416 if (id_index == -1) {
417 error = ENOENT;
418 goto done;
419 }
420
421 done:
422 if (url_loader_object) {
423 googledrivefs->ppapi()->ReleaseResource(url_loader_object);
424 }
425 if (url_request_info_object) {
426 googledrivefs->ppapi()->ReleaseResource(url_request_info_object);
427 }
428 if (url_response_info_object) {
429 googledrivefs->ppapi()->ReleaseResource(url_response_info_object);
430 }
431
432 return error;
433 }
434
435 Error RequestParentDirId(const Path& path,
436 Filesystem* filesystem,
437 std::string* out_parent_dir_id) {
438 *out_parent_dir_id = "";
439
440 if (path.Size() < 2) {
441 return EINVAL;
442 }
443
444 std::string helper_parent_dir_id = "root";
445
446 for (unsigned int i = 1; i < path.Size() - 1; ++i) {
447 std::string dir_name = path.Range(i, i + 1);
448
449 std::string dir_id = "";
450 Error error =
451 RequestDirId(helper_parent_dir_id, dir_name, filesystem, &dir_id);
452 if (error) {
453 return error;
454 }
455
456 helper_parent_dir_id = dir_id;
457 }
458 *out_parent_dir_id = helper_parent_dir_id;
459
460 return 0;
461 }
462
463 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(..)
464 Filesystem* filesystem,
465 std::string* out_response_body) {
466 GoogleDriveFs* googledrivefs = static_cast<GoogleDriveFs*>(filesystem);
467
468 URLLoaderInterface* url_loader_iface =
469 googledrivefs->ppapi()->GetURLLoaderInterface();
470 PP_Resource url_loader_object =
471 url_loader_iface->Create(googledrivefs->instance());
472 URLRequestInfoInterface* url_request_info_iface =
473 googledrivefs->ppapi()->GetURLRequestInfoInterface();
474 PP_Resource url_request_info_object =
475 url_request_info_iface->Create(googledrivefs->instance());
476 PP_Resource url_response_info_object = 0;
477 Error error(0);
478
479 RequestUrlParams p;
480
481 p.url = url;
482
483 p.method = "GET";
484
485 p.headers = "";
486
487 AddHeaders("Content-type", "application/json", &p.headers);
488 AddHeaders("Authorization", "Bearer " + googledrivefs->token(), &p.headers);
489
490 error = MakeRequest(googledrivefs->ppapi(), url_loader_object,
491 url_request_info_object, p);
492
493 if (error) {
494 goto done;
495 }
496
497 error = FinishPreparingResponse(googledrivefs->ppapi(), url_loader_object,
498 &url_response_info_object);
499
500 if (error) {
501 goto done;
502 }
503
504 if (ReadStatusCode(googledrivefs->ppapi(), url_response_info_object) !=
505 STATUSCODE_OK) {
506 error = EPERM;
507 goto done;
508 }
509
510 error =
511 ReadResponseBody(googledrivefs->ppapi(), googledrivefs->instance(),
512 url_response_info_object, INT_MAX, out_response_body);
513 if (error) {
514 goto done;
515 }
516
517 done:
518 if (url_loader_object) {
519 googledrivefs->ppapi()->ReleaseResource(url_loader_object);
520 }
521 if (url_request_info_object) {
522 googledrivefs->ppapi()->ReleaseResource(url_request_info_object);
523 }
524 if (url_response_info_object) {
525 googledrivefs->ppapi()->ReleaseResource(url_response_info_object);
526 }
527
528 return error;
529 }
530
531 } // namespace nacl_io
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698