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