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

Side by Side Diff: native_client_sdk/src/libraries/nacl_io/mount_http.cc

Issue 16232016: [NaCl SDK] nacl_io: big refactor to return error value (errno). (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: merge master, fix windows Created 7 years, 6 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 | Annotate | Revision Log
OLDNEW
1 /* Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 /* Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be 2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file. 3 * found in the LICENSE file.
4 */ 4 */
5 5
6 #include "nacl_io/mount_http.h" 6 #include "nacl_io/mount_http.h"
7
7 #include <assert.h> 8 #include <assert.h>
8 #include <ctype.h> 9 #include <ctype.h>
9 #include <errno.h> 10 #include <errno.h>
10 #include <fcntl.h> 11 #include <fcntl.h>
11 #include <ppapi/c/pp_errors.h>
12 #include <stdio.h> 12 #include <stdio.h>
13 #include <string.h> 13 #include <string.h>
14 #include <sys/stat.h> 14 #include <sys/stat.h>
15 #include <sys/types.h> 15 #include <sys/types.h>
16
16 #include <vector> 17 #include <vector>
18
19 #include <ppapi/c/pp_errors.h>
20
17 #include "nacl_io/mount_node_dir.h" 21 #include "nacl_io/mount_node_dir.h"
22 #include "nacl_io/mount_node_http.h"
18 #include "nacl_io/osinttypes.h" 23 #include "nacl_io/osinttypes.h"
19 #include "sdk_util/auto_lock.h" 24 #include "sdk_util/auto_lock.h"
20 25
21 #if defined(WIN32)
22 #define snprintf _snprintf
23 #endif
24
25
26 namespace { 26 namespace {
27 27
28 typedef std::vector<char *> StringList_t; 28 typedef std::vector<char*> StringList_t;
29 size_t SplitString(char *str, const char *delim, StringList_t* list) { 29 size_t SplitString(char* str, const char* delim, StringList_t* list) {
30 char *item = strtok(str, delim); 30 char* item = strtok(str, delim);
31 31
32 list->clear(); 32 list->clear();
33 while (item) { 33 while (item) {
34 list->push_back(item); 34 list->push_back(item);
35 item = strtok(NULL, delim); 35 item = strtok(NULL, delim);
36 } 36 }
37 37
38 return list->size(); 38 return list->size();
39 } 39 }
40 40
41 41 } // namespace
42 // If we're attempting to read a partial request, but the server returns a full
43 // request, we need to read all of the data up to the start of our partial
44 // request into a dummy buffer. This is the maximum size of that buffer.
45 const size_t MAX_READ_BUFFER_SIZE = 64 * 1024;
46 const int32_t STATUSCODE_OK = 200;
47 const int32_t STATUSCODE_PARTIAL_CONTENT = 206;
48 42
49 std::string NormalizeHeaderKey(const std::string& s) { 43 std::string NormalizeHeaderKey(const std::string& s) {
50 // Capitalize the first letter and any letter following a hyphen: 44 // Capitalize the first letter and any letter following a hyphen:
51 // e.g. ACCEPT-ENCODING -> Accept-Encoding 45 // e.g. ACCEPT-ENCODING -> Accept-Encoding
52 std::string result; 46 std::string result;
53 bool upper = true; 47 bool upper = true;
54 for (size_t i = 0; i < s.length(); ++i) { 48 for (size_t i = 0; i < s.length(); ++i) {
55 char c = s[i]; 49 char c = s[i];
56 result += upper ? toupper(c) : tolower(c); 50 result += upper ? toupper(c) : tolower(c);
57 upper = c == '-'; 51 upper = c == '-';
58 } 52 }
59 53
60 return result; 54 return result;
61 } 55 }
62 56
63 StringMap_t ParseHeaders(const char* headers, int32_t headers_length) { 57 Error MountHttp::Open(const Path& path, int mode, MountNode** out_node) {
64 enum State { 58 *out_node = NULL;
65 FINDING_KEY,
66 SKIPPING_WHITESPACE,
67 FINDING_VALUE,
68 };
69 59
70 StringMap_t result;
71 std::string key;
72 std::string value;
73
74 State state = FINDING_KEY;
75 const char* start = headers;
76 for (int i = 0; i < headers_length; ++i) {
77 switch (state) {
78 case FINDING_KEY:
79 if (headers[i] == ':') {
80 // Found key.
81 key.assign(start, &headers[i] - start);
82 key = NormalizeHeaderKey(key);
83 state = SKIPPING_WHITESPACE;
84 }
85 break;
86
87 case SKIPPING_WHITESPACE:
88 if (headers[i] == ' ') {
89 // Found whitespace, keep going...
90 break;
91 }
92
93 // Found a non-whitespace, mark this as the start of the value.
94 start = &headers[i];
95 state = FINDING_VALUE;
96 // Fallthrough to start processing value without incrementing i.
97
98 case FINDING_VALUE:
99 if (headers[i] == '\n') {
100 // Found value.
101 value.assign(start, &headers[i] - start);
102 result[key] = value;
103 start = &headers[i + 1];
104 state = FINDING_KEY;
105 }
106 break;
107 }
108 }
109
110 return result;
111 }
112
113 bool ParseContentLength(const StringMap_t& headers, size_t* content_length) {
114 StringMap_t::const_iterator iter = headers.find("Content-Length");
115 if (iter == headers.end())
116 return false;
117
118 *content_length = strtoul(iter->second.c_str(), NULL, 10);
119 return true;
120 }
121
122 bool ParseContentRange(const StringMap_t& headers, size_t* read_start,
123 size_t* read_end, size_t* entity_length) {
124 StringMap_t::const_iterator iter = headers.find("Content-Range");
125 if (iter == headers.end())
126 return false;
127
128 // The key should look like "bytes ##-##/##" or "bytes ##-##/*". The last
129 // value is the entity length, which can potentially be * (i.e. unknown).
130 int read_start_int;
131 int read_end_int;
132 int entity_length_int;
133 int result = sscanf(iter->second.c_str(), "bytes %"SCNuS"-%"SCNuS"/%"SCNuS,
134 &read_start_int, &read_end_int, &entity_length_int);
135
136 // The Content-Range header specifies an inclusive range: e.g. the first ten
137 // bytes is "bytes 0-9/*". Convert it to a half-open range by incrementing
138 // read_end.
139 if (result == 2) {
140 *read_start = read_start_int;
141 *read_end = read_end_int + 1;
142 *entity_length = 0;
143 return true;
144 } else if (result == 3) {
145 *read_start = read_start_int;
146 *read_end = read_end_int + 1;
147 *entity_length = entity_length_int;
148 return true;
149 }
150
151 return false;
152 }
153
154 } // namespace
155
156
157 class MountNodeHttp : public MountNode {
158 public:
159 virtual int FSync();
160 virtual int GetDents(size_t offs, struct dirent* pdir, size_t count);
161 virtual int GetStat(struct stat* stat);
162 virtual int Read(size_t offs, void* buf, size_t count);
163 virtual int FTruncate(off_t size);
164 virtual int Write(size_t offs, const void* buf, size_t count);
165 virtual size_t GetSize();
166
167 void SetCachedSize(off_t size);
168
169 protected:
170 MountNodeHttp(Mount* mount, const std::string& url, bool cache_content);
171
172 private:
173 bool OpenUrl(const char* method,
174 StringMap_t* request_headers,
175 PP_Resource* out_loader,
176 PP_Resource* out_request,
177 PP_Resource* out_response,
178 int32_t* out_statuscode,
179 StringMap_t* out_response_headers);
180
181 int DownloadToCache();
182 int ReadPartialFromCache(size_t offs, void* buf, size_t count);
183 int DownloadPartial(size_t offs, void* buf, size_t count);
184 int DownloadToBuffer(PP_Resource loader, void* buf, size_t count);
185
186 std::string url_;
187 std::vector<char> buffer_;
188
189 bool cache_content_;
190 bool has_cached_size_;
191 std::vector<char> cached_data_;
192
193 friend class MountHttp;
194 };
195
196 void MountNodeHttp::SetCachedSize(off_t size) {
197 has_cached_size_ = true;
198 stat_.st_size = size;
199 }
200
201 int MountNodeHttp::FSync() {
202 errno = ENOSYS;
203 return -1;
204 }
205
206 int MountNodeHttp::GetDents(size_t offs, struct dirent* pdir, size_t count) {
207 errno = ENOSYS;
208 return -1;
209 }
210
211 int MountNodeHttp::GetStat(struct stat* stat) {
212 AutoLock lock(&lock_);
213
214 // Assume we need to 'HEAD' if we do not know the size, otherwise, assume
215 // that the information is constant. We can add a timeout if needed.
216 MountHttp* mount = static_cast<MountHttp*>(mount_);
217 if (stat_.st_size == 0 || !mount->cache_stat_) {
218 StringMap_t headers;
219 PP_Resource loader;
220 PP_Resource request;
221 PP_Resource response;
222 int32_t statuscode;
223 StringMap_t response_headers;
224 if (!OpenUrl("HEAD", &headers, &loader, &request, &response, &statuscode,
225 &response_headers)) {
226 // errno is already set by OpenUrl.
227 return -1;
228 }
229
230 ScopedResource scoped_loader(mount_->ppapi(), loader);
231 ScopedResource scoped_request(mount_->ppapi(), request);
232 ScopedResource scoped_response(mount_->ppapi(), response);
233
234
235 size_t entity_length;
236 if (ParseContentLength(response_headers, &entity_length)) {
237 SetCachedSize(static_cast<off_t>(entity_length));
238 } else if (cache_content_ && !has_cached_size_) {
239 DownloadToCache();
240 } else {
241 // Don't use SetCachedSize here -- it is actually unknown.
242 stat_.st_size = 0;
243 }
244
245 stat_.st_atime = 0; // TODO(binji): Use "Last-Modified".
246 stat_.st_mtime = 0;
247 stat_.st_ctime = 0;
248 }
249
250 // Fill the stat structure if provided
251 if (stat) {
252 memcpy(stat, &stat_, sizeof(stat_));
253 }
254 return 0;
255 }
256
257 int MountNodeHttp::Read(size_t offs, void* buf, size_t count) {
258 AutoLock lock(&lock_);
259 if (cache_content_) {
260 if (cached_data_.empty()) {
261 if (DownloadToCache() < 0)
262 return -1;
263 }
264
265 return ReadPartialFromCache(offs, buf, count);
266 }
267
268 return DownloadPartial(offs, buf, count);
269 }
270
271 int MountNodeHttp::FTruncate(off_t size) {
272 errno = ENOSYS;
273 return -1;
274 }
275
276 int MountNodeHttp::Write(size_t offs, const void* buf, size_t count) {
277 // TODO(binji): support POST?
278 errno = ENOSYS;
279 return -1;
280 }
281
282 size_t MountNodeHttp::GetSize() {
283 // TODO(binji): This value should be cached properly; i.e. obey the caching
284 // headers returned by the server.
285 AutoLock lock(&lock_);
286 if (!has_cached_size_) {
287 // Even if DownloadToCache fails, the best result we can return is what
288 // was written to stat_.st_size.
289 if (cache_content_)
290 DownloadToCache();
291 }
292
293 return stat_.st_size;
294 }
295
296 MountNodeHttp::MountNodeHttp(Mount* mount, const std::string& url,
297 bool cache_content)
298 : MountNode(mount),
299 url_(url),
300 cache_content_(cache_content),
301 has_cached_size_(false) {
302 }
303
304 bool MountNodeHttp::OpenUrl(const char* method,
305 StringMap_t* request_headers,
306 PP_Resource* out_loader,
307 PP_Resource* out_request,
308 PP_Resource* out_response,
309 int32_t* out_statuscode,
310 StringMap_t* out_response_headers) {
311 // Assume lock_ is already held.
312
313 PepperInterface* ppapi = mount_->ppapi();
314
315 MountHttp* mount_http = static_cast<MountHttp*>(mount_);
316 ScopedResource request(ppapi,
317 mount_http->MakeUrlRequestInfo(url_, method,
318 request_headers));
319 if (!request.pp_resource()) {
320 errno = EINVAL;
321 return false;
322 }
323
324 URLLoaderInterface* loader_interface = ppapi->GetURLLoaderInterface();
325 URLResponseInfoInterface* response_interface =
326 ppapi->GetURLResponseInfoInterface();
327 VarInterface* var_interface = ppapi->GetVarInterface();
328
329 ScopedResource loader(ppapi, loader_interface->Create(ppapi->GetInstance()));
330 if (!loader.pp_resource()) {
331 errno = EINVAL;
332 return false;
333 }
334
335 int32_t result = loader_interface->Open(
336 loader.pp_resource(), request.pp_resource(), PP_BlockUntilComplete());
337 if (result != PP_OK) {
338 errno = PPErrorToErrno(result);
339 return false;
340 }
341
342 ScopedResource response(
343 ppapi,
344 loader_interface->GetResponseInfo(loader.pp_resource()));
345 if (!response.pp_resource()) {
346 errno = EINVAL;
347 return false;
348 }
349
350 // Get response statuscode.
351 PP_Var statuscode = response_interface->GetProperty(
352 response.pp_resource(),
353 PP_URLRESPONSEPROPERTY_STATUSCODE);
354
355 if (statuscode.type != PP_VARTYPE_INT32) {
356 errno = EINVAL;
357 return false;
358 }
359
360 *out_statuscode = statuscode.value.as_int;
361
362 // Only accept OK or Partial Content.
363 if (*out_statuscode != STATUSCODE_OK &&
364 *out_statuscode != STATUSCODE_PARTIAL_CONTENT) {
365 errno = EINVAL;
366 return false;
367 }
368
369 // Get response headers.
370 PP_Var response_headers_var = response_interface->GetProperty(
371 response.pp_resource(),
372 PP_URLRESPONSEPROPERTY_HEADERS);
373
374 uint32_t response_headers_length;
375 const char* response_headers_str = var_interface->VarToUtf8(
376 response_headers_var,
377 &response_headers_length);
378
379 *out_loader = loader.Release();
380 *out_request = request.Release();
381 *out_response = response.Release();
382 *out_response_headers = ParseHeaders(response_headers_str,
383 response_headers_length);
384
385 return true;
386 }
387
388 int MountNodeHttp::DownloadToCache() {
389 StringMap_t headers;
390 PP_Resource loader;
391 PP_Resource request;
392 PP_Resource response;
393 int32_t statuscode;
394 StringMap_t response_headers;
395 if (!OpenUrl("GET", &headers, &loader, &request, &response, &statuscode,
396 &response_headers)) {
397 // errno is already set by OpenUrl.
398 return -1;
399 }
400
401 PepperInterface* ppapi = mount_->ppapi();
402 ScopedResource scoped_loader(ppapi, loader);
403 ScopedResource scoped_request(ppapi, request);
404 ScopedResource scoped_response(ppapi, response);
405
406 size_t content_length = 0;
407 if (ParseContentLength(response_headers, &content_length)) {
408 cached_data_.resize(content_length);
409 int real_size = DownloadToBuffer(loader, cached_data_.data(),
410 content_length);
411 if (real_size < 0)
412 return -1;
413
414 SetCachedSize(real_size);
415 cached_data_.resize(real_size);
416 return real_size;
417 }
418
419 // We don't know how big the file is. Read in chunks.
420 cached_data_.resize(MAX_READ_BUFFER_SIZE);
421 size_t total_bytes_read = 0;
422 size_t bytes_to_read = MAX_READ_BUFFER_SIZE;
423 while (true) {
424 char* buf = cached_data_.data() + total_bytes_read;
425 int bytes_read = DownloadToBuffer(loader, buf, bytes_to_read);
426 if (bytes_read < 0)
427 return -1;
428
429 total_bytes_read += bytes_read;
430
431 if (bytes_read < bytes_to_read) {
432 SetCachedSize(total_bytes_read);
433 cached_data_.resize(total_bytes_read);
434 return total_bytes_read;
435 }
436
437 cached_data_.resize(total_bytes_read + bytes_to_read);
438 }
439 }
440
441 int MountNodeHttp::ReadPartialFromCache(size_t offs, void* buf, size_t count) {
442 if (offs > cached_data_.size()) {
443 errno = EINVAL;
444 return -1;
445 }
446
447 count = std::min(count, cached_data_.size() - offs);
448 memcpy(buf, &cached_data_.data()[offs], count);
449 return count;
450 }
451
452 int MountNodeHttp::DownloadPartial(size_t offs, void* buf, size_t count) {
453 StringMap_t headers;
454
455 char buffer[100];
456 // Range request is inclusive: 0-99 returns 100 bytes.
457 snprintf(&buffer[0], sizeof(buffer), "bytes=%"PRIuS"-%"PRIuS,
458 offs, offs + count - 1);
459 headers["Range"] = buffer;
460
461 PP_Resource loader;
462 PP_Resource request;
463 PP_Resource response;
464 int32_t statuscode;
465 StringMap_t response_headers;
466 if (!OpenUrl("GET", &headers, &loader, &request, &response, &statuscode,
467 &response_headers)) {
468 // errno is already set by OpenUrl.
469 return -1;
470 }
471
472 PepperInterface* ppapi = mount_->ppapi();
473 ScopedResource scoped_loader(ppapi, loader);
474 ScopedResource scoped_request(ppapi, request);
475 ScopedResource scoped_response(ppapi, response);
476
477 size_t read_start = 0;
478 if (statuscode == STATUSCODE_OK) {
479 // No partial result, read everything starting from the part we care about.
480 size_t content_length;
481 if (ParseContentLength(response_headers, &content_length)) {
482 if (offs >= content_length) {
483 errno = EINVAL;
484 return 0;
485 }
486
487 // Clamp count, if trying to read past the end of the file.
488 if (offs + count > content_length) {
489 count = content_length - offs;
490 }
491 }
492 } else if (statuscode == STATUSCODE_PARTIAL_CONTENT) {
493 // Determine from the headers where we are reading.
494 size_t read_end;
495 size_t entity_length;
496 if (ParseContentRange(response_headers, &read_start, &read_end,
497 &entity_length)) {
498 if (read_start > offs || read_start > read_end) {
499 // If this error occurs, the server is returning bogus values.
500 errno = EINVAL;
501 return -1;
502 }
503
504 // Clamp count, if trying to read past the end of the file.
505 count = std::min(read_end - read_start, count);
506 } else {
507 // Partial Content without Content-Range. Assume that the server gave us
508 // exactly what we asked for. This can happen even when the server
509 // returns 200 -- the cache may return 206 in this case, but not modify
510 // the headers.
511 read_start = offs;
512 }
513 }
514
515 if (read_start < offs) {
516 // We aren't yet at the location where we want to start reading. Read into
517 // our dummy buffer until then.
518 size_t bytes_to_read = offs - read_start;
519 if (buffer_.size() < bytes_to_read)
520 buffer_.resize(std::min(bytes_to_read, MAX_READ_BUFFER_SIZE));
521
522 while (bytes_to_read > 0) {
523 int32_t bytes_read = DownloadToBuffer(loader, buffer_.data(),
524 buffer_.size());
525 if (bytes_read < 0)
526 return -1;
527
528 bytes_to_read -= bytes_read;
529 }
530 }
531
532 return DownloadToBuffer(loader, buf, count);
533 }
534
535 int MountNodeHttp::DownloadToBuffer(PP_Resource loader, void* buf,
536 size_t count) {
537 PepperInterface* ppapi = mount_->ppapi();
538 URLLoaderInterface* loader_interface = ppapi->GetURLLoaderInterface();
539
540 char* out_buffer = static_cast<char*>(buf);
541 size_t bytes_to_read = count;
542 while (bytes_to_read > 0) {
543 int32_t bytes_read = loader_interface->ReadResponseBody(
544 loader, out_buffer, bytes_to_read, PP_BlockUntilComplete());
545
546 if (bytes_read == 0) {
547 // This is not an error -- it may just be that we were trying to read
548 // more data than exists.
549 return count - bytes_to_read;
550 }
551
552 if (bytes_read < 0) {
553 errno = PPErrorToErrno(bytes_read);
554 return -1;
555 }
556
557 assert(bytes_read <= bytes_to_read);
558 bytes_to_read -= bytes_read;
559 out_buffer += bytes_read;
560 }
561
562 return count;
563 }
564
565 MountNode *MountHttp::Open(const Path& path, int mode) {
566 assert(url_root_.empty() || url_root_[url_root_.length() - 1] == '/'); 60 assert(url_root_.empty() || url_root_[url_root_.length() - 1] == '/');
567 61
568 NodeMap_t::iterator iter = node_cache_.find(path.Join()); 62 NodeMap_t::iterator iter = node_cache_.find(path.Join());
569 if (iter != node_cache_.end()) { 63 if (iter != node_cache_.end()) {
570 return iter->second; 64 *out_node = iter->second;
65 return 0;
571 } 66 }
572 67
573 // If we can't find the node in the cache, create it 68 // If we can't find the node in the cache, create it
574 std::string url = url_root_ + (path.IsAbsolute() ? 69 std::string url = url_root_ + (path.IsAbsolute() ? path.Range(1, path.Size())
575 path.Range(1, path.Size()) : 70 : path.Join());
576 path.Join());
577 71
578 MountNodeHttp* node = new MountNodeHttp(this, url, cache_content_); 72 MountNodeHttp* node = new MountNodeHttp(this, url, cache_content_);
579 if (!node->Init(mode) || (0 != node->GetStat(NULL))) { 73 Error error = node->Init(mode);
74 if (error) {
580 node->Release(); 75 node->Release();
581 return NULL; 76 return error;
582 } 77 }
583 78
584 MountNodeDir* parent = FindOrCreateDir(path.Parent()); 79 error = node->GetStat(NULL);
80 if (error) {
81 node->Release();
82 return error;
83 }
84
85 MountNodeDir* parent;
86 error = FindOrCreateDir(path.Parent(), &parent);
87 if (error) {
88 node->Release();
89 return error;
90 }
91
92 error = parent->AddChild(path.Basename(), node);
93 if (error) {
94 node->Release();
95 return error;
96 }
97
585 node_cache_[path.Join()] = node; 98 node_cache_[path.Join()] = node;
586 parent->AddChild(path.Basename(), node); 99
587 return node; 100 *out_node = node;
101 return 0;
588 } 102 }
589 103
590 int MountHttp::Unlink(const Path& path) { 104 Error MountHttp::Unlink(const Path& path) { return ENOSYS; }
591 errno = ENOSYS;
592 return -1;
593 }
594 105
595 int MountHttp::Mkdir(const Path& path, int permissions) { 106 Error MountHttp::Mkdir(const Path& path, int permissions) { return ENOSYS; }
596 errno = ENOSYS;
597 return -1;
598 }
599 107
600 int MountHttp::Rmdir(const Path& path) { 108 Error MountHttp::Rmdir(const Path& path) { return ENOSYS; }
601 errno = ENOSYS;
602 return -1;
603 }
604 109
605 int MountHttp::Remove(const Path& path) { 110 Error MountHttp::Remove(const Path& path) { return ENOSYS; }
606 errno = ENOSYS;
607 return -1;
608 }
609 111
610 PP_Resource MountHttp::MakeUrlRequestInfo( 112 PP_Resource MountHttp::MakeUrlRequestInfo(const std::string& url,
611 const std::string& url, 113 const char* method,
612 const char* method, 114 StringMap_t* additional_headers) {
613 StringMap_t* additional_headers) {
614 URLRequestInfoInterface* interface = ppapi_->GetURLRequestInfoInterface(); 115 URLRequestInfoInterface* interface = ppapi_->GetURLRequestInfoInterface();
615 VarInterface* var_interface = ppapi_->GetVarInterface(); 116 VarInterface* var_interface = ppapi_->GetVarInterface();
616 117
617 PP_Resource request_info = interface->Create(ppapi_->GetInstance()); 118 PP_Resource request_info = interface->Create(ppapi_->GetInstance());
618 if (!request_info) 119 if (!request_info)
619 return 0; 120 return 0;
620 121
621 interface->SetProperty( 122 interface->SetProperty(request_info,
622 request_info, PP_URLREQUESTPROPERTY_URL, 123 PP_URLREQUESTPROPERTY_URL,
623 var_interface->VarFromUtf8(url.c_str(), url.length())); 124 var_interface->VarFromUtf8(url.c_str(), url.length()));
624 interface->SetProperty(request_info, PP_URLREQUESTPROPERTY_METHOD, 125 interface->SetProperty(request_info,
126 PP_URLREQUESTPROPERTY_METHOD,
625 var_interface->VarFromUtf8(method, strlen(method))); 127 var_interface->VarFromUtf8(method, strlen(method)));
626 interface->SetProperty(request_info, 128 interface->SetProperty(request_info,
627 PP_URLREQUESTPROPERTY_ALLOWCROSSORIGINREQUESTS, 129 PP_URLREQUESTPROPERTY_ALLOWCROSSORIGINREQUESTS,
628 PP_MakeBool(allow_cors_ ? PP_TRUE : PP_FALSE)); 130 PP_MakeBool(allow_cors_ ? PP_TRUE : PP_FALSE));
629 interface->SetProperty(request_info, PP_URLREQUESTPROPERTY_ALLOWCREDENTIALS, 131 interface->SetProperty(request_info,
132 PP_URLREQUESTPROPERTY_ALLOWCREDENTIALS,
630 PP_MakeBool(allow_credentials_ ? PP_TRUE : PP_FALSE)); 133 PP_MakeBool(allow_credentials_ ? PP_TRUE : PP_FALSE));
631 134
632 // Merge the mount headers with the request headers. If the field is already 135 // Merge the mount headers with the request headers. If the field is already
633 // set it |additional_headers|, don't use the one from headers_. 136 // set it |additional_headers|, don't use the one from headers_.
634 for (StringMap_t::iterator iter = headers_.begin(); iter != headers_.end(); 137 for (StringMap_t::iterator iter = headers_.begin(); iter != headers_.end();
635 ++iter) { 138 ++iter) {
636 const std::string& key = NormalizeHeaderKey(iter->first); 139 const std::string& key = NormalizeHeaderKey(iter->first);
637 if (additional_headers->find(key) == additional_headers->end()) { 140 if (additional_headers->find(key) == additional_headers->end()) {
638 additional_headers->insert(std::make_pair(key, iter->second)); 141 additional_headers->insert(std::make_pair(key, iter->second));
639 } 142 }
640 } 143 }
641 144
642 // Join the headers into one string. 145 // Join the headers into one string.
643 std::string headers; 146 std::string headers;
644 for (StringMap_t::iterator iter = additional_headers->begin(); 147 for (StringMap_t::iterator iter = additional_headers->begin();
645 iter != additional_headers->end(); ++iter) { 148 iter != additional_headers->end();
149 ++iter) {
646 headers += iter->first + ": " + iter->second + '\n'; 150 headers += iter->first + ": " + iter->second + '\n';
647 } 151 }
648 152
649 interface->SetProperty( 153 interface->SetProperty(
650 request_info, PP_URLREQUESTPROPERTY_HEADERS, 154 request_info,
155 PP_URLREQUESTPROPERTY_HEADERS,
651 var_interface->VarFromUtf8(headers.c_str(), headers.length())); 156 var_interface->VarFromUtf8(headers.c_str(), headers.length()));
652 157
653 return request_info; 158 return request_info;
654 } 159 }
655 160
656 MountHttp::MountHttp() 161 MountHttp::MountHttp()
657 : allow_cors_(false), 162 : allow_cors_(false),
658 allow_credentials_(false), 163 allow_credentials_(false),
659 cache_stat_(true), 164 cache_stat_(true),
660 cache_content_(true) { 165 cache_content_(true) {}
661 }
662 166
663 bool MountHttp::Init(int dev, StringMap_t& args, PepperInterface* ppapi) { 167 Error MountHttp::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
664 if (!Mount::Init(dev, args, ppapi)) 168 Error error = Mount::Init(dev, args, ppapi);
665 return false; 169 if (error)
170 return error;
666 171
667 // Parse mount args. 172 // Parse mount args.
668 for (StringMap_t::iterator iter = args.begin(); iter != args.end(); ++iter) { 173 for (StringMap_t::iterator iter = args.begin(); iter != args.end(); ++iter) {
669 if (iter->first == "SOURCE") { 174 if (iter->first == "SOURCE") {
670 url_root_ = iter->second; 175 url_root_ = iter->second;
671 176
672 // Make sure url_root_ ends with a slash. 177 // Make sure url_root_ ends with a slash.
673 if (!url_root_.empty() && url_root_[url_root_.length() - 1] != '/') { 178 if (!url_root_.empty() && url_root_[url_root_.length() - 1] != '/') {
674 url_root_ += '/'; 179 url_root_ += '/';
675 } 180 }
676 } else if (iter->first == "manifest") { 181 } else if (iter->first == "manifest") {
677 char *text = LoadManifest(iter->second); 182 char* text;
678 if (text != NULL) { 183 error = LoadManifest(iter->second, &text);
679 ParseManifest(text); 184 if (error)
185 return error;
186
187 error = ParseManifest(text);
188 if (error) {
680 delete[] text; 189 delete[] text;
190 return error;
681 } 191 }
192
193 delete[] text;
682 } else if (iter->first == "allow_cross_origin_requests") { 194 } else if (iter->first == "allow_cross_origin_requests") {
683 allow_cors_ = iter->second == "true"; 195 allow_cors_ = iter->second == "true";
684 } else if (iter->first == "allow_credentials") { 196 } else if (iter->first == "allow_credentials") {
685 allow_credentials_ = iter->second == "true"; 197 allow_credentials_ = iter->second == "true";
686 } else if (iter->first == "cache_stat") { 198 } else if (iter->first == "cache_stat") {
687 cache_stat_ = iter->second == "true"; 199 cache_stat_ = iter->second == "true";
688 } else if (iter->first == "cache_content") { 200 } else if (iter->first == "cache_content") {
689 cache_content_ = iter->second == "true"; 201 cache_content_ = iter->second == "true";
690 } else { 202 } else {
691 // Assume it is a header to pass to an HTTP request. 203 // Assume it is a header to pass to an HTTP request.
692 headers_[NormalizeHeaderKey(iter->first)] = iter->second; 204 headers_[NormalizeHeaderKey(iter->first)] = iter->second;
693 } 205 }
694 } 206 }
695 207
696 return true; 208 return 0;
697 } 209 }
698 210
699 void MountHttp::Destroy() { 211 void MountHttp::Destroy() {}
700 }
701 212
702 MountNodeDir* MountHttp::FindOrCreateDir(const Path& path) { 213 Error MountHttp::FindOrCreateDir(const Path& path, MountNodeDir** out_node) {
214 *out_node = NULL;
215
703 std::string strpath = path.Join(); 216 std::string strpath = path.Join();
704 NodeMap_t::iterator iter = node_cache_.find(strpath); 217 NodeMap_t::iterator iter = node_cache_.find(strpath);
705 if (iter != node_cache_.end()) { 218 if (iter != node_cache_.end()) {
706 return static_cast<MountNodeDir*>(iter->second); 219 *out_node = static_cast<MountNodeDir*>(iter->second);
220 return 0;
707 } 221 }
708 222
709 // If the node does not exist, create it, and add it to the node cache 223 // If the node does not exist, create it.
710 MountNodeDir* node = new MountNodeDir(this); 224 MountNodeDir* node = new MountNodeDir(this);
711 node->Init(S_IREAD); 225 Error error = node->Init(S_IREAD);
712 node_cache_[strpath] = node; 226 if (error) {
227 node->Release();
228 return error;
229 }
713 230
714 // If not the root node, find the parent node and add it to the parent 231 // If not the root node, find the parent node and add it to the parent
715 if (!path.Top()) { 232 if (!path.Top()) {
716 MountNodeDir* parent = FindOrCreateDir(path.Parent()); 233 MountNodeDir* parent;
717 parent->AddChild(path.Basename(), node); 234 error = FindOrCreateDir(path.Parent(), &parent);
235 if (error) {
236 node->Release();
237 return error;
238 }
239
240 error = parent->AddChild(path.Basename(), node);
241 if (error) {
242 node->Release();
243 return error;
244 }
718 } 245 }
719 246
720 return node; 247 // Add it to the node cache.
248 node_cache_[strpath] = node;
249
250 *out_node = node;
251 return 0;
721 } 252 }
722 253
723 bool MountHttp::ParseManifest(char *text) { 254 Error MountHttp::ParseManifest(char* text) {
724 StringList_t lines; 255 StringList_t lines;
725 SplitString(text, "\n", &lines); 256 SplitString(text, "\n", &lines);
726 257
727 for (size_t i = 0; i < lines.size(); i++) { 258 for (size_t i = 0; i < lines.size(); i++) {
728 StringList_t words; 259 StringList_t words;
729 SplitString(lines[i], " ", &words); 260 SplitString(lines[i], " ", &words);
730 261
731 if (words.size() == 3) { 262 if (words.size() == 3) {
732 char* modestr = words[0]; 263 char* modestr = words[0];
733 char* lenstr = words[1]; 264 char* lenstr = words[1];
734 char* name = words[2]; 265 char* name = words[2];
735 266
736 assert(modestr && strlen(modestr) == 4); 267 assert(modestr && strlen(modestr) == 4);
737 assert(name && name[0] == '/'); 268 assert(name && name[0] == '/');
738 assert(lenstr); 269 assert(lenstr);
739 270
740 // Only support regular and streams for now 271 // Only support regular and streams for now
741 // Ignore EXEC bit 272 // Ignore EXEC bit
742 int mode = S_IFREG; 273 int mode = S_IFREG;
743 switch (modestr[0]) { 274 switch (modestr[0]) {
744 case '-': mode = S_IFREG; break; 275 case '-':
745 case 'c': mode = S_IFCHR; break; 276 mode = S_IFREG;
277 break;
278 case 'c':
279 mode = S_IFCHR;
280 break;
746 default: 281 default:
747 fprintf(stderr, "Unable to parse type %s for %s.\n", modestr, name); 282 fprintf(stderr, "Unable to parse type %s for %s.\n", modestr, name);
748 return false; 283 return EINVAL;
749 } 284 }
750 285
751 switch (modestr[1]) { 286 switch (modestr[1]) {
752 case '-': break; 287 case '-':
753 case 'r': mode |= S_IREAD; break; 288 break;
289 case 'r':
290 mode |= S_IREAD;
291 break;
754 default: 292 default:
755 fprintf(stderr, "Unable to parse read %s for %s.\n", modestr, name); 293 fprintf(stderr, "Unable to parse read %s for %s.\n", modestr, name);
756 return false; 294 return EINVAL;
757 } 295 }
758 296
759 switch (modestr[2]) { 297 switch (modestr[2]) {
760 case '-': break; 298 case '-':
761 case 'w': mode |= S_IWRITE; break; 299 break;
300 case 'w':
301 mode |= S_IWRITE;
302 break;
762 default: 303 default:
763 fprintf(stderr, "Unable to parse write %s for %s.\n", modestr, name); 304 fprintf(stderr, "Unable to parse write %s for %s.\n", modestr, name);
764 return false; 305 return EINVAL;
765 } 306 }
766 307
767 Path path(name); 308 Path path(name);
768 std::string url = url_root_ + (path.IsAbsolute() ? 309 std::string url =
769 path.Range(1, path.Size()) : 310 url_root_ +
770 path.Join()); 311 (path.IsAbsolute() ? path.Range(1, path.Size()) : path.Join());
771 312
772 MountNodeHttp* node = new MountNodeHttp(this, url, cache_content_); 313 MountNodeHttp* node = new MountNodeHttp(this, url, cache_content_);
773 node->Init(mode); 314 Error error = node->Init(mode);
315 if (error) {
316 node->Release();
317 return error;
318 }
319
774 node->SetCachedSize(atoi(lenstr)); 320 node->SetCachedSize(atoi(lenstr));
775 321
776 MountNodeDir* dir_node = FindOrCreateDir(path.Parent()); 322 MountNodeDir* dir_node;
777 dir_node->AddChild(path.Basename(), node); 323 error = FindOrCreateDir(path.Parent(), &dir_node);
324 if (error) {
325 node->Release();
326 return error;
327 }
328
329 error = dir_node->AddChild(path.Basename(), node);
330 if (error) {
331 node->Release();
332 return error;
333 }
778 334
779 std::string pname = path.Join(); 335 std::string pname = path.Join();
780 node_cache_[pname] = node; 336 node_cache_[pname] = node;
781 } 337 }
782 } 338 }
783 339
784 return true; 340 return 0;
785 } 341 }
786 342
787 char *MountHttp::LoadManifest(const std::string& manifest_name) { 343 Error MountHttp::LoadManifest(const std::string& manifest_name,
344 char** out_manifest) {
788 Path manifest_path(manifest_name); 345 Path manifest_path(manifest_name);
789 MountNode* manifest_node = Open(manifest_path, O_RDONLY); 346 MountNode* manifest_node = NULL;
347 *out_manifest = NULL;
790 348
791 if (manifest_node) { 349 int error = Open(manifest_path, O_RDONLY, &manifest_node);
792 char *text = new char[manifest_node->GetSize() + 1]; 350 if (error)
793 off_t len = manifest_node->Read(0, text, manifest_node->GetSize()); 351 return error;
352
353 size_t size;
354 error = manifest_node->GetSize(&size);
355 if (error) {
794 manifest_node->Release(); 356 manifest_node->Release();
795 357 return error;
796 text[len] = 0;
797 return text;
798 } 358 }
799 359
800 fprintf(stderr, "Could not open manifest: %s\n", manifest_name.c_str()); 360 char* text = new char[size + 1];
801 return NULL; 361 int len;
362 error = manifest_node->Read(0, text, size, &len);
363 if (error) {
364 manifest_node->Release();
365 return error;
366 }
367
368 manifest_node->Release();
369 text[len] = 0;
370
371 *out_manifest = text;
372 return 0;
802 } 373 }
OLDNEW
« no previous file with comments | « native_client_sdk/src/libraries/nacl_io/mount_http.h ('k') | native_client_sdk/src/libraries/nacl_io/mount_mem.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698