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 |