| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 "pdf/document_loader.h" | 5 #include "pdf/document_loader.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 #include <stdint.h> | 8 #include <stdint.h> |
| 9 | 9 |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 45 } | 45 } |
| 46 } | 46 } |
| 47 return false; | 47 return false; |
| 48 } | 48 } |
| 49 | 49 |
| 50 // If the headers have a multi-part response, returns the boundary name. | 50 // If the headers have a multi-part response, returns the boundary name. |
| 51 // Otherwise returns an empty string. | 51 // Otherwise returns an empty string. |
| 52 std::string GetMultiPartBoundary(const std::string& headers) { | 52 std::string GetMultiPartBoundary(const std::string& headers) { |
| 53 net::HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\n"); | 53 net::HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\n"); |
| 54 while (it.GetNext()) { | 54 while (it.GetNext()) { |
| 55 if (base::LowerCaseEqualsASCII(it.name(), "content-type")) { | 55 if (!base::LowerCaseEqualsASCII(it.name(), "content-type")) |
| 56 std::string type = base::ToLowerASCII(it.values()); | 56 continue; |
| 57 if (base::StartsWith(type, "multipart/", base::CompareCase::SENSITIVE)) { | |
| 58 const char* boundary = strstr(type.c_str(), "boundary="); | |
| 59 if (!boundary) { | |
| 60 NOTREACHED(); | |
| 61 break; | |
| 62 } | |
| 63 | 57 |
| 64 return std::string(boundary + 9); | 58 std::string type = base::ToLowerASCII(it.values()); |
| 65 } | 59 if (!base::StartsWith(type, "multipart/", base::CompareCase::SENSITIVE)) |
| 60 continue; |
| 61 |
| 62 static constexpr char kBoundary[] = "boundary="; |
| 63 const char* boundary = strstr(type.c_str(), kBoundary); |
| 64 if (!boundary) { |
| 65 NOTREACHED(); |
| 66 return std::string(); |
| 66 } | 67 } |
| 68 |
| 69 return std::string(boundary + strlen(kBoundary)); |
| 67 } | 70 } |
| 68 return std::string(); | 71 return std::string(); |
| 69 } | 72 } |
| 70 | 73 |
| 71 // Return true if the HTTP response of |loader| is a successful one and loading | 74 // Return true if the HTTP response of |loader| is a successful one and loading |
| 72 // should continue. 4xx error indicate subsequent requests will fail too. | 75 // should continue. 4xx error indicate subsequent requests will fail too. |
| 73 // e.g. resource has been removed from the server while loading it. 301 | 76 // e.g. resource has been removed from the server while loading it. 301 |
| 74 // indicates a redirect was returned which won't be successful because we | 77 // indicates a redirect was returned which won't be successful because we |
| 75 // disable following redirects for PDF loading (we assume they are already | 78 // disable following redirects for PDF loading (we assume they are already |
| 76 // resolved by the browser. | 79 // resolved by the browser. |
| 77 bool ResponseStatusSuccess(const pp::URLLoader& loader) { | 80 bool ResponseStatusSuccess(const pp::URLLoader& loader) { |
| 78 int32_t http_code = loader.GetResponseInfo().GetStatusCode(); | 81 int32_t http_code = loader.GetResponseInfo().GetStatusCode(); |
| 79 return (http_code < 400 && http_code != 301) || http_code >= 500; | 82 return (http_code < 400 && http_code != 301) || http_code >= 500; |
| 80 } | 83 } |
| 81 | 84 |
| 82 bool IsValidContentType(const std::string& type) { | 85 bool IsValidContentType(const std::string& type) { |
| 83 return base::EndsWith(type, "/pdf", base::CompareCase::INSENSITIVE_ASCII) || | 86 return base::EndsWith(type, "/pdf", base::CompareCase::INSENSITIVE_ASCII) || |
| 84 base::EndsWith(type, ".pdf", base::CompareCase::INSENSITIVE_ASCII) || | 87 base::EndsWith(type, ".pdf", base::CompareCase::INSENSITIVE_ASCII) || |
| 85 base::EndsWith(type, "/x-pdf", base::CompareCase::INSENSITIVE_ASCII) || | 88 base::EndsWith(type, "/x-pdf", base::CompareCase::INSENSITIVE_ASCII) || |
| 86 base::EndsWith(type, "/*", base::CompareCase::INSENSITIVE_ASCII) || | 89 base::EndsWith(type, "/*", base::CompareCase::INSENSITIVE_ASCII) || |
| 87 base::EndsWith(type, "/acrobat", | 90 base::EndsWith(type, "/acrobat", |
| 88 base::CompareCase::INSENSITIVE_ASCII) || | 91 base::CompareCase::INSENSITIVE_ASCII) || |
| 89 base::EndsWith(type, "/unknown", base::CompareCase::INSENSITIVE_ASCII); | 92 base::EndsWith(type, "/unknown", base::CompareCase::INSENSITIVE_ASCII); |
| 90 } | 93 } |
| 91 | 94 |
| 95 bool IsDoubleNewlines(const char* buffer, int index) { |
| 96 DCHECK_GE(index, 2); |
| 97 static constexpr char kLF2[] = "\n\n"; |
| 98 static constexpr char kCRLF2[] = "\r\n\r\n"; |
| 99 if (strncmp(&buffer[index - 2], kLF2, strlen(kLF2)) == 0) |
| 100 return true; |
| 101 return index >= 4 && strncmp(&buffer[index - 4], kCRLF2, strlen(kCRLF2)) == 0; |
| 102 } |
| 103 |
| 92 } // namespace | 104 } // namespace |
| 93 | 105 |
| 94 DocumentLoader::Client::~Client() {} | 106 DocumentLoader::Client::~Client() {} |
| 95 | 107 |
| 96 DocumentLoader::DocumentLoader(Client* client) | 108 DocumentLoader::DocumentLoader(Client* client) |
| 97 : client_(client), | 109 : client_(client), |
| 98 partial_document_(false), | 110 partial_document_(false), |
| 99 request_pending_(false), | 111 request_pending_(false), |
| 100 current_pos_(0), | 112 current_pos_(0), |
| 101 current_chunk_size_(0), | 113 current_chunk_size_(0), |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 213 ReadMore(); | 225 ReadMore(); |
| 214 } | 226 } |
| 215 | 227 |
| 216 bool DocumentLoader::IsDocumentComplete() const { | 228 bool DocumentLoader::IsDocumentComplete() const { |
| 217 if (document_size_ == 0) // Document size unknown. | 229 if (document_size_ == 0) // Document size unknown. |
| 218 return false; | 230 return false; |
| 219 return IsDataAvailable(0, document_size_); | 231 return IsDataAvailable(0, document_size_); |
| 220 } | 232 } |
| 221 | 233 |
| 222 uint32_t DocumentLoader::GetAvailableData() const { | 234 uint32_t DocumentLoader::GetAvailableData() const { |
| 223 if (document_size_ == 0) { // If document size is unknown. | 235 if (document_size_ == 0) // Document size unknown. |
| 224 return current_pos_; | 236 return current_pos_; |
| 225 } | |
| 226 | 237 |
| 227 std::vector<std::pair<size_t, size_t>> ranges; | 238 std::vector<std::pair<size_t, size_t>> ranges; |
| 228 chunk_stream_.GetMissedRanges(0, document_size_, &ranges); | 239 chunk_stream_.GetMissedRanges(0, document_size_, &ranges); |
| 229 uint32_t available = document_size_; | 240 uint32_t available = document_size_; |
| 230 for (const auto& range : ranges) | 241 for (const auto& range : ranges) |
| 231 available -= range.second; | 242 available -= range.second; |
| 232 return available; | 243 return available; |
| 233 } | 244 } |
| 234 | 245 |
| 235 void DocumentLoader::ClearPendingRequests() { | 246 void DocumentLoader::ClearPendingRequests() { |
| 236 pending_requests_.erase(pending_requests_.begin(), pending_requests_.end()); | 247 pending_requests_.clear(); |
| 237 } | 248 } |
| 238 | 249 |
| 239 bool DocumentLoader::GetBlock(uint32_t position, | 250 bool DocumentLoader::GetBlock(uint32_t position, |
| 240 uint32_t size, | 251 uint32_t size, |
| 241 void* buf) const { | 252 void* buf) const { |
| 242 return chunk_stream_.ReadData(position, size, buf); | 253 return chunk_stream_.ReadData(position, size, buf); |
| 243 } | 254 } |
| 244 | 255 |
| 245 bool DocumentLoader::IsDataAvailable(uint32_t position, uint32_t size) const { | 256 bool DocumentLoader::IsDataAvailable(uint32_t position, uint32_t size) const { |
| 246 return chunk_stream_.IsRangeAvailable(position, size); | 257 return chunk_stream_.IsRangeAvailable(position, size); |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 394 // Leave position untouched for now, when we read the data we'll get it. | 405 // Leave position untouched for now, when we read the data we'll get it. |
| 395 is_multipart_ = true; | 406 is_multipart_ = true; |
| 396 multipart_boundary_ = boundary; | 407 multipart_boundary_ = boundary; |
| 397 } else { | 408 } else { |
| 398 // Need to make sure that the server returned a byte-range, since it's | 409 // Need to make sure that the server returned a byte-range, since it's |
| 399 // possible for a server to just ignore our byte-range request and just | 410 // possible for a server to just ignore our byte-range request and just |
| 400 // return the entire document even if it supports byte-range requests. | 411 // return the entire document even if it supports byte-range requests. |
| 401 // i.e. sniff response to | 412 // i.e. sniff response to |
| 402 // http://www.act.org/compass/sample/pdf/geometry.pdf | 413 // http://www.act.org/compass/sample/pdf/geometry.pdf |
| 403 current_pos_ = 0; | 414 current_pos_ = 0; |
| 404 uint32_t start_pos, end_pos; | 415 uint32_t start_pos; |
| 416 uint32_t end_pos; |
| 405 if (GetByteRange(headers, &start_pos, &end_pos)) { | 417 if (GetByteRange(headers, &start_pos, &end_pos)) { |
| 406 current_pos_ = start_pos; | 418 current_pos_ = start_pos; |
| 407 if (end_pos && end_pos > start_pos) | 419 if (end_pos && end_pos > start_pos) |
| 408 current_chunk_size_ = end_pos - start_pos + 1; | 420 current_chunk_size_ = end_pos - start_pos + 1; |
| 409 } else { | 421 } else { |
| 410 partial_document_ = false; | 422 partial_document_ = false; |
| 411 } | 423 } |
| 412 } | 424 } |
| 413 | 425 |
| 414 ReadMore(); | 426 ReadMore(); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 429 // case where an error occurred, the renderer will detect that we're missing | 441 // case where an error occurred, the renderer will detect that we're missing |
| 430 // data and will display a message. | 442 // data and will display a message. |
| 431 ReadComplete(); | 443 ReadComplete(); |
| 432 return; | 444 return; |
| 433 } | 445 } |
| 434 | 446 |
| 435 char* start = buffer_; | 447 char* start = buffer_; |
| 436 size_t length = result; | 448 size_t length = result; |
| 437 if (is_multipart_ && result > 2) { | 449 if (is_multipart_ && result > 2) { |
| 438 for (int i = 2; i < result; ++i) { | 450 for (int i = 2; i < result; ++i) { |
| 439 if ((buffer_[i - 1] == '\n' && buffer_[i - 2] == '\n') || | 451 if (IsDoubleNewlines(buffer_, i)) { |
| 440 (i >= 4 && buffer_[i - 1] == '\n' && buffer_[i - 2] == '\r' && | 452 uint32_t start_pos; |
| 441 buffer_[i - 3] == '\n' && buffer_[i - 4] == '\r')) { | 453 uint32_t end_pos; |
| 442 uint32_t start_pos, end_pos; | |
| 443 if (GetByteRange(std::string(buffer_, i), &start_pos, &end_pos)) { | 454 if (GetByteRange(std::string(buffer_, i), &start_pos, &end_pos)) { |
| 444 current_pos_ = start_pos; | 455 current_pos_ = start_pos; |
| 445 start += i; | 456 start += i; |
| 446 length -= i; | 457 length -= i; |
| 447 if (end_pos && end_pos > start_pos) | 458 if (end_pos && end_pos > start_pos) |
| 448 current_chunk_size_ = end_pos - start_pos + 1; | 459 current_chunk_size_ = end_pos - start_pos + 1; |
| 449 } | 460 } |
| 450 break; | 461 break; |
| 451 } | 462 } |
| 452 } | 463 } |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 550 | 561 |
| 551 void DocumentLoader::UpdateRendering() { | 562 void DocumentLoader::UpdateRendering() { |
| 552 if (header_request_) | 563 if (header_request_) |
| 553 client_->OnPartialDocumentLoaded(); | 564 client_->OnPartialDocumentLoaded(); |
| 554 else | 565 else |
| 555 client_->OnPendingRequestComplete(); | 566 client_->OnPendingRequestComplete(); |
| 556 header_request_ = false; | 567 header_request_ = false; |
| 557 } | 568 } |
| 558 | 569 |
| 559 } // namespace chrome_pdf | 570 } // namespace chrome_pdf |
| OLD | NEW |