[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 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 |
| 3 | // found in the LICENSE file. |
| 4 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 5 | #include "pdf/document_loader_impl.h" |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 6 | |
avi | a7c09d5 | 2015-12-21 19:49:43 | [diff] [blame] | 7 | #include <stddef.h> |
| 8 | #include <stdint.h> |
| 9 | |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 10 | #include <algorithm> |
Lei Zhang | 533165f | 2018-02-27 19:09:10 | [diff] [blame] | 11 | #include <utility> |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 12 | |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 13 | #include "base/logging.h" |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 14 | #include "base/numerics/safe_math.h" |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 15 | #include "base/strings/string_util.h" |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 16 | #include "pdf/url_loader_wrapper.h" |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 17 | #include "ppapi/c/pp_errors.h" |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 18 | #include "ui/gfx/range/range.h" |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 19 | |
| 20 | namespace chrome_pdf { |
| 21 | |
thestig | 945cd0cb | 2015-05-28 01:58:05 | [diff] [blame] | 22 | namespace { |
| 23 | |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 24 | // The distance from last received chunk, when we wait requesting data, using |
| 25 | // current connection (like playing a cassette tape) and do not send new range |
| 26 | // request (like rewind a cassette tape, and continue playing after). |
| 27 | // Experimentally chosen value. |
Henrique Nakashima | 1c5da8e | 2018-10-05 21:56:43 | [diff] [blame] | 28 | constexpr int kChunkCloseDistance = 10; |
thestig | 945cd0cb | 2015-05-28 01:58:05 | [diff] [blame] | 29 | |
raymes | a8563ff | 2016-11-15 23:50:01 | [diff] [blame] | 30 | // Return true if the HTTP response of |loader| is a successful one and loading |
| 31 | // should continue. 4xx error indicate subsequent requests will fail too. |
| 32 | // e.g. resource has been removed from the server while loading it. 301 |
| 33 | // indicates a redirect was returned which won't be successful because we |
| 34 | // disable following redirects for PDF loading (we assume they are already |
| 35 | // resolved by the browser. |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 36 | bool ResponseStatusSuccess(const URLLoaderWrapper* loader) { |
| 37 | int32_t http_code = loader->GetStatusCode(); |
raymes | a8563ff | 2016-11-15 23:50:01 | [diff] [blame] | 38 | return (http_code < 400 && http_code != 301) || http_code >= 500; |
| 39 | } |
| 40 | |
thestig | 488102f | 2015-05-29 03:25:26 | [diff] [blame] | 41 | bool IsValidContentType(const std::string& type) { |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 42 | return ( |
| 43 | base::EndsWith(type, "/pdf", base::CompareCase::INSENSITIVE_ASCII) || |
| 44 | base::EndsWith(type, ".pdf", base::CompareCase::INSENSITIVE_ASCII) || |
| 45 | base::EndsWith(type, "/x-pdf", base::CompareCase::INSENSITIVE_ASCII) || |
| 46 | base::EndsWith(type, "/*", base::CompareCase::INSENSITIVE_ASCII) || |
| 47 | base::EndsWith(type, "/octet-stream", |
| 48 | base::CompareCase::INSENSITIVE_ASCII) || |
| 49 | base::EndsWith(type, "/acrobat", base::CompareCase::INSENSITIVE_ASCII) || |
| 50 | base::EndsWith(type, "/unknown", base::CompareCase::INSENSITIVE_ASCII)); |
thestig | 1d7b16f9 | 2017-05-30 20:25:34 | [diff] [blame] | 51 | } |
| 52 | |
thestig | 945cd0cb | 2015-05-28 01:58:05 | [diff] [blame] | 53 | } // namespace |
| 54 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 55 | DocumentLoaderImpl::Chunk::Chunk() = default; |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 56 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 57 | DocumentLoaderImpl::Chunk::~Chunk() = default; |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 58 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 59 | void DocumentLoaderImpl::Chunk::Clear() { |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 60 | chunk_index = 0; |
| 61 | data_size = 0; |
| 62 | chunk_data.reset(); |
dsinclair | 07a72bd | 2017-08-14 23:27:04 | [diff] [blame] | 63 | } |
Artem Strygin | 9a6d148 | 2017-07-26 21:08:56 | [diff] [blame] | 64 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 65 | DocumentLoaderImpl::DocumentLoaderImpl(Client* client) |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 66 | : client_(client), loader_factory_(this) {} |
| 67 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 68 | DocumentLoaderImpl::~DocumentLoaderImpl() = default; |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 69 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 70 | bool DocumentLoaderImpl::Init(std::unique_ptr<URLLoaderWrapper> loader, |
| 71 | const std::string& url) { |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 72 | DCHECK(url_.empty()); |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 73 | DCHECK(!loader_); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 74 | |
raymes | a8563ff | 2016-11-15 23:50:01 | [diff] [blame] | 75 | // Check that the initial response status is a valid one. |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 76 | if (!ResponseStatusSuccess(loader.get())) |
raymes | a8563ff | 2016-11-15 23:50:01 | [diff] [blame] | 77 | return false; |
| 78 | |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 79 | std::string type = loader->GetContentType(); |
thestig | 488102f | 2015-05-29 03:25:26 | [diff] [blame] | 80 | |
| 81 | // This happens for PDFs not loaded from http(s) sources. |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 82 | if (type == "text/plain") { |
brettw | 9550931 | 2015-07-16 23:57:33 | [diff] [blame] | 83 | if (!base::StartsWith(url, "http://", |
| 84 | base::CompareCase::INSENSITIVE_ASCII) && |
| 85 | !base::StartsWith(url, "https://", |
| 86 | base::CompareCase::INSENSITIVE_ASCII)) { |
thestig | 488102f | 2015-05-29 03:25:26 | [diff] [blame] | 87 | type = "application/pdf"; |
| 88 | } |
| 89 | } |
thestig | 488102f | 2015-05-29 03:25:26 | [diff] [blame] | 90 | if (!type.empty() && !IsValidContentType(type)) |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 91 | return false; |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 92 | |
| 93 | if (base::StartsWith(loader->GetContentDisposition(), "attachment", |
brettw | 9550931 | 2015-07-16 23:57:33 | [diff] [blame] | 94 | base::CompareCase::INSENSITIVE_ASCII)) |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 95 | return false; |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 96 | |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 97 | url_ = url; |
| 98 | loader_ = std::move(loader); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 99 | |
Lei Zhang | 6fbfb09 | 2018-03-28 16:58:56 | [diff] [blame] | 100 | if (!loader_->IsContentEncoded()) |
K. Moon | 6f6c6e4 | 2020-03-19 04:21:53 | [diff] [blame^] | 101 | chunk_stream_.set_eof_pos(std::max(0, loader_->GetContentLength())); |
Lei Zhang | 6fbfb09 | 2018-03-28 16:58:56 | [diff] [blame] | 102 | |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 103 | int64_t bytes_received = 0; |
| 104 | int64_t total_bytes_to_be_received = 0; |
Lei Zhang | 6fbfb09 | 2018-03-28 16:58:56 | [diff] [blame] | 105 | if (GetDocumentSize() == 0 && |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 106 | loader_->GetDownloadProgress(&bytes_received, |
| 107 | &total_bytes_to_be_received)) { |
K. Moon | 6f6c6e4 | 2020-03-19 04:21:53 | [diff] [blame^] | 108 | chunk_stream_.set_eof_pos( |
| 109 | std::max(0, static_cast<int>(total_bytes_to_be_received))); |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 110 | } |
| 111 | |
| 112 | SetPartialLoadingEnabled( |
| 113 | partial_loading_enabled_ && |
| 114 | !base::StartsWith(url, "file://", base::CompareCase::INSENSITIVE_ASCII) && |
| 115 | loader_->IsAcceptRangesBytes() && !loader_->IsContentEncoded() && |
| 116 | GetDocumentSize()); |
| 117 | |
| 118 | ReadMore(); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 119 | return true; |
| 120 | } |
| 121 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 122 | bool DocumentLoaderImpl::IsDocumentComplete() const { |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 123 | return chunk_stream_.IsComplete(); |
dsinclair | 07a72bd | 2017-08-14 23:27:04 | [diff] [blame] | 124 | } |
| 125 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 126 | uint32_t DocumentLoaderImpl::GetDocumentSize() const { |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 127 | return chunk_stream_.eof_pos(); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 128 | } |
| 129 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 130 | uint32_t DocumentLoaderImpl::BytesReceived() const { |
| 131 | return bytes_received_; |
| 132 | } |
| 133 | |
| 134 | void DocumentLoaderImpl::ClearPendingRequests() { |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 135 | pending_requests_.Clear(); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 136 | } |
| 137 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 138 | bool DocumentLoaderImpl::GetBlock(uint32_t position, |
| 139 | uint32_t size, |
| 140 | void* buf) const { |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 141 | base::CheckedNumeric<uint32_t> addition_result = position; |
| 142 | addition_result += size; |
| 143 | if (!addition_result.IsValid()) |
| 144 | return false; |
| 145 | return chunk_stream_.ReadData( |
| 146 | gfx::Range(position, addition_result.ValueOrDie()), buf); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 147 | } |
| 148 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 149 | bool DocumentLoaderImpl::IsDataAvailable(uint32_t position, |
| 150 | uint32_t size) const { |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 151 | base::CheckedNumeric<uint32_t> addition_result = position; |
| 152 | addition_result += size; |
| 153 | if (!addition_result.IsValid()) |
| 154 | return false; |
| 155 | return chunk_stream_.IsRangeAvailable( |
| 156 | gfx::Range(position, addition_result.ValueOrDie())); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 157 | } |
| 158 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 159 | void DocumentLoaderImpl::RequestData(uint32_t position, uint32_t size) { |
Lei Zhang | 6fbfb09 | 2018-03-28 16:58:56 | [diff] [blame] | 160 | if (size == 0 || IsDataAvailable(position, size)) |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 161 | return; |
Lei Zhang | 6fbfb09 | 2018-03-28 16:58:56 | [diff] [blame] | 162 | |
| 163 | const uint32_t document_size = GetDocumentSize(); |
| 164 | if (document_size != 0) { |
| 165 | // Check for integer overflow. |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 166 | base::CheckedNumeric<uint32_t> addition_result = position; |
| 167 | addition_result += size; |
| 168 | if (!addition_result.IsValid()) |
| 169 | return; |
Lei Zhang | 6fbfb09 | 2018-03-28 16:58:56 | [diff] [blame] | 170 | |
| 171 | if (addition_result.ValueOrDie() > document_size) |
| 172 | return; |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 173 | } |
| 174 | |
Lei Zhang | 6fbfb09 | 2018-03-28 16:58:56 | [diff] [blame] | 175 | // We have some artifact request from |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 176 | // PDFiumEngine::OnDocumentComplete() -> FPDFAvail_IsPageAvail after |
| 177 | // document is complete. |
| 178 | // We need this fix in PDFIum. Adding this as a work around. |
| 179 | // Bug: http://code.google.com/p/chromium/issues/detail?id=79996 |
| 180 | // Test url: |
| 181 | // http://www.icann.org/en/correspondence/holtzman-to-jeffrey-02mar11-en.pdf |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 182 | if (!loader_) |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 183 | return; |
| 184 | |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 185 | RangeSet requested_chunks(chunk_stream_.GetChunksRange(position, size)); |
| 186 | requested_chunks.Subtract(chunk_stream_.filled_chunks()); |
| 187 | if (requested_chunks.IsEmpty()) { |
| 188 | NOTREACHED(); |
| 189 | return; |
| 190 | } |
| 191 | pending_requests_.Union(requested_chunks); |
dsinclair | 07a72bd | 2017-08-14 23:27:04 | [diff] [blame] | 192 | } |
| 193 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 194 | void DocumentLoaderImpl::SetPartialLoadingEnabled(bool enabled) { |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 195 | partial_loading_enabled_ = enabled; |
| 196 | if (!enabled) { |
| 197 | is_partial_loader_active_ = false; |
dsinclair | 07a72bd | 2017-08-14 23:27:04 | [diff] [blame] | 198 | } |
| 199 | } |
| 200 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 201 | bool DocumentLoaderImpl::ShouldCancelLoading() const { |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 202 | if (!loader_) |
| 203 | return true; |
Artem Strygin | 2cf20af4 | 2018-06-14 14:26:53 | [diff] [blame] | 204 | |
| 205 | if (!partial_loading_enabled_) |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 206 | return false; |
Artem Strygin | 2cf20af4 | 2018-06-14 14:26:53 | [diff] [blame] | 207 | |
| 208 | if (pending_requests_.IsEmpty()) { |
| 209 | // Cancel loading if this is unepected data from server. |
| 210 | return !chunk_stream_.IsValidChunkIndex(chunk_.chunk_index) || |
| 211 | chunk_stream_.IsChunkAvailable(chunk_.chunk_index); |
| 212 | } |
| 213 | |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 214 | const gfx::Range current_range(chunk_.chunk_index, |
| 215 | chunk_.chunk_index + kChunkCloseDistance); |
| 216 | return !pending_requests_.Intersects(current_range); |
| 217 | } |
art-snake | 3704ccf0 | 2016-11-03 02:13:20 | [diff] [blame] | 218 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 219 | void DocumentLoaderImpl::ContinueDownload() { |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 220 | if (!ShouldCancelLoading()) |
| 221 | return ReadMore(); |
Lei Zhang | 6fbfb09 | 2018-03-28 16:58:56 | [diff] [blame] | 222 | |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 223 | DCHECK(partial_loading_enabled_); |
| 224 | DCHECK(!IsDocumentComplete()); |
Lei Zhang | 6fbfb09 | 2018-03-28 16:58:56 | [diff] [blame] | 225 | DCHECK_GT(GetDocumentSize(), 0U); |
Artem Strygin | 9a6d148 | 2017-07-26 21:08:56 | [diff] [blame] | 226 | |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 227 | const uint32_t range_start = |
| 228 | pending_requests_.IsEmpty() ? 0 : pending_requests_.First().start(); |
| 229 | RangeSet candidates_for_request( |
| 230 | gfx::Range(range_start, chunk_stream_.total_chunks_count())); |
| 231 | candidates_for_request.Subtract(chunk_stream_.filled_chunks()); |
| 232 | DCHECK(!candidates_for_request.IsEmpty()); |
| 233 | gfx::Range next_request = candidates_for_request.First(); |
| 234 | if (candidates_for_request.Size() == 1 && |
| 235 | next_request.length() < kChunkCloseDistance) { |
| 236 | // We have only request at the end, try to enlarge it to improve back order |
| 237 | // reading. |
| 238 | const int additional_chunks_count = |
| 239 | kChunkCloseDistance - next_request.length(); |
| 240 | int new_start = std::max( |
| 241 | 0, static_cast<int>(next_request.start()) - additional_chunks_count); |
| 242 | candidates_for_request = |
| 243 | RangeSet(gfx::Range(new_start, next_request.end())); |
| 244 | candidates_for_request.Subtract(chunk_stream_.filled_chunks()); |
| 245 | next_request = candidates_for_request.Last(); |
dsinclair | adf55f3f | 2016-12-07 14:00:41 | [diff] [blame] | 246 | } |
gene | 7cafb2ce6 | 2014-10-24 00:56:53 | [diff] [blame] | 247 | |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 248 | loader_.reset(); |
| 249 | chunk_.Clear(); |
Robbie McElrath | 44e2d30 | 2019-07-15 23:28:55 | [diff] [blame] | 250 | is_partial_loader_active_ = true; |
dsinclair | adf55f3f | 2016-12-07 14:00:41 | [diff] [blame] | 251 | |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 252 | const uint32_t start = next_request.start() * DataStream::kChunkSize; |
| 253 | const uint32_t length = |
Lei Zhang | 6fbfb09 | 2018-03-28 16:58:56 | [diff] [blame] | 254 | std::min(GetDocumentSize() - start, |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 255 | next_request.length() * DataStream::kChunkSize); |
dsinclair | adf55f3f | 2016-12-07 14:00:41 | [diff] [blame] | 256 | |
Artem Strygin | 9a6d148 | 2017-07-26 21:08:56 | [diff] [blame] | 257 | loader_ = client_->CreateURLLoader(); |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 258 | |
| 259 | loader_->OpenRange( |
| 260 | url_, url_, start, length, |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 261 | loader_factory_.NewCallback(&DocumentLoaderImpl::DidOpenPartial)); |
Artem Strygin | 9a6d148 | 2017-07-26 21:08:56 | [diff] [blame] | 262 | } |
| 263 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 264 | void DocumentLoaderImpl::DidOpenPartial(int32_t result) { |
Artem Strygin | 9a6d148 | 2017-07-26 21:08:56 | [diff] [blame] | 265 | if (result != PP_OK) { |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 266 | return ReadComplete(); |
Artem Strygin | 9a6d148 | 2017-07-26 21:08:56 | [diff] [blame] | 267 | } |
| 268 | |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 269 | if (!ResponseStatusSuccess(loader_.get())) |
| 270 | return ReadComplete(); |
Artem Strygin | 9a6d148 | 2017-07-26 21:08:56 | [diff] [blame] | 271 | |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 272 | // Leave position untouched for multiparted responce for now, when we read the |
| 273 | // data we'll get it. |
Lei Zhang | 02a3a0f | 2017-12-11 20:25:48 | [diff] [blame] | 274 | if (loader_->IsMultipart()) { |
| 275 | // Needs more data to calc chunk index. |
| 276 | return ReadMore(); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 277 | } |
Lei Zhang | 02a3a0f | 2017-12-11 20:25:48 | [diff] [blame] | 278 | |
| 279 | // Need to make sure that the server returned a byte-range, since it's |
| 280 | // possible for a server to just ignore our byte-range request and just |
| 281 | // return the entire document even if it supports byte-range requests. |
| 282 | // i.e. sniff response to |
| 283 | // http://www.act.org/compass/sample/pdf/geometry.pdf |
| 284 | int start_pos = 0; |
| 285 | if (loader_->GetByteRangeStart(&start_pos)) { |
| 286 | if (start_pos % DataStream::kChunkSize != 0) |
| 287 | return ReadComplete(); |
| 288 | |
| 289 | DCHECK(!chunk_.chunk_data); |
| 290 | chunk_.chunk_index = chunk_stream_.GetChunkIndex(start_pos); |
| 291 | } else { |
| 292 | SetPartialLoadingEnabled(false); |
| 293 | } |
| 294 | return ContinueDownload(); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 295 | } |
| 296 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 297 | void DocumentLoaderImpl::ReadMore() { |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 298 | loader_->ReadResponseBody( |
| 299 | buffer_, sizeof(buffer_), |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 300 | loader_factory_.NewCallback(&DocumentLoaderImpl::DidRead)); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 301 | } |
| 302 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 303 | void DocumentLoaderImpl::DidRead(int32_t result) { |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 304 | if (result < 0) { |
| 305 | // An error occurred. |
| 306 | // The renderer will detect that we're missing data and will display a |
| 307 | // message. |
| 308 | return ReadComplete(); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 309 | } |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 310 | if (result == 0) { |
| 311 | loader_.reset(); |
| 312 | if (!is_partial_loader_active_) |
| 313 | return ReadComplete(); |
| 314 | return ContinueDownload(); |
| 315 | } |
| 316 | if (loader_->IsMultipart()) { |
| 317 | int start_pos = 0; |
Lei Zhang | 02a3a0f | 2017-12-11 20:25:48 | [diff] [blame] | 318 | if (!loader_->GetByteRangeStart(&start_pos)) |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 319 | return ReadComplete(); |
Lei Zhang | 02a3a0f | 2017-12-11 20:25:48 | [diff] [blame] | 320 | |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 321 | DCHECK(!chunk_.chunk_data); |
| 322 | chunk_.chunk_index = chunk_stream_.GetChunkIndex(start_pos); |
spelchat | 5efbaf82 | 2016-05-24 23:29:56 | [diff] [blame] | 323 | } |
Lei Zhang | 32094aac | 2018-03-28 18:29:15 | [diff] [blame] | 324 | if (!SaveBuffer(buffer_, result)) |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 325 | return ReadMore(); |
Lei Zhang | 02a3a0f | 2017-12-11 20:25:48 | [diff] [blame] | 326 | if (IsDocumentComplete()) |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 327 | return ReadComplete(); |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 328 | return ContinueDownload(); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 329 | } |
| 330 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 331 | bool DocumentLoaderImpl::SaveBuffer(char* input, uint32_t input_size) { |
Lei Zhang | 32094aac | 2018-03-28 18:29:15 | [diff] [blame] | 332 | const uint32_t document_size = GetDocumentSize(); |
Lei Zhang | 6fbfb09 | 2018-03-28 16:58:56 | [diff] [blame] | 333 | bytes_received_ += input_size; |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 334 | bool chunk_saved = false; |
| 335 | bool loading_pending_request = pending_requests_.Contains(chunk_.chunk_index); |
| 336 | while (input_size > 0) { |
Lei Zhang | 6fbfb09 | 2018-03-28 16:58:56 | [diff] [blame] | 337 | if (chunk_.data_size == 0) |
Lei Zhang | 64aa552c | 2017-10-17 18:35:53 | [diff] [blame] | 338 | chunk_.chunk_data = std::make_unique<DataStream::ChunkData>(); |
Lei Zhang | 6fbfb09 | 2018-03-28 16:58:56 | [diff] [blame] | 339 | |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 340 | const uint32_t new_chunk_data_len = |
| 341 | std::min(DataStream::kChunkSize - chunk_.data_size, input_size); |
| 342 | memcpy(chunk_.chunk_data->data() + chunk_.data_size, input, |
| 343 | new_chunk_data_len); |
| 344 | chunk_.data_size += new_chunk_data_len; |
| 345 | if (chunk_.data_size == DataStream::kChunkSize || |
Artem Strygin | 2cf20af4 | 2018-06-14 14:26:53 | [diff] [blame] | 346 | (document_size > 0 && document_size <= EndOfCurrentChunk())) { |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 347 | pending_requests_.Subtract( |
| 348 | gfx::Range(chunk_.chunk_index, chunk_.chunk_index + 1)); |
Lei Zhang | 32094aac | 2018-03-28 18:29:15 | [diff] [blame] | 349 | SaveChunkData(); |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 350 | chunk_saved = true; |
| 351 | } |
| 352 | |
| 353 | input += new_chunk_data_len; |
| 354 | input_size -= new_chunk_data_len; |
| 355 | } |
| 356 | |
| 357 | client_->OnNewDataReceived(); |
| 358 | |
| 359 | if (IsDocumentComplete()) |
| 360 | return true; |
| 361 | |
| 362 | if (!chunk_saved) |
| 363 | return false; |
| 364 | |
| 365 | if (loading_pending_request && |
| 366 | !pending_requests_.Contains(chunk_.chunk_index)) { |
| 367 | client_->OnPendingRequestComplete(); |
| 368 | } |
| 369 | return true; |
spelchat | 3ba2a281 | 2015-12-10 00:44:15 | [diff] [blame] | 370 | } |
| 371 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 372 | void DocumentLoaderImpl::SaveChunkData() { |
Lei Zhang | 32094aac | 2018-03-28 18:29:15 | [diff] [blame] | 373 | chunk_stream_.SetChunkData(chunk_.chunk_index, std::move(chunk_.chunk_data)); |
| 374 | chunk_.data_size = 0; |
| 375 | ++chunk_.chunk_index; |
| 376 | } |
| 377 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 378 | uint32_t DocumentLoaderImpl::EndOfCurrentChunk() const { |
Lei Zhang | 6fbfb09 | 2018-03-28 16:58:56 | [diff] [blame] | 379 | return chunk_.chunk_index * DataStream::kChunkSize + chunk_.data_size; |
| 380 | } |
| 381 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 382 | void DocumentLoaderImpl::ReadComplete() { |
Lei Zhang | 32094aac | 2018-03-28 18:29:15 | [diff] [blame] | 383 | if (GetDocumentSize() != 0) { |
| 384 | // If there is remaining data in |chunk_|, then save whatever can be saved. |
| 385 | // e.g. In the underrun case. |
| 386 | if (chunk_.data_size != 0) |
| 387 | SaveChunkData(); |
| 388 | } else { |
Lei Zhang | 6fbfb09 | 2018-03-28 16:58:56 | [diff] [blame] | 389 | uint32_t eof = EndOfCurrentChunk(); |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 390 | if (!chunk_stream_.filled_chunks().IsEmpty()) { |
| 391 | eof = std::max( |
| 392 | chunk_stream_.filled_chunks().Last().end() * DataStream::kChunkSize, |
| 393 | eof); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 394 | } |
K. Moon | 6f6c6e4 | 2020-03-19 04:21:53 | [diff] [blame^] | 395 | chunk_stream_.set_eof_pos(eof); |
Lei Zhang | 32094aac | 2018-03-28 18:29:15 | [diff] [blame] | 396 | if (eof == EndOfCurrentChunk()) |
| 397 | SaveChunkData(); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 398 | } |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 399 | loader_.reset(); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 400 | if (IsDocumentComplete()) { |
| 401 | client_->OnDocumentComplete(); |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 402 | } else { |
| 403 | client_->OnDocumentCanceled(); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 404 | } |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 405 | } |
| 406 | |
| 407 | } // namespace chrome_pdf |