| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 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/mount_node_http.h" | 5 #include "nacl_io/mount_node_http.h" |
| 6 | 6 |
| 7 #include <assert.h> | 7 #include <assert.h> |
| 8 #include <errno.h> | 8 #include <errno.h> |
| 9 #include <stdio.h> | 9 #include <stdio.h> |
| 10 #include <string.h> | 10 #include <string.h> |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 144 return EIO; | 144 return EIO; |
| 145 } | 145 } |
| 146 | 146 |
| 147 } // namespace | 147 } // namespace |
| 148 | 148 |
| 149 void MountNodeHttp::SetCachedSize(off_t size) { | 149 void MountNodeHttp::SetCachedSize(off_t size) { |
| 150 has_cached_size_ = true; | 150 has_cached_size_ = true; |
| 151 stat_.st_size = size; | 151 stat_.st_size = size; |
| 152 } | 152 } |
| 153 | 153 |
| 154 Error MountNodeHttp::FSync() { return ENOSYS; } | 154 Error MountNodeHttp::FSync() { return EACCES; } |
| 155 | 155 |
| 156 Error MountNodeHttp::GetDents(size_t offs, | 156 Error MountNodeHttp::GetDents(size_t offs, |
| 157 struct dirent* pdir, | 157 struct dirent* pdir, |
| 158 size_t count, | 158 size_t count, |
| 159 int* out_bytes) { | 159 int* out_bytes) { |
| 160 *out_bytes = 0; | 160 *out_bytes = 0; |
| 161 return ENOSYS; | 161 return EACCES; |
| 162 } | 162 } |
| 163 | 163 |
| 164 Error MountNodeHttp::GetStat(struct stat* stat) { | 164 Error MountNodeHttp::GetStat(struct stat* stat) { |
| 165 AUTO_LOCK(node_lock_); | 165 AUTO_LOCK(node_lock_); |
| 166 | 166 |
| 167 // Assume we need to 'HEAD' if we do not know the size, otherwise, assume | 167 // Assume we need to 'HEAD' if we do not know the size, otherwise, assume |
| 168 // that the information is constant. We can add a timeout if needed. | 168 // that the information is constant. We can add a timeout if needed. |
| 169 MountHttp* mount = static_cast<MountHttp*>(mount_); | 169 MountHttp* mount = static_cast<MountHttp*>(mount_); |
| 170 if (stat_.st_size == 0 || !mount->cache_stat_) { | 170 if (stat_.st_size == 0 || !mount->cache_stat_) { |
| 171 StringMap_t headers; | 171 StringMap_t headers; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 186 | 186 |
| 187 ScopedResource scoped_loader(mount_->ppapi(), loader); | 187 ScopedResource scoped_loader(mount_->ppapi(), loader); |
| 188 ScopedResource scoped_request(mount_->ppapi(), request); | 188 ScopedResource scoped_request(mount_->ppapi(), request); |
| 189 ScopedResource scoped_response(mount_->ppapi(), response); | 189 ScopedResource scoped_response(mount_->ppapi(), response); |
| 190 | 190 |
| 191 size_t entity_length; | 191 size_t entity_length; |
| 192 if (ParseContentLength(response_headers, &entity_length)) { | 192 if (ParseContentLength(response_headers, &entity_length)) { |
| 193 SetCachedSize(static_cast<off_t>(entity_length)); | 193 SetCachedSize(static_cast<off_t>(entity_length)); |
| 194 } else if (cache_content_ && !has_cached_size_) { | 194 } else if (cache_content_ && !has_cached_size_) { |
| 195 error = DownloadToCache(); | 195 error = DownloadToCache(); |
| 196 // TODO(binji): this error should not be dropped, but it requires a bit | 196 if (error) |
| 197 // of a refactor of the tests. See crbug.com/245431 | 197 return error; |
| 198 // if (error) | |
| 199 // return error; | |
| 200 } else { | 198 } else { |
| 201 // Don't use SetCachedSize here -- it is actually unknown. | 199 // Don't use SetCachedSize here -- it is actually unknown. |
| 202 stat_.st_size = 0; | 200 stat_.st_size = 0; |
| 203 } | 201 } |
| 204 | 202 |
| 205 stat_.st_atime = 0; // TODO(binji): Use "Last-Modified". | 203 stat_.st_atime = 0; // TODO(binji): Use "Last-Modified". |
| 206 stat_.st_mtime = 0; | 204 stat_.st_mtime = 0; |
| 207 stat_.st_ctime = 0; | 205 stat_.st_ctime = 0; |
| 208 | 206 |
| 209 stat_.st_mode |= S_IFREG; | 207 stat_.st_mode |= S_IFREG; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 223 *out_bytes = 0; | 221 *out_bytes = 0; |
| 224 | 222 |
| 225 AUTO_LOCK(node_lock_); | 223 AUTO_LOCK(node_lock_); |
| 226 if (cache_content_) { | 224 if (cache_content_) { |
| 227 if (cached_data_.empty()) { | 225 if (cached_data_.empty()) { |
| 228 Error error = DownloadToCache(); | 226 Error error = DownloadToCache(); |
| 229 if (error) | 227 if (error) |
| 230 return error; | 228 return error; |
| 231 } | 229 } |
| 232 | 230 |
| 233 return ReadPartialFromCache(attr.offs, buf, count, out_bytes); | 231 return ReadPartialFromCache(attr, buf, count, out_bytes); |
| 234 } | 232 } |
| 235 | 233 |
| 236 return DownloadPartial(attr.offs, buf, count, out_bytes); | 234 return DownloadPartial(attr, buf, count, out_bytes); |
| 237 } | 235 } |
| 238 | 236 |
| 239 Error MountNodeHttp::FTruncate(off_t size) { return ENOSYS; } | 237 Error MountNodeHttp::FTruncate(off_t size) { return EACCES; } |
| 240 | 238 |
| 241 Error MountNodeHttp::Write(const HandleAttr& attr, | 239 Error MountNodeHttp::Write(const HandleAttr& attr, |
| 242 const void* buf, | 240 const void* buf, |
| 243 size_t count, | 241 size_t count, |
| 244 int* out_bytes) { | 242 int* out_bytes) { |
| 245 // TODO(binji): support POST? | 243 // TODO(binji): support POST? |
| 246 *out_bytes = 0; | 244 *out_bytes = 0; |
| 247 return ENOSYS; | 245 return EACCES; |
| 248 } | 246 } |
| 249 | 247 |
| 250 Error MountNodeHttp::GetSize(size_t* out_size) { | 248 Error MountNodeHttp::GetSize(size_t* out_size) { |
| 251 *out_size = 0; | 249 *out_size = 0; |
| 252 | 250 |
| 253 // TODO(binji): This value should be cached properly; i.e. obey the caching | 251 // TODO(binji): This value should be cached properly; i.e. obey the caching |
| 254 // headers returned by the server. | 252 // headers returned by the server. |
| 255 AUTO_LOCK(node_lock_); | 253 AUTO_LOCK(node_lock_); |
| 256 if (!has_cached_size_) { | 254 if (!has_cached_size_) { |
| 257 // Even if DownloadToCache fails, the best result we can return is what | 255 // Even if DownloadToCache fails, the best result we can return is what |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 335 uint32_t response_headers_length; | 333 uint32_t response_headers_length; |
| 336 const char* response_headers_str = | 334 const char* response_headers_str = |
| 337 var_interface->VarToUtf8(response_headers_var, &response_headers_length); | 335 var_interface->VarToUtf8(response_headers_var, &response_headers_length); |
| 338 | 336 |
| 339 *out_loader = loader.Release(); | 337 *out_loader = loader.Release(); |
| 340 *out_request = request.Release(); | 338 *out_request = request.Release(); |
| 341 *out_response = response.Release(); | 339 *out_response = response.Release(); |
| 342 *out_response_headers = | 340 *out_response_headers = |
| 343 ParseHeaders(response_headers_str, response_headers_length); | 341 ParseHeaders(response_headers_str, response_headers_length); |
| 344 | 342 |
| 343 var_interface->Release(response_headers_var); |
| 344 |
| 345 return 0; | 345 return 0; |
| 346 } | 346 } |
| 347 | 347 |
| 348 Error MountNodeHttp::DownloadToCache() { | 348 Error MountNodeHttp::DownloadToCache() { |
| 349 StringMap_t headers; | 349 StringMap_t headers; |
| 350 PP_Resource loader; | 350 PP_Resource loader; |
| 351 PP_Resource request; | 351 PP_Resource request; |
| 352 PP_Resource response; | 352 PP_Resource response; |
| 353 int32_t statuscode; | 353 int32_t statuscode; |
| 354 StringMap_t response_headers; | 354 StringMap_t response_headers; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 397 if (bytes_read < bytes_to_read) { | 397 if (bytes_read < bytes_to_read) { |
| 398 SetCachedSize(total_bytes_read); | 398 SetCachedSize(total_bytes_read); |
| 399 cached_data_.resize(total_bytes_read); | 399 cached_data_.resize(total_bytes_read); |
| 400 return 0; | 400 return 0; |
| 401 } | 401 } |
| 402 | 402 |
| 403 cached_data_.resize(total_bytes_read + bytes_to_read); | 403 cached_data_.resize(total_bytes_read + bytes_to_read); |
| 404 } | 404 } |
| 405 } | 405 } |
| 406 | 406 |
| 407 Error MountNodeHttp::ReadPartialFromCache(size_t offs, | 407 Error MountNodeHttp::ReadPartialFromCache(const HandleAttr& attr, |
| 408 void* buf, | 408 void* buf, |
| 409 int count, | 409 int count, |
| 410 int* out_bytes) { | 410 int* out_bytes) { |
| 411 *out_bytes = 0; | 411 *out_bytes = 0; |
| 412 size_t size = cached_data_.size(); |
| 412 | 413 |
| 413 if (offs > cached_data_.size()) | 414 if (attr.offs + count > size) |
| 414 return EINVAL; | 415 count = size - attr.offs; |
| 415 | 416 |
| 416 count = std::min(count, static_cast<int>(cached_data_.size() - offs)); | 417 if (count <= 0) |
| 417 memcpy(buf, &cached_data_.data()[offs], count); | 418 return 0; |
| 418 | 419 |
| 420 memcpy(buf, &cached_data_.data()[attr.offs], count); |
| 419 *out_bytes = count; | 421 *out_bytes = count; |
| 420 return 0; | 422 return 0; |
| 421 } | 423 } |
| 422 | 424 |
| 423 Error MountNodeHttp::DownloadPartial(size_t offs, | 425 Error MountNodeHttp::DownloadPartial(const HandleAttr& attr, |
| 424 void* buf, | 426 void* buf, |
| 425 size_t count, | 427 size_t count, |
| 426 int* out_bytes) { | 428 int* out_bytes) { |
| 427 *out_bytes = 0; | 429 *out_bytes = 0; |
| 428 | 430 |
| 429 StringMap_t headers; | 431 StringMap_t headers; |
| 430 | 432 |
| 431 char buffer[100]; | 433 char buffer[100]; |
| 432 // Range request is inclusive: 0-99 returns 100 bytes. | 434 // Range request is inclusive: 0-99 returns 100 bytes. |
| 433 snprintf(&buffer[0], | 435 snprintf(&buffer[0], |
| 434 sizeof(buffer), | 436 sizeof(buffer), |
| 435 "bytes=%" PRIuS "-%" PRIuS, | 437 "bytes=%" PRIuS "-%" PRIuS, |
| 436 offs, | 438 attr.offs, |
| 437 offs + count - 1); | 439 attr.offs + count - 1); |
| 438 headers["Range"] = buffer; | 440 headers["Range"] = buffer; |
| 439 | 441 |
| 440 PP_Resource loader; | 442 PP_Resource loader; |
| 441 PP_Resource request; | 443 PP_Resource request; |
| 442 PP_Resource response; | 444 PP_Resource response; |
| 443 int32_t statuscode; | 445 int32_t statuscode; |
| 444 StringMap_t response_headers; | 446 StringMap_t response_headers; |
| 445 Error error = OpenUrl("GET", | 447 Error error = OpenUrl("GET", |
| 446 &headers, | 448 &headers, |
| 447 &loader, | 449 &loader, |
| 448 &request, | 450 &request, |
| 449 &response, | 451 &response, |
| 450 &statuscode, | 452 &statuscode, |
| 451 &response_headers); | 453 &response_headers); |
| 452 if (error) | 454 if (error) |
| 453 return error; | 455 return error; |
| 454 | 456 |
| 455 PepperInterface* ppapi = mount_->ppapi(); | 457 PepperInterface* ppapi = mount_->ppapi(); |
| 456 ScopedResource scoped_loader(ppapi, loader); | 458 ScopedResource scoped_loader(ppapi, loader); |
| 457 ScopedResource scoped_request(ppapi, request); | 459 ScopedResource scoped_request(ppapi, request); |
| 458 ScopedResource scoped_response(ppapi, response); | 460 ScopedResource scoped_response(ppapi, response); |
| 459 | 461 |
| 460 size_t read_start = 0; | 462 size_t read_start = 0; |
| 461 if (statuscode == STATUSCODE_OK) { | 463 if (statuscode == STATUSCODE_OK) { |
| 462 // No partial result, read everything starting from the part we care about. | 464 // No partial result, read everything starting from the part we care about. |
| 463 size_t content_length; | 465 size_t content_length; |
| 464 if (ParseContentLength(response_headers, &content_length)) { | 466 if (ParseContentLength(response_headers, &content_length)) { |
| 465 if (offs >= content_length) | 467 if (attr.offs >= content_length) |
| 466 return EINVAL; | 468 return EINVAL; |
| 467 | 469 |
| 468 // Clamp count, if trying to read past the end of the file. | 470 // Clamp count, if trying to read past the end of the file. |
| 469 if (offs + count > content_length) { | 471 if (attr.offs + count > content_length) { |
| 470 count = content_length - offs; | 472 count = content_length - attr.offs; |
| 471 } | 473 } |
| 472 } | 474 } |
| 473 } else if (statuscode == STATUSCODE_PARTIAL_CONTENT) { | 475 } else if (statuscode == STATUSCODE_PARTIAL_CONTENT) { |
| 474 // Determine from the headers where we are reading. | 476 // Determine from the headers where we are reading. |
| 475 size_t read_end; | 477 size_t read_end; |
| 476 size_t entity_length; | 478 size_t entity_length; |
| 477 if (ParseContentRange( | 479 if (ParseContentRange( |
| 478 response_headers, &read_start, &read_end, &entity_length)) { | 480 response_headers, &read_start, &read_end, &entity_length)) { |
| 479 if (read_start > offs || read_start > read_end) { | 481 if (read_start > attr.offs || read_start > read_end) { |
| 480 // If this error occurs, the server is returning bogus values. | 482 // If this error occurs, the server is returning bogus values. |
| 481 return EINVAL; | 483 return EINVAL; |
| 482 } | 484 } |
| 483 | 485 |
| 484 // Clamp count, if trying to read past the end of the file. | 486 // Clamp count, if trying to read past the end of the file. |
| 485 count = std::min(read_end - read_start, count); | 487 count = std::min(read_end - read_start, count); |
| 486 } else { | 488 } else { |
| 487 // Partial Content without Content-Range. Assume that the server gave us | 489 // Partial Content without Content-Range. Assume that the server gave us |
| 488 // exactly what we asked for. This can happen even when the server | 490 // exactly what we asked for. This can happen even when the server |
| 489 // returns 200 -- the cache may return 206 in this case, but not modify | 491 // returns 200 -- the cache may return 206 in this case, but not modify |
| 490 // the headers. | 492 // the headers. |
| 491 read_start = offs; | 493 read_start = attr.offs; |
| 492 } | 494 } |
| 493 } | 495 } |
| 494 | 496 |
| 495 if (read_start < offs) { | 497 if (read_start < attr.offs) { |
| 496 // We aren't yet at the location where we want to start reading. Read into | 498 // We aren't yet at the location where we want to start reading. Read into |
| 497 // our dummy buffer until then. | 499 // our dummy buffer until then. |
| 498 size_t bytes_to_read = offs - read_start; | 500 size_t bytes_to_read = attr.offs - read_start; |
| 499 if (buffer_.size() < bytes_to_read) | 501 if (buffer_.size() < bytes_to_read) |
| 500 buffer_.resize(std::min(bytes_to_read, MAX_READ_BUFFER_SIZE)); | 502 buffer_.resize(std::min(bytes_to_read, MAX_READ_BUFFER_SIZE)); |
| 501 | 503 |
| 502 while (bytes_to_read > 0) { | 504 while (bytes_to_read > 0) { |
| 503 int32_t bytes_read; | 505 int32_t bytes_read; |
| 504 Error error = | 506 Error error = |
| 505 DownloadToBuffer(loader, buffer_.data(), buffer_.size(), &bytes_read); | 507 DownloadToBuffer(loader, buffer_.data(), buffer_.size(), &bytes_read); |
| 506 if (error) | 508 if (error) |
| 507 return error; | 509 return error; |
| 508 | 510 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 542 bytes_to_read -= bytes_read; | 544 bytes_to_read -= bytes_read; |
| 543 out_buffer += bytes_read; | 545 out_buffer += bytes_read; |
| 544 } | 546 } |
| 545 | 547 |
| 546 *out_bytes = count; | 548 *out_bytes = count; |
| 547 return 0; | 549 return 0; |
| 548 } | 550 } |
| 549 | 551 |
| 550 } // namespace nacl_io | 552 } // namespace nacl_io |
| 551 | 553 |
| OLD | NEW |