Browser process changes for Resource Timing sizes.
This is part of the changes to add the size fields to the
PerformanceResourceTiming API.
See the design doc at
https://docs.google.com/document/d/1ckL-rKLFRsdI4nn1golvQ6I1zRIvxgFkDXMrZb8KduY/edit
These are the browser-side changes to pass the "encodedBodySize" field to the
renderer. The field is named encoded_body_length in the //content code for
consistency with the existing encoded_data_length field.
For async resource fetches the value is passed one chunk at a time in the
ResourceMsg_InlinedDataChunkReceived and ResourceMsg_DataReceived IPCs. For sync
XHR it is passed in the ResourceResponseInfo struct.
BUG=467945
Review-Url: https://codereview.chromium.org/2092993002
Cr-Commit-Position: refs/heads/master@{#405015}
diff --git a/content/browser/loader/async_resource_handler.cc b/content/browser/loader/async_resource_handler.cc
index 518d274..91d0350b 100644
--- a/content/browser/loader/async_resource_handler.cc
+++ b/content/browser/loader/async_resource_handler.cc
@@ -29,6 +29,7 @@
#include "content/public/browser/resource_dispatcher_host_delegate.h"
#include "content/public/common/content_features.h"
#include "content/public/common/resource_response.h"
+#include "ipc/ipc_message_macros.h"
#include "net/base/io_buffer.h"
#include "net/base/load_flags.h"
#include "net/log/net_log.h"
@@ -72,6 +73,14 @@
GetNumericArg("resource-buffer-max-allocation-size", &kMaxAllocationSize);
}
+// Updates |*cached| to |updated| and returns the difference from the old
+// value.
+int TrackDifference(int64_t updated, int64_t* cached) {
+ int difference = updated - *cached;
+ *cached = updated;
+ return difference;
+}
+
} // namespace
// Used when kOptimizeLoadingIPCForSmallResources is enabled.
@@ -117,6 +126,7 @@
// Returns true if the received data is sent to the consumer.
bool SendInlinedDataIfApplicable(int bytes_read,
int encoded_data_length,
+ int encoded_body_length,
IPC::Sender* sender,
int request_id) {
DCHECK(sender);
@@ -129,7 +139,7 @@
leading_chunk_buffer_ = nullptr;
sender->Send(new ResourceMsg_InlinedDataChunkReceived(
- request_id, data, encoded_data_length));
+ request_id, data, encoded_data_length, encoded_body_length));
return true;
}
@@ -206,7 +216,8 @@
inlining_helper_(new InliningHelper),
last_upload_position_(0),
waiting_for_upload_progress_ack_(false),
- reported_transfer_size_(0) {
+ reported_transfer_size_(0),
+ reported_encoded_body_length_(0) {
InitializeResourceBufferConstants();
}
@@ -439,10 +450,12 @@
return false;
int encoded_data_length = CalculateEncodedDataLengthToReport();
+ int encoded_body_length = CalculateEncodedBodyLengthToReport();
// Return early if InliningHelper handled the received data.
if (inlining_helper_->SendInlinedDataIfApplicable(
- bytes_read, encoded_data_length, filter, GetRequestID()))
+ bytes_read, encoded_data_length, encoded_body_length, filter,
+ GetRequestID()))
return true;
buffer_->ShrinkLastAllocation(bytes_read);
@@ -460,8 +473,9 @@
int data_offset = buffer_->GetLastAllocationOffset();
- filter->Send(new ResourceMsg_DataReceived(
- GetRequestID(), data_offset, bytes_read, encoded_data_length));
+ filter->Send(new ResourceMsg_DataReceived(GetRequestID(), data_offset,
+ bytes_read, encoded_data_length,
+ encoded_body_length));
++pending_data_count_;
if (!buffer_->CanAllocate()) {
@@ -565,10 +579,13 @@
}
int AsyncResourceHandler::CalculateEncodedDataLengthToReport() {
- int64_t current_transfer_size = request()->GetTotalReceivedBytes();
- int encoded_data_length = current_transfer_size - reported_transfer_size_;
- reported_transfer_size_ = current_transfer_size;
- return encoded_data_length;
+ return TrackDifference(request()->GetTotalReceivedBytes(),
+ &reported_transfer_size_);
+}
+
+int AsyncResourceHandler::CalculateEncodedBodyLengthToReport() {
+ return TrackDifference(request()->GetRawBodyBytes(),
+ &reported_encoded_body_length_);
}
void AsyncResourceHandler::RecordHistogram() {
diff --git a/content/browser/loader/async_resource_handler.h b/content/browser/loader/async_resource_handler.h
index 0991021..c087f16 100644
--- a/content/browser/loader/async_resource_handler.h
+++ b/content/browser/loader/async_resource_handler.h
@@ -14,6 +14,7 @@
#include "base/timer/timer.h"
#include "content/browser/loader/resource_handler.h"
#include "content/browser/loader/resource_message_delegate.h"
+#include "content/common/content_export.h"
#include "net/base/io_buffer.h"
#include "url/gurl.h"
@@ -30,8 +31,8 @@
// Used to complete an asynchronous resource request in response to resource
// load events from the resource dispatcher host.
-class AsyncResourceHandler : public ResourceHandler,
- public ResourceMessageDelegate {
+class CONTENT_EXPORT AsyncResourceHandler : public ResourceHandler,
+ public ResourceMessageDelegate {
public:
AsyncResourceHandler(net::URLRequest* request,
ResourceDispatcherHostImpl* rdh);
@@ -70,6 +71,7 @@
void OnDefer();
bool CheckForSufficientResource();
int CalculateEncodedDataLengthToReport();
+ int CalculateEncodedBodyLengthToReport();
void RecordHistogram();
scoped_refptr<ResourceBuffer> buffer_;
@@ -96,6 +98,7 @@
base::RepeatingTimer progress_timer_;
int64_t reported_transfer_size_;
+ int64_t reported_encoded_body_length_;
DISALLOW_COPY_AND_ASSIGN(AsyncResourceHandler);
};
diff --git a/content/browser/loader/async_resource_handler_unittest.cc b/content/browser/loader/async_resource_handler_unittest.cc
new file mode 100644
index 0000000..69f2f59
--- /dev/null
+++ b/content/browser/loader/async_resource_handler_unittest.cc
@@ -0,0 +1,339 @@
+// 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 "content/browser/loader/async_resource_handler.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <memory>
+#include <string>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/feature_list.h"
+#include "base/format_macros.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/process/process.h"
+#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "content/browser/loader/resource_dispatcher_host_impl.h"
+#include "content/browser/loader/resource_loader.h"
+#include "content/browser/loader/resource_loader_delegate.h"
+#include "content/browser/loader/resource_message_filter.h"
+#include "content/browser/loader/resource_request_info_impl.h"
+#include "content/common/resource_messages.h"
+#include "content/common/resource_request.h"
+#include "content/public/browser/resource_context.h"
+#include "content/public/browser/resource_request_info.h"
+#include "content/public/common/content_features.h"
+#include "content/public/common/process_type.h"
+#include "content/public/common/resource_type.h"
+#include "content/public/test/mock_resource_context.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "ipc/ipc_message.h"
+#include "ipc/ipc_message_macros.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_util.h"
+#include "net/ssl/client_cert_store.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_job_factory_impl.h"
+#include "net/url_request/url_request_test_job.h"
+#include "net/url_request/url_request_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/page_transition_types.h"
+#include "url/gurl.h"
+
+namespace content {
+
+namespace {
+
+std::string GenerateHeader(size_t response_data_size) {
+ return base::StringPrintf(
+ "HTTP/1.1 200 OK\n"
+ "Content-type: text/html\n"
+ "Content-Length: %" PRIuS "\n",
+ response_data_size);
+}
+
+std::string GenerateData(size_t response_data_size) {
+ return std::string(response_data_size, 'a');
+}
+
+// This test job adds a Content-Length header and implements
+// GetTotalReceivedBytes().
+class TestJob : public net::URLRequestTestJob {
+ public:
+ TestJob(net::URLRequest* request,
+ net::NetworkDelegate* network_delegate,
+ size_t response_data_size)
+ : net::URLRequestTestJob(request,
+ network_delegate,
+ GenerateHeader(response_data_size),
+ GenerateData(response_data_size),
+ true) {}
+
+ static TestJob* CreateJob(net::URLRequest* request,
+ net::NetworkDelegate* network_delegate,
+ size_t response_data_size) {
+ return new TestJob(request, network_delegate, response_data_size);
+ }
+
+ // URLRequestJob implementation:
+ // TODO(ricea): Move this to URLRequestTestJob.
+ int64_t GetTotalReceivedBytes() const override {
+ std::string http_headers = net::HttpUtil::ConvertHeadersBackToHTTPResponse(
+ response_headers_->raw_headers());
+ return http_headers.size() + offset_;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestJob);
+};
+
+class TestJobProtocolHandler
+ : public net::URLRequestJobFactory::ProtocolHandler {
+ public:
+ TestJobProtocolHandler(size_t response_data_size)
+ : response_data_size_(response_data_size) {}
+
+ net::URLRequestJob* MaybeCreateJob(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) const override {
+ return TestJob::CreateJob(request, network_delegate, response_data_size_);
+ }
+
+ private:
+ size_t response_data_size_;
+};
+
+// A subclass of ResourceMessageFilter that records IPC messages that are sent.
+class RecordingResourceMessageFilter : public ResourceMessageFilter {
+ public:
+ RecordingResourceMessageFilter(ResourceContext* resource_context,
+ net::URLRequestContext* request_context)
+ : ResourceMessageFilter(
+ 0,
+ PROCESS_TYPE_RENDERER,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ base::Bind(&RecordingResourceMessageFilter::GetContexts,
+ base::Unretained(this))),
+ resource_context_(resource_context),
+ request_context_(request_context) {
+ set_peer_process_for_testing(base::Process::Current());
+ }
+
+ const std::vector<std::unique_ptr<IPC::Message>>& messages() const {
+ return messages_;
+ }
+
+ // IPC::Sender implementation:
+ bool Send(IPC::Message* message) override {
+ // Unpickle the base::SharedMemoryHandle to avoid warnings about
+ // "MessageAttachmentSet destroyed with unconsumed descriptors".
+ if (message->type() == ResourceMsg_SetDataBuffer::ID) {
+ ResourceMsg_SetDataBuffer::Param params;
+ ResourceMsg_SetDataBuffer::Read(message, ¶ms);
+ }
+ messages_.push_back(base::WrapUnique(message));
+ return true;
+ }
+
+ private:
+ ~RecordingResourceMessageFilter() override {}
+
+ void GetContexts(ResourceType resource_type,
+ int origin_pid,
+ ResourceContext** resource_context,
+ net::URLRequestContext** request_context) {
+ *resource_context = resource_context_;
+ *request_context = request_context_;
+ }
+
+ ResourceContext* const resource_context_;
+ net::URLRequestContext* const request_context_;
+ std::vector<std::unique_ptr<IPC::Message>> messages_;
+};
+
+class AsyncResourceHandlerTest : public ::testing::Test,
+ public ResourceLoaderDelegate {
+ protected:
+ AsyncResourceHandlerTest()
+ : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP), context_(true) {}
+
+ void TearDown() override {
+ // Prevent memory leaks.
+ rdh_.Shutdown();
+ base::RunLoop().RunUntilIdle();
+ }
+
+ void CreateRequestWithResponseDataSize(size_t response_data_size) {
+ test_job_factory_.SetProtocolHandler(
+ "test", base::MakeUnique<TestJobProtocolHandler>(response_data_size));
+ context_.set_job_factory(&test_job_factory_);
+ context_.Init();
+ std::unique_ptr<net::URLRequest> request = context_.CreateRequest(
+ GURL("test:test"), net::DEFAULT_PRIORITY, nullptr);
+ resource_context_ = base::MakeUnique<MockResourceContext>(&context_);
+ filter_ =
+ new RecordingResourceMessageFilter(resource_context_.get(), &context_);
+ ResourceRequestInfoImpl* info = new ResourceRequestInfoImpl(
+ PROCESS_TYPE_RENDERER, // process_type
+ 0, // child_id
+ 0, // route_id
+ -1, // frame_tree_node_id
+ 0, // origin_pid
+ 0, // request_id
+ 0, // render_frame_id
+ false, // is_main_frame
+ false, // parent_is_main_frame
+ RESOURCE_TYPE_IMAGE, // resource_type
+ ui::PAGE_TRANSITION_LINK, // transition_type
+ false, // should_replace_current_entry
+ false, // is_download
+ false, // is_stream
+ false, // allow_download
+ false, // has_user_gesture
+ false, // enable load timing
+ false, // enable upload progress
+ false, // do_not_prompt_for_login
+ blink::WebReferrerPolicyDefault, // referrer_policy
+ blink::WebPageVisibilityStateVisible, // visibility_state
+ resource_context_.get(), // context
+ filter_->GetWeakPtr(), // filter
+ false, // report_raw_headers
+ true, // is_async
+ false, // is_using_lofi
+ std::string(), // original_headers
+ nullptr, // body
+ false); // initiated_in_secure_context
+ info->AssociateWithRequest(request.get());
+ std::unique_ptr<AsyncResourceHandler> handler =
+ base::MakeUnique<AsyncResourceHandler>(request.get(), &rdh_);
+ loader_ = base::MakeUnique<ResourceLoader>(
+ std::move(request), std::move(handler), nullptr, this);
+ }
+
+ void StartRequestAndWaitWithResponseDataSize(size_t response_data_size) {
+ CreateRequestWithResponseDataSize(response_data_size);
+ loader_->StartRequest();
+ finish_waiter_.reset(new base::RunLoop);
+ finish_waiter_->Run();
+ }
+
+ scoped_refptr<RecordingResourceMessageFilter> filter_;
+
+ private:
+ // ResourceLoaderDelegate implementation:
+ ResourceDispatcherHostLoginDelegate* CreateLoginDelegate(
+ ResourceLoader* loader,
+ net::AuthChallengeInfo* auth_info) override {
+ return nullptr;
+ }
+
+ bool HandleExternalProtocol(ResourceLoader* loader,
+ const GURL& url) override {
+ return false;
+ }
+ void DidStartRequest(ResourceLoader* loader) override {}
+ void DidReceiveRedirect(ResourceLoader* loader,
+ const GURL& new_url) override {}
+ void DidReceiveResponse(ResourceLoader* loader) override {}
+ void DidFinishLoading(ResourceLoader* loader) override {
+ loader_.reset();
+ finish_waiter_->Quit();
+ }
+ std::unique_ptr<net::ClientCertStore> CreateClientCertStore(
+ ResourceLoader* loader) override {
+ return nullptr;
+ }
+
+ TestBrowserThreadBundle thread_bundle_;
+ ResourceDispatcherHostImpl rdh_;
+ net::TestURLRequestContext context_;
+ net::URLRequestJobFactoryImpl test_job_factory_;
+ std::unique_ptr<MockResourceContext> resource_context_;
+ std::unique_ptr<ResourceLoader> loader_;
+ std::unique_ptr<base::RunLoop> finish_waiter_;
+};
+
+TEST_F(AsyncResourceHandlerTest, Construct) {
+ CreateRequestWithResponseDataSize(1);
+}
+
+TEST_F(AsyncResourceHandlerTest, OneChunkLengths) {
+ // Larger than kInlinedLeadingChunkSize and smaller than
+ // kMaxAllocationSize.
+ StartRequestAndWaitWithResponseDataSize(4096);
+ const auto& messages = filter_->messages();
+ ASSERT_EQ(4u, messages.size());
+ ASSERT_EQ(ResourceMsg_DataReceived::ID, messages[2]->type());
+ ResourceMsg_DataReceived::Param params;
+ ResourceMsg_DataReceived::Read(messages[2].get(), ¶ms);
+
+ int encoded_data_length = std::get<3>(params);
+ EXPECT_EQ(4162, encoded_data_length);
+ int encoded_body_length = std::get<4>(params);
+ EXPECT_EQ(4096, encoded_body_length);
+}
+
+TEST_F(AsyncResourceHandlerTest, InlinedChunkLengths) {
+ // TODO(ricea): Remove this Feature-enabling code once the feature is on by
+ // default.
+ auto feature_list = base::MakeUnique<base::FeatureList>();
+ feature_list->InitializeFromCommandLine(
+ features::kOptimizeLoadingIPCForSmallResources.name, "");
+ base::FeatureList::ClearInstanceForTesting();
+ base::FeatureList::SetInstance(std::move(feature_list));
+
+ // Smaller than kInlinedLeadingChunkSize.
+ StartRequestAndWaitWithResponseDataSize(8);
+ const auto& messages = filter_->messages();
+ ASSERT_EQ(3u, messages.size());
+ ASSERT_EQ(ResourceMsg_InlinedDataChunkReceived::ID, messages[1]->type());
+ ResourceMsg_InlinedDataChunkReceived::Param params;
+ ResourceMsg_InlinedDataChunkReceived::Read(messages[1].get(), ¶ms);
+
+ int encoded_data_length = std::get<2>(params);
+ EXPECT_EQ(71, encoded_data_length);
+ int encoded_body_length = std::get<3>(params);
+ EXPECT_EQ(8, encoded_body_length);
+}
+
+TEST_F(AsyncResourceHandlerTest, TwoChunksLengths) {
+ // Larger than kMaxAllocationSize.
+ StartRequestAndWaitWithResponseDataSize(64*1024);
+ const auto& messages = filter_->messages();
+ ASSERT_EQ(5u, messages.size());
+ ASSERT_EQ(ResourceMsg_DataReceived::ID, messages[2]->type());
+ ResourceMsg_DataReceived::Param params;
+ ResourceMsg_DataReceived::Read(messages[2].get(), ¶ms);
+
+ int encoded_data_length = std::get<3>(params);
+ EXPECT_EQ(32835, encoded_data_length);
+ int encoded_body_length = std::get<4>(params);
+ EXPECT_EQ(32768, encoded_body_length);
+
+ ASSERT_EQ(ResourceMsg_DataReceived::ID, messages[3]->type());
+ ResourceMsg_DataReceived::Read(messages[3].get(), ¶ms);
+
+ encoded_data_length = std::get<3>(params);
+ EXPECT_EQ(32768, encoded_data_length);
+ encoded_body_length = std::get<4>(params);
+ EXPECT_EQ(32768, encoded_body_length);
+}
+
+} // namespace
+
+} // namespace content
diff --git a/content/browser/loader/sync_resource_handler.cc b/content/browser/loader/sync_resource_handler.cc
index 83277f0..c4217b29 100644
--- a/content/browser/loader/sync_resource_handler.cc
+++ b/content/browser/loader/sync_resource_handler.cc
@@ -127,6 +127,7 @@
int total_transfer_size = request()->GetTotalReceivedBytes();
result_.encoded_data_length = total_transfer_size_ + total_transfer_size;
+ result_.encoded_body_length = request()->GetRawBodyBytes();
ResourceHostMsg_SyncLoad::WriteReplyParams(result_message_, result_);
filter->Send(result_message_);
diff --git a/content/child/resource_dispatcher.cc b/content/child/resource_dispatcher.cc
index 461da5c..55fa5554 100644
--- a/content/child/resource_dispatcher.cc
+++ b/content/child/resource_dispatcher.cc
@@ -226,7 +226,8 @@
void ResourceDispatcher::OnReceivedInlinedDataChunk(
int request_id,
const std::vector<char>& data,
- int encoded_data_length) {
+ int encoded_data_length,
+ int encoded_body_length) {
TRACE_EVENT0("loader", "ResourceDispatcher::OnReceivedInlinedDataChunk");
DCHECK(!data.empty());
DCHECK(base::FeatureList::IsEnabled(
@@ -254,7 +255,8 @@
void ResourceDispatcher::OnReceivedData(int request_id,
int data_offset,
int data_length,
- int encoded_data_length) {
+ int encoded_data_length,
+ int encoded_body_length) {
TRACE_EVENT0("loader", "ResourceDispatcher::OnReceivedData");
DCHECK_GT(data_length, 0);
PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
diff --git a/content/child/resource_dispatcher.h b/content/child/resource_dispatcher.h
index 11062c6..8a56030 100644
--- a/content/child/resource_dispatcher.h
+++ b/content/child/resource_dispatcher.h
@@ -178,11 +178,13 @@
base::ProcessId renderer_pid);
void OnReceivedInlinedDataChunk(int request_id,
const std::vector<char>& data,
- int encoded_data_length);
+ int encoded_data_length,
+ int encoded_body_length);
void OnReceivedData(int request_id,
int data_offset,
int data_length,
- int encoded_data_length);
+ int encoded_data_length,
+ int encoded_body_length);
void OnDownloadedData(int request_id, int data_len, int encoded_data_length);
void OnRequestComplete(
int request_id,
diff --git a/content/child/resource_dispatcher_unittest.cc b/content/child/resource_dispatcher_unittest.cc
index 07fbecf..5d072120 100644
--- a/content/child/resource_dispatcher_unittest.cc
+++ b/content/child/resource_dispatcher_unittest.cc
@@ -13,6 +13,7 @@
#include <utility>
#include <vector>
+#include "base/feature_list.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/shared_memory.h"
@@ -30,6 +31,7 @@
#include "content/public/child/fixed_received_data.h"
#include "content/public/child/request_peer.h"
#include "content/public/child/resource_dispatcher_delegate.h"
+#include "content/public/common/content_features.h"
#include "content/public/common/resource_response.h"
#include "net/base/net_errors.h"
#include "net/http/http_response_headers.h"
@@ -275,11 +277,19 @@
memcpy(shared_memory_map_[request_id]->memory(), data.c_str(),
data.length());
- EXPECT_TRUE(dispatcher_->OnMessageReceived(
- ResourceMsg_DataReceived(request_id, 0, data.length(), data.length())));
+ EXPECT_TRUE(dispatcher_->OnMessageReceived(ResourceMsg_DataReceived(
+ request_id, 0, data.length(), data.length(), data.length())));
}
- void NotifyDataDownloaded(int request_id, int decoded_length,
+ void NotifyInlinedDataChunkReceived(int request_id,
+ const std::vector<char>& data) {
+ auto size = data.size();
+ EXPECT_TRUE(dispatcher_->OnMessageReceived(
+ ResourceMsg_InlinedDataChunkReceived(request_id, data, size, size)));
+ }
+
+ void NotifyDataDownloaded(int request_id,
+ int decoded_length,
int encoded_length) {
EXPECT_TRUE(dispatcher_->OnMessageReceived(ResourceMsg_DataDownloaded(
request_id, decoded_length, encoded_length)));
@@ -369,6 +379,35 @@
EXPECT_EQ(0u, queued_messages());
}
+// A simple request with an inline data response.
+TEST_F(ResourceDispatcherTest, ResponseWithInlinedData) {
+ auto feature_list = base::MakeUnique<base::FeatureList>();
+ feature_list->InitializeFromCommandLine(
+ features::kOptimizeLoadingIPCForSmallResources.name, std::string());
+ base::FeatureList::ClearInstanceForTesting();
+ base::FeatureList::SetInstance(std::move(feature_list));
+ std::unique_ptr<RequestInfo> request_info(CreateRequestInfo(false));
+ TestRequestPeer::Context peer_context;
+ StartAsync(*request_info.get(), NULL, &peer_context);
+
+ int id = ConsumeRequestResource();
+ EXPECT_EQ(0u, queued_messages());
+
+ NotifyReceivedResponse(id);
+ EXPECT_EQ(0u, queued_messages());
+ EXPECT_TRUE(peer_context.received_response);
+
+ std::vector<char> data(kTestPageContents,
+ kTestPageContents + strlen(kTestPageContents));
+ NotifyInlinedDataChunkReceived(id, data);
+ EXPECT_EQ(0u, queued_messages());
+
+ NotifyRequestComplete(id, strlen(kTestPageContents));
+ EXPECT_EQ(kTestPageContents, peer_context.data);
+ EXPECT_TRUE(peer_context.complete);
+ EXPECT_EQ(0u, queued_messages());
+}
+
// Tests that the request IDs are straight when there are two interleaving
// requests.
TEST_F(ResourceDispatcherTest, MultipleRequests) {
diff --git a/content/common/resource_messages.h b/content/common/resource_messages.h
index 0f343e72..a918d54 100644
--- a/content/common/resource_messages.h
+++ b/content/common/resource_messages.h
@@ -159,6 +159,7 @@
IPC_STRUCT_TRAITS_MEMBER(has_major_certificate_errors)
IPC_STRUCT_TRAITS_MEMBER(content_length)
IPC_STRUCT_TRAITS_MEMBER(encoded_data_length)
+ IPC_STRUCT_TRAITS_MEMBER(encoded_body_length)
IPC_STRUCT_TRAITS_MEMBER(appcache_id)
IPC_STRUCT_TRAITS_MEMBER(appcache_manifest_url)
IPC_STRUCT_TRAITS_MEMBER(load_timing)
@@ -307,19 +308,21 @@
// Sent when a chunk of data from a resource request is ready, and the resource
// is expected to be small enough to fit in the inlined buffer.
// The data is sent as a part of IPC message.
-IPC_MESSAGE_CONTROL3(ResourceMsg_InlinedDataChunkReceived,
+IPC_MESSAGE_CONTROL4(ResourceMsg_InlinedDataChunkReceived,
int /* request_id */,
std::vector<char> /* data */,
- int /* encoded_data_length */)
+ int /* encoded_data_length */,
+ int /* encoded_body_length */)
// Sent when some data from a resource request is ready. The data offset and
// length specify a byte range into the shared memory buffer provided by the
// SetDataBuffer message.
-IPC_MESSAGE_CONTROL4(ResourceMsg_DataReceived,
+IPC_MESSAGE_CONTROL5(ResourceMsg_DataReceived,
int /* request_id */,
int /* data_offset */,
int /* data_length */,
- int /* encoded_data_length */)
+ int /* encoded_data_length */,
+ int /* encoded_body_length */)
// Sent when some data from a resource request has been downloaded to
// file. This is only called in the 'download_to_file' case and replaces
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index 1d634bc..bc70a69 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -507,6 +507,7 @@
'browser/indexed_db/mock_indexed_db_database_callbacks.h',
'browser/indexed_db/mock_indexed_db_factory.cc',
'browser/indexed_db/mock_indexed_db_factory.h',
+ 'browser/loader/async_resource_handler_unittest.cc',
'browser/loader/async_revalidation_driver_unittest.cc',
'browser/loader/async_revalidation_manager_unittest.cc',
'browser/loader/mime_type_resource_handler_unittest.cc',
diff --git a/content/public/common/resource_response.cc b/content/public/common/resource_response.cc
index 3633eba8..0b94574 100644
--- a/content/public/common/resource_response.cc
+++ b/content/public/common/resource_response.cc
@@ -23,6 +23,7 @@
head.has_major_certificate_errors;
new_response->head.content_length = head.content_length;
new_response->head.encoded_data_length = head.encoded_data_length;
+ new_response->head.encoded_body_length = head.encoded_body_length;
new_response->head.appcache_id = head.appcache_id;
new_response->head.appcache_manifest_url = head.appcache_manifest_url;
new_response->head.load_timing = head.load_timing;
diff --git a/content/public/common/resource_response_info.cc b/content/public/common/resource_response_info.cc
index d471f2df..eed1a98ed 100644
--- a/content/public/common/resource_response_info.cc
+++ b/content/public/common/resource_response_info.cc
@@ -13,6 +13,7 @@
: has_major_certificate_errors(false),
content_length(-1),
encoded_data_length(-1),
+ encoded_body_length(-1),
appcache_id(kAppCacheNoCacheId),
was_fetched_via_spdy(false),
was_npn_negotiated(false),
diff --git a/content/public/common/resource_response_info.h b/content/public/common/resource_response_info.h
index 9c004aa..3c7a9c5 100644
--- a/content/public/common/resource_response_info.h
+++ b/content/public/common/resource_response_info.h
@@ -64,6 +64,10 @@
// no data, contains -1.
int64_t encoded_data_length;
+ // Length of the response body data before decompression. -1 unless the body
+ // has been read to the end.
+ int64_t encoded_body_length;
+
// The appcache this response was loaded from, or kAppCacheNoCacheId.
int64_t appcache_id;