Commit 2cf20af4 authored by Artem Strygin's avatar Artem Strygin Committed by Commit Bot

Fix download PDF document with server extra data.

In case of range request, if server send unexpectedly
extra data, ignore it.

BUG=825829

Steps to reproduce:
1) Clear browser cache.
2) Open PDF:
http://www.major-landrover.ru/upload/attachments/f/9/f96aab07dab04ae89c8a509ec1ef2b31.pdf#page=55
3) Wait until document finish loading

Expected:
 The loading of document is finished
Actual:
 Some times the loading of document is never finished.

Change-Id: I46fc8001bea5701e1e93d26d1ea6527d4736ff05
Reviewed-on: https://chromium-review.googlesource.com/1094634Reviewed-by: default avatardsinclair <dsinclair@chromium.org>
Commit-Queue: Art Snake <art-snake@yandex-team.ru>
Cr-Commit-Position: refs/heads/master@{#567257}
parent 75294fa2
......@@ -81,6 +81,10 @@ class ChunkStream {
return filled_chunks_.Contains(chunks_range);
}
bool IsChunkAvailable(uint32_t chunk_index) const {
return filled_chunks_.Contains(chunk_index);
}
void set_eof_pos(uint32_t eof_pos) { eof_pos_ = eof_pos; }
uint32_t eof_pos() const { return eof_pos_; }
......@@ -90,6 +94,10 @@ class ChunkStream {
return eof_pos_ > 0 && IsRangeAvailable(gfx::Range(0, eof_pos_));
}
bool IsValidChunkIndex(uint32_t chunk_index) const {
return !eof_pos_ || (chunk_index <= GetChunkIndex(eof_pos_ - 1));
}
void Clear() {
data_.clear();
eof_pos_ = 0;
......
......@@ -204,8 +204,16 @@ void DocumentLoaderImpl::SetPartialLoadingEnabled(bool enabled) {
bool DocumentLoaderImpl::ShouldCancelLoading() const {
if (!loader_)
return true;
if (!partial_loading_enabled_ || pending_requests_.IsEmpty())
if (!partial_loading_enabled_)
return false;
if (pending_requests_.IsEmpty()) {
// Cancel loading if this is unepected data from server.
return !chunk_stream_.IsValidChunkIndex(chunk_.chunk_index) ||
chunk_stream_.IsChunkAvailable(chunk_.chunk_index);
}
const gfx::Range current_range(chunk_.chunk_index,
chunk_.chunk_index + kChunkCloseDistance);
return !pending_requests_.Intersects(current_range);
......@@ -328,11 +336,6 @@ void DocumentLoaderImpl::DidRead(int32_t result) {
bool DocumentLoaderImpl::SaveBuffer(char* input, uint32_t input_size) {
const uint32_t document_size = GetDocumentSize();
if (document_size != 0) {
// If the HTTP server sends more data than expected, then truncate
// |input_size| to the expected size.
input_size = std::min(document_size - bytes_received_, input_size);
}
bytes_received_ += input_size;
bool chunk_saved = false;
bool loading_pending_request = pending_requests_.Contains(chunk_.chunk_index);
......@@ -346,7 +349,7 @@ bool DocumentLoaderImpl::SaveBuffer(char* input, uint32_t input_size) {
new_chunk_data_len);
chunk_.data_size += new_chunk_data_len;
if (chunk_.data_size == DataStream::kChunkSize ||
document_size == EndOfCurrentChunk()) {
(document_size > 0 && document_size <= EndOfCurrentChunk())) {
pending_requests_.Subtract(
gfx::Range(chunk_.chunk_index, chunk_.chunk_index + 1));
SaveChunkData();
......
......@@ -1068,4 +1068,99 @@ TEST_F(DocumentLoaderImplTest,
Mock::VerifyAndClear(&client);
}
TEST_F(DocumentLoaderImplTest, IgnoreDataMoreThanExpectedWithPartial) {
static constexpr uint32_t kDocSize = kDefaultRequestSize * 80 - 321;
TestClient client;
client.SetCanUsePartialLoading();
client.full_page_loader_data()->set_content_length(kDocSize);
DocumentLoaderImpl loader(&client);
loader.Init(client.CreateFullPageLoader(), "http://url.com");
// Request data at and.
loader.RequestData(kDocSize - 100, 100);
// Always send initial data from FullPageLoader.
client.full_page_loader_data()->CallReadCallback(kDefaultRequestSize);
EXPECT_TRUE(client.full_page_loader_data()->closed());
EXPECT_FALSE(client.partial_loader_data()->closed());
// Request data at middle to continue loading partial, but not all remaining
// data.
loader.RequestData(kDocSize / 2, 100);
// Fill data at the end, the partial loding should be started for second
// requested data after receive data for first request.
client.SendAllPartialData();
ASSERT_TRUE(client.partial_loader_data()->IsWaitOpen());
// Process second request.
const uint32_t expected_length =
client.partial_loader_data()->open_byte_range().length();
// Send data.
client.partial_loader_data()->set_byte_range(
client.partial_loader_data()->open_byte_range());
client.partial_loader_data()->CallOpenCallback(0);
uint32_t length = expected_length;
while (length > 0) {
const uint32_t max_part_len = kDefaultRequestSize;
const uint32_t part_len = std::min(length, max_part_len);
client.partial_loader_data()->CallReadCallback(part_len);
length -= part_len;
}
// The partial loading should be finished for current chunks sequence, if
// expected range was received, and remaining sequence should start loading.
EXPECT_FALSE(client.partial_loader_data()->IsWaitRead());
ASSERT_TRUE(client.partial_loader_data()->IsWaitOpen());
// Send other document data.
client.SendAllPartialData();
// The downloads should be finished.
EXPECT_TRUE(client.full_page_loader_data()->closed());
EXPECT_TRUE(client.partial_loader_data()->closed());
}
TEST_F(DocumentLoaderImplTest, IgnoreDataMoreThanExpectedWithPartialAtFileEnd) {
static constexpr uint32_t kExtraSize = 100;
static constexpr uint32_t kRealSize = kDefaultRequestSize * 20 - 300;
static constexpr uint32_t kDocSize = kRealSize - kExtraSize;
TestClient client;
client.SetCanUsePartialLoading();
client.full_page_loader_data()->set_content_length(kDocSize);
DocumentLoaderImpl loader(&client);
loader.Init(client.CreateFullPageLoader(), "http://url.com");
// Request data at middle.
static constexpr uint32_t kFirstPartial = kDefaultRequestSize * 11;
loader.RequestData(kFirstPartial, kDefaultRequestSize);
// Always send initial data from FullPageLoader.
client.full_page_loader_data()->CallReadCallback(kDefaultRequestSize);
EXPECT_TRUE(client.full_page_loader_data()->closed());
EXPECT_FALSE(client.partial_loader_data()->closed());
// Send data to file end and extra non expected data.
client.partial_loader_data()->set_byte_range(
gfx::Range(kFirstPartial, kRealSize));
client.partial_loader_data()->CallOpenCallback(0);
uint32_t length = client.partial_loader_data()->byte_range().length();
while (length > 0) {
const uint32_t max_part_len = kDefaultRequestSize;
const uint32_t part_len = std::min(length, max_part_len);
client.partial_loader_data()->CallReadCallback(part_len);
length -= part_len;
}
// The partial loading should be finished for current chunks sequence, if
// eof was reached, and remaining sequence should start loading.
EXPECT_FALSE(client.partial_loader_data()->IsWaitRead());
EXPECT_EQ(gfx::Range(kDefaultRequestSize, kFirstPartial),
client.partial_loader_data()->open_byte_range());
// Send other document data.
client.SendAllPartialData();
// The downloads should be finished.
EXPECT_TRUE(client.full_page_loader_data()->closed());
EXPECT_TRUE(client.partial_loader_data()->closed());
}
} // namespace chrome_pdf
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment