[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()) |
| 101 | SetDocumentSize(std::max(0, loader_->GetContentLength())); |
| 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)) { |
Lei Zhang | 6fbfb09 | 2018-03-28 16:58:56 | [diff] [blame] | 108 | SetDocumentSize(std::max(0, static_cast<int>(total_bytes_to_be_received))); |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 109 | } |
| 110 | |
| 111 | SetPartialLoadingEnabled( |
| 112 | partial_loading_enabled_ && |
| 113 | !base::StartsWith(url, "file://", base::CompareCase::INSENSITIVE_ASCII) && |
| 114 | loader_->IsAcceptRangesBytes() && !loader_->IsContentEncoded() && |
| 115 | GetDocumentSize()); |
| 116 | |
| 117 | ReadMore(); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 118 | return true; |
| 119 | } |
| 120 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 121 | bool DocumentLoaderImpl::IsDocumentComplete() const { |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 122 | return chunk_stream_.IsComplete(); |
dsinclair | 07a72bd | 2017-08-14 23:27:04 | [diff] [blame] | 123 | } |
| 124 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 125 | void DocumentLoaderImpl::SetDocumentSize(uint32_t size) { |
Lei Zhang | 6fbfb09 | 2018-03-28 16:58:56 | [diff] [blame] | 126 | chunk_stream_.set_eof_pos(size); |
| 127 | } |
| 128 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 129 | uint32_t DocumentLoaderImpl::GetDocumentSize() const { |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 130 | return chunk_stream_.eof_pos(); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 131 | } |
| 132 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 133 | uint32_t DocumentLoaderImpl::BytesReceived() const { |
| 134 | return bytes_received_; |
| 135 | } |
| 136 | |
| 137 | void DocumentLoaderImpl::ClearPendingRequests() { |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 138 | pending_requests_.Clear(); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 139 | } |
| 140 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 141 | bool DocumentLoaderImpl::GetBlock(uint32_t position, |
| 142 | uint32_t size, |
| 143 | void* buf) const { |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 144 | base::CheckedNumeric<uint32_t> addition_result = position; |
| 145 | addition_result += size; |
| 146 | if (!addition_result.IsValid()) |
| 147 | return false; |
| 148 | return chunk_stream_.ReadData( |
| 149 | gfx::Range(position, addition_result.ValueOrDie()), buf); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 150 | } |
| 151 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 152 | bool DocumentLoaderImpl::IsDataAvailable(uint32_t position, |
| 153 | uint32_t size) const { |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 154 | base::CheckedNumeric<uint32_t> addition_result = position; |
| 155 | addition_result += size; |
| 156 | if (!addition_result.IsValid()) |
| 157 | return false; |
| 158 | return chunk_stream_.IsRangeAvailable( |
| 159 | gfx::Range(position, addition_result.ValueOrDie())); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 160 | } |
| 161 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 162 | void DocumentLoaderImpl::RequestData(uint32_t position, uint32_t size) { |
Lei Zhang | 6fbfb09 | 2018-03-28 16:58:56 | [diff] [blame] | 163 | if (size == 0 || IsDataAvailable(position, size)) |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 164 | return; |
Lei Zhang | 6fbfb09 | 2018-03-28 16:58:56 | [diff] [blame] | 165 | |
| 166 | const uint32_t document_size = GetDocumentSize(); |
| 167 | if (document_size != 0) { |
| 168 | // Check for integer overflow. |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 169 | base::CheckedNumeric<uint32_t> addition_result = position; |
| 170 | addition_result += size; |
| 171 | if (!addition_result.IsValid()) |
| 172 | return; |
Lei Zhang | 6fbfb09 | 2018-03-28 16:58:56 | [diff] [blame] | 173 | |
| 174 | if (addition_result.ValueOrDie() > document_size) |
| 175 | return; |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 176 | } |
| 177 | |
Lei Zhang | 6fbfb09 | 2018-03-28 16:58:56 | [diff] [blame] | 178 | // We have some artifact request from |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 179 | // PDFiumEngine::OnDocumentComplete() -> FPDFAvail_IsPageAvail after |
| 180 | // document is complete. |
| 181 | // We need this fix in PDFIum. Adding this as a work around. |
| 182 | // Bug: http://code.google.com/p/chromium/issues/detail?id=79996 |
| 183 | // Test url: |
| 184 | // http://www.icann.org/en/correspondence/holtzman-to-jeffrey-02mar11-en.pdf |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 185 | if (!loader_) |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 186 | return; |
| 187 | |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 188 | RangeSet requested_chunks(chunk_stream_.GetChunksRange(position, size)); |
| 189 | requested_chunks.Subtract(chunk_stream_.filled_chunks()); |
| 190 | if (requested_chunks.IsEmpty()) { |
| 191 | NOTREACHED(); |
| 192 | return; |
| 193 | } |
| 194 | pending_requests_.Union(requested_chunks); |
dsinclair | 07a72bd | 2017-08-14 23:27:04 | [diff] [blame] | 195 | } |
| 196 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 197 | void DocumentLoaderImpl::SetPartialLoadingEnabled(bool enabled) { |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 198 | partial_loading_enabled_ = enabled; |
| 199 | if (!enabled) { |
| 200 | is_partial_loader_active_ = false; |
dsinclair | 07a72bd | 2017-08-14 23:27:04 | [diff] [blame] | 201 | } |
| 202 | } |
| 203 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 204 | bool DocumentLoaderImpl::ShouldCancelLoading() const { |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 205 | if (!loader_) |
| 206 | return true; |
Artem Strygin | 2cf20af4 | 2018-06-14 14:26:53 | [diff] [blame] | 207 | |
| 208 | if (!partial_loading_enabled_) |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 209 | return false; |
Artem Strygin | 2cf20af4 | 2018-06-14 14:26:53 | [diff] [blame] | 210 | |
| 211 | if (pending_requests_.IsEmpty()) { |
| 212 | // Cancel loading if this is unepected data from server. |
| 213 | return !chunk_stream_.IsValidChunkIndex(chunk_.chunk_index) || |
| 214 | chunk_stream_.IsChunkAvailable(chunk_.chunk_index); |
| 215 | } |
| 216 | |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 217 | const gfx::Range current_range(chunk_.chunk_index, |
| 218 | chunk_.chunk_index + kChunkCloseDistance); |
| 219 | return !pending_requests_.Intersects(current_range); |
| 220 | } |
art-snake | 3704ccf0 | 2016-11-03 02:13:20 | [diff] [blame] | 221 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 222 | void DocumentLoaderImpl::ContinueDownload() { |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 223 | if (!ShouldCancelLoading()) |
| 224 | return ReadMore(); |
Lei Zhang | 6fbfb09 | 2018-03-28 16:58:56 | [diff] [blame] | 225 | |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 226 | DCHECK(partial_loading_enabled_); |
| 227 | DCHECK(!IsDocumentComplete()); |
Lei Zhang | 6fbfb09 | 2018-03-28 16:58:56 | [diff] [blame] | 228 | DCHECK_GT(GetDocumentSize(), 0U); |
Artem Strygin | 9a6d148 | 2017-07-26 21:08:56 | [diff] [blame] | 229 | |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 230 | const uint32_t range_start = |
| 231 | pending_requests_.IsEmpty() ? 0 : pending_requests_.First().start(); |
| 232 | RangeSet candidates_for_request( |
| 233 | gfx::Range(range_start, chunk_stream_.total_chunks_count())); |
| 234 | candidates_for_request.Subtract(chunk_stream_.filled_chunks()); |
| 235 | DCHECK(!candidates_for_request.IsEmpty()); |
| 236 | gfx::Range next_request = candidates_for_request.First(); |
| 237 | if (candidates_for_request.Size() == 1 && |
| 238 | next_request.length() < kChunkCloseDistance) { |
| 239 | // We have only request at the end, try to enlarge it to improve back order |
| 240 | // reading. |
| 241 | const int additional_chunks_count = |
| 242 | kChunkCloseDistance - next_request.length(); |
| 243 | int new_start = std::max( |
| 244 | 0, static_cast<int>(next_request.start()) - additional_chunks_count); |
| 245 | candidates_for_request = |
| 246 | RangeSet(gfx::Range(new_start, next_request.end())); |
| 247 | candidates_for_request.Subtract(chunk_stream_.filled_chunks()); |
| 248 | next_request = candidates_for_request.Last(); |
dsinclair | adf55f3f | 2016-12-07 14:00:41 | [diff] [blame] | 249 | } |
gene | 7cafb2ce6 | 2014-10-24 00:56:53 | [diff] [blame] | 250 | |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 251 | loader_.reset(); |
| 252 | chunk_.Clear(); |
Robbie McElrath | 44e2d30 | 2019-07-15 23:28:55 | [diff] [blame^] | 253 | is_partial_loader_active_ = true; |
dsinclair | adf55f3f | 2016-12-07 14:00:41 | [diff] [blame] | 254 | |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 255 | const uint32_t start = next_request.start() * DataStream::kChunkSize; |
| 256 | const uint32_t length = |
Lei Zhang | 6fbfb09 | 2018-03-28 16:58:56 | [diff] [blame] | 257 | std::min(GetDocumentSize() - start, |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 258 | next_request.length() * DataStream::kChunkSize); |
dsinclair | adf55f3f | 2016-12-07 14:00:41 | [diff] [blame] | 259 | |
Artem Strygin | 9a6d148 | 2017-07-26 21:08:56 | [diff] [blame] | 260 | loader_ = client_->CreateURLLoader(); |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 261 | |
| 262 | loader_->OpenRange( |
| 263 | url_, url_, start, length, |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 264 | loader_factory_.NewCallback(&DocumentLoaderImpl::DidOpenPartial)); |
Artem Strygin | 9a6d148 | 2017-07-26 21:08:56 | [diff] [blame] | 265 | } |
| 266 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 267 | void DocumentLoaderImpl::DidOpenPartial(int32_t result) { |
Artem Strygin | 9a6d148 | 2017-07-26 21:08:56 | [diff] [blame] | 268 | if (result != PP_OK) { |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 269 | return ReadComplete(); |
Artem Strygin | 9a6d148 | 2017-07-26 21:08:56 | [diff] [blame] | 270 | } |
| 271 | |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 272 | if (!ResponseStatusSuccess(loader_.get())) |
| 273 | return ReadComplete(); |
Artem Strygin | 9a6d148 | 2017-07-26 21:08:56 | [diff] [blame] | 274 | |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 275 | // Leave position untouched for multiparted responce for now, when we read the |
| 276 | // data we'll get it. |
Lei Zhang | 02a3a0f | 2017-12-11 20:25:48 | [diff] [blame] | 277 | if (loader_->IsMultipart()) { |
| 278 | // Needs more data to calc chunk index. |
| 279 | return ReadMore(); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 280 | } |
Lei Zhang | 02a3a0f | 2017-12-11 20:25:48 | [diff] [blame] | 281 | |
| 282 | // Need to make sure that the server returned a byte-range, since it's |
| 283 | // possible for a server to just ignore our byte-range request and just |
| 284 | // return the entire document even if it supports byte-range requests. |
| 285 | // i.e. sniff response to |
| 286 | // http://www.act.org/compass/sample/pdf/geometry.pdf |
| 287 | int start_pos = 0; |
| 288 | if (loader_->GetByteRangeStart(&start_pos)) { |
| 289 | if (start_pos % DataStream::kChunkSize != 0) |
| 290 | return ReadComplete(); |
| 291 | |
| 292 | DCHECK(!chunk_.chunk_data); |
| 293 | chunk_.chunk_index = chunk_stream_.GetChunkIndex(start_pos); |
| 294 | } else { |
| 295 | SetPartialLoadingEnabled(false); |
| 296 | } |
| 297 | return ContinueDownload(); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 298 | } |
| 299 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 300 | void DocumentLoaderImpl::ReadMore() { |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 301 | loader_->ReadResponseBody( |
| 302 | buffer_, sizeof(buffer_), |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 303 | loader_factory_.NewCallback(&DocumentLoaderImpl::DidRead)); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 304 | } |
| 305 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 306 | void DocumentLoaderImpl::DidRead(int32_t result) { |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 307 | if (result < 0) { |
| 308 | // An error occurred. |
| 309 | // The renderer will detect that we're missing data and will display a |
| 310 | // message. |
| 311 | return ReadComplete(); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 312 | } |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 313 | if (result == 0) { |
| 314 | loader_.reset(); |
| 315 | if (!is_partial_loader_active_) |
| 316 | return ReadComplete(); |
| 317 | return ContinueDownload(); |
| 318 | } |
| 319 | if (loader_->IsMultipart()) { |
| 320 | int start_pos = 0; |
Lei Zhang | 02a3a0f | 2017-12-11 20:25:48 | [diff] [blame] | 321 | if (!loader_->GetByteRangeStart(&start_pos)) |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 322 | return ReadComplete(); |
Lei Zhang | 02a3a0f | 2017-12-11 20:25:48 | [diff] [blame] | 323 | |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 324 | DCHECK(!chunk_.chunk_data); |
| 325 | chunk_.chunk_index = chunk_stream_.GetChunkIndex(start_pos); |
spelchat | 5efbaf82 | 2016-05-24 23:29:56 | [diff] [blame] | 326 | } |
Lei Zhang | 32094aac | 2018-03-28 18:29:15 | [diff] [blame] | 327 | if (!SaveBuffer(buffer_, result)) |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 328 | return ReadMore(); |
Lei Zhang | 02a3a0f | 2017-12-11 20:25:48 | [diff] [blame] | 329 | if (IsDocumentComplete()) |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 330 | return ReadComplete(); |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 331 | return ContinueDownload(); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 332 | } |
| 333 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 334 | bool DocumentLoaderImpl::SaveBuffer(char* input, uint32_t input_size) { |
Lei Zhang | 32094aac | 2018-03-28 18:29:15 | [diff] [blame] | 335 | const uint32_t document_size = GetDocumentSize(); |
Lei Zhang | 6fbfb09 | 2018-03-28 16:58:56 | [diff] [blame] | 336 | bytes_received_ += input_size; |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 337 | bool chunk_saved = false; |
| 338 | bool loading_pending_request = pending_requests_.Contains(chunk_.chunk_index); |
| 339 | while (input_size > 0) { |
Lei Zhang | 6fbfb09 | 2018-03-28 16:58:56 | [diff] [blame] | 340 | if (chunk_.data_size == 0) |
Lei Zhang | 64aa552c | 2017-10-17 18:35:53 | [diff] [blame] | 341 | chunk_.chunk_data = std::make_unique<DataStream::ChunkData>(); |
Lei Zhang | 6fbfb09 | 2018-03-28 16:58:56 | [diff] [blame] | 342 | |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 343 | const uint32_t new_chunk_data_len = |
| 344 | std::min(DataStream::kChunkSize - chunk_.data_size, input_size); |
| 345 | memcpy(chunk_.chunk_data->data() + chunk_.data_size, input, |
| 346 | new_chunk_data_len); |
| 347 | chunk_.data_size += new_chunk_data_len; |
| 348 | if (chunk_.data_size == DataStream::kChunkSize || |
Artem Strygin | 2cf20af4 | 2018-06-14 14:26:53 | [diff] [blame] | 349 | (document_size > 0 && document_size <= EndOfCurrentChunk())) { |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 350 | pending_requests_.Subtract( |
| 351 | gfx::Range(chunk_.chunk_index, chunk_.chunk_index + 1)); |
Lei Zhang | 32094aac | 2018-03-28 18:29:15 | [diff] [blame] | 352 | SaveChunkData(); |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 353 | chunk_saved = true; |
| 354 | } |
| 355 | |
| 356 | input += new_chunk_data_len; |
| 357 | input_size -= new_chunk_data_len; |
| 358 | } |
| 359 | |
| 360 | client_->OnNewDataReceived(); |
| 361 | |
| 362 | if (IsDocumentComplete()) |
| 363 | return true; |
| 364 | |
| 365 | if (!chunk_saved) |
| 366 | return false; |
| 367 | |
| 368 | if (loading_pending_request && |
| 369 | !pending_requests_.Contains(chunk_.chunk_index)) { |
| 370 | client_->OnPendingRequestComplete(); |
| 371 | } |
| 372 | return true; |
spelchat | 3ba2a281 | 2015-12-10 00:44:15 | [diff] [blame] | 373 | } |
| 374 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 375 | void DocumentLoaderImpl::SaveChunkData() { |
Lei Zhang | 32094aac | 2018-03-28 18:29:15 | [diff] [blame] | 376 | chunk_stream_.SetChunkData(chunk_.chunk_index, std::move(chunk_.chunk_data)); |
| 377 | chunk_.data_size = 0; |
| 378 | ++chunk_.chunk_index; |
| 379 | } |
| 380 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 381 | uint32_t DocumentLoaderImpl::EndOfCurrentChunk() const { |
Lei Zhang | 6fbfb09 | 2018-03-28 16:58:56 | [diff] [blame] | 382 | return chunk_.chunk_index * DataStream::kChunkSize + chunk_.data_size; |
| 383 | } |
| 384 | |
Lei Zhang | e98901a | 2018-04-25 23:23:59 | [diff] [blame] | 385 | void DocumentLoaderImpl::ReadComplete() { |
Lei Zhang | 32094aac | 2018-03-28 18:29:15 | [diff] [blame] | 386 | if (GetDocumentSize() != 0) { |
| 387 | // If there is remaining data in |chunk_|, then save whatever can be saved. |
| 388 | // e.g. In the underrun case. |
| 389 | if (chunk_.data_size != 0) |
| 390 | SaveChunkData(); |
| 391 | } else { |
Lei Zhang | 6fbfb09 | 2018-03-28 16:58:56 | [diff] [blame] | 392 | uint32_t eof = EndOfCurrentChunk(); |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 393 | if (!chunk_stream_.filled_chunks().IsEmpty()) { |
| 394 | eof = std::max( |
| 395 | chunk_stream_.filled_chunks().Last().end() * DataStream::kChunkSize, |
| 396 | eof); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 397 | } |
Lei Zhang | 6fbfb09 | 2018-03-28 16:58:56 | [diff] [blame] | 398 | SetDocumentSize(eof); |
Lei Zhang | 32094aac | 2018-03-28 18:29:15 | [diff] [blame] | 399 | if (eof == EndOfCurrentChunk()) |
| 400 | SaveChunkData(); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 401 | } |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 402 | loader_.reset(); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 403 | if (IsDocumentComplete()) { |
| 404 | client_->OnDocumentComplete(); |
Artem Strygin | af1b4342 | 2017-09-12 18:48:24 | [diff] [blame] | 405 | } else { |
| 406 | client_->OnDocumentCanceled(); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 407 | } |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 408 | } |
| 409 | |
| 410 | } // namespace chrome_pdf |