OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 #include "nacl_io/httpfs/http_fs.h" | 5 #include "nacl_io/httpfs/http_fs.h" |
6 | 6 |
7 #include <assert.h> | 7 #include <assert.h> |
8 #include <ctype.h> | 8 #include <ctype.h> |
9 #include <errno.h> | 9 #include <errno.h> |
10 #include <fcntl.h> | 10 #include <fcntl.h> |
(...skipping 24 matching lines...) Expand all Loading... |
35 for (size_t i = 0; i < s.length(); ++i) { | 35 for (size_t i = 0; i < s.length(); ++i) { |
36 char c = s[i]; | 36 char c = s[i]; |
37 result += upper ? toupper(c) : tolower(c); | 37 result += upper ? toupper(c) : tolower(c); |
38 upper = c == '-'; | 38 upper = c == '-'; |
39 } | 39 } |
40 | 40 |
41 return result; | 41 return result; |
42 } | 42 } |
43 | 43 |
44 Error HttpFs::Access(const Path& path, int a_mode) { | 44 Error HttpFs::Access(const Path& path, int a_mode) { |
45 NodeMap_t::iterator iter = node_cache_.find(path.Join()); | 45 ScopedNode node = FindExistingNode(path); |
46 if (iter == node_cache_.end()) { | 46 if (node.get() == NULL) { |
47 // If we can't find the node in the cache, fetch it | 47 // If we can't find the node in the cache, fetch it |
48 std::string url = MakeUrl(path); | 48 std::string url = MakeUrl(path); |
49 ScopedNode node(new HttpFsNode(this, url, cache_content_)); | 49 node.reset(new HttpFsNode(this, url, cache_content_)); |
50 Error error = node->Init(0); | 50 Error error = node->Init(0); |
51 if (error) | 51 if (error) |
52 return error; | 52 return error; |
53 | 53 |
54 error = node->GetStat(NULL); | 54 error = node->GetStat(NULL); |
55 if (error) | 55 if (error) |
56 return error; | 56 return error; |
57 } | 57 } |
58 | 58 |
59 // Don't allow write or execute access. | 59 int obj_mode = node->GetMode(); |
60 if (a_mode & (W_OK | X_OK)) | 60 if (((a_mode & R_OK) && !(obj_mode & S_IREAD)) || |
| 61 ((a_mode & W_OK) && !(obj_mode & S_IWRITE)) || |
| 62 ((a_mode & X_OK) && !(obj_mode & S_IEXEC))) { |
61 return EACCES; | 63 return EACCES; |
| 64 } |
62 | 65 |
63 return 0; | 66 return 0; |
64 } | 67 } |
65 | 68 |
66 Error HttpFs::Open(const Path& path, int open_flags, ScopedNode* out_node) { | 69 Error HttpFs::Open(const Path& path, int open_flags, ScopedNode* out_node) { |
67 out_node->reset(NULL); | 70 out_node->reset(NULL); |
68 | 71 |
69 NodeMap_t::iterator iter = node_cache_.find(path.Join()); | 72 ScopedNode node = FindExistingNode(path); |
70 if (iter != node_cache_.end()) { | 73 if (node.get() != NULL) { |
71 *out_node = iter->second; | 74 *out_node = node; |
72 return 0; | 75 return 0; |
73 } | 76 } |
74 | 77 |
75 // If we can't find the node in the cache, create it | 78 // If we can't find the node in the cache, create it |
76 std::string url = MakeUrl(path); | 79 std::string url = MakeUrl(path); |
77 ScopedNode node(new HttpFsNode(this, url, cache_content_)); | 80 node.reset(new HttpFsNode(this, url, cache_content_)); |
78 Error error = node->Init(open_flags); | 81 Error error = node->Init(open_flags); |
79 if (error) | 82 if (error) |
80 return error; | 83 return error; |
81 | 84 |
82 error = node->GetStat(NULL); | 85 error = node->GetStat(NULL); |
83 if (error) | 86 if (error) |
84 return error; | 87 return error; |
85 | 88 |
86 ScopedNode parent; | 89 ScopedNode parent; |
87 error = FindOrCreateDir(path.Parent(), &parent); | 90 error = FindOrCreateDir(path.Parent(), &parent); |
88 if (error) | 91 if (error) |
89 return error; | 92 return error; |
90 | 93 |
91 error = parent->AddChild(path.Basename(), node); | 94 error = parent->AddChild(path.Basename(), node); |
92 if (error) | 95 if (error) |
93 return error; | 96 return error; |
94 | 97 |
95 node_cache_[path.Join()] = node; | 98 node_cache_[path.Join()] = node; |
96 *out_node = node; | 99 *out_node = node; |
97 return 0; | 100 return 0; |
98 } | 101 } |
99 | 102 |
100 Error HttpFs::Unlink(const Path& path) { | 103 ScopedNode HttpFs::FindExistingNode(const Path& path) { |
101 NodeMap_t::iterator iter = node_cache_.find(path.Join()); | 104 NodeMap_t::iterator iter = node_cache_.find(path.Join()); |
102 if (iter == node_cache_.end()) | 105 if (iter == node_cache_.end()) |
| 106 return ScopedNode(); |
| 107 return iter->second; |
| 108 } |
| 109 |
| 110 Error HttpFs::Unlink(const Path& path) { |
| 111 ScopedNode node = FindExistingNode(path); |
| 112 if (node.get() == NULL) |
103 return ENOENT; | 113 return ENOENT; |
104 | 114 |
105 if (iter->second->IsaDir()) | 115 if (node->IsaDir()) |
106 return EISDIR; | 116 return EISDIR; |
107 | 117 |
108 return EACCES; | 118 return EACCES; |
109 } | 119 } |
110 | 120 |
111 Error HttpFs::Mkdir(const Path& path, int permissions) { | 121 Error HttpFs::Mkdir(const Path& path, int permissions) { |
112 NodeMap_t::iterator iter = node_cache_.find(path.Join()); | 122 ScopedNode node = FindExistingNode(path); |
113 if (iter != node_cache_.end()) { | 123 if (node.get() != NULL && node->IsaDir()) |
114 if (iter->second->IsaDir()) | 124 return EEXIST; |
115 return EEXIST; | 125 |
116 } | |
117 return EACCES; | 126 return EACCES; |
118 } | 127 } |
119 | 128 |
120 Error HttpFs::Rmdir(const Path& path) { | 129 Error HttpFs::Rmdir(const Path& path) { |
121 NodeMap_t::iterator iter = node_cache_.find(path.Join()); | 130 ScopedNode node = FindExistingNode(path); |
122 if (iter == node_cache_.end()) | 131 if (node.get() == NULL) |
123 return ENOENT; | 132 return ENOENT; |
124 | 133 |
125 if (!iter->second->IsaDir()) | 134 if (!node->IsaDir()) |
126 return ENOTDIR; | 135 return ENOTDIR; |
127 | 136 |
128 return EACCES; | 137 return EACCES; |
129 } | 138 } |
130 | 139 |
131 Error HttpFs::Remove(const Path& path) { | 140 Error HttpFs::Remove(const Path& path) { |
132 NodeMap_t::iterator iter = node_cache_.find(path.Join()); | 141 ScopedNode node = FindExistingNode(path); |
133 if (iter == node_cache_.end()) | 142 if (node.get() == NULL) |
134 return ENOENT; | 143 return ENOENT; |
135 | 144 |
136 return EACCES; | 145 return EACCES; |
137 } | 146 } |
138 | 147 |
139 Error HttpFs::Rename(const Path& path, const Path& newpath) { | 148 Error HttpFs::Rename(const Path& path, const Path& newpath) { |
140 NodeMap_t::iterator iter = node_cache_.find(path.Join()); | 149 ScopedNode node = FindExistingNode(path); |
141 if (iter == node_cache_.end()) | 150 if (node.get() == NULL) |
142 return ENOENT; | 151 return ENOENT; |
143 | 152 |
144 return EACCES; | 153 return EACCES; |
145 } | 154 } |
146 | 155 |
147 PP_Resource HttpFs::MakeUrlRequestInfo(const std::string& url, | 156 PP_Resource HttpFs::MakeUrlRequestInfo(const std::string& url, |
148 const char* method, | 157 const char* method, |
149 StringMap_t* additional_headers) { | 158 StringMap_t* additional_headers) { |
150 URLRequestInfoInterface* interface = ppapi_->GetURLRequestInfoInterface(); | 159 URLRequestInfoInterface* interface = ppapi_->GetURLRequestInfoInterface(); |
151 VarInterface* var_interface = ppapi_->GetVarInterface(); | 160 VarInterface* var_interface = ppapi_->GetVarInterface(); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
190 PP_URLREQUESTPROPERTY_HEADERS, | 199 PP_URLREQUESTPROPERTY_HEADERS, |
191 var_interface->VarFromUtf8(headers.c_str(), headers.length())); | 200 var_interface->VarFromUtf8(headers.c_str(), headers.length())); |
192 | 201 |
193 return request_info; | 202 return request_info; |
194 } | 203 } |
195 | 204 |
196 HttpFs::HttpFs() | 205 HttpFs::HttpFs() |
197 : allow_cors_(false), | 206 : allow_cors_(false), |
198 allow_credentials_(false), | 207 allow_credentials_(false), |
199 cache_stat_(true), | 208 cache_stat_(true), |
200 cache_content_(true) { | 209 cache_content_(true), |
| 210 is_blob_url_(false) { |
201 } | 211 } |
202 | 212 |
203 Error HttpFs::Init(const FsInitArgs& args) { | 213 Error HttpFs::Init(const FsInitArgs& args) { |
204 Error error = Filesystem::Init(args); | 214 Error error = Filesystem::Init(args); |
205 if (error) | 215 if (error) |
206 return error; | 216 return error; |
207 | 217 |
208 // Parse filesystem args. | 218 // Parse filesystem args. |
209 for (StringMap_t::const_iterator iter = args.string_map.begin(); | 219 for (StringMap_t::const_iterator iter = args.string_map.begin(); |
210 iter != args.string_map.end(); | 220 iter != args.string_map.end(); |
211 ++iter) { | 221 ++iter) { |
212 if (iter->first == "SOURCE") { | 222 if (iter->first == "SOURCE") { |
213 url_root_ = iter->second; | 223 url_root_ = iter->second; |
214 is_blob_url_ = strncmp(url_root_.c_str(), "blob:", 5) == 0; | 224 is_blob_url_ = strncmp(url_root_.c_str(), "blob:", 5) == 0; |
215 | 225 |
216 // Make sure url_root_ ends with a slash, except for blob URLs. | |
217 if (!is_blob_url_ && !url_root_.empty() && | |
218 url_root_[url_root_.length() - 1] != '/') { | |
219 url_root_ += '/'; | |
220 } | |
221 } else if (iter->first == "manifest") { | 226 } else if (iter->first == "manifest") { |
222 char* text; | 227 char* text; |
223 error = LoadManifest(iter->second, &text); | 228 error = LoadManifest(iter->second, &text); |
224 if (error) | 229 if (error) |
225 return error; | 230 return error; |
226 | 231 |
227 error = ParseManifest(text); | 232 error = ParseManifest(text); |
228 if (error) { | 233 if (error) { |
229 free(text); | 234 free(text); |
230 return error; | 235 return error; |
231 } | 236 } |
232 | 237 |
233 free(text); | 238 free(text); |
234 } else if (iter->first == "allow_cross_origin_requests") { | 239 } else if (iter->first == "allow_cross_origin_requests") { |
235 allow_cors_ = iter->second == "true"; | 240 allow_cors_ = iter->second == "true"; |
236 } else if (iter->first == "allow_credentials") { | 241 } else if (iter->first == "allow_credentials") { |
237 allow_credentials_ = iter->second == "true"; | 242 allow_credentials_ = iter->second == "true"; |
238 } else if (iter->first == "cache_stat") { | 243 } else if (iter->first == "cache_stat") { |
239 cache_stat_ = iter->second == "true"; | 244 cache_stat_ = iter->second == "true"; |
240 } else if (iter->first == "cache_content") { | 245 } else if (iter->first == "cache_content") { |
241 cache_content_ = iter->second == "true"; | 246 cache_content_ = iter->second == "true"; |
242 } else { | 247 } else { |
243 // Assume it is a header to pass to an HTTP request. | 248 // Assume it is a header to pass to an HTTP request. |
244 headers_[NormalizeHeaderKey(iter->first)] = iter->second; | 249 headers_[NormalizeHeaderKey(iter->first)] = iter->second; |
245 } | 250 } |
246 } | 251 } |
247 | 252 |
| 253 if (!is_blob_url_) { |
| 254 if (!url_root_.empty() && url_root_[url_root_.length() - 1] != '/') { |
| 255 // Make sure url_root_ ends with a slash, except for blob URLs. |
| 256 url_root_ += '/'; |
| 257 } |
| 258 |
| 259 ScopedNode root; |
| 260 error = FindOrCreateDir(Path("/"), &root); |
| 261 if (error) |
| 262 return error; |
| 263 } |
| 264 |
248 return 0; | 265 return 0; |
249 } | 266 } |
250 | 267 |
251 void HttpFs::Destroy() { | 268 void HttpFs::Destroy() { |
252 } | 269 } |
253 | 270 |
254 Error HttpFs::FindOrCreateDir(const Path& path, ScopedNode* out_node) { | 271 Error HttpFs::FindOrCreateDir(const Path& path, ScopedNode* out_node) { |
255 out_node->reset(NULL); | 272 out_node->reset(NULL); |
256 std::string strpath = path.Join(); | 273 |
257 NodeMap_t::iterator iter = node_cache_.find(strpath); | 274 ScopedNode node = FindExistingNode(path); |
258 if (iter != node_cache_.end()) { | 275 if (node.get() != NULL) { |
259 *out_node = iter->second; | 276 *out_node = node; |
260 return 0; | 277 return 0; |
261 } | 278 } |
262 | 279 |
263 // If the node does not exist, create it. | 280 // If the node does not exist, create it. |
264 ScopedNode node(new DirNode(this)); | 281 node.reset(new DirNode(this)); |
265 Error error = node->Init(0); | 282 Error error = node->Init(0); |
266 if (error) | 283 if (error) |
267 return error; | 284 return error; |
| 285 // Directorys in http filesystems are never writable. |
| 286 node->SetMode(node->GetMode() & ~S_IWALL); |
268 | 287 |
269 // If not the root node, find the parent node and add it to the parent | 288 // If not the root node, find the parent node and add it to the parent |
270 if (!path.IsRoot()) { | 289 if (!path.IsRoot()) { |
271 ScopedNode parent; | 290 ScopedNode parent; |
272 error = FindOrCreateDir(path.Parent(), &parent); | 291 error = FindOrCreateDir(path.Parent(), &parent); |
273 if (error) | 292 if (error) |
274 return error; | 293 return error; |
275 | 294 |
276 error = parent->AddChild(path.Basename(), node); | 295 error = parent->AddChild(path.Basename(), node); |
277 if (error) | 296 if (error) |
278 return error; | 297 return error; |
279 } | 298 } |
280 | 299 |
281 // Add it to the node cache. | 300 // Add it to the node cache. |
282 node_cache_[strpath] = node; | 301 node_cache_[path.Join()] = node; |
283 *out_node = node; | 302 *out_node = node; |
284 return 0; | 303 return 0; |
285 } | 304 } |
286 | 305 |
287 Error HttpFs::ParseManifest(const char* text) { | 306 Error HttpFs::ParseManifest(const char* text) { |
288 std::vector<std::string> lines; | 307 std::vector<std::string> lines; |
289 sdk_util::SplitString(text, '\n', &lines); | 308 sdk_util::SplitString(text, '\n', &lines); |
290 | 309 |
291 for (size_t i = 0; i < lines.size(); i++) { | 310 for (size_t i = 0; i < lines.size(); i++) { |
292 std::vector<std::string> words; | 311 std::vector<std::string> words; |
(...skipping 11 matching lines...) Expand all Loading... |
304 if (non_empty_words.size() == 3) { | 323 if (non_empty_words.size() == 3) { |
305 const std::string& modestr = non_empty_words[0]; | 324 const std::string& modestr = non_empty_words[0]; |
306 const std::string& lenstr = non_empty_words[1]; | 325 const std::string& lenstr = non_empty_words[1]; |
307 const std::string& name = non_empty_words[2]; | 326 const std::string& name = non_empty_words[2]; |
308 | 327 |
309 assert(modestr.size() == 4); | 328 assert(modestr.size() == 4); |
310 assert(name[0] == '/'); | 329 assert(name[0] == '/'); |
311 | 330 |
312 // Only support regular and streams for now | 331 // Only support regular and streams for now |
313 // Ignore EXEC bit | 332 // Ignore EXEC bit |
314 int mode = S_IFREG; | 333 int type = 0; |
315 switch (modestr[0]) { | 334 switch (modestr[0]) { |
316 case '-': | 335 case '-': |
317 mode = S_IFREG; | 336 type = S_IFREG; |
318 break; | 337 break; |
319 case 'c': | 338 case 'c': |
320 mode = S_IFCHR; | 339 type = S_IFCHR; |
321 break; | 340 break; |
322 default: | 341 default: |
323 LOG_ERROR("Unable to parse type %s for %s.", | 342 LOG_ERROR("Unable to parse type %s for %s.", |
324 modestr.c_str(), | 343 modestr.c_str(), |
325 name.c_str()); | 344 name.c_str()); |
326 return EINVAL; | 345 return EINVAL; |
327 } | 346 } |
328 | 347 |
| 348 int mode = 0; |
329 switch (modestr[1]) { | 349 switch (modestr[1]) { |
330 case '-': | 350 case '-': |
331 break; | 351 break; |
332 case 'r': | 352 case 'r': |
333 mode |= S_IRUSR | S_IRGRP | S_IROTH; | 353 mode |= S_IRUSR | S_IRGRP | S_IROTH; |
334 break; | 354 break; |
335 default: | 355 default: |
336 LOG_ERROR("Unable to parse read %s for %s.", | 356 LOG_ERROR("Unable to parse read %s for %s.", |
337 modestr.c_str(), | 357 modestr.c_str(), |
338 name.c_str()); | 358 name.c_str()); |
(...skipping 10 matching lines...) Expand all Loading... |
349 LOG_ERROR("Unable to parse write %s for %s.", | 369 LOG_ERROR("Unable to parse write %s for %s.", |
350 modestr.c_str(), | 370 modestr.c_str(), |
351 name.c_str()); | 371 name.c_str()); |
352 return EINVAL; | 372 return EINVAL; |
353 } | 373 } |
354 | 374 |
355 Path path(name); | 375 Path path(name); |
356 std::string url = MakeUrl(path); | 376 std::string url = MakeUrl(path); |
357 | 377 |
358 HttpFsNode* http_node = new HttpFsNode(this, url, cache_content_); | 378 HttpFsNode* http_node = new HttpFsNode(this, url, cache_content_); |
359 http_node->SetMode(mode); | |
360 ScopedNode node(http_node); | 379 ScopedNode node(http_node); |
| 380 node->SetMode(mode); |
| 381 node->SetType(type); |
361 | 382 |
362 Error error = node->Init(0); | 383 Error error = node->Init(0); |
363 if (error) | 384 if (error) |
364 return error; | 385 return error; |
365 http_node->SetCachedSize(atoi(lenstr.c_str())); | 386 http_node->SetCachedSize(atoi(lenstr.c_str())); |
366 | 387 |
367 ScopedNode dir_node; | 388 ScopedNode dir_node; |
368 error = FindOrCreateDir(path.Parent(), &dir_node); | 389 error = FindOrCreateDir(path.Parent(), &dir_node); |
369 if (error) | 390 if (error) |
370 return error; | 391 return error; |
371 | 392 |
372 error = dir_node->AddChild(path.Basename(), node); | 393 error = dir_node->AddChild(path.Basename(), node); |
373 if (error) | 394 if (error) |
374 return error; | 395 return error; |
375 | 396 |
376 std::string pname = path.Join(); | 397 node_cache_[path.Join()] = node; |
377 node_cache_[pname] = node; | |
378 } | 398 } |
379 } | 399 } |
380 | 400 |
381 return 0; | 401 return 0; |
382 } | 402 } |
383 | 403 |
384 Error HttpFs::LoadManifest(const std::string& manifest_name, | 404 Error HttpFs::LoadManifest(const std::string& manifest_name, |
385 char** out_manifest) { | 405 char** out_manifest) { |
386 Path manifest_path(manifest_name); | 406 Path manifest_path(manifest_name); |
387 ScopedNode manifest_node; | 407 ScopedNode manifest_node; |
(...skipping 21 matching lines...) Expand all Loading... |
409 *out_manifest = text; | 429 *out_manifest = text; |
410 return 0; | 430 return 0; |
411 } | 431 } |
412 | 432 |
413 std::string HttpFs::MakeUrl(const Path& path) { | 433 std::string HttpFs::MakeUrl(const Path& path) { |
414 return url_root_ + | 434 return url_root_ + |
415 (path.IsAbsolute() ? path.Range(1, path.Size()) : path.Join()); | 435 (path.IsAbsolute() ? path.Range(1, path.Size()) : path.Join()); |
416 } | 436 } |
417 | 437 |
418 } // namespace nacl_io | 438 } // namespace nacl_io |
OLD | NEW |