From eb1b563148e0bcdc3d5c73368c24a7dad383e903 Mon Sep 17 00:00:00 2001 From: thestig Date: Wed, 26 Oct 2016 12:22:28 -0700 Subject: [PATCH] Revert of Improve linearized pdf load/show time. (patchset #18 id:340001 of https://codereview.chromium.org/2349753003/ ) Reason for revert: https://build.chromium.org/p/chromium/builders/Win%20x64/builds/5423/steps/compile/logs/stdio FAILED: obj/pdf/pdf_unittests/document_loader_unittest.obj pdf\document_loader_unittest.cc(631): error C2131: expression did not evaluate to a constant pdf\document_loader_unittest.cc(631): note: failure was caused by call of undefined function or one not declared 'constexpr' pdf\document_loader_unittest.cc(631): note: see usage of 'chrome_pdf::DocumentLoader::default_request_size' Original issue's description: > Improve linearized pdf load/show time. > Reduce Pdf Plugin's count of reconnects. > Add tests for PDFPlugin DocumentLoader. > > DocumentLoader was splitted into separate components, and missing tests was added for them. > > The main ideas in this CL are: > > 1) Do not reset browser initiated connection at start (includes case when we can use range requests), if we request data near current downloading position. > 2) Request as much data as we can on each request, and continue loading data using current range request. (like tape rewind) > 3) Isolate RangeRequest logic into DocumentLoader. Method OnPendingRequestComplete is called, when we receive requested data (main connection, or Range connection). (like tape playing without rewing). > 4) Fill this logic by tests. > > Example URL: > http://www.major-landrover.ru/upload/attachments/f/9/f96aab07dab04ae89c8a509ec1ef2b31.pdf > Comparison of changes: > https://drive.google.com/file/d/0BzWfMBOuik2QNGg0SG93Y3lpUlE/view?usp=sharing > > Committed: https://crrev.com/7fd7423cdee0dba84faf480d10dd66dcb57110d9 > Cr-Commit-Position: refs/heads/master@{#427752} TBR=jochen@chromium.org,raymes@chromium.org,spelchat@chromium.org,rsesek@chromium.org,art-snake@yandex-team.ru # Skipping CQ checks because original CL landed less than 1 days ago. NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true Review-Url: https://codereview.chromium.org/2458493002 Cr-Commit-Position: refs/heads/master@{#427772} --- pdf/BUILD.gn | 30 +- pdf/DEPS | 1 - pdf/chunk_stream.cc | 175 +++++ pdf/chunk_stream.h | 103 +-- pdf/chunk_stream_unittest.cc | 99 --- pdf/document_loader.cc | 634 ++++++++++------- pdf/document_loader.h | 110 +-- pdf/document_loader_unittest.cc | 1184 ------------------------------- pdf/out_of_process_instance.cc | 15 +- pdf/out_of_process_instance.h | 1 - pdf/pdf_engine.h | 5 +- pdf/pdfium/pdfium_engine.cc | 158 ++--- pdf/pdfium/pdfium_engine.h | 17 +- pdf/preview_mode_client.cc | 2 - pdf/preview_mode_client.h | 1 - pdf/range_set.cc | 253 ------- pdf/range_set.h | 77 -- pdf/range_set_unittest.cc | 303 -------- pdf/run_all_unittests.cc | 24 - pdf/timer.cc | 31 - pdf/timer.h | 35 - pdf/url_loader_wrapper.h | 62 -- pdf/url_loader_wrapper_impl.cc | 318 --------- pdf/url_loader_wrapper_impl.h | 89 --- 24 files changed, 742 insertions(+), 2985 deletions(-) create mode 100644 pdf/chunk_stream.cc delete mode 100644 pdf/chunk_stream_unittest.cc delete mode 100644 pdf/document_loader_unittest.cc delete mode 100644 pdf/range_set.cc delete mode 100644 pdf/range_set.h delete mode 100644 pdf/range_set_unittest.cc delete mode 100644 pdf/run_all_unittests.cc delete mode 100644 pdf/timer.cc delete mode 100644 pdf/timer.h delete mode 100644 pdf/url_loader_wrapper.h delete mode 100644 pdf/url_loader_wrapper_impl.cc delete mode 100644 pdf/url_loader_wrapper_impl.h diff --git a/pdf/BUILD.gn b/pdf/BUILD.gn index c5556563ba2df0..f017ed2ff4468e 100644 --- a/pdf/BUILD.gn +++ b/pdf/BUILD.gn @@ -3,7 +3,6 @@ # found in the LICENSE file. import("//build/config/features.gni") -import("//testing/test.gni") import("//third_party/pdfium/pdfium.gni") assert(enable_pdf) @@ -18,10 +17,10 @@ static_library("pdf") { "//ppapi/cpp:objects", "//ppapi/cpp/private:internal_module", "//ui/base", - "//ui/gfx/range", ] sources = [ + "chunk_stream.cc", "chunk_stream.h", "document_loader.cc", "document_loader.h", @@ -38,13 +37,6 @@ static_library("pdf") { "pdf_engine.h", "preview_mode_client.cc", "preview_mode_client.h", - "range_set.cc", - "range_set.h", - "timer.cc", - "timer.h", - "url_loader_wrapper.h", - "url_loader_wrapper_impl.cc", - "url_loader_wrapper_impl.h", ] # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. @@ -78,23 +70,3 @@ static_library("pdf") { defines += [ "PDF_ENABLE_XFA" ] } } - -test("pdf_unittests") { - sources = [ - "chunk_stream_unittest.cc", - "document_loader_unittest.cc", - "range_set_unittest.cc", - "run_all_unittests.cc", - ] - - deps = [ - ":pdf", - "//base", - "//base/test:test_support", - "//ppapi/c", - "//ppapi/cpp", - "//testing/gmock", - "//testing/gtest", - "//ui/gfx/range", - ] -} diff --git a/pdf/DEPS b/pdf/DEPS index d0888055e0a83d..b7a8a170e88882 100644 --- a/pdf/DEPS +++ b/pdf/DEPS @@ -4,6 +4,5 @@ include_rules = [ "+ppapi", "+ui/base/window_open_disposition.h", "+ui/events/keycodes/keyboard_codes.h", - "+ui/gfx/range/range.h", "+v8/include/v8.h" ] diff --git a/pdf/chunk_stream.cc b/pdf/chunk_stream.cc new file mode 100644 index 00000000000000..adb3cb6edaf5c9 --- /dev/null +++ b/pdf/chunk_stream.cc @@ -0,0 +1,175 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "pdf/chunk_stream.h" + +#include +#include + +#define __STDC_LIMIT_MACROS +#ifdef _WIN32 +#include +#else +#include +#endif + +#include + +namespace chrome_pdf { + +ChunkStream::ChunkStream() : stream_size_(0) { +} + +ChunkStream::~ChunkStream() { +} + +void ChunkStream::Clear() { + chunks_.clear(); + data_.clear(); + stream_size_ = 0; +} + +void ChunkStream::Preallocate(size_t stream_size) { + data_.reserve(stream_size); + stream_size_ = stream_size; +} + +size_t ChunkStream::GetSize() const { + return data_.size(); +} + +bool ChunkStream::WriteData(size_t offset, void* buffer, size_t size) { + if (SIZE_MAX - size < offset) + return false; + + if (data_.size() < offset + size) + data_.resize(offset + size); + + memcpy(&data_[offset], buffer, size); + + if (chunks_.empty()) { + chunks_[offset] = size; + return true; + } + + std::map::iterator start = chunks_.upper_bound(offset); + if (start != chunks_.begin()) + --start; // start now points to the key equal or lower than offset. + if (start->first + start->second < offset) + ++start; // start element is entirely before current chunk, skip it. + + std::map::iterator end = chunks_.upper_bound(offset + size); + if (start == end) { // No chunks to merge. + chunks_[offset] = size; + return true; + } + + --end; + + size_t new_offset = std::min(start->first, offset); + size_t new_size = + std::max(end->first + end->second, offset + size) - new_offset; + + chunks_.erase(start, ++end); + + chunks_[new_offset] = new_size; + + return true; +} + +bool ChunkStream::ReadData(size_t offset, size_t size, void* buffer) const { + if (!IsRangeAvailable(offset, size)) + return false; + + memcpy(buffer, &data_[offset], size); + return true; +} + +bool ChunkStream::GetMissedRanges( + size_t offset, size_t size, + std::vector >* ranges) const { + if (IsRangeAvailable(offset, size)) + return false; + + ranges->clear(); + if (chunks_.empty()) { + ranges->push_back(std::pair(offset, size)); + return true; + } + + std::map::const_iterator start = chunks_.upper_bound(offset); + if (start != chunks_.begin()) + --start; // start now points to the key equal or lower than offset. + if (start->first + start->second < offset) + ++start; // start element is entirely before current chunk, skip it. + + std::map::const_iterator end = + chunks_.upper_bound(offset + size); + if (start == end) { // No data in the current range available. + ranges->push_back(std::pair(offset, size)); + return true; + } + + size_t cur_offset = offset; + std::map::const_iterator it; + for (it = start; it != end; ++it) { + if (cur_offset < it->first) { + size_t new_size = it->first - cur_offset; + ranges->push_back(std::pair(cur_offset, new_size)); + cur_offset = it->first + it->second; + } else if (cur_offset < it->first + it->second) { + cur_offset = it->first + it->second; + } + } + + // Add last chunk. + if (cur_offset < offset + size) + ranges->push_back(std::pair(cur_offset, + offset + size - cur_offset)); + + return true; +} + +bool ChunkStream::IsRangeAvailable(size_t offset, size_t size) const { + if (chunks_.empty()) + return false; + + if (SIZE_MAX - size < offset) + return false; + + std::map::const_iterator it = chunks_.upper_bound(offset); + if (it == chunks_.begin()) + return false; // No chunks includes offset byte. + + --it; // Now it starts equal or before offset. + return (it->first + it->second) >= (offset + size); +} + +size_t ChunkStream::GetFirstMissingByte() const { + if (chunks_.empty()) + return 0; + std::map::const_iterator begin = chunks_.begin(); + return begin->first > 0 ? 0 : begin->second; +} + +size_t ChunkStream::GetFirstMissingByteInInterval(size_t offset) const { + if (chunks_.empty()) + return 0; + std::map::const_iterator it = chunks_.upper_bound(offset); + if (it == chunks_.begin()) + return 0; + --it; + return it->first + it->second; +} + +size_t ChunkStream::GetLastMissingByteInInterval(size_t offset) const { + if (chunks_.empty()) + return stream_size_ - 1; + std::map::const_iterator it = chunks_.upper_bound(offset); + if (it == chunks_.end()) + return stream_size_ - 1; + return it->first - 1; +} + +} // namespace chrome_pdf diff --git a/pdf/chunk_stream.h b/pdf/chunk_stream.h index b8b3c831e900df..d2d8d2a13d4a43 100644 --- a/pdf/chunk_stream.h +++ b/pdf/chunk_stream.h @@ -6,103 +6,46 @@ #define PDF_CHUNK_STREAM_H_ #include -#include -#include -#include -#include +#include +#include #include -#include "pdf/range_set.h" - namespace chrome_pdf { // This class collects a chunks of data into one data stream. Client can check // if data in certain range is available, and get missing chunks of data. -template class ChunkStream { public: - static constexpr uint32_t kChunkSize = N; - using ChunkData = typename std::array; - - ChunkStream() {} - ~ChunkStream() {} - - void SetChunkData(uint32_t chunk_index, std::unique_ptr data) { - if (!data) - return; - if (chunk_index >= data_.size()) { - data_.resize(chunk_index + 1); - } - if (!data_[chunk_index]) { - ++filled_chunks_count_; - } - data_[chunk_index] = std::move(data); - filled_chunks_.Union(gfx::Range(chunk_index, chunk_index + 1)); - } - - bool ReadData(const gfx::Range& range, void* buffer) const { - if (!IsRangeAvailable(range)) { - return false; - } - unsigned char* data_buffer = static_cast(buffer); - uint32_t start = range.start(); - while (start != range.end()) { - const uint32_t chunk_index = GetChunkIndex(start); - const uint32_t chunk_start = start % kChunkSize; - const uint32_t len = - std::min(kChunkSize - chunk_start, range.end() - start); - memcpy(data_buffer, data_[chunk_index]->data() + chunk_start, len); - data_buffer += len; - start += len; - } - return true; - } + ChunkStream(); + ~ChunkStream(); - uint32_t GetChunkIndex(uint32_t offset) const { return offset / kChunkSize; } + void Clear(); - gfx::Range GetChunksRange(uint32_t offset, uint32_t size) const { - return gfx::Range(GetChunkIndex(offset), - GetChunkIndex(offset + size + kChunkSize - 1)); - } + void Preallocate(size_t stream_size); + size_t GetSize() const; - bool IsRangeAvailable(const gfx::Range& range) const { - if (!range.IsValid() || range.is_reversed() || - (eof_pos_ > 0 && eof_pos_ < range.end())) - return false; - if (range.is_empty()) - return true; - const gfx::Range chunks_range(GetChunkIndex(range.start()), - GetChunkIndex(range.end() + kChunkSize - 1)); - return filled_chunks_.Contains(chunks_range); - } + bool WriteData(size_t offset, void* buffer, size_t size); + bool ReadData(size_t offset, size_t size, void* buffer) const; - void set_eof_pos(uint32_t eof_pos) { eof_pos_ = eof_pos; } - uint32_t eof_pos() const { return eof_pos_; } + // Returns vector of pairs where first is an offset, second is a size. + bool GetMissedRanges(size_t offset, size_t size, + std::vector >* ranges) const; + bool IsRangeAvailable(size_t offset, size_t size) const; + size_t GetFirstMissingByte() const; - const RangeSet& filled_chunks() const { return filled_chunks_; } + // Finds the first byte of the missing byte interval that offset belongs to. + size_t GetFirstMissingByteInInterval(size_t offset) const; + // Returns the last byte of the missing byte interval that offset belongs to. + size_t GetLastMissingByteInInterval(size_t offset) const; - bool IsComplete() const { - return eof_pos_ > 0 && IsRangeAvailable(gfx::Range(0, eof_pos_)); - } - - void Clear() { - data_.clear(); - eof_pos_ = 0; - filled_chunks_.Clear(); - filled_chunks_count_ = 0; - } + private: + std::vector data_; - uint32_t filled_chunks_count() const { return filled_chunks_count_; } - uint32_t total_chunks_count() const { - return GetChunkIndex(eof_pos_ + kChunkSize - 1); - } + // Pair, first - begining of the chunk, second - size of the chunk. + std::map chunks_; - private: - std::vector> data_; - uint32_t eof_pos_ = 0; - RangeSet filled_chunks_; - uint32_t filled_chunks_count_ = 0; + size_t stream_size_; }; }; // namespace chrome_pdf diff --git a/pdf/chunk_stream_unittest.cc b/pdf/chunk_stream_unittest.cc deleted file mode 100644 index f6b3f3c2e91a4d..00000000000000 --- a/pdf/chunk_stream_unittest.cc +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "pdf/chunk_stream.h" - -#include -#include - -#include "base/memory/ptr_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace chrome_pdf { -namespace { -typedef ChunkStream<10> TestChunkStream; - -std::unique_ptr CreateChunkData() { - return base::MakeUnique(); -} -} - -TEST(ChunkStreamTest, InRow) { - TestChunkStream stream; - EXPECT_FALSE(stream.IsComplete()); - EXPECT_FALSE(stream.IsRangeAvailable(gfx::Range(0, 10))); - stream.SetChunkData(0, CreateChunkData()); - EXPECT_TRUE(stream.IsRangeAvailable(gfx::Range(0, 10))); - EXPECT_FALSE(stream.IsRangeAvailable(gfx::Range(0, 20))); - stream.SetChunkData(1, CreateChunkData()); - EXPECT_TRUE(stream.IsRangeAvailable(gfx::Range(0, 20))); - EXPECT_FALSE(stream.IsRangeAvailable(gfx::Range(0, 30))); - stream.SetChunkData(2, CreateChunkData()); - EXPECT_TRUE(stream.IsRangeAvailable(gfx::Range(0, 30))); - stream.set_eof_pos(25); - EXPECT_FALSE(stream.IsRangeAvailable(gfx::Range(0, 30))); - EXPECT_TRUE(stream.IsRangeAvailable(gfx::Range(0, 25))); - EXPECT_TRUE(stream.IsComplete()); -} - -TEST(ChunkStreamTest, InBackRow) { - TestChunkStream stream; - stream.set_eof_pos(25); - EXPECT_FALSE(stream.IsComplete()); - EXPECT_FALSE(stream.IsRangeAvailable(gfx::Range(20, 25))); - stream.SetChunkData(2, CreateChunkData()); - EXPECT_TRUE(stream.IsRangeAvailable(gfx::Range(20, 25))); - EXPECT_FALSE(stream.IsRangeAvailable(gfx::Range(10, 20))); - stream.SetChunkData(1, CreateChunkData()); - EXPECT_TRUE(stream.IsRangeAvailable(gfx::Range(10, 20))); - EXPECT_FALSE(stream.IsRangeAvailable(gfx::Range(0, 10))); - stream.SetChunkData(0, CreateChunkData()); - EXPECT_TRUE(stream.IsRangeAvailable(gfx::Range(0, 10))); - EXPECT_TRUE(stream.IsComplete()); -} - -TEST(ChunkStreamTest, FillGap) { - TestChunkStream stream; - stream.set_eof_pos(25); - EXPECT_FALSE(stream.IsComplete()); - stream.SetChunkData(0, CreateChunkData()); - stream.SetChunkData(2, CreateChunkData()); - EXPECT_TRUE(stream.IsRangeAvailable(gfx::Range(0, 10))); - EXPECT_TRUE(stream.IsRangeAvailable(gfx::Range(20, 25))); - EXPECT_FALSE(stream.IsRangeAvailable(gfx::Range(0, 25))); - stream.SetChunkData(1, CreateChunkData()); - EXPECT_TRUE(stream.IsRangeAvailable(gfx::Range(0, 25))); - EXPECT_TRUE(stream.IsComplete()); -} - -TEST(ChunkStreamTest, Read) { - TestChunkStream stream; - stream.set_eof_pos(25); - const unsigned char start_value = 33; - unsigned char value = start_value; - auto chunk_0 = CreateChunkData(); - for (auto& it : *chunk_0) { - it = ++value; - } - auto chunk_1 = CreateChunkData(); - for (auto& it : *chunk_1) { - it = ++value; - } - auto chunk_2 = CreateChunkData(); - for (auto& it : *chunk_2) { - it = ++value; - } - stream.SetChunkData(0, std::move(chunk_0)); - stream.SetChunkData(2, std::move(chunk_2)); - stream.SetChunkData(1, std::move(chunk_1)); - - std::array result_data; - EXPECT_TRUE(stream.ReadData(gfx::Range(0, 25), result_data.data())); - - value = start_value; - for (const auto& it : result_data) { - EXPECT_EQ(++value, it); - } -} -} // namespace chrome_pdf diff --git a/pdf/document_loader.cc b/pdf/document_loader.cc index 67ac8ff789089c..ea4b664b27b53a 100644 --- a/pdf/document_loader.cc +++ b/pdf/document_loader.cc @@ -7,25 +7,66 @@ #include #include -#include - #include "base/logging.h" -#include "base/memory/ptr_util.h" -#include "base/numerics/safe_math.h" #include "base/strings/string_util.h" -#include "pdf/url_loader_wrapper.h" +#include "net/http/http_util.h" #include "ppapi/c/pp_errors.h" -#include "ui/gfx/range/range.h" +#include "ppapi/cpp/url_loader.h" +#include "ppapi/cpp/url_request_info.h" +#include "ppapi/cpp/url_response_info.h" namespace chrome_pdf { namespace { -// The distance from last received chunk, when we wait requesting data, using -// current connection (like playing a cassette tape) and do not send new range -// request (like rewind a cassette tape, and continue playing after). -// Experimentally chosen value. -const int kChunkCloseDistance = 10; +// If the headers have a byte-range response, writes the start and end +// positions and returns true if at least the start position was parsed. +// The end position will be set to 0 if it was not found or parsed from the +// response. +// Returns false if not even a start position could be parsed. +bool GetByteRange(const std::string& headers, uint32_t* start, uint32_t* end) { + net::HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\n"); + while (it.GetNext()) { + if (base::LowerCaseEqualsASCII(it.name(), "content-range")) { + std::string range = it.values().c_str(); + if (base::StartsWith(range, "bytes", + base::CompareCase::INSENSITIVE_ASCII)) { + range = range.substr(strlen("bytes")); + std::string::size_type pos = range.find('-'); + std::string range_end; + if (pos != std::string::npos) + range_end = range.substr(pos + 1); + base::TrimWhitespaceASCII(range, base::TRIM_LEADING, &range); + base::TrimWhitespaceASCII(range_end, base::TRIM_LEADING, &range_end); + *start = atoi(range.c_str()); + *end = atoi(range_end.c_str()); + return true; + } + } + } + return false; +} + +// If the headers have a multi-part response, returns the boundary name. +// Otherwise returns an empty string. +std::string GetMultiPartBoundary(const std::string& headers) { + net::HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\n"); + while (it.GetNext()) { + if (base::LowerCaseEqualsASCII(it.name(), "content-type")) { + std::string type = base::ToLowerASCII(it.values()); + if (base::StartsWith(type, "multipart/", base::CompareCase::SENSITIVE)) { + const char* boundary = strstr(type.c_str(), "boundary="); + if (!boundary) { + NOTREACHED(); + break; + } + + return std::string(boundary + 9); + } + } + } + return std::string(); +} bool IsValidContentType(const std::string& type) { return (base::EndsWith(type, "/pdf", base::CompareCase::INSENSITIVE_ASCII) || @@ -44,31 +85,43 @@ bool IsValidContentType(const std::string& type) { DocumentLoader::Client::~Client() { } -DocumentLoader::Chunk::Chunk() {} - -DocumentLoader::Chunk::~Chunk() {} - -void DocumentLoader::Chunk::Clear() { - chunk_index = 0; - data_size = 0; - chunk_data.reset(); -} - DocumentLoader::DocumentLoader(Client* client) - : client_(client), loader_factory_(this) {} + : client_(client), partial_document_(false), request_pending_(false), + current_pos_(0), current_chunk_size_(0), current_chunk_read_(0), + document_size_(0), header_request_(true), is_multipart_(false) { + loader_factory_.Initialize(this); +} DocumentLoader::~DocumentLoader() { } -bool DocumentLoader::Init(std::unique_ptr loader, - const std::string& url) { +bool DocumentLoader::Init(const pp::URLLoader& loader, + const std::string& url, + const std::string& headers) { DCHECK(url_.empty()); - DCHECK(!loader_); + url_ = url; + loader_ = loader; + + std::string response_headers; + if (!headers.empty()) { + response_headers = headers; + } else { + pp::URLResponseInfo response = loader_.GetResponseInfo(); + pp::Var headers_var = response.GetHeaders(); + + if (headers_var.is_string()) { + response_headers = headers_var.AsString(); + } + } - std::string type = loader->GetContentType(); + bool accept_ranges_bytes = false; + bool content_encoded = false; + uint32_t content_length = 0; + std::string type; + std::string disposition; // This happens for PDFs not loaded from http(s) sources. - if (type == "text/plain") { + if (response_headers == "Content-Type: text/plain") { if (!base::StartsWith(url, "http://", base::CompareCase::INSENSITIVE_ASCII) && !base::StartsWith(url, "https://", @@ -76,85 +129,109 @@ bool DocumentLoader::Init(std::unique_ptr loader, type = "application/pdf"; } } + if (type.empty() && !response_headers.empty()) { + net::HttpUtil::HeadersIterator it(response_headers.begin(), + response_headers.end(), "\n"); + while (it.GetNext()) { + if (base::LowerCaseEqualsASCII(it.name(), "content-length")) { + content_length = atoi(it.values().c_str()); + } else if (base::LowerCaseEqualsASCII(it.name(), "accept-ranges")) { + accept_ranges_bytes = base::LowerCaseEqualsASCII(it.values(), "bytes"); + } else if (base::LowerCaseEqualsASCII(it.name(), "content-encoding")) { + content_encoded = true; + } else if (base::LowerCaseEqualsASCII(it.name(), "content-type")) { + type = it.values(); + size_t semi_colon_pos = type.find(';'); + if (semi_colon_pos != std::string::npos) { + type = type.substr(0, semi_colon_pos); + } + TrimWhitespaceASCII(type, base::TRIM_ALL, &type); + } else if (base::LowerCaseEqualsASCII(it.name(), "content-disposition")) { + disposition = it.values(); + } + } + } if (!type.empty() && !IsValidContentType(type)) return false; - - if (base::StartsWith(loader->GetContentDisposition(), "attachment", + if (base::StartsWith(disposition, "attachment", base::CompareCase::INSENSITIVE_ASCII)) return false; - url_ = url; - loader_ = std::move(loader); + if (content_length > 0) + chunk_stream_.Preallocate(content_length); - if (!loader_->IsContentEncoded()) { - chunk_stream_.set_eof_pos(std::max(0, loader_->GetContentLength())); - } - int64_t bytes_received = 0; - int64_t total_bytes_to_be_received = 0; - if (!chunk_stream_.eof_pos() && - loader_->GetDownloadProgress(&bytes_received, - &total_bytes_to_be_received)) { - chunk_stream_.set_eof_pos( - std::max(0, static_cast(total_bytes_to_be_received))); + document_size_ = content_length; + requests_count_ = 0; + + // Enable partial loading only if file size is above the threshold. + // It will allow avoiding latency for multiple requests. + if (content_length > kMinFileSize && + accept_ranges_bytes && + !content_encoded) { + LoadPartialDocument(); + } else { + LoadFullDocument(); } + return true; +} - SetPartialLoadingEnabled( - partial_loading_enabled_ && - !base::StartsWith(url, "file://", base::CompareCase::INSENSITIVE_ASCII) && - loader_->IsAcceptRangesBytes() && !loader_->IsContentEncoded() && - GetDocumentSize()); +void DocumentLoader::LoadPartialDocument() { + // The current request is a full request (not a range request) so it starts at + // 0 and ends at |document_size_|. + current_chunk_size_ = document_size_; + current_pos_ = 0; + current_request_offset_ = 0; + current_request_size_ = 0; + current_request_extended_size_ = document_size_; + request_pending_ = true; + + partial_document_ = true; + header_request_ = true; + ReadMore(); +} +void DocumentLoader::LoadFullDocument() { + partial_document_ = false; + chunk_buffer_.clear(); ReadMore(); - return true; } bool DocumentLoader::IsDocumentComplete() const { - return chunk_stream_.IsComplete(); + if (document_size_ == 0) // Document size unknown. + return false; + return IsDataAvailable(0, document_size_); } -uint32_t DocumentLoader::GetDocumentSize() const { - return chunk_stream_.eof_pos(); +uint32_t DocumentLoader::GetAvailableData() const { + if (document_size_ == 0) { // If document size is unknown. + return current_pos_; + } + + std::vector > ranges; + chunk_stream_.GetMissedRanges(0, document_size_, &ranges); + uint32_t available = document_size_; + for (const auto& range : ranges) + available -= range.second; + return available; } void DocumentLoader::ClearPendingRequests() { - pending_requests_.Clear(); + pending_requests_.erase(pending_requests_.begin(), + pending_requests_.end()); } bool DocumentLoader::GetBlock(uint32_t position, uint32_t size, void* buf) const { - base::CheckedNumeric addition_result = position; - addition_result += size; - if (!addition_result.IsValid()) - return false; - return chunk_stream_.ReadData( - gfx::Range(position, addition_result.ValueOrDie()), buf); + return chunk_stream_.ReadData(position, size, buf); } bool DocumentLoader::IsDataAvailable(uint32_t position, uint32_t size) const { - base::CheckedNumeric addition_result = position; - addition_result += size; - if (!addition_result.IsValid()) - return false; - return chunk_stream_.IsRangeAvailable( - gfx::Range(position, addition_result.ValueOrDie())); + return chunk_stream_.IsRangeAvailable(position, size); } void DocumentLoader::RequestData(uint32_t position, uint32_t size) { - if (!size || IsDataAvailable(position, size)) { - return; - } - { - // Check integer overflow. - base::CheckedNumeric addition_result = position; - addition_result += size; - if (!addition_result.IsValid()) - return; - } - - if (GetDocumentSize() && (position + size > GetDocumentSize())) { - return; - } + DCHECK(partial_document_); // We have some artefact request from // PDFiumEngine::OnDocumentComplete() -> FPDFAvail_IsPageAvail after @@ -163,230 +240,307 @@ void DocumentLoader::RequestData(uint32_t position, uint32_t size) { // Bug: http://code.google.com/p/chromium/issues/detail?id=79996 // Test url: // http://www.icann.org/en/correspondence/holtzman-to-jeffrey-02mar11-en.pdf - if (!loader_) + if (IsDocumentComplete()) return; - RangeSet requested_chunks(chunk_stream_.GetChunksRange(position, size)); - requested_chunks.Subtract(chunk_stream_.filled_chunks()); - if (requested_chunks.IsEmpty()) { - NOTREACHED(); - return; - } - pending_requests_.Union(requested_chunks); + pending_requests_.push_back(std::pair(position, size)); + DownloadPendingRequests(); } -void DocumentLoader::SetPartialLoadingEnabled(bool enabled) { - partial_loading_enabled_ = enabled; - if (!enabled) { - is_partial_loader_active_ = false; +void DocumentLoader::RemoveCompletedRanges() { + // Split every request that has been partially downloaded already into smaller + // requests. + std::vector > ranges; + auto it = pending_requests_.begin(); + while (it != pending_requests_.end()) { + chunk_stream_.GetMissedRanges(it->first, it->second, &ranges); + pending_requests_.insert(it, ranges.begin(), ranges.end()); + ranges.clear(); + pending_requests_.erase(it++); } } -bool DocumentLoader::ShouldCancelLoading() const { - if (!loader_) - return true; - if (!partial_loading_enabled_ || pending_requests_.IsEmpty()) - return false; - const gfx::Range current_range(chunk_.chunk_index, - chunk_.chunk_index + kChunkCloseDistance); - return !pending_requests_.Intersects(current_range); -} +void DocumentLoader::DownloadPendingRequests() { + if (request_pending_) + return; + + uint32_t pos; + uint32_t size; + if (pending_requests_.empty()) { + // If the document is not complete and we have no outstanding requests, + // download what's left for as long as no other request gets added to + // |pending_requests_|. + pos = chunk_stream_.GetFirstMissingByte(); + if (pos >= document_size_) { + // We're done downloading the document. + return; + } + // Start with size 0, we'll set |current_request_extended_size_| to > 0. + // This way this request will get cancelled as soon as the renderer wants + // another portion of the document. + size = 0; + } else { + RemoveCompletedRanges(); -void DocumentLoader::ContinueDownload() { - if (!ShouldCancelLoading()) - return ReadMore(); - DCHECK(partial_loading_enabled_); - DCHECK(!IsDocumentComplete()); - DCHECK(GetDocumentSize()); - - const uint32_t range_start = - pending_requests_.IsEmpty() ? 0 : pending_requests_.First().start(); - RangeSet candidates_for_request( - gfx::Range(range_start, chunk_stream_.total_chunks_count())); - candidates_for_request.Subtract(chunk_stream_.filled_chunks()); - DCHECK(!candidates_for_request.IsEmpty()); - gfx::Range next_request = candidates_for_request.First(); - if (candidates_for_request.Size() == 1 && - next_request.length() < kChunkCloseDistance) { - // We have only request at the end, try to enlarge it to improve back order - // reading. - const int additional_chunks_count = - kChunkCloseDistance - next_request.length(); - int new_start = std::max( - 0, static_cast(next_request.start()) - additional_chunks_count); - candidates_for_request = - RangeSet(gfx::Range(new_start, next_request.end())); - candidates_for_request.Subtract(chunk_stream_.filled_chunks()); - next_request = candidates_for_request.Last(); + pos = pending_requests_.front().first; + size = pending_requests_.front().second; + if (IsDataAvailable(pos, size)) { + ReadComplete(); + return; + } } - loader_.reset(); - chunk_.Clear(); - if (!is_partial_loader_active_) { - client_->CancelBrowserDownload(); - is_partial_loader_active_ = true; + size_t last_byte_before = chunk_stream_.GetFirstMissingByteInInterval(pos); + if (size < kDefaultRequestSize) { + // Try to extend before pos, up to size |kDefaultRequestSize|. + if (pos + size - last_byte_before > kDefaultRequestSize) { + pos += size - kDefaultRequestSize; + size = kDefaultRequestSize; + } else { + size += pos - last_byte_before; + pos = last_byte_before; + } } + if (pos - last_byte_before < kDefaultRequestSize) { + // Don't leave a gap smaller than |kDefaultRequestSize|. + size += pos - last_byte_before; + pos = last_byte_before; + } + + current_request_offset_ = pos; + current_request_size_ = size; - const uint32_t start = next_request.start() * DataStream::kChunkSize; - const uint32_t length = - std::min(chunk_stream_.eof_pos() - start, - next_request.length() * DataStream::kChunkSize); + // Extend the request until the next downloaded byte or the end of the + // document. + size_t last_missing_byte = + chunk_stream_.GetLastMissingByteInInterval(pos + size - 1); + current_request_extended_size_ = last_missing_byte - pos + 1; + request_pending_ = true; + + // Start downloading first pending request. + loader_.Close(); loader_ = client_->CreateURLLoader(); + pp::CompletionCallback callback = + loader_factory_.NewCallback(&DocumentLoader::DidOpen); + pp::URLRequestInfo request = GetRequest(pos, current_request_extended_size_); + requests_count_++; + int rv = loader_.Open(request, callback); + if (rv != PP_OK_COMPLETIONPENDING) + callback.Run(rv); +} - loader_->OpenRange( - url_, url_, start, length, - loader_factory_.NewCallback(&DocumentLoader::DidOpenPartial)); +pp::URLRequestInfo DocumentLoader::GetRequest(uint32_t position, + uint32_t size) const { + pp::URLRequestInfo request(client_->GetPluginInstance()); + request.SetURL(url_); + request.SetMethod("GET"); + request.SetFollowRedirects(false); + request.SetCustomReferrerURL(url_); + + const size_t kBufSize = 100; + char buf[kBufSize]; + // According to rfc2616, byte range specifies position of the first and last + // bytes in the requested range inclusively. Therefore we should subtract 1 + // from the position + size, to get index of the last byte that needs to be + // downloaded. + base::snprintf(buf, kBufSize, "Range: bytes=%d-%d", position, + position + size - 1); + pp::Var header(buf); + request.SetHeaders(header); + + return request; } -void DocumentLoader::DidOpenPartial(int32_t result) { +void DocumentLoader::DidOpen(int32_t result) { if (result != PP_OK) { - return ReadComplete(); + NOTREACHED(); + return; } - int32_t http_code = loader_->GetStatusCode(); + int32_t http_code = loader_.GetResponseInfo().GetStatusCode(); if (http_code >= 400 && http_code < 500) { // Error accessing resource. 4xx error indicate subsequent requests // will fail too. // E.g. resource has been removed from the server while loading it. - return ReadComplete(); + // https://code.google.com/p/chromium/issues/detail?id=414827 + return; } - // Leave position untouched for multiparted responce for now, when we read the - // data we'll get it. - if (!loader_->IsMultipart()) { + is_multipart_ = false; + current_chunk_size_ = 0; + current_chunk_read_ = 0; + + pp::Var headers_var = loader_.GetResponseInfo().GetHeaders(); + std::string headers; + if (headers_var.is_string()) + headers = headers_var.AsString(); + + std::string boundary = GetMultiPartBoundary(headers); + if (!boundary.empty()) { + // Leave position untouched for now, when we read the data we'll get it. + is_multipart_ = true; + multipart_boundary_ = boundary; + } else { // Need to make sure that the server returned a byte-range, since it's // possible for a server to just ignore our byte-range request and just // return the entire document even if it supports byte-range requests. // i.e. sniff response to // http://www.act.org/compass/sample/pdf/geometry.pdf - int start_pos = 0; - int end_pos = 0; - if (loader_->GetByteRange(&start_pos, &end_pos)) { - if (start_pos % DataStream::kChunkSize != 0) { - return ReadComplete(); - } - DCHECK(!chunk_.chunk_data); - chunk_.chunk_index = chunk_stream_.GetChunkIndex(start_pos); + current_pos_ = 0; + uint32_t start_pos, end_pos; + if (GetByteRange(headers, &start_pos, &end_pos)) { + current_pos_ = start_pos; + if (end_pos && end_pos > start_pos) + current_chunk_size_ = end_pos - start_pos + 1; } else { - SetPartialLoadingEnabled(false); + partial_document_ = false; } - return ContinueDownload(); } - // Needs more data to calc chunk index. - return ReadMore(); + + ReadMore(); } void DocumentLoader::ReadMore() { - loader_->ReadResponseBody( - buffer_, sizeof(buffer_), - loader_factory_.NewCallback(&DocumentLoader::DidRead)); + pp::CompletionCallback callback = + loader_factory_.NewCallback(&DocumentLoader::DidRead); + int rv = loader_.ReadResponseBody(buffer_, sizeof(buffer_), callback); + if (rv != PP_OK_COMPLETIONPENDING) + callback.Run(rv); } void DocumentLoader::DidRead(int32_t result) { - if (result < 0) { - // An error occurred. - // The renderer will detect that we're missing data and will display a - // message. - return ReadComplete(); - } - if (result == 0) { - loader_.reset(); - if (!is_partial_loader_active_) - return ReadComplete(); - return ContinueDownload(); + if (result <= 0) { + // If |result| == PP_OK, the document was loaded, otherwise an error was + // encountered. Either way we want to stop processing the response. In the + // case where an error occurred, the renderer will detect that we're missing + // data and will display a message. + ReadComplete(); + return; } - if (loader_->IsMultipart()) { - int start_pos = 0; - int end_pos = 0; - if (!loader_->GetByteRange(&start_pos, &end_pos)) { - return ReadComplete(); + + char* start = buffer_; + size_t length = result; + if (is_multipart_ && result > 2) { + for (int i = 2; i < result; ++i) { + if ((buffer_[i - 1] == '\n' && buffer_[i - 2] == '\n') || + (i >= 4 && buffer_[i - 1] == '\n' && buffer_[i - 2] == '\r' && + buffer_[i - 3] == '\n' && buffer_[i - 4] == '\r')) { + uint32_t start_pos, end_pos; + if (GetByteRange(std::string(buffer_, i), &start_pos, &end_pos)) { + current_pos_ = start_pos; + start += i; + length -= i; + if (end_pos && end_pos > start_pos) + current_chunk_size_ = end_pos - start_pos + 1; + } + break; + } } - DCHECK(!chunk_.chunk_data); - chunk_.chunk_index = chunk_stream_.GetChunkIndex(start_pos); + + // Reset this flag so we don't look inside the buffer in future calls of + // DidRead for this response. Note that this code DOES NOT handle multi- + // part responses with more than one part (we don't issue them at the + // moment, so they shouldn't arrive). + is_multipart_ = false; } - if (!SaveChunkData(buffer_, result)) { - return ReadMore(); + + if (current_chunk_size_ && current_chunk_read_ + length > current_chunk_size_) + length = current_chunk_size_ - current_chunk_read_; + + if (length) { + if (document_size_ > 0) { + chunk_stream_.WriteData(current_pos_, start, length); + } else { + // If we did not get content-length in the response, we can't + // preallocate buffer for the entire document. Resizing array causing + // memory fragmentation issues on the large files and OOM exceptions. + // To fix this, we collect all chunks of the file to the list and + // concatenate them together after request is complete. + std::vector buf(length); + memcpy(buf.data(), start, length); + chunk_buffer_.push_back(std::move(buf)); + } + current_pos_ += length; + current_chunk_read_ += length; + client_->OnNewDataAvailable(); } - if (IsDocumentComplete()) { - return ReadComplete(); + + // Only call the renderer if we allow partial loading. + if (!partial_document_) { + ReadMore(); + return; } - return ContinueDownload(); -} -bool DocumentLoader::SaveChunkData(char* input, uint32_t input_size) { - count_of_bytes_received_ += input_size; - bool chunk_saved = false; - bool loading_pending_request = pending_requests_.Contains(chunk_.chunk_index); - while (input_size > 0) { - if (chunk_.data_size == 0) { - chunk_.chunk_data = base::MakeUnique(); + UpdateRendering(); + RemoveCompletedRanges(); + + if (!pending_requests_.empty()) { + // If there are pending requests and the current content we're downloading + // doesn't satisfy any of these requests, cancel the current request to + // fullfill those more important requests. + bool satisfying_pending_request = + SatisfyingRequest(current_request_offset_, current_request_size_); + for (const auto& pending_request : pending_requests_) { + if (SatisfyingRequest(pending_request.first, pending_request.second)) { + satisfying_pending_request = true; + break; + } } - const uint32_t new_chunk_data_len = - std::min(DataStream::kChunkSize - chunk_.data_size, input_size); - memcpy(chunk_.chunk_data->data() + chunk_.data_size, input, - new_chunk_data_len); - chunk_.data_size += new_chunk_data_len; - if (chunk_.data_size == DataStream::kChunkSize || - chunk_stream_.eof_pos() == - chunk_.chunk_index * DataStream::kChunkSize + chunk_.data_size) { - chunk_stream_.SetChunkData(chunk_.chunk_index, - std::move(chunk_.chunk_data)); - pending_requests_.Subtract( - gfx::Range(chunk_.chunk_index, chunk_.chunk_index + 1)); - chunk_.data_size = 0; - ++(chunk_.chunk_index); - chunk_saved = true; + // Cancel the request as it's not satisfying any request from the + // renderer, unless the current request is finished in which case we let + // it finish cleanly. + if (!satisfying_pending_request && + current_pos_ < + current_request_offset_ + current_request_extended_size_) { + loader_.Close(); } - - input += new_chunk_data_len; - input_size -= new_chunk_data_len; } - if (IsDocumentComplete()) - return true; - - if (!chunk_saved) - return false; + ReadMore(); +} - if (loading_pending_request && - !pending_requests_.Contains(chunk_.chunk_index)) { - client_->OnPendingRequestComplete(); - } - client_->OnNewDataAvailable(); - return true; +bool DocumentLoader::SatisfyingRequest(size_t offset, size_t size) const { + return offset <= current_pos_ + kDefaultRequestSize && + current_pos_ < offset + size; } void DocumentLoader::ReadComplete() { - if (!GetDocumentSize()) { - uint32_t eof = - chunk_.chunk_index * DataStream::kChunkSize + chunk_.data_size; - if (!chunk_stream_.filled_chunks().IsEmpty()) { - eof = std::max( - chunk_stream_.filled_chunks().Last().end() * DataStream::kChunkSize, - eof); - } - chunk_stream_.set_eof_pos(eof); - if (eof == chunk_.chunk_index * DataStream::kChunkSize + chunk_.data_size) { - chunk_stream_.SetChunkData(chunk_.chunk_index, - std::move(chunk_.chunk_data)); + if (!partial_document_) { + if (document_size_ == 0) { + // For the document with no 'content-length" specified we've collected all + // the chunks already. Let's allocate final document buffer and copy them + // over. + chunk_stream_.Preallocate(current_pos_); + uint32_t pos = 0; + for (auto& chunk : chunk_buffer_) { + chunk_stream_.WriteData(pos, chunk.data(), chunk.size()); + pos += chunk.size(); + } + chunk_buffer_.clear(); } + document_size_ = current_pos_; + client_->OnDocumentComplete(); + return; } - loader_.reset(); + + request_pending_ = false; + if (IsDocumentComplete()) { client_->OnDocumentComplete(); - } else { - client_->OnDocumentCanceled(); + return; } + + UpdateRendering(); + DownloadPendingRequests(); } -float DocumentLoader::GetProgress() const { - if (!GetDocumentSize()) - return -1; - if (IsDocumentComplete()) - return 1; - return static_cast(chunk_stream_.filled_chunks_count()) / - chunk_stream_.total_chunks_count(); +void DocumentLoader::UpdateRendering() { + if (header_request_) + client_->OnPartialDocumentLoaded(); + else + client_->OnPendingRequestComplete(); + header_request_ = false; } } // namespace chrome_pdf diff --git a/pdf/document_loader.h b/pdf/document_loader.h index 6f2705fe1ce7f2..cf85e99e5a1add 100644 --- a/pdf/document_loader.h +++ b/pdf/document_loader.h @@ -9,18 +9,16 @@ #include #include -#include #include #include #include #include "pdf/chunk_stream.h" +#include "ppapi/cpp/url_loader.h" #include "ppapi/utility/completion_callback_factory.h" namespace chrome_pdf { -class URLLoaderWrapper; - class DocumentLoader { public: class Client { @@ -30,23 +28,25 @@ class DocumentLoader { // Gets the pp::Instance object. virtual pp::Instance* GetPluginInstance() = 0; // Creates new URLLoader based on client settings. - virtual std::unique_ptr CreateURLLoader() = 0; + virtual pp::URLLoader CreateURLLoader() = 0; + // Notification called when partial information about document is available. + // Only called for urls that returns full content size and supports byte + // range requests. + virtual void OnPartialDocumentLoaded() = 0; // Notification called when all outstanding pending requests are complete. virtual void OnPendingRequestComplete() = 0; // Notification called when new data is available. virtual void OnNewDataAvailable() = 0; // Notification called when document is fully loaded. virtual void OnDocumentComplete() = 0; - // Notification called when document loading is canceled. - virtual void OnDocumentCanceled() = 0; - // Called when initial loader was closed. - virtual void CancelBrowserDownload() = 0; }; explicit DocumentLoader(Client* client); ~DocumentLoader(); - bool Init(std::unique_ptr loader, const std::string& url); + bool Init(const pp::URLLoader& loader, + const std::string& url, + const std::string& headers); // Data access interface. Return true is successful. bool GetBlock(uint32_t position, uint32_t size, void* buf) const; @@ -58,63 +58,77 @@ class DocumentLoader { void RequestData(uint32_t position, uint32_t size); bool IsDocumentComplete() const; - uint32_t GetDocumentSize() const; - uint32_t count_of_bytes_received() const { return count_of_bytes_received_; } - float GetProgress() const; + uint32_t document_size() const { return document_size_; } + + // Return number of bytes available. + uint32_t GetAvailableData() const; // Clear pending requests from the queue. void ClearPendingRequests(); - void SetPartialLoadingEnabled(bool enabled); - - bool is_partial_loader_active() const { return is_partial_loader_active_; } - - static uint32_t default_request_size() { return kDefaultRequestSize; } + bool is_partial_document() const { return partial_document_; } private: - // Number was chosen in crbug.com/78264#c8 - static constexpr uint32_t kDefaultRequestSize = 65536; - - using DataStream = ChunkStream; - struct Chunk { - Chunk(); - ~Chunk(); - - void Clear(); - - uint32_t chunk_index = 0; - uint32_t data_size = 0; - std::unique_ptr chunk_data; - }; - // Called by the completion callback of the document's URLLoader. - void DidOpenPartial(int32_t result); + void DidOpen(int32_t result); // Call to read data from the document's URLLoader. void ReadMore(); // Called by the completion callback of the document's URLLoader. void DidRead(int32_t result); - bool ShouldCancelLoading() const; - void ContinueDownload(); - // Called when we complete server request. + // Called when we detect that partial document load is possible. + void LoadPartialDocument(); + // Called when we have to load full document. + void LoadFullDocument(); + // Download pending requests. + void DownloadPendingRequests(); + // Remove completed ranges. + void RemoveCompletedRanges(); + // Returns true if we are already in progress satisfying the request, or just + // about ready to start. This helps us avoid expensive jumping around, and + // even worse leaving tiny gaps in the byte stream that might have to be + // filled later. + bool SatisfyingRequest(size_t pos, size_t size) const; + // Called when we complete server request and read all data from it. void ReadComplete(); + // Creates request to download size byte of data data starting from position. + pp::URLRequestInfo GetRequest(uint32_t position, uint32_t size) const; + // Updates the rendering by the Client. + void UpdateRendering(); - bool SaveChunkData(char* input, uint32_t input_size); + // Document below size will be downloaded in one chunk. + static const uint32_t kMinFileSize = 64 * 1024; + // Number was chosen in crbug.com/78264#c8 + enum { kDefaultRequestSize = 65536 }; Client* const client_; std::string url_; - std::unique_ptr loader_; - + pp::URLLoader loader_; pp::CompletionCallbackFactory loader_factory_; - - DataStream chunk_stream_; - bool partial_loading_enabled_ = true; - bool is_partial_loader_active_ = false; - char buffer_[DataStream::kChunkSize]; - - Chunk chunk_; - RangeSet pending_requests_; - uint32_t count_of_bytes_received_ = 0; + ChunkStream chunk_stream_; + bool partial_document_; + bool request_pending_; + typedef std::list > PendingRequests; + PendingRequests pending_requests_; + // The starting position of the HTTP request currently being processed. + size_t current_request_offset_; + // The size of the byte range the current HTTP request must download before + // being cancelled. + size_t current_request_size_; + // The actual byte range size of the current HTTP request. This may be larger + // than |current_request_size_| and the request may be cancelled before + // reaching |current_request_offset_| + |current_request_extended_size_|. + size_t current_request_extended_size_; + char buffer_[kDefaultRequestSize]; + uint32_t current_pos_; + uint32_t current_chunk_size_; + uint32_t current_chunk_read_; + uint32_t document_size_; + bool header_request_; + bool is_multipart_; + std::string multipart_boundary_; + uint32_t requests_count_; + std::vector > chunk_buffer_; }; } // namespace chrome_pdf diff --git a/pdf/document_loader_unittest.cc b/pdf/document_loader_unittest.cc deleted file mode 100644 index 51a27ad6805af8..00000000000000 --- a/pdf/document_loader_unittest.cc +++ /dev/null @@ -1,1184 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "pdf/document_loader.h" - -#include -#include - -#include "base/logging.h" -#include "pdf/url_loader_wrapper.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/gfx/range/range.h" - -using ::testing::_; -using ::testing::Mock; -using ::testing::Sequence; -using ::testing::NiceMock; -using ::testing::Return; - -namespace chrome_pdf { - -namespace { - -class TestURLLoader : public URLLoaderWrapper { - public: - class LoaderData { - public: - LoaderData() {} - - int content_length() const { return content_length_; } - void set_content_length(int content_length) { - content_length_ = content_length; - } - bool accept_ranges_bytes() const { return accept_ranges_bytes_; } - void set_accept_ranges_bytes(bool accept_ranges_bytes) { - accept_ranges_bytes_ = accept_ranges_bytes; - } - bool content_encoded() const { return content_encoded_; } - void set_content_encoded(bool content_encoded) { - content_encoded_ = content_encoded; - } - const std::string& content_type() const { return content_type_; } - void set_content_type(const std::string& content_type) { - content_type_ = content_type; - } - const std::string& content_disposition() const { - return content_disposition_; - } - void set_content_disposition(const std::string& content_disposition) { - content_disposition_ = content_disposition; - } - const std::string& multipart_boundary() const { - return multipart_boundary_; - } - void set_multipart_boundary(const std::string& multipart_boundary) { - multipart_boundary_ = multipart_boundary; - } - const gfx::Range& byte_range() const { return byte_range_; } - void set_byte_range(const gfx::Range& byte_range) { - byte_range_ = byte_range; - } - bool is_multipart() const { return is_multipart_; } - void set_is_multipart(bool is_multipart) { is_multipart_ = is_multipart; } - int status_code() const { return status_code_; } - void set_status_code(int status_code) { status_code_ = status_code; } - bool closed() const { return closed_; } - void set_closed(bool closed) { closed_ = closed; } - const gfx::Range& open_byte_range() const { return open_byte_range_; } - void set_open_byte_range(const gfx::Range& open_byte_range) { - open_byte_range_ = open_byte_range; - } - - bool IsWaitRead() const { return !did_read_callback_.IsOptional(); } - bool IsWaitOpen() const { return !did_open_callback_.IsOptional(); } - char* buffer() const { return buffer_; } - int buffer_size() const { return buffer_size_; } - - void SetReadCallback(const pp::CompletionCallback& read_callback, - char* buffer, - int buffer_size) { - did_read_callback_ = read_callback; - buffer_ = buffer; - buffer_size_ = buffer_size; - } - - void SetOpenCallback(const pp::CompletionCallback& open_callback, - gfx::Range req_byte_range) { - did_open_callback_ = open_callback; - set_open_byte_range(req_byte_range); - } - - void CallOpenCallback(int result) { - DCHECK(IsWaitOpen()); - did_open_callback_.RunAndClear(result); - } - - void CallReadCallback(int result) { - DCHECK(IsWaitRead()); - did_read_callback_.RunAndClear(result); - } - - private: - pp::CompletionCallback did_open_callback_; - pp::CompletionCallback did_read_callback_; - char* buffer_ = nullptr; - int buffer_size_ = 0; - - int content_length_ = -1; - bool accept_ranges_bytes_ = false; - bool content_encoded_ = false; - std::string content_type_; - std::string content_disposition_; - std::string multipart_boundary_; - gfx::Range byte_range_ = gfx::Range::InvalidRange(); - bool is_multipart_ = false; - int status_code_ = 0; - bool closed_ = true; - gfx::Range open_byte_range_ = gfx::Range::InvalidRange(); - - DISALLOW_COPY_AND_ASSIGN(LoaderData); - }; - - explicit TestURLLoader(LoaderData* data) : data_(data) { - data_->set_closed(false); - } - - ~TestURLLoader() override { Close(); } - - int GetContentLength() const override { return data_->content_length(); } - - bool IsAcceptRangesBytes() const override { - return data_->accept_ranges_bytes(); - } - - bool IsContentEncoded() const override { return data_->content_encoded(); } - - std::string GetContentType() const override { return data_->content_type(); } - - std::string GetContentDisposition() const override { - return data_->content_disposition(); - } - - int GetStatusCode() const override { return data_->status_code(); } - - bool IsMultipart() const override { return data_->is_multipart(); } - - bool GetByteRange(int* start, int* end) const override { - *start = data_->byte_range().start(); - *end = data_->byte_range().end(); - return data_->byte_range().IsValid(); - } - - void Close() override { data_->set_closed(true); } - - void OpenRange(const std::string& url, - const std::string& referrer_url, - uint32_t position, - uint32_t size, - const pp::CompletionCallback& cc) override { - data_->SetOpenCallback(cc, gfx::Range(position, position + size)); - } - - void ReadResponseBody(char* buffer, - int buffer_size, - const pp::CompletionCallback& cc) override { - data_->SetReadCallback(cc, buffer, buffer_size); - } - - bool GetDownloadProgress(int64_t* bytes_received, - int64_t* total_bytes_to_be_received) const override { - return false; - } - - private: - LoaderData* data_; - - DISALLOW_COPY_AND_ASSIGN(TestURLLoader); -}; - -class TestClient : public DocumentLoader::Client { - public: - TestClient() { full_page_loader_data()->set_content_type("application/pdf"); } - ~TestClient() override {} - - // DocumentLoader::Client overrides: - pp::Instance* GetPluginInstance() override { return nullptr; } - std::unique_ptr CreateURLLoader() override { - return std::unique_ptr( - new TestURLLoader(partial_loader_data())); - } - void OnPendingRequestComplete() override {} - void OnNewDataAvailable() override {} - void OnDocumentComplete() override {} - void OnDocumentCanceled() override {} - void CancelBrowserDownload() override {} - - std::unique_ptr CreateFullPageLoader() { - return std::unique_ptr( - new TestURLLoader(full_page_loader_data())); - } - - TestURLLoader::LoaderData* full_page_loader_data() { - return &full_page_loader_data_; - } - TestURLLoader::LoaderData* partial_loader_data() { - return &partial_loader_data_; - } - - void SetCanUsePartialLoading() { - full_page_loader_data()->set_content_length(10 * 1024 * 1024); - full_page_loader_data()->set_content_encoded(false); - full_page_loader_data()->set_accept_ranges_bytes(true); - } - - void SendAllPartialData() { - partial_loader_data_.set_byte_range(partial_loader_data_.open_byte_range()); - partial_loader_data_.CallOpenCallback(0); - uint32_t length = partial_loader_data_.byte_range().length(); - while (length > 0) { - const uint32_t part_len = - std::min(length, DocumentLoader::default_request_size()); - partial_loader_data_.CallReadCallback(part_len); - length -= part_len; - } - if (partial_loader_data_.IsWaitRead()) { - partial_loader_data_.CallReadCallback(0); - } - } - - private: - TestURLLoader::LoaderData full_page_loader_data_; - TestURLLoader::LoaderData partial_loader_data_; - - DISALLOW_COPY_AND_ASSIGN(TestClient); -}; - -class MockClient : public TestClient { - public: - MockClient() {} - - MOCK_METHOD0(OnPendingRequestComplete, void()); - MOCK_METHOD0(OnNewDataAvailable, void()); - MOCK_METHOD0(OnDocumentComplete, void()); - MOCK_METHOD0(OnDocumentCanceled, void()); - - private: - DISALLOW_COPY_AND_ASSIGN(MockClient); -}; - -} // namespace - -class DocumentLoaderTest : public ::testing::Test { - public: - DocumentLoaderTest() {} - ~DocumentLoaderTest() override {} - void SetUp() override {} - void TearDown() override {} -}; - -TEST_F(DocumentLoaderTest, PartialLoadingEnabled) { - TestClient client; - client.SetCanUsePartialLoading(); - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - loader.RequestData(1000000, 1); - EXPECT_FALSE(loader.is_partial_loader_active()); - // Always send initial data from FullPageLoader. - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - EXPECT_TRUE(loader.is_partial_loader_active()); -} - -TEST_F(DocumentLoaderTest, PartialLoadingDisabledOnSmallFiles) { - TestClient client; - client.SetCanUsePartialLoading(); - client.full_page_loader_data()->set_content_length( - DocumentLoader::default_request_size() * 2); - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - loader.RequestData(1000000, 1); - EXPECT_FALSE(loader.is_partial_loader_active()); - // Always send initial data from FullPageLoader. - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - EXPECT_FALSE(loader.is_partial_loader_active()); -} - -TEST_F(DocumentLoaderTest, PartialLoadingDisabledIfContentEncoded) { - TestClient client; - client.SetCanUsePartialLoading(); - client.full_page_loader_data()->set_content_encoded(true); - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - loader.RequestData(1000000, 1); - EXPECT_FALSE(loader.is_partial_loader_active()); - // Always send initial data from FullPageLoader. - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - EXPECT_FALSE(loader.is_partial_loader_active()); -} - -TEST_F(DocumentLoaderTest, PartialLoadingDisabledNoAcceptRangeBytes) { - TestClient client; - client.SetCanUsePartialLoading(); - client.full_page_loader_data()->set_accept_ranges_bytes(false); - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - loader.RequestData(1000000, 1); - EXPECT_FALSE(loader.is_partial_loader_active()); - // Always send initial data from FullPageLoader. - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - EXPECT_FALSE(loader.is_partial_loader_active()); -} - -TEST_F(DocumentLoaderTest, PartialLoadingReallyDisabledRequestFromBegin) { - TestClient client; - DocumentLoader loader(&client); - client.SetCanUsePartialLoading(); - loader.SetPartialLoadingEnabled(false); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - // We should not start partial loading if requested data is beside full page - // loading position. - loader.RequestData(DocumentLoader::default_request_size(), 1); - EXPECT_FALSE(loader.is_partial_loader_active()); - // Always send initial data from FullPageLoader. - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - EXPECT_FALSE(loader.is_partial_loader_active()); -} - -TEST_F(DocumentLoaderTest, PartialLoadingReallyDisabledRequestFromMiddle) { - TestClient client; - client.SetCanUsePartialLoading(); - DocumentLoader loader(&client); - loader.SetPartialLoadingEnabled(false); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - loader.RequestData(1000000, 1); - EXPECT_FALSE(loader.is_partial_loader_active()); - // Always send initial data from FullPageLoader. - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - EXPECT_FALSE(loader.is_partial_loader_active()); -} - -TEST_F(DocumentLoaderTest, PartialLoadingSimple) { - TestClient client; - client.SetCanUsePartialLoading(); - - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - - // While we have no requests, we should not start partial loading. - EXPECT_FALSE(loader.is_partial_loader_active()); - - loader.RequestData(5000000, 1); - - EXPECT_FALSE(client.partial_loader_data()->IsWaitOpen()); - EXPECT_FALSE(loader.is_partial_loader_active()); - - // Always send initial data from FullPageLoader. - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - - // Partial loader should request headers. - EXPECT_TRUE(client.partial_loader_data()->IsWaitOpen()); - EXPECT_TRUE(loader.is_partial_loader_active()); - // Loader should be stopped. - EXPECT_TRUE(client.full_page_loader_data()->closed()); - - EXPECT_EQ("{4980736,10485760}", - client.partial_loader_data()->open_byte_range().ToString()); -} - -TEST_F(DocumentLoaderTest, PartialLoadingBackOrder) { - TestClient client; - client.SetCanUsePartialLoading(); - - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - - // While we have no requests, we should not start partial loading. - EXPECT_FALSE(loader.is_partial_loader_active()); - - loader.RequestData(client.full_page_loader_data()->content_length() - 1, 1); - - EXPECT_FALSE(client.partial_loader_data()->IsWaitOpen()); - EXPECT_FALSE(loader.is_partial_loader_active()); - - // Always send initial data from FullPageLoader. - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - - // Partial loader should request headers. - EXPECT_TRUE(client.partial_loader_data()->IsWaitOpen()); - EXPECT_TRUE(loader.is_partial_loader_active()); - // Loader should be stopped. - EXPECT_TRUE(client.full_page_loader_data()->closed()); - - // Requested range should be enlarged. - EXPECT_GT(client.partial_loader_data()->open_byte_range().length(), 1u); - EXPECT_EQ("{9830400,10485760}", - client.partial_loader_data()->open_byte_range().ToString()); -} - -TEST_F(DocumentLoaderTest, CompleteWithoutPartial) { - TestClient client; - client.SetCanUsePartialLoading(); - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - EXPECT_FALSE(client.full_page_loader_data()->closed()); - while (client.full_page_loader_data()->IsWaitRead()) { - client.full_page_loader_data()->CallReadCallback(1000); - } - EXPECT_TRUE(loader.IsDocumentComplete()); - EXPECT_TRUE(client.full_page_loader_data()->closed()); -} - -TEST_F(DocumentLoaderTest, ErrorDownloadFullDocument) { - TestClient client; - client.SetCanUsePartialLoading(); - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - EXPECT_TRUE(client.full_page_loader_data()->IsWaitRead()); - EXPECT_FALSE(client.full_page_loader_data()->closed()); - client.full_page_loader_data()->CallReadCallback(-3); - EXPECT_TRUE(client.full_page_loader_data()->closed()); - EXPECT_FALSE(loader.IsDocumentComplete()); -} - -TEST_F(DocumentLoaderTest, CompleteNoContentLength) { - TestClient client; - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - EXPECT_FALSE(client.full_page_loader_data()->closed()); - for (int i = 0; i < 10; ++i) { - EXPECT_TRUE(client.full_page_loader_data()->IsWaitRead()); - client.full_page_loader_data()->CallReadCallback(1000); - } - EXPECT_TRUE(client.full_page_loader_data()->IsWaitRead()); - client.full_page_loader_data()->CallReadCallback(0); - EXPECT_EQ(10000ul, loader.GetDocumentSize()); - EXPECT_TRUE(loader.IsDocumentComplete()); - EXPECT_TRUE(client.full_page_loader_data()->closed()); -} - -TEST_F(DocumentLoaderTest, CompleteWithPartial) { - TestClient client; - client.SetCanUsePartialLoading(); - client.full_page_loader_data()->set_content_length( - DocumentLoader::default_request_size() * 20); - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - loader.RequestData(19 * DocumentLoader::default_request_size(), - DocumentLoader::default_request_size()); - EXPECT_FALSE(client.full_page_loader_data()->closed()); - EXPECT_FALSE(client.partial_loader_data()->IsWaitRead()); - EXPECT_FALSE(client.partial_loader_data()->IsWaitOpen()); - - // Always send initial data from FullPageLoader. - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - EXPECT_TRUE(client.full_page_loader_data()->closed()); - EXPECT_FALSE(client.partial_loader_data()->closed()); - - client.SendAllPartialData(); - // Now we should send other document data. - client.SendAllPartialData(); - EXPECT_TRUE(client.full_page_loader_data()->closed()); - EXPECT_TRUE(client.partial_loader_data()->closed()); -} - -TEST_F(DocumentLoaderTest, PartialRequestLastChunk) { - const uint32_t kLastChunkSize = 300; - TestClient client; - client.SetCanUsePartialLoading(); - client.full_page_loader_data()->set_content_length( - DocumentLoader::default_request_size() * 20 + kLastChunkSize); - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - loader.RequestData(20 * DocumentLoader::default_request_size(), 1); - - // Always send initial data from FullPageLoader. - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - - EXPECT_TRUE(client.partial_loader_data()->IsWaitOpen()); - EXPECT_EQ( - static_cast(client.partial_loader_data()->open_byte_range().end()), - client.full_page_loader_data()->content_length()); - client.partial_loader_data()->set_byte_range( - client.partial_loader_data()->open_byte_range()); - client.partial_loader_data()->CallOpenCallback(0); - uint32_t data_length = client.partial_loader_data()->byte_range().length(); - while (data_length > DocumentLoader::default_request_size()) { - client.partial_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - data_length -= DocumentLoader::default_request_size(); - } - EXPECT_EQ(kLastChunkSize, data_length); - client.partial_loader_data()->CallReadCallback(kLastChunkSize); - EXPECT_TRUE(loader.IsDataAvailable( - DocumentLoader::default_request_size() * 20, kLastChunkSize)); -} - -TEST_F(DocumentLoaderTest, DocumentSize) { - TestClient client; - client.SetCanUsePartialLoading(); - client.full_page_loader_data()->set_content_length(123456789); - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - EXPECT_EQ(static_cast(loader.GetDocumentSize()), - client.full_page_loader_data()->content_length()); -} - -TEST_F(DocumentLoaderTest, DocumentSizeNoContentLength) { - TestClient client; - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - EXPECT_EQ(0ul, loader.GetDocumentSize()); - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - client.full_page_loader_data()->CallReadCallback(1000); - client.full_page_loader_data()->CallReadCallback(500); - client.full_page_loader_data()->CallReadCallback(0); - EXPECT_EQ(DocumentLoader::default_request_size() + 1000ul + 500ul, - loader.GetDocumentSize()); - EXPECT_TRUE(loader.IsDocumentComplete()); -} - -TEST_F(DocumentLoaderTest, ClearPendingRequests) { - TestClient client; - client.SetCanUsePartialLoading(); - client.full_page_loader_data()->set_content_length( - DocumentLoader::default_request_size() * 100 + 58383); - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - loader.RequestData(17 * DocumentLoader::default_request_size() + 100, 10); - loader.ClearPendingRequests(); - loader.RequestData(15 * DocumentLoader::default_request_size() + 200, 20); - // pending requests are accumulating, and will be processed after initial data - // load. - EXPECT_FALSE(client.partial_loader_data()->IsWaitOpen()); - - // Send initial data from FullPageLoader. - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - - { - EXPECT_TRUE(client.partial_loader_data()->IsWaitOpen()); - const gfx::Range range_requested( - 15 * DocumentLoader::default_request_size(), - 16 * DocumentLoader::default_request_size()); - EXPECT_EQ(range_requested.start(), - client.partial_loader_data()->open_byte_range().start()); - EXPECT_LE(range_requested.end(), - client.partial_loader_data()->open_byte_range().end()); - client.partial_loader_data()->set_byte_range( - client.partial_loader_data()->open_byte_range()); - } - // clear requests before Open callback. - loader.ClearPendingRequests(); - // Current request should continue loading. - EXPECT_TRUE(client.partial_loader_data()->IsWaitOpen()); - client.partial_loader_data()->CallOpenCallback(0); - client.partial_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - EXPECT_FALSE(client.partial_loader_data()->closed()); - // Current request should continue loading, because no other request queued. - - loader.RequestData(18 * DocumentLoader::default_request_size() + 200, 20); - // Requests queue is processed only on receiving data. - client.partial_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - // New request within close distance from the one currently loading. Loading - // isn't restarted. - EXPECT_FALSE(client.partial_loader_data()->IsWaitOpen()); - - loader.ClearPendingRequests(); - // request again two. - loader.RequestData(60 * DocumentLoader::default_request_size() + 100, 10); - loader.RequestData(35 * DocumentLoader::default_request_size() + 200, 20); - // Requests queue is processed only on receiving data. - client.partial_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - { - // new requset not with in close distance from current loading. - // Loading should be restarted. - EXPECT_TRUE(client.partial_loader_data()->IsWaitOpen()); - // The first requested chunk should be processed. - const gfx::Range range_requested( - 35 * DocumentLoader::default_request_size(), - 36 * DocumentLoader::default_request_size()); - EXPECT_EQ(range_requested.start(), - client.partial_loader_data()->open_byte_range().start()); - EXPECT_LE(range_requested.end(), - client.partial_loader_data()->open_byte_range().end()); - client.partial_loader_data()->set_byte_range( - client.partial_loader_data()->open_byte_range()); - } - EXPECT_TRUE(client.partial_loader_data()->IsWaitOpen()); - client.partial_loader_data()->CallOpenCallback(0); - // Override pending requests. - loader.ClearPendingRequests(); - loader.RequestData(70 * DocumentLoader::default_request_size() + 100, 10); - - // Requests queue is processed only on receiving data. - client.partial_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - { - // New requset not with in close distance from current loading. - // Loading should be restarted . - EXPECT_TRUE(client.partial_loader_data()->IsWaitOpen()); - // The first requested chunk should be processed. - const gfx::Range range_requested( - 70 * DocumentLoader::default_request_size(), - 71 * DocumentLoader::default_request_size()); - EXPECT_EQ(range_requested.start(), - client.partial_loader_data()->open_byte_range().start()); - EXPECT_LE(range_requested.end(), - client.partial_loader_data()->open_byte_range().end()); - client.partial_loader_data()->set_byte_range( - client.partial_loader_data()->open_byte_range()); - } - EXPECT_TRUE(client.partial_loader_data()->IsWaitOpen()); -} - -TEST_F(DocumentLoaderTest, GetBlock) { - char buffer[DocumentLoader::default_request_size()]; - TestClient client; - client.SetCanUsePartialLoading(); - client.full_page_loader_data()->set_content_length( - DocumentLoader::default_request_size() * 20 + 58383); - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - EXPECT_FALSE(loader.GetBlock(0, 1000, buffer)); - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - EXPECT_TRUE(loader.GetBlock(0, 1000, buffer)); - EXPECT_FALSE( - loader.GetBlock(DocumentLoader::default_request_size(), 1500, buffer)); - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - EXPECT_TRUE( - loader.GetBlock(DocumentLoader::default_request_size(), 1500, buffer)); - - EXPECT_FALSE(loader.GetBlock(17 * DocumentLoader::default_request_size(), - 3000, buffer)); - loader.RequestData(17 * DocumentLoader::default_request_size() + 100, 10); - EXPECT_FALSE(loader.GetBlock(17 * DocumentLoader::default_request_size(), - 3000, buffer)); - - // Requests queue is processed only on receiving data. - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - - client.SendAllPartialData(); - EXPECT_TRUE(loader.GetBlock(17 * DocumentLoader::default_request_size(), 3000, - buffer)); -} - -TEST_F(DocumentLoaderTest, IsDataAvailable) { - TestClient client; - client.SetCanUsePartialLoading(); - client.full_page_loader_data()->set_content_length( - DocumentLoader::default_request_size() * 20 + 58383); - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - EXPECT_FALSE(loader.IsDataAvailable(0, 1000)); - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - EXPECT_TRUE(loader.IsDataAvailable(0, 1000)); - EXPECT_FALSE( - loader.IsDataAvailable(DocumentLoader::default_request_size(), 1500)); - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - EXPECT_TRUE( - loader.IsDataAvailable(DocumentLoader::default_request_size(), 1500)); - - EXPECT_FALSE(loader.IsDataAvailable( - 17 * DocumentLoader::default_request_size(), 3000)); - loader.RequestData(17 * DocumentLoader::default_request_size() + 100, 10); - EXPECT_FALSE(loader.IsDataAvailable( - 17 * DocumentLoader::default_request_size(), 3000)); - - // Requests queue is processed only on receiving data. - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - - client.SendAllPartialData(); - EXPECT_TRUE(loader.IsDataAvailable( - 17 * DocumentLoader::default_request_size(), 3000)); -} - -TEST_F(DocumentLoaderTest, RequestData) { - TestClient client; - client.SetCanUsePartialLoading(); - client.full_page_loader_data()->set_content_length( - DocumentLoader::default_request_size() * 100 + 58383); - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - loader.RequestData(37 * DocumentLoader::default_request_size() + 200, 10); - loader.RequestData(25 * DocumentLoader::default_request_size() + 600, 100); - loader.RequestData(13 * DocumentLoader::default_request_size() + 900, 500); - - // Send initial data from FullPageLoader. - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - - { - EXPECT_TRUE(client.partial_loader_data()->IsWaitOpen()); - const gfx::Range range_requested( - 13 * DocumentLoader::default_request_size(), - 14 * DocumentLoader::default_request_size()); - EXPECT_EQ(range_requested.start(), - client.partial_loader_data()->open_byte_range().start()); - EXPECT_LE(range_requested.end(), - client.partial_loader_data()->open_byte_range().end()); - client.partial_loader_data()->set_byte_range( - client.partial_loader_data()->open_byte_range()); - } - client.partial_loader_data()->CallOpenCallback(0); - // Override pending requests. - loader.ClearPendingRequests(); - loader.RequestData(38 * DocumentLoader::default_request_size() + 200, 10); - loader.RequestData(26 * DocumentLoader::default_request_size() + 600, 100); - // Requests queue is processed only on receiving data. - client.partial_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - { - EXPECT_TRUE(client.partial_loader_data()->IsWaitOpen()); - const gfx::Range range_requested( - 26 * DocumentLoader::default_request_size(), - 27 * DocumentLoader::default_request_size()); - EXPECT_EQ(range_requested.start(), - client.partial_loader_data()->open_byte_range().start()); - EXPECT_LE(range_requested.end(), - client.partial_loader_data()->open_byte_range().end()); - client.partial_loader_data()->set_byte_range( - client.partial_loader_data()->open_byte_range()); - } - client.partial_loader_data()->CallOpenCallback(0); - // Override pending requests. - loader.ClearPendingRequests(); - loader.RequestData(39 * DocumentLoader::default_request_size() + 200, 10); - // Requests queue is processed only on receiving data. - client.partial_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - { - EXPECT_TRUE(client.partial_loader_data()->IsWaitOpen()); - const gfx::Range range_requested( - 39 * DocumentLoader::default_request_size(), - 40 * DocumentLoader::default_request_size()); - EXPECT_EQ(range_requested.start(), - client.partial_loader_data()->open_byte_range().start()); - EXPECT_LE(range_requested.end(), - client.partial_loader_data()->open_byte_range().end()); - client.partial_loader_data()->set_byte_range( - client.partial_loader_data()->open_byte_range()); - } - // Fill all gaps. - while (!loader.IsDocumentComplete()) { - client.SendAllPartialData(); - } - EXPECT_TRUE(client.partial_loader_data()->closed()); -} - -TEST_F(DocumentLoaderTest, DoNotLoadAvailablePartialData) { - TestClient client; - client.SetCanUsePartialLoading(); - client.full_page_loader_data()->set_content_length( - DocumentLoader::default_request_size() * 20 + 58383); - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - // Send initial data from FullPageLoader. - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - - // Send more data from FullPageLoader. - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - - loader.RequestData(2 * DocumentLoader::default_request_size() + 200, 10); - - // Send more data from FullPageLoader. - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - - // Partial loading should not have started for already available data. - EXPECT_TRUE(client.partial_loader_data()->closed()); -} - -TEST_F(DocumentLoaderTest, DoNotLoadDataAfterComplete) { - TestClient client; - client.SetCanUsePartialLoading(); - client.full_page_loader_data()->set_content_length( - DocumentLoader::default_request_size() * 20); - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - - for (int i = 0; i < 20; ++i) { - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - } - - EXPECT_TRUE(loader.IsDocumentComplete()); - - loader.RequestData(17 * DocumentLoader::default_request_size() + 200, 10); - - EXPECT_TRUE(client.partial_loader_data()->closed()); - EXPECT_TRUE(client.full_page_loader_data()->closed()); -} - -TEST_F(DocumentLoaderTest, DoNotLoadPartialDataAboveDocumentSize) { - TestClient client; - client.SetCanUsePartialLoading(); - client.full_page_loader_data()->set_content_length( - DocumentLoader::default_request_size() * 20); - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - - loader.RequestData(20 * DocumentLoader::default_request_size() + 200, 10); - - // Send initial data from FullPageLoader. - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - - EXPECT_TRUE(client.partial_loader_data()->closed()); -} - -TEST_F(DocumentLoaderTest, MergePendingRequests) { - TestClient client; - client.SetCanUsePartialLoading(); - client.full_page_loader_data()->set_content_length( - DocumentLoader::default_request_size() * 50 + 58383); - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - loader.RequestData(17 * DocumentLoader::default_request_size() + 200, 10); - loader.RequestData(16 * DocumentLoader::default_request_size() + 600, 100); - - // Send initial data from FullPageLoader. - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - - const gfx::Range range_requested(16 * DocumentLoader::default_request_size(), - 18 * DocumentLoader::default_request_size()); - EXPECT_EQ(range_requested.start(), - client.partial_loader_data()->open_byte_range().start()); - EXPECT_LE(range_requested.end(), - client.partial_loader_data()->open_byte_range().end()); - - EXPECT_TRUE(client.partial_loader_data()->IsWaitOpen()); - - // Fill all gaps. - while (!loader.IsDocumentComplete()) { - client.SendAllPartialData(); - } - EXPECT_TRUE(client.partial_loader_data()->closed()); -} - -TEST_F(DocumentLoaderTest, PartialStopOnStatusCodeError) { - TestClient client; - client.SetCanUsePartialLoading(); - client.full_page_loader_data()->set_content_length( - DocumentLoader::default_request_size() * 20); - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - - loader.RequestData(17 * DocumentLoader::default_request_size() + 200, 10); - - // Send initial data from FullPageLoader. - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - - EXPECT_TRUE(client.partial_loader_data()->IsWaitOpen()); - client.partial_loader_data()->set_status_code(404); - client.partial_loader_data()->CallOpenCallback(0); - EXPECT_TRUE(client.partial_loader_data()->closed()); -} - -TEST_F(DocumentLoaderTest, - PartialAsFullDocumentLoadingRangeRequestNoRangeField) { - TestClient client; - client.SetCanUsePartialLoading(); - client.full_page_loader_data()->set_content_length( - DocumentLoader::default_request_size() * 20); - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - - loader.RequestData(17 * DocumentLoader::default_request_size() + 200, 10); - - // Send initial data from FullPageLoader. - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - - EXPECT_TRUE(client.partial_loader_data()->IsWaitOpen()); - client.partial_loader_data()->set_byte_range(gfx::Range::InvalidRange()); - client.partial_loader_data()->CallOpenCallback(0); - EXPECT_FALSE(client.partial_loader_data()->closed()); - // Partial loader is used to load the whole page, like full page loader. - EXPECT_FALSE(loader.is_partial_loader_active()); -} - -TEST_F(DocumentLoaderTest, PartialMultiPart) { - TestClient client; - client.SetCanUsePartialLoading(); - client.full_page_loader_data()->set_content_length( - DocumentLoader::default_request_size() * 20); - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - - loader.RequestData(17 * DocumentLoader::default_request_size() + 200, 10); - - // Send initial data from FullPageLoader. - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - - EXPECT_TRUE(client.partial_loader_data()->IsWaitOpen()); - client.partial_loader_data()->set_is_multipart(true); - client.partial_loader_data()->CallOpenCallback(0); - client.partial_loader_data()->set_byte_range( - gfx::Range(17 * DocumentLoader::default_request_size(), - 18 * DocumentLoader::default_request_size())); - client.partial_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - EXPECT_TRUE( - loader.IsDataAvailable(17 * DocumentLoader::default_request_size(), - DocumentLoader::default_request_size())); -} - -TEST_F(DocumentLoaderTest, PartialMultiPartRangeError) { - TestClient client; - client.SetCanUsePartialLoading(); - client.full_page_loader_data()->set_content_length( - DocumentLoader::default_request_size() * 20); - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - - loader.RequestData(17 * DocumentLoader::default_request_size() + 200, 10); - - // Send initial data from FullPageLoader. - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - - EXPECT_TRUE(client.partial_loader_data()->IsWaitOpen()); - client.partial_loader_data()->set_is_multipart(true); - client.partial_loader_data()->CallOpenCallback(0); - client.partial_loader_data()->set_byte_range(gfx::Range::InvalidRange()); - client.partial_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - EXPECT_FALSE( - loader.IsDataAvailable(17 * DocumentLoader::default_request_size(), - DocumentLoader::default_request_size())); - EXPECT_TRUE(client.partial_loader_data()->closed()); -} - -TEST_F(DocumentLoaderTest, PartialConnectionErrorOnOpen) { - TestClient client; - client.SetCanUsePartialLoading(); - client.full_page_loader_data()->set_content_length( - DocumentLoader::default_request_size() * 20); - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - - loader.RequestData(17 * DocumentLoader::default_request_size() + 200, 10); - - // Send initial data from FullPageLoader. - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - - EXPECT_TRUE(client.partial_loader_data()->IsWaitOpen()); - client.partial_loader_data()->CallOpenCallback(-3); - EXPECT_TRUE(client.partial_loader_data()->closed()); - - // Partial loading should not restart after any error. - loader.RequestData(18 * DocumentLoader::default_request_size() + 200, 10); - - EXPECT_FALSE(client.partial_loader_data()->IsWaitOpen()); - EXPECT_TRUE(client.partial_loader_data()->closed()); -} - -TEST_F(DocumentLoaderTest, PartialConnectionErrorOnRead) { - TestClient client; - client.SetCanUsePartialLoading(); - client.full_page_loader_data()->set_content_length( - DocumentLoader::default_request_size() * 20); - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - - loader.RequestData(17 * DocumentLoader::default_request_size() + 200, 10); - - // Send initial data from FullPageLoader. - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - - EXPECT_TRUE(client.partial_loader_data()->IsWaitOpen()); - client.partial_loader_data()->set_byte_range( - gfx::Range(17 * DocumentLoader::default_request_size(), - 18 * DocumentLoader::default_request_size())); - client.partial_loader_data()->CallOpenCallback(0); - EXPECT_TRUE(client.partial_loader_data()->IsWaitRead()); - client.partial_loader_data()->CallReadCallback(-3); - EXPECT_TRUE(client.partial_loader_data()->closed()); - - // Partial loading should not restart after any error. - loader.RequestData(18 * DocumentLoader::default_request_size() + 200, 10); - - EXPECT_FALSE(client.partial_loader_data()->IsWaitOpen()); - EXPECT_TRUE(client.partial_loader_data()->closed()); -} - -TEST_F(DocumentLoaderTest, GetProgress) { - TestClient client; - client.SetCanUsePartialLoading(); - client.full_page_loader_data()->set_content_length( - DocumentLoader::default_request_size() * 20); - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - EXPECT_EQ(0., loader.GetProgress()); - - for (int i = 0; i < 20; ++i) { - EXPECT_EQ(i * 100 / 20, static_cast(loader.GetProgress() * 100)); - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - } - EXPECT_EQ(1., loader.GetProgress()); -} - -TEST_F(DocumentLoaderTest, GetProgressNoContentLength) { - TestClient client; - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - EXPECT_EQ(-1., loader.GetProgress()); - - for (int i = 0; i < 20; ++i) { - EXPECT_EQ(-1., loader.GetProgress()); - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - } - client.full_page_loader_data()->CallReadCallback(0); - EXPECT_EQ(1., loader.GetProgress()); -} - -TEST_F(DocumentLoaderTest, ClientCompleteCallbacks) { - MockClient client; - client.SetCanUsePartialLoading(); - client.full_page_loader_data()->set_content_length( - DocumentLoader::default_request_size() * 20); - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - - EXPECT_CALL(client, OnDocumentComplete()).Times(0); - for (int i = 0; i < 19; ++i) { - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - } - Mock::VerifyAndClear(&client); - - EXPECT_CALL(client, OnDocumentComplete()).Times(1); - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - Mock::VerifyAndClear(&client); -} - -TEST_F(DocumentLoaderTest, ClientCompleteCallbacksNoContentLength) { - MockClient client; - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - - EXPECT_CALL(client, OnDocumentCanceled()).Times(0); - EXPECT_CALL(client, OnDocumentComplete()).Times(0); - for (int i = 0; i < 20; ++i) { - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - } - Mock::VerifyAndClear(&client); - - EXPECT_CALL(client, OnDocumentCanceled()).Times(0); - EXPECT_CALL(client, OnDocumentComplete()).Times(1); - client.full_page_loader_data()->CallReadCallback(0); - Mock::VerifyAndClear(&client); -} - -TEST_F(DocumentLoaderTest, ClientCancelCallback) { - MockClient client; - client.SetCanUsePartialLoading(); - client.full_page_loader_data()->set_content_length( - DocumentLoader::default_request_size() * 20); - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - - EXPECT_CALL(client, OnDocumentCanceled()).Times(0); - EXPECT_CALL(client, OnDocumentComplete()).Times(0); - for (int i = 0; i < 10; ++i) { - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - } - Mock::VerifyAndClear(&client); - - EXPECT_CALL(client, OnDocumentComplete()).Times(0); - EXPECT_CALL(client, OnDocumentCanceled()).Times(1); - client.full_page_loader_data()->CallReadCallback(-3); - Mock::VerifyAndClear(&client); -} - -TEST_F(DocumentLoaderTest, NewDataAvailable) { - MockClient client; - client.SetCanUsePartialLoading(); - client.full_page_loader_data()->set_content_length( - DocumentLoader::default_request_size() * 20); - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - - EXPECT_CALL(client, OnNewDataAvailable()).Times(1); - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - Mock::VerifyAndClear(&client); - - EXPECT_CALL(client, OnNewDataAvailable()).Times(0); - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size() - 100); - Mock::VerifyAndClear(&client); - - EXPECT_CALL(client, OnNewDataAvailable()).Times(1); - client.full_page_loader_data()->CallReadCallback(100); - Mock::VerifyAndClear(&client); -} - -TEST_F(DocumentLoaderTest, ClientPendingRequestCompleteFullLoader) { - MockClient client; - client.SetCanUsePartialLoading(); - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - - loader.RequestData(1000, 4000); - - EXPECT_CALL(client, OnPendingRequestComplete()).Times(1); - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - Mock::VerifyAndClear(&client); -} - -TEST_F(DocumentLoaderTest, ClientPendingRequestCompletePartialLoader) { - MockClient client; - client.SetCanUsePartialLoading(); - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - - EXPECT_CALL(client, OnPendingRequestComplete()).Times(1); - loader.RequestData(15 * DocumentLoader::default_request_size() + 4000, 4000); - - // Always send initial data from FullPageLoader. - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - - client.SendAllPartialData(); - Mock::VerifyAndClear(&client); -} - -TEST_F(DocumentLoaderTest, ClientPendingRequestCompletePartialAndFullLoader) { - MockClient client; - client.SetCanUsePartialLoading(); - DocumentLoader loader(&client); - loader.Init(client.CreateFullPageLoader(), "http://url.com"); - - EXPECT_CALL(client, OnPendingRequestComplete()).Times(1); - loader.RequestData(16 * DocumentLoader::default_request_size() + 4000, 4000); - loader.RequestData(4 * DocumentLoader::default_request_size() + 4000, 4000); - - for (int i = 0; i < 5; ++i) { - client.full_page_loader_data()->CallReadCallback( - DocumentLoader::default_request_size()); - } - - Mock::VerifyAndClear(&client); - - EXPECT_CALL(client, OnPendingRequestComplete()).Times(1); - client.SendAllPartialData(); - Mock::VerifyAndClear(&client); -} - -} // namespace chrome_pdf diff --git a/pdf/out_of_process_instance.cc b/pdf/out_of_process_instance.cc index eb1c17a022a4d6..981bfaf8d3753d 100644 --- a/pdf/out_of_process_instance.cc +++ b/pdf/out_of_process_instance.cc @@ -855,6 +855,15 @@ void OutOfProcessInstance::DidOpen(int32_t result) { NOTREACHED(); DocumentLoadFailed(); } + + // If it's a progressive load, cancel the stream URL request so that requests + // can be made on the original URL. + // TODO(raymes): Make this clearer once the in-process plugin is deleted. + if (engine_->IsProgressiveLoad()) { + pp::VarDictionary message; + message.Set(kType, kJSCancelStreamUrlType); + PostMessage(message); + } } void OutOfProcessInstance::DidOpenPreview(int32_t result) { @@ -1492,12 +1501,6 @@ uint32_t OutOfProcessInstance::GetBackgroundColor() { return background_color_; } -void OutOfProcessInstance::CancelBrowserDownload() { - pp::VarDictionary message; - message.Set(kType, kJSCancelStreamUrlType); - PostMessage(message); -} - void OutOfProcessInstance::IsSelectingChanged(bool is_selecting) { pp::VarDictionary message; message.Set(kType, kJSSetIsSelectingType); diff --git a/pdf/out_of_process_instance.h b/pdf/out_of_process_instance.h index e2c0eacfde3204..0e2e69ea36f031 100644 --- a/pdf/out_of_process_instance.h +++ b/pdf/out_of_process_instance.h @@ -135,7 +135,6 @@ class OutOfProcessInstance : public pp::Instance, void FormTextFieldFocusChange(bool in_focus) override; bool IsPrintPreview() override; uint32_t GetBackgroundColor() override; - void CancelBrowserDownload() override; void IsSelectingChanged(bool is_selecting) override; // PreviewModeClient::Client implementation. diff --git a/pdf/pdf_engine.h b/pdf/pdf_engine.h index 334e2cc5ed5467..a394d0271f2d94 100644 --- a/pdf/pdf_engine.h +++ b/pdf/pdf_engine.h @@ -186,9 +186,6 @@ class PDFEngine { // Get the background color of the PDF. virtual uint32_t GetBackgroundColor() = 0; - // Cancel browser initiated document download. - virtual void CancelBrowserDownload() = 0; - // Sets selection status. virtual void IsSelectingChanged(bool is_selecting) {} }; @@ -301,6 +298,8 @@ class PDFEngine { virtual void SetScrollPosition(const pp::Point& position) = 0; #endif + virtual bool IsProgressiveLoad() = 0; + virtual std::string GetMetadata(const std::string& key) = 0; }; diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc index b3386d3f3ed9e3..cd0b6c61fbba12 100644 --- a/pdf/pdfium/pdfium_engine.cc +++ b/pdf/pdfium/pdfium_engine.cc @@ -17,7 +17,6 @@ #include "base/lazy_instance.h" #include "base/logging.h" #include "base/macros.h" -#include "base/memory/ptr_util.h" #include "base/numerics/safe_conversions.h" #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" @@ -31,7 +30,6 @@ #include "pdf/pdfium/pdfium_api_string_buffer_adapter.h" #include "pdf/pdfium/pdfium_mem_buffer_file_read.h" #include "pdf/pdfium/pdfium_mem_buffer_file_write.h" -#include "pdf/url_loader_wrapper_impl.h" #include "ppapi/c/pp_errors.h" #include "ppapi/c/pp_input_event.h" #include "ppapi/c/ppb_core.h" @@ -539,6 +537,7 @@ PDFiumEngine::PDFiumEngine(PDFEngine::Client* client) : client_(client), current_zoom_(1.0), current_rotation_(0), + doc_loader_(this), password_tries_remaining_(0), doc_(nullptr), form_(nullptr), @@ -565,15 +564,15 @@ PDFiumEngine::PDFiumEngine(PDFEngine::Client* client) file_access_.m_FileLen = 0; file_access_.m_GetBlock = &GetBlock; - file_access_.m_Param = this; + file_access_.m_Param = &doc_loader_; file_availability_.version = 1; file_availability_.IsDataAvail = &IsDataAvail; - file_availability_.engine = this; + file_availability_.loader = &doc_loader_; download_hints_.version = 1; download_hints_.AddSegment = &AddSegment; - download_hints_.engine = this; + download_hints_.loader = &doc_loader_; // Initialize FPDF_FORMFILLINFO member variables. Deriving from this struct // allows the static callbacks to be able to cast the FPDF_FORMFILLINFO in @@ -843,22 +842,22 @@ int PDFiumEngine::Form_GetLanguage(FPDF_FORMFILLINFO* param, int PDFiumEngine::GetBlock(void* param, unsigned long position, unsigned char* buffer, unsigned long size) { - PDFiumEngine* engine = static_cast(param); - return engine->doc_loader_->GetBlock(position, size, buffer); + DocumentLoader* loader = static_cast(param); + return loader->GetBlock(position, size, buffer); } FPDF_BOOL PDFiumEngine::IsDataAvail(FX_FILEAVAIL* param, size_t offset, size_t size) { PDFiumEngine::FileAvail* file_avail = static_cast(param); - return file_avail->engine->doc_loader_->IsDataAvailable(offset, size); + return file_avail->loader->IsDataAvailable(offset, size); } void PDFiumEngine::AddSegment(FX_DOWNLOADHINTS* param, size_t offset, size_t size) { PDFiumEngine::DownloadHints* download_hints = static_cast(param); - return download_hints->engine->doc_loader_->RequestData(offset, size); + return download_hints->loader->RequestData(offset, size); } bool PDFiumEngine::New(const char* url, @@ -993,27 +992,15 @@ void PDFiumEngine::PostPaint() { bool PDFiumEngine::HandleDocumentLoad(const pp::URLLoader& loader) { password_tries_remaining_ = kMaxPasswordTries; - process_when_pending_request_complete_ = true; - auto loader_wrapper = - base::MakeUnique(GetPluginInstance(), loader); - loader_wrapper->SetResponseHeaders(headers_); - - doc_loader_ = base::MakeUnique(this); - if (doc_loader_->Init(std::move(loader_wrapper), url_)) { - // request initial data. - doc_loader_->RequestData(0, 1); - return true; - } - return false; + return doc_loader_.Init(loader, url_, headers_); } pp::Instance* PDFiumEngine::GetPluginInstance() { return client_->GetPluginInstance(); } -std::unique_ptr PDFiumEngine::CreateURLLoader() { - return base::MakeUnique(GetPluginInstance(), - client_->CreateURLLoader()); +pp::URLLoader PDFiumEngine::CreateURLLoader() { + return client_->CreateURLLoader(); } void PDFiumEngine::AppendPage(PDFEngine* engine, int index) { @@ -1038,32 +1025,35 @@ void PDFiumEngine::SetScrollPosition(const pp::Point& position) { } #endif +bool PDFiumEngine::IsProgressiveLoad() { + return doc_loader_.is_partial_document(); +} + std::string PDFiumEngine::GetMetadata(const std::string& key) { return GetDocumentMetadata(doc(), key); } -void PDFiumEngine::OnPendingRequestComplete() { - if (!process_when_pending_request_complete_) - return; +void PDFiumEngine::OnPartialDocumentLoaded() { + file_access_.m_FileLen = doc_loader_.document_size(); if (!fpdf_availability_) { - file_access_.m_FileLen = doc_loader_->GetDocumentSize(); fpdf_availability_ = FPDFAvail_Create(&file_availability_, &file_access_); DCHECK(fpdf_availability_); - // Currently engine does not deal efficiently with some non-linearized - // files. - // See http://code.google.com/p/chromium/issues/detail?id=59400 - // To improve user experience we download entire file for non-linearized - // PDF. - if (FPDFAvail_IsLinearized(fpdf_availability_) != PDF_LINEARIZED) { - // Wait complete document. - process_when_pending_request_complete_ = false; - FPDFAvail_Destroy(fpdf_availability_); - fpdf_availability_ = nullptr; - return; - } } - if (!doc_) { + // Currently engine does not deal efficiently with some non-linearized files. + // See http://code.google.com/p/chromium/issues/detail?id=59400 + // To improve user experience we download entire file for non-linearized PDF. + if (!FPDFAvail_IsLinearized(fpdf_availability_)) { + doc_loader_.RequestData(0, doc_loader_.document_size()); + return; + } + + LoadDocument(); +} + +void PDFiumEngine::OnPendingRequestComplete() { + if (!doc_ || !form_) { + DCHECK(fpdf_availability_); LoadDocument(); return; } @@ -1085,51 +1075,26 @@ void PDFiumEngine::OnPendingRequestComplete() { } void PDFiumEngine::OnNewDataAvailable() { - const float progress = doc_loader_->GetProgress(); - if (progress < 0.001) { - client_->DocumentLoadProgress(0, 0); - } else { - client_->DocumentLoadProgress(progress * 10000, 10000); - } + client_->DocumentLoadProgress(doc_loader_.GetAvailableData(), + doc_loader_.document_size()); } void PDFiumEngine::OnDocumentComplete() { - if (doc_) { - return FinishLoadingDocument(); - } - file_access_.m_FileLen = doc_loader_->GetDocumentSize(); - if (!fpdf_availability_) { - fpdf_availability_ = FPDFAvail_Create(&file_availability_, &file_access_); - DCHECK(fpdf_availability_); + if (!doc_ || !form_) { + file_access_.m_FileLen = doc_loader_.document_size(); + if (!fpdf_availability_) { + fpdf_availability_ = FPDFAvail_Create(&file_availability_, &file_access_); + DCHECK(fpdf_availability_); + } + LoadDocument(); + return; } - LoadDocument(); -} -void PDFiumEngine::OnDocumentCanceled() { - OnDocumentComplete(); -} - -void PDFiumEngine::CancelBrowserDownload() { - client_->CancelBrowserDownload(); + FinishLoadingDocument(); } void PDFiumEngine::FinishLoadingDocument() { - DCHECK(doc_loader_->IsDocumentComplete() && doc_); - - if (!form_) { - int form_status = - FPDFAvail_IsFormAvail(fpdf_availability_, &download_hints_); - if (form_status != PDF_FORM_NOTAVAIL) { - form_ = FPDFDOC_InitFormFillEnvironment( - doc_, static_cast(this)); -#if defined(PDF_ENABLE_XFA) - FPDF_LoadXFA(doc_); -#endif - - FPDF_SetFormFieldHighlightColor(form_, 0, kFormHighlightColor); - FPDF_SetFormFieldHighlightAlpha(form_, kFormHighlightAlpha); - } - } + DCHECK(doc_loader_.IsDocumentComplete() && doc_); bool need_update = false; for (size_t i = 0; i < pages_.size(); ++i) { @@ -1341,7 +1306,7 @@ pp::Buffer_Dev PDFiumEngine::PrintPagesAsRasterPDF( return pp::Buffer_Dev(); // If document is not downloaded yet, disable printing. - if (doc_ && !doc_loader_->IsDocumentComplete()) + if (doc_ && !doc_loader_.IsDocumentComplete()) return pp::Buffer_Dev(); FPDF_DOCUMENT output_doc = FPDF_CreateNewDocument(); @@ -2485,7 +2450,7 @@ void PDFiumEngine::AppendBlankPages(int num_pages) { void PDFiumEngine::LoadDocument() { // Check if the document is ready for loading. If it isn't just bail for now, // we will call LoadDocument() again later. - if (!doc_ && !doc_loader_->IsDocumentComplete() && + if (!doc_ && !doc_loader_.IsDocumentComplete() && !FPDFAvail_IsDocAvail(fpdf_availability_, &download_hints_)) { return; } @@ -2524,7 +2489,7 @@ bool PDFiumEngine::TryLoadingDoc(const std::string& password, password_cstr = password.c_str(); password_tries_remaining_--; } - if (doc_loader_->IsDocumentComplete() && + if (doc_loader_.IsDocumentComplete() && !FPDFAvail_IsLinearized(fpdf_availability_)) { doc_ = FPDF_LoadCustomDocument(&file_access_, password_cstr); } else { @@ -2582,7 +2547,26 @@ void PDFiumEngine::ContinueLoadingDocument(const std::string& password) { permissions_ = FPDF_GetDocPermissions(doc_); permissions_handler_revision_ = FPDF_GetSecurityHandlerRevision(doc_); - if (!doc_loader_->IsDocumentComplete()) { + if (!form_) { + int form_status = + FPDFAvail_IsFormAvail(fpdf_availability_, &download_hints_); + bool doc_complete = doc_loader_.IsDocumentComplete(); + // Try again if the data is not available and the document hasn't finished + // downloading. + if (form_status == PDF_FORM_NOTAVAIL && !doc_complete) + return; + + form_ = FPDFDOC_InitFormFillEnvironment( + doc_, static_cast(this)); +#if defined(PDF_ENABLE_XFA) + FPDF_LoadXFA(doc_); +#endif + + FPDF_SetFormFieldHighlightColor(form_, 0, kFormHighlightColor); + FPDF_SetFormFieldHighlightAlpha(form_, kFormHighlightAlpha); + } + + if (!doc_loader_.IsDocumentComplete()) { // Check if the first page is available. In a linearized PDF, that is not // always page 0. Doing this gives us the default page size, since when the // document is available, the first page is available as well. @@ -2591,7 +2575,7 @@ void PDFiumEngine::ContinueLoadingDocument(const std::string& password) { LoadPageInfo(false); - if (doc_loader_->IsDocumentComplete()) + if (doc_loader_.IsDocumentComplete()) FinishLoadingDocument(); } @@ -2601,7 +2585,7 @@ void PDFiumEngine::LoadPageInfo(bool reload) { document_size_ = pp::Size(); std::vector page_rects; int page_count = FPDF_GetPageCount(doc_); - bool doc_complete = doc_loader_->IsDocumentComplete(); + bool doc_complete = doc_loader_.IsDocumentComplete(); bool is_linear = FPDFAvail_IsLinearized(fpdf_availability_) == PDF_LINEARIZED; for (int i = 0; i < page_count; ++i) { if (i != 0) { @@ -2658,12 +2642,10 @@ void PDFiumEngine::LoadPageInfo(bool reload) { } void PDFiumEngine::CalculateVisiblePages() { - if (!doc_loader_) - return; // Clear pending requests queue, since it may contain requests to the pages // that are already invisible (after scrolling for example). pending_pages_.clear(); - doc_loader_->ClearPendingRequests(); + doc_loader_.ClearPendingRequests(); visible_pages_.clear(); pp::Rect visible_rect(plugin_size_); @@ -2724,7 +2706,7 @@ void PDFiumEngine::ScrollToPage(int page) { } bool PDFiumEngine::CheckPageAvailable(int index, std::vector* pending) { - if (!doc_) + if (!doc_ || !form_) return false; const int num_pages = static_cast(pages_.size()); diff --git a/pdf/pdfium/pdfium_engine.h b/pdf/pdfium/pdfium_engine.h index 0334a602433e80..8f8609ad623b15 100644 --- a/pdf/pdfium/pdfium_engine.h +++ b/pdf/pdfium/pdfium_engine.h @@ -108,16 +108,16 @@ class PDFiumEngine : public PDFEngine, #if defined(PDF_ENABLE_XFA) void SetScrollPosition(const pp::Point& position) override; #endif + bool IsProgressiveLoad() override; std::string GetMetadata(const std::string& key) override; // DocumentLoader::Client implementation. pp::Instance* GetPluginInstance() override; - std::unique_ptr CreateURLLoader() override; + pp::URLLoader CreateURLLoader() override; + void OnPartialDocumentLoaded() override; void OnPendingRequestComplete() override; void OnNewDataAvailable() override; void OnDocumentComplete() override; - void OnDocumentCanceled() override; - void CancelBrowserDownload() override; void UnsupportedFeature(int type); void FontSubstituted(); @@ -191,11 +191,11 @@ class PDFiumEngine : public PDFEngine, friend class SelectionChangeInvalidator; struct FileAvail : public FX_FILEAVAIL { - PDFiumEngine* engine; + DocumentLoader* loader; }; struct DownloadHints : public FX_DOWNLOADHINTS { - PDFiumEngine* engine; + DocumentLoader* loader; }; // PDFium interface to get block of data. @@ -602,7 +602,7 @@ class PDFiumEngine : public PDFEngine, double current_zoom_; unsigned int current_rotation_; - std::unique_ptr doc_loader_; // Main document's loader. + DocumentLoader doc_loader_; // Main document's loader. std::string url_; std::string headers_; pp::CompletionCallbackFactory find_factory_; @@ -731,11 +731,6 @@ class PDFiumEngine : public PDFEngine, // to false after the user finishes getting their password. bool getting_password_; - // While true, the document try to be opened and parsed after download each - // part. Else the document will be opened and parsed only on finish of - // downloading. - bool process_when_pending_request_complete_ = true; - DISALLOW_COPY_AND_ASSIGN(PDFiumEngine); }; diff --git a/pdf/preview_mode_client.cc b/pdf/preview_mode_client.cc index ec139d3c020dfe..b3744c93eb7ac8 100644 --- a/pdf/preview_mode_client.cc +++ b/pdf/preview_mode_client.cc @@ -162,8 +162,6 @@ bool PreviewModeClient::IsPrintPreview() { return false; } -void PreviewModeClient::CancelBrowserDownload() {} - uint32_t PreviewModeClient::GetBackgroundColor() { NOTREACHED(); return 0; diff --git a/pdf/preview_mode_client.h b/pdf/preview_mode_client.h index 0874325e4b6977..676d7189161217 100644 --- a/pdf/preview_mode_client.h +++ b/pdf/preview_mode_client.h @@ -71,7 +71,6 @@ class PreviewModeClient : public PDFEngine::Client { void DocumentLoadProgress(uint32_t available, uint32_t doc_size) override; void FormTextFieldFocusChange(bool in_focus) override; bool IsPrintPreview() override; - void CancelBrowserDownload() override; uint32_t GetBackgroundColor() override; private: diff --git a/pdf/range_set.cc b/pdf/range_set.cc deleted file mode 100644 index df53d660023e5f..00000000000000 --- a/pdf/range_set.cc +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "pdf/range_set.h" - -#include -#include -#include - -namespace chrome_pdf { - -namespace { - -gfx::Range FixDirection(const gfx::Range& range) { - if (!range.IsValid() || !range.is_reversed()) - return range; - return gfx::Range(range.end() + 1, range.start() + 1); -} - -} // namespace - -RangeSet::RangeSet() {} - -RangeSet::RangeSet(const gfx::Range& range) { - Union(range); -} - -RangeSet::RangeSet(const RangeSet& range_set) : ranges_(range_set.ranges_) {} - -RangeSet::RangeSet(RangeSet&& range_set) - : ranges_(std::move(range_set.ranges_)) {} - -RangeSet& RangeSet::operator=(const RangeSet& other) { - ranges_ = other.ranges_; - return *this; -} - -RangeSet::~RangeSet() {} - -bool RangeSet::operator==(const RangeSet& other) const { - return other.ranges_ == ranges_; -} - -bool RangeSet::operator!=(const RangeSet& other) const { - return other.ranges_ != ranges_; -} - -void RangeSet::Union(const gfx::Range& range) { - if (range.is_empty()) - return; - gfx::Range fixed_range = FixDirection(range); - if (IsEmpty()) { - ranges_.insert(fixed_range); - return; - } - - auto start = ranges_.upper_bound(fixed_range); - if (start != ranges_.begin()) - --start; // start now points to the key equal or lower than offset. - if (start->end() < fixed_range.start()) - ++start; // start element is entirely before current range, skip it. - - auto end = ranges_.upper_bound(gfx::Range(fixed_range.end())); - if (start == end) { // No ranges to merge. - ranges_.insert(fixed_range); - return; - } - - --end; - - int new_start = std::min(start->start(), fixed_range.start()); - int new_end = std::max(end->end(), fixed_range.end()); - - ranges_.erase(start, ++end); - ranges_.insert(gfx::Range(new_start, new_end)); -} - -void RangeSet::Union(const RangeSet& range_set) { - if (&range_set == this) - return; - for (const auto& it : range_set.ranges()) { - Union(it); - } -} - -bool RangeSet::Contains(uint32_t point) const { - return Contains(gfx::Range(point, point + 1)); -} - -bool RangeSet::Contains(const gfx::Range& range) const { - if (range.is_empty()) - return false; - const gfx::Range fixed_range = FixDirection(range); - auto it = ranges().upper_bound(fixed_range); - if (it == ranges().begin()) - return false; // No ranges includes range.start(). - - --it; // Now it starts equal or before range.start(). - return it->end() >= fixed_range.end(); -} - -bool RangeSet::Contains(const RangeSet& range_set) const { - for (const auto& it : range_set.ranges()) { - if (!Contains(it)) - return false; - } - return true; -} - -bool RangeSet::Intersects(const gfx::Range& range) const { - if (IsEmpty() || range.is_empty()) - return false; - const gfx::Range fixed_range = FixDirection(range); - auto start = ranges_.upper_bound(fixed_range); - if (start != ranges_.begin()) { - --start; - } - // start now points to the key equal or lower than range.start(). - if (start->end() < range.start()) { - // start element is entirely before current range, skip it. - ++start; - } - auto end = ranges_.upper_bound(gfx::Range(fixed_range.end())); - for (auto it = start; it != end; ++it) { - if (fixed_range.end() > it->start() && fixed_range.start() < it->end()) - return true; - } - return false; -} - -bool RangeSet::Intersects(const RangeSet& range_set) const { - for (const auto& it : range_set.ranges()) { - if (Intersects(it)) - return true; - } - return false; -} - -void RangeSet::Intersect(const gfx::Range& range) { - Intersect(RangeSet(range)); -} - -void RangeSet::Intersect(const RangeSet& range_set) { - if (IsEmpty()) - return; - RangesContainer new_ranges; - for (const auto& range : range_set.ranges()) { - auto start = ranges_.upper_bound(range); - if (start != ranges_.begin()) - --start; // start now points to the key equal or lower than - // range.start(). - if (start->end() < range.start()) - ++start; // start element is entirely before current range, skip it. - auto end = ranges_.upper_bound(gfx::Range(range.end())); - if (start == end) { // No data in the current range available. - continue; - } - for (auto it = start; it != end; ++it) { - const gfx::Range new_range = range.Intersect(*it); - if (!new_range.is_empty()) { - new_ranges.insert(new_range); - } - } - } - new_ranges.swap(ranges_); -} - -void RangeSet::Subtract(const gfx::Range& range) { - if (range.is_empty() || IsEmpty()) - return; - const gfx::Range fixed_range = FixDirection(range); - auto start = ranges_.upper_bound(fixed_range); - if (start != ranges_.begin()) - --start; // start now points to the key equal or lower than - // range.start(). - if (start->end() < fixed_range.start()) - ++start; // start element is entirely before current range, skip it. - auto end = ranges_.upper_bound(gfx::Range(fixed_range.end())); - if (start == end) { // No data in the current range available. - return; - } - std::vector new_ranges; - for (auto it = start; it != end; ++it) { - const gfx::Range left(it->start(), - std::min(it->end(), fixed_range.start())); - const gfx::Range right(std::max(it->start(), fixed_range.end()), it->end()); - if (!left.is_empty() && !left.is_reversed()) { - new_ranges.push_back(left); - } - if (!right.is_empty() && !right.is_reversed() && right != left) { - new_ranges.push_back(right); - } - } - ranges_.erase(start, end); - for (const auto& it : new_ranges) { - ranges_.insert(it); - } -} - -void RangeSet::Subtract(const RangeSet& range_set) { - if (&range_set == this) { - ranges_.clear(); - return; - } - for (const auto& range : range_set.ranges()) { - Subtract(range); - } -} - -void RangeSet::Xor(const gfx::Range& range) { - Xor(RangeSet(range)); -} - -void RangeSet::Xor(const RangeSet& range_set) { - RangeSet tmp = *this; - tmp.Intersect(range_set); - Union(range_set); - Subtract(tmp); -} - -bool RangeSet::IsEmpty() const { - return ranges().empty(); -} - -void RangeSet::Clear() { - ranges_.clear(); -} - -gfx::Range RangeSet::First() const { - return *ranges().begin(); -} - -gfx::Range RangeSet::Last() const { - return *ranges().rbegin(); -} - -std::string RangeSet::ToString() const { - std::stringstream ss; - ss << "{"; - for (const auto& it : ranges()) { - ss << "[" << it.start() << "," << it.end() << ")"; - } - ss << "}"; - return ss.str(); -} - -} // namespace chrome_pdf - -std::ostream& operator<<(std::ostream& os, - const chrome_pdf::RangeSet& range_set) { - return (os << range_set.ToString()); -} diff --git a/pdf/range_set.h b/pdf/range_set.h deleted file mode 100644 index b615999285a5ac..00000000000000 --- a/pdf/range_set.h +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Defines a set of geometric ranges, and standard operations on it. - -#ifndef PDF_RANGE_SET_H_ -#define PDF_RANGE_SET_H_ - -#include -#include -#include - -#include "ui/gfx/range/range.h" - -namespace chrome_pdf { - -class RangeSet { - public: - RangeSet(); - explicit RangeSet(const gfx::Range& range); - ~RangeSet(); - - RangeSet(const RangeSet& range_set); - RangeSet(RangeSet&& range_set); - RangeSet& operator=(const RangeSet& other); - - bool operator==(const RangeSet& other) const; - bool operator!=(const RangeSet& other) const; - - bool Contains(uint32_t point) const; - bool Contains(const gfx::Range& range) const; - bool Contains(const RangeSet& range_set) const; - - bool Intersects(const gfx::Range& range) const; - bool Intersects(const RangeSet& range_set) const; - - void Union(const gfx::Range& range); - void Union(const RangeSet& range_set); - - void Intersect(const gfx::Range& range); - void Intersect(const RangeSet& range_set); - - void Subtract(const gfx::Range& range); - void Subtract(const RangeSet& range_set); - - void Xor(const gfx::Range& range); - void Xor(const RangeSet& range_set); - - bool IsEmpty() const; - void Clear(); - - gfx::Range First() const; - gfx::Range Last() const; - std::string ToString() const; - - struct range_compare { - bool operator()(const gfx::Range& lval, const gfx::Range& rval) const { - return lval.start() < rval.start(); - } - }; - - using RangesContainer = std::set; - - const RangesContainer& ranges() const { return ranges_; } - size_t Size() const { return ranges_.size(); } - - private: - RangesContainer ranges_; -}; - -} // namespace chrome_pdf - -std::ostream& operator<<(std::ostream& os, - const chrome_pdf::RangeSet& range_set); - -#endif // PDF_RANGE_SET_H_ diff --git a/pdf/range_set_unittest.cc b/pdf/range_set_unittest.cc deleted file mode 100644 index 75047dd5ac91cc..00000000000000 --- a/pdf/range_set_unittest.cc +++ /dev/null @@ -1,303 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "pdf/range_set.h" - -#include "testing/gtest/include/gtest/gtest.h" - -namespace chrome_pdf { - -TEST(RangeSetTest, Union) { - { - RangeSet range_set; - EXPECT_EQ("{}", range_set.ToString()); - range_set.Union(gfx::Range(50, 100)); - EXPECT_EQ("{[50,100)}", range_set.ToString()); - range_set.Union(gfx::Range(80, 150)); - EXPECT_EQ("{[50,150)}", range_set.ToString()); - range_set.Union(gfx::Range(0, 70)); - EXPECT_EQ("{[0,150)}", range_set.ToString()); - range_set.Union(gfx::Range(70, 120)); - EXPECT_EQ("{[0,150)}", range_set.ToString()); - range_set.Union(gfx::Range(200, 150)); - EXPECT_EQ("{[0,150)[151,201)}", range_set.ToString()); - range_set.Union(gfx::Range(150, 151)); - EXPECT_EQ("{[0,201)}", range_set.ToString()); - range_set.Union(gfx::Range(0, 300)); - EXPECT_EQ("{[0,300)}", range_set.ToString()); - range_set.Union(gfx::Range(500, 600)); - EXPECT_EQ("{[0,300)[500,600)}", range_set.ToString()); - } - { - RangeSet range_set_1; - range_set_1.Union(gfx::Range(0, 10)); - range_set_1.Union(gfx::Range(20, 30)); - range_set_1.Union(gfx::Range(40, 50)); - - EXPECT_EQ("{[0,10)[20,30)[40,50)}", range_set_1.ToString()); - range_set_1.Union(range_set_1); - EXPECT_EQ("{[0,10)[20,30)[40,50)}", range_set_1.ToString()); - - RangeSet range_set_2; - range_set_2.Union(gfx::Range(10, 20)); - range_set_2.Union(gfx::Range(30, 40)); - range_set_2.Union(gfx::Range(50, 60)); - - EXPECT_EQ("{[10,20)[30,40)[50,60)}", range_set_2.ToString()); - range_set_1.Union(range_set_2); - EXPECT_EQ("{[0,60)}", range_set_1.ToString()); - EXPECT_EQ(RangeSet(gfx::Range(0, 60)), range_set_1); - } -} - -TEST(RangeSetTest, Contains) { - RangeSet range_set; - range_set.Union(gfx::Range(10, 20)); - range_set.Union(gfx::Range(30, 40)); - range_set.Union(gfx::Range(50, 60)); - EXPECT_TRUE(range_set.Contains(range_set)); - - { - EXPECT_FALSE(range_set.Contains(9)); - EXPECT_FALSE(range_set.Contains(29)); - EXPECT_FALSE(range_set.Contains(49)); - - EXPECT_TRUE(range_set.Contains(10)); - EXPECT_TRUE(range_set.Contains(30)); - EXPECT_TRUE(range_set.Contains(50)); - - EXPECT_TRUE(range_set.Contains(15)); - EXPECT_TRUE(range_set.Contains(35)); - EXPECT_TRUE(range_set.Contains(55)); - - EXPECT_TRUE(range_set.Contains(19)); - EXPECT_TRUE(range_set.Contains(39)); - EXPECT_TRUE(range_set.Contains(59)); - - EXPECT_FALSE(range_set.Contains(20)); - EXPECT_FALSE(range_set.Contains(40)); - EXPECT_FALSE(range_set.Contains(60)); - } - { - EXPECT_FALSE(range_set.Contains(gfx::Range(0, 10))); - EXPECT_FALSE(range_set.Contains(gfx::Range(20, 30))); - EXPECT_FALSE(range_set.Contains(gfx::Range(40, 50))); - - EXPECT_FALSE(range_set.Contains(gfx::Range(5, 15))); - EXPECT_FALSE(range_set.Contains(gfx::Range(25, 35))); - EXPECT_FALSE(range_set.Contains(gfx::Range(45, 55))); - - EXPECT_TRUE(range_set.Contains(gfx::Range(10, 15))); - EXPECT_TRUE(range_set.Contains(gfx::Range(30, 35))); - EXPECT_TRUE(range_set.Contains(gfx::Range(50, 55))); - - EXPECT_TRUE(range_set.Contains(gfx::Range(15, 20))); - EXPECT_TRUE(range_set.Contains(gfx::Range(35, 40))); - EXPECT_TRUE(range_set.Contains(gfx::Range(55, 60))); - - EXPECT_TRUE(range_set.Contains(gfx::Range(10, 20))); - EXPECT_TRUE(range_set.Contains(gfx::Range(30, 40))); - EXPECT_TRUE(range_set.Contains(gfx::Range(50, 60))); - - EXPECT_FALSE(range_set.Contains(gfx::Range(15, 25))); - EXPECT_FALSE(range_set.Contains(gfx::Range(35, 45))); - EXPECT_FALSE(range_set.Contains(gfx::Range(55, 65))); - - EXPECT_FALSE(range_set.Contains(gfx::Range(20, 25))); - EXPECT_FALSE(range_set.Contains(gfx::Range(40, 45))); - EXPECT_FALSE(range_set.Contains(gfx::Range(60, 65))); - - EXPECT_FALSE(range_set.Contains(gfx::Range(0, 100))); - } - { - RangeSet range_set_2 = range_set; - EXPECT_TRUE(range_set_2.Contains(range_set)); - range_set_2.Union(gfx::Range(100, 200)); - EXPECT_TRUE(range_set_2.Contains(range_set)); - EXPECT_FALSE(range_set.Contains(range_set_2)); - } -} - -TEST(RangeSetTest, Intersects) { - RangeSet range_set; - range_set.Union(gfx::Range(10, 20)); - range_set.Union(gfx::Range(30, 40)); - range_set.Union(gfx::Range(50, 60)); - EXPECT_TRUE(range_set.Intersects(range_set)); - { - EXPECT_FALSE(range_set.Intersects(gfx::Range(0, 10))); - EXPECT_FALSE(range_set.Intersects(gfx::Range(20, 30))); - EXPECT_FALSE(range_set.Intersects(gfx::Range(40, 50))); - - EXPECT_TRUE(range_set.Intersects(gfx::Range(5, 15))); - EXPECT_TRUE(range_set.Intersects(gfx::Range(25, 35))); - EXPECT_TRUE(range_set.Intersects(gfx::Range(45, 55))); - - EXPECT_TRUE(range_set.Intersects(gfx::Range(10, 15))); - EXPECT_TRUE(range_set.Intersects(gfx::Range(30, 35))); - EXPECT_TRUE(range_set.Intersects(gfx::Range(50, 55))); - - EXPECT_TRUE(range_set.Intersects(gfx::Range(15, 20))); - EXPECT_TRUE(range_set.Intersects(gfx::Range(35, 40))); - EXPECT_TRUE(range_set.Intersects(gfx::Range(55, 60))); - - EXPECT_TRUE(range_set.Intersects(gfx::Range(10, 20))); - EXPECT_TRUE(range_set.Intersects(gfx::Range(30, 40))); - EXPECT_TRUE(range_set.Intersects(gfx::Range(50, 60))); - - EXPECT_TRUE(range_set.Intersects(gfx::Range(15, 25))); - EXPECT_TRUE(range_set.Intersects(gfx::Range(35, 45))); - EXPECT_TRUE(range_set.Intersects(gfx::Range(55, 65))); - - EXPECT_FALSE(range_set.Intersects(gfx::Range(20, 25))); - EXPECT_FALSE(range_set.Intersects(gfx::Range(40, 45))); - EXPECT_FALSE(range_set.Intersects(gfx::Range(60, 65))); - - EXPECT_TRUE(range_set.Intersects(gfx::Range(0, 100))); - } - { - RangeSet range_set_2; - range_set_2.Union(gfx::Range(5, 15)); - range_set_2.Union(gfx::Range(25, 35)); - range_set_2.Union(gfx::Range(45, 55)); - EXPECT_TRUE(range_set_2.Intersects(range_set)); - } - { - RangeSet range_set_2; - range_set_2.Union(gfx::Range(5, 10)); - range_set_2.Union(gfx::Range(25, 30)); - range_set_2.Union(gfx::Range(45, 50)); - EXPECT_FALSE(range_set_2.Intersects(range_set)); - } -} - -TEST(RangeSetTest, Intersect) { - { - RangeSet range_set; - range_set.Union(gfx::Range(10, 20)); - range_set.Union(gfx::Range(30, 40)); - range_set.Union(gfx::Range(50, 60)); - - EXPECT_EQ("{[10,20)[30,40)[50,60)}", range_set.ToString()); - range_set.Intersect(range_set); - EXPECT_EQ("{[10,20)[30,40)[50,60)}", range_set.ToString()); - range_set.Intersect(gfx::Range(0, 100)); - EXPECT_EQ("{[10,20)[30,40)[50,60)}", range_set.ToString()); - range_set.Intersect(gfx::Range(0, 55)); - EXPECT_EQ("{[10,20)[30,40)[50,55)}", range_set.ToString()); - range_set.Intersect(gfx::Range(15, 100)); - EXPECT_EQ("{[15,20)[30,40)[50,55)}", range_set.ToString()); - range_set.Intersect(gfx::Range(17, 53)); - EXPECT_EQ("{[17,20)[30,40)[50,53)}", range_set.ToString()); - range_set.Intersect(gfx::Range(19, 45)); - EXPECT_EQ("{[19,20)[30,40)}", range_set.ToString()); - range_set.Intersect(gfx::Range(30, 45)); - EXPECT_EQ("{[30,40)}", range_set.ToString()); - range_set.Intersect(gfx::Range(35, 40)); - EXPECT_EQ("{[35,40)}", range_set.ToString()); - range_set.Intersect(gfx::Range(35, 35)); - EXPECT_TRUE(range_set.IsEmpty()); - } - { - RangeSet range_set; - range_set.Union(gfx::Range(10, 20)); - range_set.Union(gfx::Range(30, 40)); - range_set.Union(gfx::Range(50, 60)); - - RangeSet range_set_2; - range_set_2.Union(gfx::Range(12, 17)); - range_set_2.Union(gfx::Range(25, 35)); - range_set_2.Union(gfx::Range(39, 55)); - range_set_2.Union(gfx::Range(59, 100)); - - range_set.Intersect(range_set_2); - EXPECT_EQ("{[12,17)[30,35)[39,40)[50,55)[59,60)}", range_set.ToString()); - } -} - -TEST(RangeSetTest, Subtract) { - { - RangeSet range_set; - range_set.Union(gfx::Range(10, 20)); - range_set.Union(gfx::Range(30, 40)); - range_set.Union(gfx::Range(50, 60)); - - EXPECT_EQ("{[10,20)[30,40)[50,60)}", range_set.ToString()); - range_set.Subtract(gfx::Range(35, 35)); - EXPECT_EQ("{[10,20)[30,40)[50,60)}", range_set.ToString()); - range_set.Subtract(gfx::Range(0, 5)); - EXPECT_EQ("{[10,20)[30,40)[50,60)}", range_set.ToString()); - range_set.Subtract(gfx::Range(70, 80)); - EXPECT_EQ("{[10,20)[30,40)[50,60)}", range_set.ToString()); - range_set.Subtract(gfx::Range(35, 39)); - EXPECT_EQ("{[10,20)[30,35)[39,40)[50,60)}", range_set.ToString()); - range_set.Subtract(gfx::Range(15, 32)); - EXPECT_EQ("{[10,15)[32,35)[39,40)[50,60)}", range_set.ToString()); - range_set.Subtract(gfx::Range(15, 55)); - EXPECT_EQ("{[10,15)[55,60)}", range_set.ToString()); - range_set.Subtract(gfx::Range(0, 100)); - EXPECT_EQ("{}", range_set.ToString()); - } - { - RangeSet range_set; - range_set.Union(gfx::Range(10, 20)); - range_set.Union(gfx::Range(30, 40)); - range_set.Union(gfx::Range(50, 60)); - range_set.Subtract(range_set); - EXPECT_EQ("{}", range_set.ToString()); - } - { - RangeSet range_set; - range_set.Union(gfx::Range(10, 20)); - range_set.Union(gfx::Range(30, 40)); - range_set.Union(gfx::Range(50, 60)); - - RangeSet range_set_2; - range_set_2.Union(gfx::Range(12, 17)); - range_set_2.Union(gfx::Range(25, 35)); - range_set_2.Union(gfx::Range(39, 55)); - range_set_2.Union(gfx::Range(59, 100)); - - range_set.Subtract(range_set_2); - EXPECT_EQ("{[10,12)[17,20)[35,39)[55,59)}", range_set.ToString()); - } -} - -TEST(RangeSetTest, Xor) { - { - RangeSet range_set; - range_set.Union(gfx::Range(10, 20)); - range_set.Union(gfx::Range(30, 40)); - range_set.Union(gfx::Range(50, 60)); - range_set.Xor(range_set); - EXPECT_EQ("{}", range_set.ToString()); - } - { - RangeSet range_set; - range_set.Union(gfx::Range(10, 20)); - range_set.Union(gfx::Range(30, 40)); - range_set.Union(gfx::Range(50, 60)); - - RangeSet range_set_2; - range_set_2.Union(gfx::Range(12, 17)); - range_set_2.Union(gfx::Range(25, 35)); - range_set_2.Union(gfx::Range(39, 55)); - range_set_2.Union(gfx::Range(59, 100)); - - range_set.Xor(range_set_2); - EXPECT_EQ("{[10,12)[17,20)[25,30)[35,39)[40,50)[55,59)[60,100)}", - range_set.ToString()); - } -} - -TEST(RangeSetTest, OperationsOnEmptySet) { - RangeSet range_set; - range_set.Intersect(gfx::Range(10, 20)); - range_set.Intersects(gfx::Range(10, 20)); - range_set.Subtract(gfx::Range(10, 20)); - range_set.Xor(gfx::Range(30, 40)); - range_set.Union(gfx::Range(10, 20)); -} - -} // namespace chrome_pdf diff --git a/pdf/run_all_unittests.cc b/pdf/run_all_unittests.cc deleted file mode 100644 index 138e5a2361f876..00000000000000 --- a/pdf/run_all_unittests.cc +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/test/launcher/unit_test_launcher.h" -#include "base/test/test_suite.h" - -// ppapi_cpp won't link w/o this. -namespace pp { - -class Module; - -Module* CreateModule() { - return nullptr; -} - -} // namespace pp - -int main(int argc, char** argv) { - base::TestSuite test_suite(argc, argv); - return base::LaunchUnitTests( - argc, argv, - base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite))); -} diff --git a/pdf/timer.cc b/pdf/timer.cc deleted file mode 100644 index a6890b245bf740..00000000000000 --- a/pdf/timer.cc +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "pdf/timer.h" - -#include "ppapi/cpp/core.h" -#include "ppapi/cpp/module.h" - -namespace chrome_pdf { - -Timer::Timer(int delay_in_milliseconds) - : delay_(delay_in_milliseconds), callback_factory_(this) { - PostCallback(); -} - -Timer::~Timer() { -} - -void Timer::PostCallback() { - pp::CompletionCallback callback = - callback_factory_.NewCallback(&Timer::TimerProc); - pp::Module::Get()->core()->CallOnMainThread(delay_, callback, 0); -} - -void Timer::TimerProc(int32_t /*result*/) { - PostCallback(); - OnTimer(); -} - -} // namespace chrome_pdf diff --git a/pdf/timer.h b/pdf/timer.h deleted file mode 100644 index a27f78f3d0b985..00000000000000 --- a/pdf/timer.h +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef PDF_TIMER_H_ -#define PDF_TIMER_H_ - -#include "base/macros.h" -#include "ppapi/utility/completion_callback_factory.h" - -namespace chrome_pdf { - -// Timer implementation for pepper plugins, based on pp::Core::CallOnMainThread. -// We can not use base::Timer for plugins, because they have no -// base::MessageLoop, on which it is based. -class Timer { - public: - explicit Timer(int delay_in_milliseconds); - virtual ~Timer(); - - virtual void OnTimer() = 0; - - private: - void PostCallback(); - void TimerProc(int32_t result); - - int delay_; - pp::CompletionCallbackFactory callback_factory_; - - DISALLOW_COPY_AND_ASSIGN(Timer); -}; - -} // namespace chrome_pdf - -#endif // PDF_TIMER_H_ diff --git a/pdf/url_loader_wrapper.h b/pdf/url_loader_wrapper.h deleted file mode 100644 index b95cfd299ff9ce..00000000000000 --- a/pdf/url_loader_wrapper.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef PDF_URL_LOADER_WRAPPER_H_ -#define PDF_URL_LOADER_WRAPPER_H_ - -#include - -#include "base/macros.h" -#include "ppapi/cpp/completion_callback.h" - -namespace chrome_pdf { - -class URLLoaderWrapper { - public: - virtual ~URLLoaderWrapper() {} - - // Returns length of content, will be -1, if it is unknown. - virtual int GetContentLength() const = 0; - // Returns if the response headers contains "accept-ranges". - virtual bool IsAcceptRangesBytes() const = 0; - // Returns if the content encoded in response. - virtual bool IsContentEncoded() const = 0; - // Returns response content type. - virtual std::string GetContentType() const = 0; - // Returns response content disposition. - virtual std::string GetContentDisposition() const = 0; - // Returns response status code. - virtual int GetStatusCode() const = 0; - // Returns if the response contains multi parts. - virtual bool IsMultipart() const = 0; - // If true, [start,end] - is byte range contains in response (include end). - // If false, response contains full document, start/end will be undefined. - virtual bool GetByteRange(int* start, int* end) const = 0; - - // Close connection. - virtual void Close() = 0; - // Open new connection and send http range request. - virtual void OpenRange(const std::string& url, - const std::string& referrer_url, - uint32_t position, - uint32_t size, - const pp::CompletionCallback& cc) = 0; - // Read the response body. The size of the buffer must be large enough to - // hold the specified number of bytes to read. - // This function might perform a partial read. - virtual void ReadResponseBody(char* buffer, - int buffer_size, - const pp::CompletionCallback& cc) = 0; - // Returns the current download progress. - // Progress only refers to the response body and does not include the headers. - // If false, progress is unknown, bytes_received/total_bytes_to_be_received - // will be undefined. - virtual bool GetDownloadProgress( - int64_t* bytes_received, - int64_t* total_bytes_to_be_received) const = 0; -}; - -} // namespace chrome_pdf - -#endif // PDF_URL_LOADER_WRAPPER_H_ diff --git a/pdf/url_loader_wrapper_impl.cc b/pdf/url_loader_wrapper_impl.cc deleted file mode 100644 index eacfa9a0b6637c..00000000000000 --- a/pdf/url_loader_wrapper_impl.cc +++ /dev/null @@ -1,318 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "pdf/url_loader_wrapper_impl.h" - -#include "base/logging.h" -#include "base/memory/ptr_util.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" -#include "net/http/http_util.h" -#include "pdf/timer.h" -#include "ppapi/c/pp_errors.h" -#include "ppapi/cpp/logging.h" -#include "ppapi/cpp/url_request_info.h" -#include "ppapi/cpp/url_response_info.h" - -namespace chrome_pdf { - -namespace { -// We should read with delay to prevent block UI thread, and reduce CPU usage. -const int kReadDelayMs = 2; - -pp::URLRequestInfo MakeRangeRequest(pp::Instance* plugin_instance, - const std::string& url, - const std::string& referrer_url, - uint32_t position, - uint32_t size) { - pp::URLRequestInfo request(plugin_instance); - request.SetURL(url); - request.SetMethod("GET"); - request.SetFollowRedirects(false); - request.SetCustomReferrerURL(referrer_url); - - // According to rfc2616, byte range specifies position of the first and last - // bytes in the requested range inclusively. Therefore we should subtract 1 - // from the position + size, to get index of the last byte that needs to be - // downloaded. - std::string str_header = - base::StringPrintf("Range: bytes=%d-%d", position, position + size - 1); - pp::Var header(str_header.c_str()); - request.SetHeaders(header); - - return request; -} - -bool GetByteRangeFromStr(const std::string& content_range_str, - int* start, - int* end) { - std::string range = content_range_str; - if (!base::StartsWith(range, "bytes", base::CompareCase::INSENSITIVE_ASCII)) - return false; - - range = range.substr(strlen("bytes")); - std::string::size_type pos = range.find('-'); - std::string range_end; - if (pos != std::string::npos) - range_end = range.substr(pos + 1); - base::TrimWhitespaceASCII(range, base::TRIM_LEADING, &range); - base::TrimWhitespaceASCII(range_end, base::TRIM_LEADING, &range_end); - *start = atoi(range.c_str()); - *end = atoi(range_end.c_str()); - return true; -} - -// If the headers have a byte-range response, writes the start and end -// positions and returns true if at least the start position was parsed. -// The end position will be set to 0 if it was not found or parsed from the -// response. -// Returns false if not even a start position could be parsed. -bool GetByteRangeFromHeaders(const std::string& headers, int* start, int* end) { - net::HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\n"); - while (it.GetNext()) { - if (base::LowerCaseEqualsASCII(it.name(), "content-range")) { - if (GetByteRangeFromStr(it.values().c_str(), start, end)) - return true; - } - } - return false; -} - -bool IsDoubleEndLineAtEnd(const char* buffer, int size) { - if (size < 2) - return false; - - if (buffer[size - 1] == '\n' && buffer[size - 2] == '\n') - return true; - - if (size < 4) - return false; - - return buffer[size - 1] == '\n' && buffer[size - 2] == '\r' && - buffer[size - 3] == '\n' && buffer[size - 4] == '\r'; -} - -} // namespace - -class URLLoaderWrapperImpl::ReadStarter : public Timer { - public: - explicit ReadStarter(URLLoaderWrapperImpl* owner) - : Timer(kReadDelayMs), owner_(owner) {} - ~ReadStarter() override {} - - // Timer overrides: - void OnTimer() override { owner_->ReadResponseBodyImpl(); } - - private: - URLLoaderWrapperImpl* owner_; -}; - -URLLoaderWrapperImpl::URLLoaderWrapperImpl(pp::Instance* plugin_instance, - const pp::URLLoader& url_loader) - : plugin_instance_(plugin_instance), - url_loader_(url_loader), - callback_factory_(this) { - SetHeadersFromLoader(); -} - -URLLoaderWrapperImpl::~URLLoaderWrapperImpl() { - Close(); -} - -int URLLoaderWrapperImpl::GetContentLength() const { - return content_length_; -} - -bool URLLoaderWrapperImpl::IsAcceptRangesBytes() const { - return accept_ranges_bytes_; -} - -bool URLLoaderWrapperImpl::IsContentEncoded() const { - return content_encoded_; -} - -std::string URLLoaderWrapperImpl::GetContentType() const { - return content_type_; -} -std::string URLLoaderWrapperImpl::GetContentDisposition() const { - return content_disposition_; -} - -int URLLoaderWrapperImpl::GetStatusCode() const { - return url_loader_.GetResponseInfo().GetStatusCode(); -} - -bool URLLoaderWrapperImpl::IsMultipart() const { - return is_multipart_; -} - -bool URLLoaderWrapperImpl::GetByteRange(int* start, int* end) const { - DCHECK(start); - DCHECK(end); - *start = byte_range_.start(); - *end = byte_range_.end(); - return byte_range_.IsValid(); -} - -bool URLLoaderWrapperImpl::GetDownloadProgress( - int64_t* bytes_received, - int64_t* total_bytes_to_be_received) const { - return url_loader_.GetDownloadProgress(bytes_received, - total_bytes_to_be_received); -} - -void URLLoaderWrapperImpl::Close() { - url_loader_.Close(); - read_starter_.reset(); -} - -void URLLoaderWrapperImpl::OpenRange(const std::string& url, - const std::string& referrer_url, - uint32_t position, - uint32_t size, - const pp::CompletionCallback& cc) { - did_open_callback_ = cc; - pp::CompletionCallback callback = - callback_factory_.NewCallback(&URLLoaderWrapperImpl::DidOpen); - int rv = url_loader_.Open( - MakeRangeRequest(plugin_instance_, url, referrer_url, position, size), - callback); - if (rv != PP_OK_COMPLETIONPENDING) - callback.Run(rv); -} - -void URLLoaderWrapperImpl::ReadResponseBody(char* buffer, - int buffer_size, - const pp::CompletionCallback& cc) { - did_read_callback_ = cc; - buffer_ = buffer; - buffer_size_ = buffer_size; - read_starter_ = base::MakeUnique(this); -} - -void URLLoaderWrapperImpl::ReadResponseBodyImpl() { - read_starter_.reset(); - pp::CompletionCallback callback = - callback_factory_.NewCallback(&URLLoaderWrapperImpl::DidRead); - int rv = url_loader_.ReadResponseBody(buffer_, buffer_size_, callback); - if (rv != PP_OK_COMPLETIONPENDING) { - callback.Run(rv); - } -} - -void URLLoaderWrapperImpl::SetResponseHeaders( - const std::string& response_headers) { - response_headers_ = response_headers; - ParseHeaders(); -} - -void URLLoaderWrapperImpl::ParseHeaders() { - content_length_ = -1; - accept_ranges_bytes_ = false; - content_encoded_ = false; - content_type_.clear(); - content_disposition_.clear(); - multipart_boundary_.clear(); - byte_range_ = gfx::Range::InvalidRange(); - is_multipart_ = false; - - if (response_headers_.empty()) - return; - - net::HttpUtil::HeadersIterator it(response_headers_.begin(), - response_headers_.end(), "\n"); - while (it.GetNext()) { - if (base::LowerCaseEqualsASCII(it.name(), "content-length")) { - content_length_ = atoi(it.values().c_str()); - } else if (base::LowerCaseEqualsASCII(it.name(), "accept-ranges")) { - accept_ranges_bytes_ = base::LowerCaseEqualsASCII(it.values(), "bytes"); - } else if (base::LowerCaseEqualsASCII(it.name(), "content-encoding")) { - content_encoded_ = true; - } else if (base::LowerCaseEqualsASCII(it.name(), "content-type")) { - content_type_ = it.values(); - size_t semi_colon_pos = content_type_.find(';'); - if (semi_colon_pos != std::string::npos) { - content_type_ = content_type_.substr(0, semi_colon_pos); - } - base::TrimWhitespaceASCII(content_type_, base::TRIM_ALL, &content_type_); - // multipart boundary. - std::string type = base::ToLowerASCII(it.values()); - if (base::StartsWith(type, "multipart/", base::CompareCase::SENSITIVE)) { - const char* boundary = strstr(type.c_str(), "boundary="); - DCHECK(boundary); - if (boundary) { - multipart_boundary_ = std::string(boundary + 9); - is_multipart_ = !multipart_boundary_.empty(); - } - } - } else if (base::LowerCaseEqualsASCII(it.name(), "content-disposition")) { - content_disposition_ = it.values(); - } else if (base::LowerCaseEqualsASCII(it.name(), "content-range")) { - int start = 0; - int end = 0; - if (GetByteRangeFromStr(it.values().c_str(), &start, &end)) { - byte_range_ = gfx::Range(start, end); - } - } - } -} - -void URLLoaderWrapperImpl::DidOpen(int32_t result) { - SetHeadersFromLoader(); - did_open_callback_.Run(result); -} - -void URLLoaderWrapperImpl::DidRead(int32_t result) { - if (multi_part_processed_) { - // Reset this flag so we look inside the buffer in calls of DidRead for this - // response only once. Note that this code DOES NOT handle multi part - // responses with more than one part (we don't issue them at the moment, so - // they shouldn't arrive). - is_multipart_ = false; - } - if (result <= 0 || !is_multipart_) { - did_read_callback_.Run(result); - return; - } - if (result <= 2) { - // TODO(art-snake): Accumulate data for parse headers. - did_read_callback_.Run(result); - return; - } - - char* start = buffer_; - size_t length = result; - multi_part_processed_ = true; - for (int i = 2; i < result; ++i) { - if (IsDoubleEndLineAtEnd(buffer_, i)) { - int start_pos = 0; - int end_pos = 0; - if (GetByteRangeFromHeaders(std::string(buffer_, i), &start_pos, - &end_pos)) { - byte_range_ = gfx::Range(start_pos, end_pos); - start += i; - length -= i; - } - break; - } - } - result = length; - if (result == 0) { - // Continue receiving. - return ReadResponseBodyImpl(); - } - DCHECK(result > 0); - memmove(buffer_, start, result); - - did_read_callback_.Run(result); -} - -void URLLoaderWrapperImpl::SetHeadersFromLoader() { - pp::URLResponseInfo response = url_loader_.GetResponseInfo(); - pp::Var headers_var = response.GetHeaders(); - - SetResponseHeaders(headers_var.is_string() ? headers_var.AsString() : ""); -} - -} // namespace chrome_pdf diff --git a/pdf/url_loader_wrapper_impl.h b/pdf/url_loader_wrapper_impl.h deleted file mode 100644 index b49481848e35a8..00000000000000 --- a/pdf/url_loader_wrapper_impl.h +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef PDF_URL_LOADER_WRAPPER_IMPL_H_ -#define PDF_URL_LOADER_WRAPPER_IMPL_H_ - -#include -#include - -#include "base/macros.h" -#include "pdf/url_loader_wrapper.h" -#include "ppapi/cpp/url_loader.h" -#include "ppapi/utility/completion_callback_factory.h" -#include "ui/gfx/range/range.h" - -namespace pp { -class Instance; -}; - -namespace chrome_pdf { - -class URLLoaderWrapperImpl : public URLLoaderWrapper { - public: - URLLoaderWrapperImpl(pp::Instance* plugin_instance, - const pp::URLLoader& url_loader); - ~URLLoaderWrapperImpl() override; - - // URLLoaderWrapper overrides: - int GetContentLength() const override; - bool IsAcceptRangesBytes() const override; - bool IsContentEncoded() const override; - std::string GetContentType() const override; - std::string GetContentDisposition() const override; - int GetStatusCode() const override; - bool IsMultipart() const override; - bool GetByteRange(int* start, int* end) const override; - bool GetDownloadProgress(int64_t* bytes_received, - int64_t* total_bytes_to_be_received) const override; - void Close() override; - void OpenRange(const std::string& url, - const std::string& referrer_url, - uint32_t position, - uint32_t size, - const pp::CompletionCallback& cc) override; - void ReadResponseBody(char* buffer, - int buffer_size, - const pp::CompletionCallback& cc) override; - - void SetResponseHeaders(const std::string& response_headers); - - private: - class ReadStarter; - - void SetHeadersFromLoader(); - void ParseHeaders(); - void DidOpen(int32_t result); - void DidRead(int32_t result); - - void ReadResponseBodyImpl(); - - pp::Instance* const plugin_instance_; - pp::URLLoader url_loader_; - std::string response_headers_; - - int content_length_ = -1; - bool accept_ranges_bytes_ = false; - bool content_encoded_ = false; - std::string content_type_; - std::string content_disposition_; - std::string multipart_boundary_; - gfx::Range byte_range_ = gfx::Range::InvalidRange(); - bool is_multipart_ = false; - char* buffer_ = nullptr; - uint32_t buffer_size_ = 0; - bool multi_part_processed_ = false; - - pp::CompletionCallback did_open_callback_; - pp::CompletionCallback did_read_callback_; - pp::CompletionCallbackFactory callback_factory_; - - std::unique_ptr read_starter_; - - DISALLOW_COPY_AND_ASSIGN(URLLoaderWrapperImpl); -}; - -} // namespace chrome_pdf - -#endif // PDF_URL_LOADER_WRAPPER_IMPL_H_