| 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 |