Chromium Code Reviews| Index: native_client_sdk/src/libraries/nacl_io/mount_http.cc |
| diff --git a/native_client_sdk/src/libraries/nacl_io/mount_http.cc b/native_client_sdk/src/libraries/nacl_io/mount_http.cc |
| index 9a6579ed07bba93c218706971f54861c66cc8bae..2a4f21b182e17d0abc464de5b607de3394d70f59 100644 |
| --- a/native_client_sdk/src/libraries/nacl_io/mount_http.cc |
| +++ b/native_client_sdk/src/libraries/nacl_io/mount_http.cc |
| @@ -4,30 +4,30 @@ |
| */ |
| #include "nacl_io/mount_http.h" |
| + |
| #include <assert.h> |
| #include <ctype.h> |
| #include <errno.h> |
| #include <fcntl.h> |
| -#include <ppapi/c/pp_errors.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| + |
| #include <vector> |
| + |
| +#include <ppapi/c/pp_errors.h> |
| + |
| #include "nacl_io/mount_node_dir.h" |
| +#include "nacl_io/mount_node_http.h" |
| #include "nacl_io/osinttypes.h" |
| #include "utils/auto_lock.h" |
| -#if defined(WIN32) |
| -#define snprintf _snprintf |
| -#endif |
| - |
| - |
| namespace { |
| -typedef std::vector<char *> StringList_t; |
| -size_t SplitString(char *str, const char *delim, StringList_t* list) { |
| - char *item = strtok(str, delim); |
| +typedef std::vector<char*> StringList_t; |
| +size_t SplitString(char* str, const char* delim, StringList_t* list) { |
| + char* item = strtok(str, delim); |
| list->clear(); |
| while (item) { |
| @@ -38,13 +38,7 @@ size_t SplitString(char *str, const char *delim, StringList_t* list) { |
| return list->size(); |
| } |
| - |
| -// If we're attempting to read a partial request, but the server returns a full |
| -// request, we need to read all of the data up to the start of our partial |
| -// request into a dummy buffer. This is the maximum size of that buffer. |
| -const size_t MAX_READ_BUFFER_SIZE = 64 * 1024; |
| -const int32_t STATUSCODE_OK = 200; |
| -const int32_t STATUSCODE_PARTIAL_CONTENT = 206; |
| +} // namespace |
| std::string NormalizeHeaderKey(const std::string& s) { |
| // Capitalize the first letter and any letter following a hyphen: |
| @@ -60,557 +54,64 @@ std::string NormalizeHeaderKey(const std::string& s) { |
| return result; |
| } |
| -StringMap_t ParseHeaders(const char* headers, int32_t headers_length) { |
| - enum State { |
| - FINDING_KEY, |
| - SKIPPING_WHITESPACE, |
| - FINDING_VALUE, |
| - }; |
| - |
| - StringMap_t result; |
| - std::string key; |
| - std::string value; |
| - |
| - State state = FINDING_KEY; |
| - const char* start = headers; |
| - for (int i = 0; i < headers_length; ++i) { |
| - switch (state) { |
| - case FINDING_KEY: |
| - if (headers[i] == ':') { |
| - // Found key. |
| - key.assign(start, &headers[i] - start); |
| - key = NormalizeHeaderKey(key); |
| - state = SKIPPING_WHITESPACE; |
| - } |
| - break; |
| - |
| - case SKIPPING_WHITESPACE: |
| - if (headers[i] == ' ') { |
| - // Found whitespace, keep going... |
| - break; |
| - } |
| - |
| - // Found a non-whitespace, mark this as the start of the value. |
| - start = &headers[i]; |
| - state = FINDING_VALUE; |
| - // Fallthrough to start processing value without incrementing i. |
| - |
| - case FINDING_VALUE: |
| - if (headers[i] == '\n') { |
| - // Found value. |
| - value.assign(start, &headers[i] - start); |
| - result[key] = value; |
| - start = &headers[i + 1]; |
| - state = FINDING_KEY; |
| - } |
| - break; |
| - } |
| - } |
| - |
| - return result; |
| -} |
| - |
| -bool ParseContentLength(const StringMap_t& headers, size_t* content_length) { |
| - StringMap_t::const_iterator iter = headers.find("Content-Length"); |
| - if (iter == headers.end()) |
| - return false; |
| - |
| - *content_length = strtoul(iter->second.c_str(), NULL, 10); |
| - return true; |
| -} |
| - |
| -bool ParseContentRange(const StringMap_t& headers, size_t* read_start, |
| - size_t* read_end, size_t* entity_length) { |
| - StringMap_t::const_iterator iter = headers.find("Content-Range"); |
| - if (iter == headers.end()) |
| - return false; |
| - |
| - // The key should look like "bytes ##-##/##" or "bytes ##-##/*". The last |
| - // value is the entity length, which can potentially be * (i.e. unknown). |
| - int read_start_int; |
| - int read_end_int; |
| - int entity_length_int; |
| - int result = sscanf(iter->second.c_str(), "bytes %"SCNuS"-%"SCNuS"/%"SCNuS, |
| - &read_start_int, &read_end_int, &entity_length_int); |
| - |
| - // The Content-Range header specifies an inclusive range: e.g. the first ten |
| - // bytes is "bytes 0-9/*". Convert it to a half-open range by incrementing |
| - // read_end. |
| - if (result == 2) { |
| - *read_start = read_start_int; |
| - *read_end = read_end_int + 1; |
| - *entity_length = 0; |
| - return true; |
| - } else if (result == 3) { |
| - *read_start = read_start_int; |
| - *read_end = read_end_int + 1; |
| - *entity_length = entity_length_int; |
| - return true; |
| - } |
| - |
| - return false; |
| -} |
| - |
| -} // namespace |
| - |
| - |
| -class MountNodeHttp : public MountNode { |
| - public: |
| - virtual int FSync(); |
| - virtual int GetDents(size_t offs, struct dirent* pdir, size_t count); |
| - virtual int GetStat(struct stat* stat); |
| - virtual int Read(size_t offs, void* buf, size_t count); |
| - virtual int FTruncate(off_t size); |
| - virtual int Write(size_t offs, const void* buf, size_t count); |
| - virtual size_t GetSize(); |
| - |
| - void SetCachedSize(off_t size); |
| - |
| - protected: |
| - MountNodeHttp(Mount* mount, const std::string& url, bool cache_content); |
| - |
| - private: |
| - bool OpenUrl(const char* method, |
| - StringMap_t* request_headers, |
| - PP_Resource* out_loader, |
| - PP_Resource* out_request, |
| - PP_Resource* out_response, |
| - int32_t* out_statuscode, |
| - StringMap_t* out_response_headers); |
| - |
| - int DownloadToCache(); |
| - int ReadPartialFromCache(size_t offs, void* buf, size_t count); |
| - int DownloadPartial(size_t offs, void* buf, size_t count); |
| - int DownloadToBuffer(PP_Resource loader, void* buf, size_t count); |
| - |
| - std::string url_; |
| - std::vector<char> buffer_; |
| - |
| - bool cache_content_; |
| - bool has_cached_size_; |
| - std::vector<char> cached_data_; |
| - |
| - friend class MountHttp; |
| -}; |
| - |
| -void MountNodeHttp::SetCachedSize(off_t size) { |
| - has_cached_size_ = true; |
| - stat_.st_size = size; |
| -} |
| - |
| -int MountNodeHttp::FSync() { |
| - errno = ENOSYS; |
| - return -1; |
| -} |
| - |
| -int MountNodeHttp::GetDents(size_t offs, struct dirent* pdir, size_t count) { |
| - errno = ENOSYS; |
| - return -1; |
| -} |
| - |
| -int MountNodeHttp::GetStat(struct stat* stat) { |
| - AutoLock lock(&lock_); |
| - |
| - // Assume we need to 'HEAD' if we do not know the size, otherwise, assume |
| - // that the information is constant. We can add a timeout if needed. |
| - MountHttp* mount = static_cast<MountHttp*>(mount_); |
| - if (stat_.st_size == 0 || !mount->cache_stat_) { |
| - StringMap_t headers; |
| - PP_Resource loader; |
| - PP_Resource request; |
| - PP_Resource response; |
| - int32_t statuscode; |
| - StringMap_t response_headers; |
| - if (!OpenUrl("HEAD", &headers, &loader, &request, &response, &statuscode, |
| - &response_headers)) { |
| - // errno is already set by OpenUrl. |
| - return -1; |
| - } |
| - |
| - ScopedResource scoped_loader(mount_->ppapi(), loader); |
| - ScopedResource scoped_request(mount_->ppapi(), request); |
| - ScopedResource scoped_response(mount_->ppapi(), response); |
| - |
| - |
| - size_t entity_length; |
| - if (ParseContentLength(response_headers, &entity_length)) { |
| - SetCachedSize(static_cast<off_t>(entity_length)); |
| - } else if (cache_content_ && !has_cached_size_) { |
| - DownloadToCache(); |
| - } else { |
| - // Don't use SetCachedSize here -- it is actually unknown. |
| - stat_.st_size = 0; |
| - } |
| - |
| - stat_.st_atime = 0; // TODO(binji): Use "Last-Modified". |
| - stat_.st_mtime = 0; |
| - stat_.st_ctime = 0; |
| - } |
| - |
| - // Fill the stat structure if provided |
| - if (stat) { |
| - memcpy(stat, &stat_, sizeof(stat_)); |
| - } |
| - return 0; |
| -} |
| - |
| -int MountNodeHttp::Read(size_t offs, void* buf, size_t count) { |
| - AutoLock lock(&lock_); |
| - if (cache_content_) { |
| - if (cached_data_.empty()) { |
| - if (DownloadToCache() < 0) |
| - return -1; |
| - } |
| - |
| - return ReadPartialFromCache(offs, buf, count); |
| - } |
| - |
| - return DownloadPartial(offs, buf, count); |
| -} |
| - |
| -int MountNodeHttp::FTruncate(off_t size) { |
| - errno = ENOSYS; |
| - return -1; |
| -} |
| - |
| -int MountNodeHttp::Write(size_t offs, const void* buf, size_t count) { |
| - // TODO(binji): support POST? |
| - errno = ENOSYS; |
| - return -1; |
| -} |
| - |
| -size_t MountNodeHttp::GetSize() { |
| - // TODO(binji): This value should be cached properly; i.e. obey the caching |
| - // headers returned by the server. |
| - AutoLock lock(&lock_); |
| - if (!has_cached_size_) { |
| - // Even if DownloadToCache fails, the best result we can return is what |
| - // was written to stat_.st_size. |
| - if (cache_content_) |
| - DownloadToCache(); |
| - } |
| - |
| - return stat_.st_size; |
| -} |
| - |
| -MountNodeHttp::MountNodeHttp(Mount* mount, const std::string& url, |
| - bool cache_content) |
| - : MountNode(mount), |
| - url_(url), |
| - cache_content_(cache_content), |
| - has_cached_size_(false) { |
| -} |
| - |
| -bool MountNodeHttp::OpenUrl(const char* method, |
| - StringMap_t* request_headers, |
| - PP_Resource* out_loader, |
| - PP_Resource* out_request, |
| - PP_Resource* out_response, |
| - int32_t* out_statuscode, |
| - StringMap_t* out_response_headers) { |
| - // Assume lock_ is already held. |
| - |
| - PepperInterface* ppapi = mount_->ppapi(); |
| - |
| - MountHttp* mount_http = static_cast<MountHttp*>(mount_); |
| - ScopedResource request(ppapi, |
| - mount_http->MakeUrlRequestInfo(url_, method, |
| - request_headers)); |
| - if (!request.pp_resource()) { |
| - errno = EINVAL; |
| - return false; |
| - } |
| - |
| - URLLoaderInterface* loader_interface = ppapi->GetURLLoaderInterface(); |
| - URLResponseInfoInterface* response_interface = |
| - ppapi->GetURLResponseInfoInterface(); |
| - VarInterface* var_interface = ppapi->GetVarInterface(); |
| - |
| - ScopedResource loader(ppapi, loader_interface->Create(ppapi->GetInstance())); |
| - if (!loader.pp_resource()) { |
| - errno = EINVAL; |
| - return false; |
| - } |
| - |
| - int32_t result = loader_interface->Open( |
| - loader.pp_resource(), request.pp_resource(), PP_BlockUntilComplete()); |
| - if (result != PP_OK) { |
| - errno = PPErrorToErrno(result); |
| - return false; |
| - } |
| - |
| - ScopedResource response( |
| - ppapi, |
| - loader_interface->GetResponseInfo(loader.pp_resource())); |
| - if (!response.pp_resource()) { |
| - errno = EINVAL; |
| - return false; |
| - } |
| - |
| - // Get response statuscode. |
| - PP_Var statuscode = response_interface->GetProperty( |
| - response.pp_resource(), |
| - PP_URLRESPONSEPROPERTY_STATUSCODE); |
| - |
| - if (statuscode.type != PP_VARTYPE_INT32) { |
| - errno = EINVAL; |
| - return false; |
| - } |
| - |
| - *out_statuscode = statuscode.value.as_int; |
| - |
| - // Only accept OK or Partial Content. |
| - if (*out_statuscode != STATUSCODE_OK && |
| - *out_statuscode != STATUSCODE_PARTIAL_CONTENT) { |
| - errno = EINVAL; |
| - return false; |
| - } |
| - |
| - // Get response headers. |
| - PP_Var response_headers_var = response_interface->GetProperty( |
| - response.pp_resource(), |
| - PP_URLRESPONSEPROPERTY_HEADERS); |
| - |
| - uint32_t response_headers_length; |
| - const char* response_headers_str = var_interface->VarToUtf8( |
| - response_headers_var, |
| - &response_headers_length); |
| - |
| - *out_loader = loader.Release(); |
| - *out_request = request.Release(); |
| - *out_response = response.Release(); |
| - *out_response_headers = ParseHeaders(response_headers_str, |
| - response_headers_length); |
| - |
| - return true; |
| -} |
| - |
| -int MountNodeHttp::DownloadToCache() { |
| - StringMap_t headers; |
| - PP_Resource loader; |
| - PP_Resource request; |
| - PP_Resource response; |
| - int32_t statuscode; |
| - StringMap_t response_headers; |
| - if (!OpenUrl("GET", &headers, &loader, &request, &response, &statuscode, |
| - &response_headers)) { |
| - // errno is already set by OpenUrl. |
| - return -1; |
| - } |
| - |
| - PepperInterface* ppapi = mount_->ppapi(); |
| - ScopedResource scoped_loader(ppapi, loader); |
| - ScopedResource scoped_request(ppapi, request); |
| - ScopedResource scoped_response(ppapi, response); |
| - |
| - size_t content_length = 0; |
| - if (ParseContentLength(response_headers, &content_length)) { |
| - cached_data_.resize(content_length); |
| - int real_size = DownloadToBuffer(loader, cached_data_.data(), |
| - content_length); |
| - if (real_size < 0) |
| - return -1; |
| - |
| - SetCachedSize(real_size); |
| - cached_data_.resize(real_size); |
| - return real_size; |
| - } |
| - |
| - // We don't know how big the file is. Read in chunks. |
| - cached_data_.resize(MAX_READ_BUFFER_SIZE); |
| - size_t total_bytes_read = 0; |
| - size_t bytes_to_read = MAX_READ_BUFFER_SIZE; |
| - while (true) { |
| - char* buf = cached_data_.data() + total_bytes_read; |
| - int bytes_read = DownloadToBuffer(loader, buf, bytes_to_read); |
| - if (bytes_read < 0) |
| - return -1; |
| - |
| - total_bytes_read += bytes_read; |
| - |
| - if (bytes_read < bytes_to_read) { |
| - SetCachedSize(total_bytes_read); |
| - cached_data_.resize(total_bytes_read); |
| - return total_bytes_read; |
| - } |
| - |
| - cached_data_.resize(total_bytes_read + bytes_to_read); |
| - } |
| -} |
| - |
| -int MountNodeHttp::ReadPartialFromCache(size_t offs, void* buf, size_t count) { |
| - if (offs > cached_data_.size()) { |
| - errno = EINVAL; |
| - return -1; |
| - } |
| - |
| - count = std::min(count, cached_data_.size() - offs); |
| - memcpy(buf, &cached_data_.data()[offs], count); |
| - return count; |
| -} |
| - |
| -int MountNodeHttp::DownloadPartial(size_t offs, void* buf, size_t count) { |
| - StringMap_t headers; |
| - |
| - char buffer[100]; |
| - // Range request is inclusive: 0-99 returns 100 bytes. |
| - snprintf(&buffer[0], sizeof(buffer), "bytes=%"PRIuS"-%"PRIuS, |
| - offs, offs + count - 1); |
| - headers["Range"] = buffer; |
| - |
| - PP_Resource loader; |
| - PP_Resource request; |
| - PP_Resource response; |
| - int32_t statuscode; |
| - StringMap_t response_headers; |
| - if (!OpenUrl("GET", &headers, &loader, &request, &response, &statuscode, |
| - &response_headers)) { |
| - // errno is already set by OpenUrl. |
| - return -1; |
| - } |
| - |
| - PepperInterface* ppapi = mount_->ppapi(); |
| - ScopedResource scoped_loader(ppapi, loader); |
| - ScopedResource scoped_request(ppapi, request); |
| - ScopedResource scoped_response(ppapi, response); |
| - |
| - size_t read_start = 0; |
| - if (statuscode == STATUSCODE_OK) { |
| - // No partial result, read everything starting from the part we care about. |
| - size_t content_length; |
| - if (ParseContentLength(response_headers, &content_length)) { |
| - if (offs >= content_length) { |
| - errno = EINVAL; |
| - return 0; |
| - } |
| +Error MountHttp::Open(const Path& path, int mode, MountNode** out_node) { |
| + *out_node = NULL; |
| - // Clamp count, if trying to read past the end of the file. |
| - if (offs + count > content_length) { |
| - count = content_length - offs; |
| - } |
| - } |
| - } else if (statuscode == STATUSCODE_PARTIAL_CONTENT) { |
| - // Determine from the headers where we are reading. |
| - size_t read_end; |
| - size_t entity_length; |
| - if (ParseContentRange(response_headers, &read_start, &read_end, |
| - &entity_length)) { |
| - if (read_start > offs || read_start > read_end) { |
| - // If this error occurs, the server is returning bogus values. |
| - errno = EINVAL; |
| - return -1; |
| - } |
| + assert(url_root_.empty() || url_root_[url_root_.length() - 1] == '/'); |
| - // Clamp count, if trying to read past the end of the file. |
| - count = std::min(read_end - read_start, count); |
| - } else { |
| - // Partial Content without Content-Range. Assume that the server gave us |
| - // exactly what we asked for. This can happen even when the server |
| - // returns 200 -- the cache may return 206 in this case, but not modify |
| - // the headers. |
| - read_start = offs; |
| - } |
| + NodeMap_t::iterator iter = node_cache_.find(path.Join()); |
| + if (iter != node_cache_.end()) { |
| + *out_node = iter->second; |
| + return 0; |
| } |
| - if (read_start < offs) { |
| - // We aren't yet at the location where we want to start reading. Read into |
| - // our dummy buffer until then. |
| - size_t bytes_to_read = offs - read_start; |
| - if (buffer_.size() < bytes_to_read) |
| - buffer_.resize(std::min(bytes_to_read, MAX_READ_BUFFER_SIZE)); |
| - |
| - while (bytes_to_read > 0) { |
| - int32_t bytes_read = DownloadToBuffer(loader, buffer_.data(), |
| - buffer_.size()); |
| - if (bytes_read < 0) |
| - return -1; |
| + // If we can't find the node in the cache, create it |
| + std::string url = url_root_ + (path.IsAbsolute() ? path.Range(1, path.Size()) |
| + : path.Join()); |
| - bytes_to_read -= bytes_read; |
| - } |
| + MountNodeHttp* node = new MountNodeHttp(this, url, cache_content_); |
| + Error error = node->Init(mode); |
| + if (error) { |
| + node->Release(); |
| + return error; |
| } |
| - return DownloadToBuffer(loader, buf, count); |
| -} |
| - |
| -int MountNodeHttp::DownloadToBuffer(PP_Resource loader, void* buf, |
| - size_t count) { |
| - PepperInterface* ppapi = mount_->ppapi(); |
| - URLLoaderInterface* loader_interface = ppapi->GetURLLoaderInterface(); |
| - |
| - char* out_buffer = static_cast<char*>(buf); |
| - size_t bytes_to_read = count; |
| - while (bytes_to_read > 0) { |
| - int32_t bytes_read = loader_interface->ReadResponseBody( |
| - loader, out_buffer, bytes_to_read, PP_BlockUntilComplete()); |
| - |
| - if (bytes_read == 0) { |
| - // This is not an error -- it may just be that we were trying to read |
| - // more data than exists. |
| - return count - bytes_to_read; |
| - } |
| - |
| - if (bytes_read < 0) { |
| - errno = PPErrorToErrno(bytes_read); |
| - return -1; |
| - } |
| - |
| - assert(bytes_read <= bytes_to_read); |
| - bytes_to_read -= bytes_read; |
| - out_buffer += bytes_read; |
| + error = node->GetStat(NULL); |
| + if (error) { |
| + node->Release(); |
| + return error; |
| } |
| - return count; |
| -} |
| - |
| -MountNode *MountHttp::Open(const Path& path, int mode) { |
| - assert(url_root_.empty() || url_root_[url_root_.length() - 1] == '/'); |
| - |
| - NodeMap_t::iterator iter = node_cache_.find(path.Join()); |
| - if (iter != node_cache_.end()) { |
| - return iter->second; |
| + MountNodeDir* parent; |
| + error = FindOrCreateDir(path.Parent(), &parent); |
| + if (error) { |
| + node->Release(); |
| + return error; |
| } |
| - // If we can't find the node in the cache, create it |
| - std::string url = url_root_ + (path.IsAbsolute() ? |
| - path.Range(1, path.Size()) : |
| - path.Join()); |
| - |
| - MountNodeHttp* node = new MountNodeHttp(this, url, cache_content_); |
| - if (!node->Init(mode) || (0 != node->GetStat(NULL))) { |
| + error = parent->AddChild(path.Basename(), node); |
| + if (error) { |
| node->Release(); |
| - return NULL; |
| + return error; |
| } |
| - MountNodeDir* parent = FindOrCreateDir(path.Parent()); |
| node_cache_[path.Join()] = node; |
| - parent->AddChild(path.Basename(), node); |
| - return node; |
| -} |
| -int MountHttp::Unlink(const Path& path) { |
| - errno = ENOSYS; |
| - return -1; |
| + *out_node = node; |
| + return 0; |
| } |
| -int MountHttp::Mkdir(const Path& path, int permissions) { |
| - errno = ENOSYS; |
| - return -1; |
| -} |
| +Error MountHttp::Unlink(const Path& path) { return ENOSYS; } |
| -int MountHttp::Rmdir(const Path& path) { |
| - errno = ENOSYS; |
| - return -1; |
| -} |
| +Error MountHttp::Mkdir(const Path& path, int permissions) { return ENOSYS; } |
| -int MountHttp::Remove(const Path& path) { |
| - errno = ENOSYS; |
| - return -1; |
| -} |
| +Error MountHttp::Rmdir(const Path& path) { return ENOSYS; } |
| + |
| +Error MountHttp::Remove(const Path& path) { return ENOSYS; } |
| -PP_Resource MountHttp::MakeUrlRequestInfo( |
| - const std::string& url, |
| - const char* method, |
| - StringMap_t* additional_headers) { |
| +PP_Resource MountHttp::MakeUrlRequestInfo(const std::string& url, |
| + const char* method, |
| + StringMap_t* additional_headers) { |
| URLRequestInfoInterface* interface = ppapi_->GetURLRequestInfoInterface(); |
| VarInterface* var_interface = ppapi_->GetVarInterface(); |
| @@ -618,21 +119,23 @@ PP_Resource MountHttp::MakeUrlRequestInfo( |
| if (!request_info) |
| return 0; |
| - interface->SetProperty( |
| - request_info, PP_URLREQUESTPROPERTY_URL, |
| - var_interface->VarFromUtf8(url.c_str(), url.length())); |
| - interface->SetProperty(request_info, PP_URLREQUESTPROPERTY_METHOD, |
| + interface->SetProperty(request_info, |
| + PP_URLREQUESTPROPERTY_URL, |
| + var_interface->VarFromUtf8(url.c_str(), url.length())); |
| + interface->SetProperty(request_info, |
| + PP_URLREQUESTPROPERTY_METHOD, |
| var_interface->VarFromUtf8(method, strlen(method))); |
| interface->SetProperty(request_info, |
| PP_URLREQUESTPROPERTY_ALLOWCROSSORIGINREQUESTS, |
| PP_MakeBool(allow_cors_ ? PP_TRUE : PP_FALSE)); |
| - interface->SetProperty(request_info, PP_URLREQUESTPROPERTY_ALLOWCREDENTIALS, |
| + interface->SetProperty(request_info, |
| + PP_URLREQUESTPROPERTY_ALLOWCREDENTIALS, |
| PP_MakeBool(allow_credentials_ ? PP_TRUE : PP_FALSE)); |
| // Merge the mount headers with the request headers. If the field is already |
| // set it |additional_headers|, don't use the one from headers_. |
| for (StringMap_t::iterator iter = headers_.begin(); iter != headers_.end(); |
| - ++iter) { |
| + ++iter) { |
| const std::string& key = NormalizeHeaderKey(iter->first); |
| if (additional_headers->find(key) == additional_headers->end()) { |
| additional_headers->insert(std::make_pair(key, iter->second)); |
| @@ -642,12 +145,14 @@ PP_Resource MountHttp::MakeUrlRequestInfo( |
| // Join the headers into one string. |
| std::string headers; |
| for (StringMap_t::iterator iter = additional_headers->begin(); |
| - iter != additional_headers->end(); ++iter) { |
| + iter != additional_headers->end(); |
| + ++iter) { |
| headers += iter->first + ": " + iter->second + '\n'; |
| } |
| interface->SetProperty( |
| - request_info, PP_URLREQUESTPROPERTY_HEADERS, |
| + request_info, |
| + PP_URLREQUESTPROPERTY_HEADERS, |
| var_interface->VarFromUtf8(headers.c_str(), headers.length())); |
| return request_info; |
| @@ -657,12 +162,12 @@ MountHttp::MountHttp() |
| : allow_cors_(false), |
| allow_credentials_(false), |
| cache_stat_(true), |
| - cache_content_(true) { |
| -} |
| + cache_content_(true) {} |
| -bool MountHttp::Init(int dev, StringMap_t& args, PepperInterface* ppapi) { |
| - if (!Mount::Init(dev, args, ppapi)) |
| - return false; |
| +Error MountHttp::Init(int dev, StringMap_t& args, PepperInterface* ppapi) { |
| + Error error = Mount::Init(dev, args, ppapi); |
| + if (error) |
|
noelallen1
2013/06/07 21:48:43
style: Single line or {}
binji
2013/06/07 23:23:11
After discussion, we'll leave without {}
|
| + return error; |
| // Parse mount args. |
| for (StringMap_t::iterator iter = args.begin(); iter != args.end(); ++iter) { |
| @@ -674,11 +179,18 @@ bool MountHttp::Init(int dev, StringMap_t& args, PepperInterface* ppapi) { |
| url_root_ += '/'; |
| } |
| } else if (iter->first == "manifest") { |
| - char *text = LoadManifest(iter->second); |
| - if (text != NULL) { |
| - ParseManifest(text); |
| + char* text; |
| + error = LoadManifest(iter->second, &text); |
| + if (error) |
| + return error; |
| + |
| + error = ParseManifest(text); |
| + if (error) { |
| delete[] text; |
| + return error; |
| } |
| + |
| + delete[] text; |
| } else if (iter->first == "allow_cross_origin_requests") { |
| allow_cors_ = iter->second == "true"; |
| } else if (iter->first == "allow_credentials") { |
| @@ -693,34 +205,53 @@ bool MountHttp::Init(int dev, StringMap_t& args, PepperInterface* ppapi) { |
| } |
| } |
| - return true; |
| + return 0; |
| } |
| -void MountHttp::Destroy() { |
| -} |
| +void MountHttp::Destroy() {} |
| + |
| +Error MountHttp::FindOrCreateDir(const Path& path, MountNodeDir** out_node) { |
| + *out_node = NULL; |
| -MountNodeDir* MountHttp::FindOrCreateDir(const Path& path) { |
| std::string strpath = path.Join(); |
| NodeMap_t::iterator iter = node_cache_.find(strpath); |
| if (iter != node_cache_.end()) { |
| - return static_cast<MountNodeDir*>(iter->second); |
| + *out_node = static_cast<MountNodeDir*>(iter->second); |
| + return 0; |
| } |
| - // If the node does not exist, create it, and add it to the node cache |
| + // If the node does not exist, create it. |
| MountNodeDir* node = new MountNodeDir(this); |
| - node->Init(S_IREAD); |
| - node_cache_[strpath] = node; |
| + Error error = node->Init(S_IREAD); |
| + if (error) { |
| + node->Release(); |
| + return error; |
| + } |
| // If not the root node, find the parent node and add it to the parent |
| if (!path.Top()) { |
| - MountNodeDir* parent = FindOrCreateDir(path.Parent()); |
| - parent->AddChild(path.Basename(), node); |
| + MountNodeDir* parent; |
| + error = FindOrCreateDir(path.Parent(), &parent); |
| + if (error) { |
| + node->Release(); |
| + return error; |
| + } |
| + |
| + error = parent->AddChild(path.Basename(), node); |
| + if (error) { |
| + node->Release(); |
| + return error; |
| + } |
| } |
| - return node; |
| + // Add it to the node cache. |
| + node_cache_[strpath] = node; |
| + |
| + *out_node = node; |
| + return 0; |
| } |
| -bool MountHttp::ParseManifest(char *text) { |
| +Error MountHttp::ParseManifest(char* text) { |
| StringList_t lines; |
| SplitString(text, "\n", &lines); |
| @@ -741,62 +272,102 @@ bool MountHttp::ParseManifest(char *text) { |
| // Ignore EXEC bit |
| int mode = S_IFREG; |
| switch (modestr[0]) { |
| - case '-': mode = S_IFREG; break; |
| - case 'c': mode = S_IFCHR; break; |
| + case '-': |
| + mode = S_IFREG; |
| + break; |
| + case 'c': |
| + mode = S_IFCHR; |
| + break; |
| default: |
| fprintf(stderr, "Unable to parse type %s for %s.\n", modestr, name); |
| - return false; |
| + return EINVAL; |
| } |
| switch (modestr[1]) { |
| - case '-': break; |
| - case 'r': mode |= S_IREAD; break; |
| + case '-': |
| + break; |
| + case 'r': |
| + mode |= S_IREAD; |
| + break; |
| default: |
| fprintf(stderr, "Unable to parse read %s for %s.\n", modestr, name); |
| - return false; |
| + return EINVAL; |
| } |
| switch (modestr[2]) { |
| - case '-': break; |
| - case 'w': mode |= S_IWRITE; break; |
| + case '-': |
| + break; |
| + case 'w': |
| + mode |= S_IWRITE; |
| + break; |
| default: |
| fprintf(stderr, "Unable to parse write %s for %s.\n", modestr, name); |
| - return false; |
| + return EINVAL; |
| } |
| Path path(name); |
| - std::string url = url_root_ + (path.IsAbsolute() ? |
| - path.Range(1, path.Size()) : |
| - path.Join()); |
| + std::string url = |
| + url_root_ + |
| + (path.IsAbsolute() ? path.Range(1, path.Size()) : path.Join()); |
| MountNodeHttp* node = new MountNodeHttp(this, url, cache_content_); |
| - node->Init(mode); |
| + Error error = node->Init(mode); |
| + if (error) { |
| + node->Release(); |
| + return error; |
| + } |
| + |
| node->SetCachedSize(atoi(lenstr)); |
| - MountNodeDir* dir_node = FindOrCreateDir(path.Parent()); |
| - dir_node->AddChild(path.Basename(), node); |
| + MountNodeDir* dir_node; |
| + error = FindOrCreateDir(path.Parent(), &dir_node); |
| + if (error) { |
| + node->Release(); |
| + return error; |
| + } |
| + |
| + error = dir_node->AddChild(path.Basename(), node); |
| + if (error) { |
| + node->Release(); |
| + return error; |
| + } |
| std::string pname = path.Join(); |
| node_cache_[pname] = node; |
| } |
| } |
| - return true; |
| + return 0; |
| } |
| -char *MountHttp::LoadManifest(const std::string& manifest_name) { |
| +Error MountHttp::LoadManifest(const std::string& manifest_name, |
| + char** out_manifest) { |
| Path manifest_path(manifest_name); |
| - MountNode* manifest_node = Open(manifest_path, O_RDONLY); |
| + MountNode* manifest_node = NULL; |
| + *out_manifest = NULL; |
| - if (manifest_node) { |
| - char *text = new char[manifest_node->GetSize() + 1]; |
| - off_t len = manifest_node->Read(0, text, manifest_node->GetSize()); |
| + int error = Open(manifest_path, O_RDONLY, &manifest_node); |
| + if (error) |
| + return error; |
| + |
| + size_t size; |
| + error = manifest_node->GetSize(&size); |
| + if (error) { |
| manifest_node->Release(); |
| + return error; |
| + } |
| - text[len] = 0; |
| - return text; |
| + char* text = new char[size + 1]; |
| + int len; |
| + error = manifest_node->Read(0, text, size, &len); |
| + if (error) { |
| + manifest_node->Release(); |
| + return error; |
| } |
| - fprintf(stderr, "Could not open manifest: %s\n", manifest_name.c_str()); |
| - return NULL; |
| + manifest_node->Release(); |
| + text[len] = 0; |
| + |
| + *out_manifest = text; |
| + return 0; |
| } |