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_node.h" | 5 #include "nacl_io/httpfs/http_fs_node.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 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
76 start = &headers[i + 1]; | 76 start = &headers[i + 1]; |
77 state = FINDING_KEY; | 77 state = FINDING_KEY; |
78 } | 78 } |
79 break; | 79 break; |
80 } | 80 } |
81 } | 81 } |
82 | 82 |
83 return result; | 83 return result; |
84 } | 84 } |
85 | 85 |
86 bool ParseContentLength(const StringMap_t& headers, size_t* content_length) { | 86 bool ParseContentLength(const StringMap_t& headers, off_t* content_length) { |
87 StringMap_t::const_iterator iter = headers.find("Content-Length"); | 87 StringMap_t::const_iterator iter = headers.find("Content-Length"); |
88 if (iter == headers.end()) | 88 if (iter == headers.end()) |
89 return false; | 89 return false; |
90 | 90 |
91 *content_length = strtoul(iter->second.c_str(), NULL, 10); | 91 *content_length = strtoull(iter->second.c_str(), NULL, 10); |
92 return true; | 92 return true; |
93 } | 93 } |
94 | 94 |
95 bool ParseContentRange(const StringMap_t& headers, | 95 bool ParseContentRange(const StringMap_t& headers, |
96 size_t* read_start, | 96 off_t* read_start, |
97 size_t* read_end, | 97 off_t* read_end, |
98 size_t* entity_length) { | 98 off_t* entity_length) { |
99 StringMap_t::const_iterator iter = headers.find("Content-Range"); | 99 StringMap_t::const_iterator iter = headers.find("Content-Range"); |
100 if (iter == headers.end()) | 100 if (iter == headers.end()) |
101 return false; | 101 return false; |
102 | 102 |
103 // The key should look like "bytes ##-##/##" or "bytes ##-##/*". The last | 103 // The key should look like "bytes ##-##/##" or "bytes ##-##/*". The last |
104 // value is the entity length, which can potentially be * (i.e. unknown). | 104 // value is the entity length, which can potentially be * (i.e. unknown). |
105 size_t read_start_int; | 105 off_t read_start_int; |
106 size_t read_end_int; | 106 off_t read_end_int; |
107 size_t entity_length_int; | 107 off_t entity_length_int; |
108 int result = sscanf(iter->second.c_str(), | 108 int result = sscanf(iter->second.c_str(), |
109 "bytes %" SCNuS "-%" SCNuS "/%" SCNuS, | 109 "bytes %" SCNi64 "-%" SCNi64 "/%" SCNi64, |
110 &read_start_int, | 110 &read_start_int, |
111 &read_end_int, | 111 &read_end_int, |
112 &entity_length_int); | 112 &entity_length_int); |
113 | 113 |
114 // The Content-Range header specifies an inclusive range: e.g. the first ten | 114 // The Content-Range header specifies an inclusive range: e.g. the first ten |
115 // bytes is "bytes 0-9/*". Convert it to a half-open range by incrementing | 115 // bytes is "bytes 0-9/*". Convert it to a half-open range by incrementing |
116 // read_end. | 116 // read_end. |
117 if (result == 2) { | 117 if (result == 2) { |
118 *read_start = read_start_int; | 118 *read_start = read_start_int; |
119 *read_end = read_end_int + 1; | 119 *read_end = read_end_int + 1; |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
191 | 191 |
192 Error HttpFsNode::Write(const HandleAttr& attr, | 192 Error HttpFsNode::Write(const HandleAttr& attr, |
193 const void* buf, | 193 const void* buf, |
194 size_t count, | 194 size_t count, |
195 int* out_bytes) { | 195 int* out_bytes) { |
196 // TODO(binji): support POST? | 196 // TODO(binji): support POST? |
197 *out_bytes = 0; | 197 *out_bytes = 0; |
198 return EACCES; | 198 return EACCES; |
199 } | 199 } |
200 | 200 |
201 Error HttpFsNode::GetSize(size_t* out_size) { | 201 Error HttpFsNode::GetSize(off_t* out_size) { |
202 *out_size = 0; | 202 *out_size = 0; |
203 | 203 |
204 // TODO(binji): This value should be cached properly; i.e. obey the caching | 204 // TODO(binji): This value should be cached properly; i.e. obey the caching |
205 // headers returned by the server. | 205 // headers returned by the server. |
206 AUTO_LOCK(node_lock_); | 206 AUTO_LOCK(node_lock_); |
207 struct stat statbuf; | 207 struct stat statbuf; |
208 Error error = GetStat_Locked(&statbuf); | 208 Error error = GetStat_Locked(&statbuf); |
209 if (error) | 209 if (error) |
210 return error; | 210 return error; |
211 | 211 |
(...skipping 25 matching lines...) Expand all Loading... |
237 Error error = OpenUrl("HEAD", | 237 Error error = OpenUrl("HEAD", |
238 &headers, | 238 &headers, |
239 &loader, | 239 &loader, |
240 &request, | 240 &request, |
241 &response, | 241 &response, |
242 &statuscode, | 242 &statuscode, |
243 &response_headers); | 243 &response_headers); |
244 if (error) | 244 if (error) |
245 return error; | 245 return error; |
246 | 246 |
247 size_t entity_length; | 247 off_t entity_length; |
248 if (ParseContentLength(response_headers, &entity_length)) { | 248 if (ParseContentLength(response_headers, &entity_length)) { |
249 SetCachedSize(static_cast<off_t>(entity_length)); | 249 SetCachedSize(static_cast<off_t>(entity_length)); |
250 } else if (cache_content_) { | 250 } else if (cache_content_) { |
251 // The server didn't give a content length; download the data to memory | 251 // The server didn't give a content length; download the data to memory |
252 // via DownloadToCache, which will also set stat_.st_size; | 252 // via DownloadToCache, which will also set stat_.st_size; |
253 error = DownloadToCache(); | 253 error = DownloadToCache(); |
254 if (error) | 254 if (error) |
255 return error; | 255 return error; |
256 } else { | 256 } else { |
257 // The user doesn't want to cache content, but we didn't get a | 257 // The user doesn't want to cache content, but we didn't get a |
258 // "Content-Length" header. Read the entire entity, and throw it away. | 258 // "Content-Length" header. Read the entire entity, and throw it away. |
259 // Don't use DownloadToCache, as that will still allocate enough memory | 259 // Don't use DownloadToCache, as that will still allocate enough memory |
260 // for the entire entity. | 260 // for the entire entity. |
261 int bytes_read; | 261 off_t bytes_read; |
262 error = DownloadToTemp(&bytes_read); | 262 error = DownloadToTemp(&bytes_read); |
263 if (error) | 263 if (error) |
264 return error; | 264 return error; |
265 | 265 |
266 SetCachedSize(bytes_read); | 266 SetCachedSize(bytes_read); |
267 } | 267 } |
268 | 268 |
269 stat_.st_atime = 0; // TODO(binji): Use "Last-Modified". | 269 stat_.st_atime = 0; // TODO(binji): Use "Last-Modified". |
270 stat_.st_mtime = 0; | 270 stat_.st_mtime = 0; |
271 stat_.st_ctime = 0; | 271 stat_.st_ctime = 0; |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
360 Error error = OpenUrl("GET", | 360 Error error = OpenUrl("GET", |
361 &headers, | 361 &headers, |
362 &loader, | 362 &loader, |
363 &request, | 363 &request, |
364 &response, | 364 &response, |
365 &statuscode, | 365 &statuscode, |
366 &response_headers); | 366 &response_headers); |
367 if (error) | 367 if (error) |
368 return error; | 368 return error; |
369 | 369 |
370 size_t content_length = 0; | 370 off_t content_length = 0; |
371 if (ParseContentLength(response_headers, &content_length)) { | 371 if (ParseContentLength(response_headers, &content_length)) { |
372 cached_data_.resize(content_length); | 372 cached_data_.resize(content_length); |
373 int real_size; | 373 int real_size; |
374 error = ReadResponseToBuffer( | 374 error = ReadResponseToBuffer( |
375 loader, cached_data_.data(), content_length, &real_size); | 375 loader, cached_data_.data(), content_length, &real_size); |
376 if (error) | 376 if (error) |
377 return error; | 377 return error; |
378 | 378 |
379 SetCachedSize(real_size); | 379 SetCachedSize(real_size); |
380 cached_data_.resize(real_size); | 380 cached_data_.resize(real_size); |
381 return 0; | 381 return 0; |
382 } | 382 } |
383 | 383 |
384 int bytes_read; | 384 int bytes_read; |
385 error = ReadEntireResponseToCache(loader, &bytes_read); | 385 error = ReadEntireResponseToCache(loader, &bytes_read); |
386 if (error) | 386 if (error) |
387 return error; | 387 return error; |
388 | 388 |
389 SetCachedSize(bytes_read); | 389 SetCachedSize(bytes_read); |
390 return 0; | 390 return 0; |
391 } | 391 } |
392 | 392 |
393 Error HttpFsNode::ReadPartialFromCache(const HandleAttr& attr, | 393 Error HttpFsNode::ReadPartialFromCache(const HandleAttr& attr, |
394 void* buf, | 394 void* buf, |
395 int count, | 395 int count, |
396 int* out_bytes) { | 396 int* out_bytes) { |
397 *out_bytes = 0; | 397 *out_bytes = 0; |
398 size_t size = cached_data_.size(); | 398 off_t size = cached_data_.size(); |
399 | 399 |
400 if (attr.offs + count > size) | 400 if (attr.offs + count > size) |
401 count = size - attr.offs; | 401 count = size - attr.offs; |
402 | 402 |
403 if (count <= 0) | 403 if (count <= 0) |
404 return 0; | 404 return 0; |
405 | 405 |
406 memcpy(buf, &cached_data_.data()[attr.offs], count); | 406 memcpy(buf, &cached_data_.data()[attr.offs], count); |
407 *out_bytes = count; | 407 *out_bytes = count; |
408 return 0; | 408 return 0; |
409 } | 409 } |
410 | 410 |
411 Error HttpFsNode::DownloadPartial(const HandleAttr& attr, | 411 Error HttpFsNode::DownloadPartial(const HandleAttr& attr, |
412 void* buf, | 412 void* buf, |
413 size_t count, | 413 off_t count, |
414 int* out_bytes) { | 414 int* out_bytes) { |
415 *out_bytes = 0; | 415 *out_bytes = 0; |
416 | 416 |
417 StringMap_t headers; | 417 StringMap_t headers; |
418 | 418 |
419 char buffer[100]; | 419 char buffer[100]; |
420 // Range request is inclusive: 0-99 returns 100 bytes. | 420 // Range request is inclusive: 0-99 returns 100 bytes. |
421 snprintf(&buffer[0], | 421 snprintf(&buffer[0], |
422 sizeof(buffer), | 422 sizeof(buffer), |
423 "bytes=%" PRIuS "-%" PRIuS, | 423 "bytes=%" PRIi64 "-%" PRIi64, |
424 attr.offs, | 424 attr.offs, |
425 attr.offs + count - 1); | 425 attr.offs + count - 1); |
426 headers["Range"] = buffer; | 426 headers["Range"] = buffer; |
427 | 427 |
428 ScopedResource loader(filesystem_->ppapi()); | 428 ScopedResource loader(filesystem_->ppapi()); |
429 ScopedResource request(filesystem_->ppapi()); | 429 ScopedResource request(filesystem_->ppapi()); |
430 ScopedResource response(filesystem_->ppapi()); | 430 ScopedResource response(filesystem_->ppapi()); |
431 int32_t statuscode; | 431 int32_t statuscode; |
432 StringMap_t response_headers; | 432 StringMap_t response_headers; |
433 Error error = OpenUrl("GET", | 433 Error error = OpenUrl("GET", |
434 &headers, | 434 &headers, |
435 &loader, | 435 &loader, |
436 &request, | 436 &request, |
437 &response, | 437 &response, |
438 &statuscode, | 438 &statuscode, |
439 &response_headers); | 439 &response_headers); |
440 if (error) { | 440 if (error) { |
441 if (statuscode == STATUSCODE_REQUESTED_RANGE_NOT_SATISFIABLE) { | 441 if (statuscode == STATUSCODE_REQUESTED_RANGE_NOT_SATISFIABLE) { |
442 // We're likely trying to read past the end. Return 0 bytes. | 442 // We're likely trying to read past the end. Return 0 bytes. |
443 *out_bytes = 0; | 443 *out_bytes = 0; |
444 return 0; | 444 return 0; |
445 } | 445 } |
446 | 446 |
447 return error; | 447 return error; |
448 } | 448 } |
449 | 449 |
450 size_t read_start = 0; | 450 off_t read_start = 0; |
451 if (statuscode == STATUSCODE_OK) { | 451 if (statuscode == STATUSCODE_OK) { |
452 // No partial result, read everything starting from the part we care about. | 452 // No partial result, read everything starting from the part we care about. |
453 size_t content_length; | 453 off_t content_length; |
454 if (ParseContentLength(response_headers, &content_length)) { | 454 if (ParseContentLength(response_headers, &content_length)) { |
455 if (attr.offs >= content_length) | 455 if (attr.offs >= content_length) |
456 return EINVAL; | 456 return EINVAL; |
457 | 457 |
458 // Clamp count, if trying to read past the end of the file. | 458 // Clamp count, if trying to read past the end of the file. |
459 if (attr.offs + count > content_length) { | 459 if (attr.offs + count > content_length) { |
460 count = content_length - attr.offs; | 460 count = content_length - attr.offs; |
461 } | 461 } |
462 } | 462 } |
463 } else if (statuscode == STATUSCODE_PARTIAL_CONTENT) { | 463 } else if (statuscode == STATUSCODE_PARTIAL_CONTENT) { |
464 // Determine from the headers where we are reading. | 464 // Determine from the headers where we are reading. |
465 size_t read_end; | 465 off_t read_end; |
466 size_t entity_length; | 466 off_t entity_length; |
467 if (ParseContentRange( | 467 if (ParseContentRange( |
468 response_headers, &read_start, &read_end, &entity_length)) { | 468 response_headers, &read_start, &read_end, &entity_length)) { |
469 if (read_start > attr.offs || read_start > read_end) { | 469 if (read_start > attr.offs || read_start > read_end) { |
470 // If this error occurs, the server is returning bogus values. | 470 // If this error occurs, the server is returning bogus values. |
471 return EINVAL; | 471 return EINVAL; |
472 } | 472 } |
473 | 473 |
474 // Clamp count, if trying to read past the end of the file. | 474 // Clamp count, if trying to read past the end of the file. |
475 count = std::min(read_end - read_start, count); | 475 count = std::min(read_end - read_start, count); |
476 } else { | 476 } else { |
(...skipping 17 matching lines...) Expand all Loading... |
494 // Tried to read past the end of the entity. | 494 // Tried to read past the end of the entity. |
495 if (bytes_read < bytes_to_read) { | 495 if (bytes_read < bytes_to_read) { |
496 *out_bytes = 0; | 496 *out_bytes = 0; |
497 return 0; | 497 return 0; |
498 } | 498 } |
499 } | 499 } |
500 | 500 |
501 return ReadResponseToBuffer(loader, buf, count, out_bytes); | 501 return ReadResponseToBuffer(loader, buf, count, out_bytes); |
502 } | 502 } |
503 | 503 |
504 Error HttpFsNode::DownloadToTemp(int* out_bytes) { | 504 Error HttpFsNode::DownloadToTemp(off_t* out_bytes) { |
505 StringMap_t headers; | 505 StringMap_t headers; |
506 ScopedResource loader(filesystem_->ppapi()); | 506 ScopedResource loader(filesystem_->ppapi()); |
507 ScopedResource request(filesystem_->ppapi()); | 507 ScopedResource request(filesystem_->ppapi()); |
508 ScopedResource response(filesystem_->ppapi()); | 508 ScopedResource response(filesystem_->ppapi()); |
509 int32_t statuscode; | 509 int32_t statuscode; |
510 StringMap_t response_headers; | 510 StringMap_t response_headers; |
511 Error error = OpenUrl("GET", | 511 Error error = OpenUrl("GET", |
512 &headers, | 512 &headers, |
513 &loader, | 513 &loader, |
514 &request, | 514 &request, |
515 &response, | 515 &response, |
516 &statuscode, | 516 &statuscode, |
517 &response_headers); | 517 &response_headers); |
518 if (error) | 518 if (error) |
519 return error; | 519 return error; |
520 | 520 |
521 size_t content_length = 0; | 521 off_t content_length = 0; |
522 if (ParseContentLength(response_headers, &content_length)) { | 522 if (ParseContentLength(response_headers, &content_length)) { |
523 *out_bytes = content_length; | 523 *out_bytes = content_length; |
524 return 0; | 524 return 0; |
525 } | 525 } |
526 | 526 |
527 return ReadEntireResponseToTemp(loader, out_bytes); | 527 return ReadEntireResponseToTemp(loader, out_bytes); |
528 } | 528 } |
529 | 529 |
530 Error HttpFsNode::ReadEntireResponseToTemp(const ScopedResource& loader, | 530 Error HttpFsNode::ReadEntireResponseToTemp(const ScopedResource& loader, |
531 int* out_bytes) { | 531 off_t* out_bytes) { |
532 *out_bytes = 0; | 532 *out_bytes = 0; |
533 | 533 |
534 const int kBytesToRead = MAX_READ_BUFFER_SIZE; | 534 const int kBytesToRead = MAX_READ_BUFFER_SIZE; |
535 buffer_.resize(kBytesToRead); | 535 buffer_.resize(kBytesToRead); |
536 | 536 |
537 while (true) { | 537 while (true) { |
538 int bytes_read; | 538 int bytes_read; |
539 Error error = | 539 Error error = |
540 ReadResponseToBuffer(loader, buffer_.data(), kBytesToRead, &bytes_read); | 540 ReadResponseToBuffer(loader, buffer_.data(), kBytesToRead, &bytes_read); |
541 if (error) | 541 if (error) |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
633 assert(bytes_read <= bytes_to_read); | 633 assert(bytes_read <= bytes_to_read); |
634 bytes_to_read -= bytes_read; | 634 bytes_to_read -= bytes_read; |
635 out_buffer += bytes_read; | 635 out_buffer += bytes_read; |
636 } | 636 } |
637 | 637 |
638 *out_bytes = count; | 638 *out_bytes = count; |
639 return 0; | 639 return 0; |
640 } | 640 } |
641 | 641 |
642 } // namespace nacl_io | 642 } // namespace nacl_io |
OLD | NEW |