Record Data Savings for Client-Side LoFi
This CL causes Chrome to record data savings for Client LoFi when it is
used, according to the Content-Range header if it's present (e.g.
"Content-Range: bytes 0-2047/10000" implies that the original resource
was 10000 bytes). This CL also adds a new PreviewsState bit field,
CLIENT_LOFI_AUTO_RELOAD, that is set when a Client LoFi image is auto
reloaded because of a decoding error, so that the browser process can
count the data used for the reload against the savings.
See design doc for more info:
https://docs.google.com/document/d/1CoZfTswPq67VaHKsr0OrkpPbWT87dhhvPq9hylOxrlU/edit
BUG=605347
Review-Url: https://codereview.chromium.org/2873793002
Cr-Commit-Position: refs/heads/master@{#470850}
diff --git a/components/data_reduction_proxy/content/browser/content_lofi_decider.cc b/components/data_reduction_proxy/content/browser/content_lofi_decider.cc
index d24fab4..dc203b9 100644
--- a/components/data_reduction_proxy/content/browser/content_lofi_decider.cc
+++ b/components/data_reduction_proxy/content/browser/content_lofi_decider.cc
@@ -221,4 +221,11 @@
(request_info->GetPreviewsState() & content::CLIENT_LOFI_ON);
}
+bool ContentLoFiDecider::IsClientLoFiAutoReloadRequest(
+ const net::URLRequest& request) const {
+ const content::ResourceRequestInfo* request_info =
+ content::ResourceRequestInfo::ForRequest(&request);
+ return request_info &&
+ (request_info->GetPreviewsState() & content::CLIENT_LOFI_AUTO_RELOAD);
+}
} // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/content/browser/content_lofi_decider.h b/components/data_reduction_proxy/content/browser/content_lofi_decider.h
index b71cd6b..b94a336 100644
--- a/components/data_reduction_proxy/content/browser/content_lofi_decider.h
+++ b/components/data_reduction_proxy/content/browser/content_lofi_decider.h
@@ -42,6 +42,8 @@
net::HttpRequestHeaders* headers) const override;
bool ShouldRecordLoFiUMA(const net::URLRequest& request) const override;
bool IsClientLoFiImageRequest(const net::URLRequest& request) const override;
+ bool IsClientLoFiAutoReloadRequest(
+ const net::URLRequest& request) const override;
private:
DISALLOW_COPY_AND_ASSIGN(ContentLoFiDecider);
diff --git a/components/data_reduction_proxy/content/browser/content_lofi_decider_unittest.cc b/components/data_reduction_proxy/content/browser/content_lofi_decider_unittest.cc
index 46f5ee2..9405f8dc 100644
--- a/components/data_reduction_proxy/content/browser/content_lofi_decider_unittest.cc
+++ b/components/data_reduction_proxy/content/browser/content_lofi_decider_unittest.cc
@@ -818,4 +818,32 @@
EXPECT_TRUE(lofi_decider->IsClientLoFiImageRequest(*request));
}
+TEST_F(ContentLoFiDeciderTest, RequestIsClientLoFiAutoReload) {
+ // IsClientLoFiAutoReloadRequest() should return true for any request with the
+ // CLIENT_LOFI_AUTO_RELOAD bit set.
+
+ EXPECT_TRUE(ContentLoFiDecider().IsClientLoFiAutoReloadRequest(
+ *CreateRequestByType(content::RESOURCE_TYPE_IMAGE, false,
+ content::CLIENT_LOFI_AUTO_RELOAD)));
+
+ EXPECT_TRUE(
+ ContentLoFiDecider().IsClientLoFiAutoReloadRequest(*CreateRequestByType(
+ content::RESOURCE_TYPE_IMAGE, true,
+ content::CLIENT_LOFI_AUTO_RELOAD | content::PREVIEWS_NO_TRANSFORM)));
+
+ EXPECT_TRUE(ContentLoFiDecider().IsClientLoFiAutoReloadRequest(
+ *CreateRequestByType(content::RESOURCE_TYPE_MAIN_FRAME, true,
+ content::CLIENT_LOFI_AUTO_RELOAD)));
+
+ EXPECT_TRUE(ContentLoFiDecider().IsClientLoFiAutoReloadRequest(
+ *CreateRequestByType(content::RESOURCE_TYPE_SCRIPT, true,
+ content::CLIENT_LOFI_AUTO_RELOAD)));
+
+ // IsClientLoFiAutoReloadRequest() should return false for any request without
+ // the CLIENT_LOFI_AUTO_RELOAD bit set.
+ EXPECT_FALSE(ContentLoFiDecider().IsClientLoFiAutoReloadRequest(
+ *CreateRequestByType(content::RESOURCE_TYPE_IMAGE, false,
+ content::PREVIEWS_NO_TRANSFORM)));
+}
+
} // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
index b6e3940..6e464cb 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
@@ -4,6 +4,7 @@
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h"
+#include <algorithm>
#include <limits>
#include <utility>
@@ -117,18 +118,48 @@
received_content_length);
}
-// Given a |request| that went through the Data Reduction Proxy, this function
-// estimates how many bytes would have been received if the response had been
-// received directly from the origin using HTTP/1.1 with a content length of
-// |adjusted_original_content_length|.
-int64_t EstimateOriginalReceivedBytes(const net::URLRequest& request) {
+// Estimate the size of the original headers of |request|. If |used_drp| is
+// true, then it's assumed that the original request would have used HTTP/1.1,
+// otherwise it assumes that the original request would have used the same
+// protocol as |request| did. This is to account for stuff like HTTP/2 header
+// compression.
+int64_t EstimateOriginalHeaderBytes(const net::URLRequest& request,
+ bool used_drp) {
+ if (used_drp) {
+ // TODO(sclittle): Remove headers added by Data Reduction Proxy when
+ // computing original size. https://crbug.com/535701.
+ return request.response_headers()->raw_headers().size();
+ }
+ return std::max<int64_t>(0, request.GetTotalReceivedBytes() -
+ request.received_response_content_length());
+}
+
+// Given a |request| that went through the Data Reduction Proxy if |used_drp| is
+// true, this function estimates how many bytes would have been received if the
+// response had been received directly from the origin without any data saver
+// optimizations.
+int64_t EstimateOriginalReceivedBytes(const net::URLRequest& request,
+ bool used_drp,
+ const LoFiDecider* lofi_decider) {
if (request.was_cached() || !request.response_headers())
return request.GetTotalReceivedBytes();
- // TODO(sclittle): Remove headers added by Data Reduction Proxy when computing
- // original size. http://crbug/535701.
- return request.response_headers()->raw_headers().size() +
- util::CalculateEffectiveOCL(request);
+ if (lofi_decider) {
+ if (lofi_decider->IsClientLoFiAutoReloadRequest(request))
+ return 0;
+
+ int64_t first, last, length;
+ if (lofi_decider->IsClientLoFiImageRequest(request) &&
+ request.response_headers()->GetContentRangeFor206(&first, &last,
+ &length) &&
+ length > request.received_response_content_length()) {
+ return EstimateOriginalHeaderBytes(request, used_drp) + length;
+ }
+ }
+
+ return used_drp ? EstimateOriginalHeaderBytes(request, used_drp) +
+ util::CalculateEffectiveOCL(request)
+ : request.GetTotalReceivedBytes();
}
// Verifies that the chrome proxy related request headers are set correctly.
@@ -380,15 +411,15 @@
net_error);
net::HttpRequestHeaders request_headers;
- bool server_lofi = data_reduction_proxy_io_data_ &&
- request->response_headers() &&
+ bool server_lofi = request->response_headers() &&
IsEmptyImagePreview(*(request->response_headers()));
bool client_lofi =
data_reduction_proxy_io_data_ &&
data_reduction_proxy_io_data_->lofi_decider() &&
data_reduction_proxy_io_data_->lofi_decider()->IsClientLoFiImageRequest(
*request);
- if (server_lofi || client_lofi) {
+ if ((server_lofi || client_lofi) && data_reduction_proxy_io_data_ &&
+ data_reduction_proxy_io_data_->lofi_ui_service()) {
data_reduction_proxy_io_data_->lofi_ui_service()->OnLoFiReponseReceived(
*request);
} else if (data_reduction_proxy_io_data_ && request->response_headers() &&
@@ -460,10 +491,11 @@
// Estimate how many bytes would have been used if the DataReductionProxy was
// not used, and record the data usage.
- int64_t original_size = data_used;
-
- if (request_type == VIA_DATA_REDUCTION_PROXY)
- original_size = EstimateOriginalReceivedBytes(request);
+ int64_t original_size = EstimateOriginalReceivedBytes(
+ request, request_type == VIA_DATA_REDUCTION_PROXY,
+ data_reduction_proxy_io_data_
+ ? data_reduction_proxy_io_data_->lofi_decider()
+ : nullptr);
std::string mime_type;
if (request.response_headers())
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
index 1d651c9..902cc28 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
@@ -136,6 +136,7 @@
public:
TestLoFiDecider()
: should_be_client_lofi_(false),
+ should_be_client_lofi_auto_reload_(false),
should_request_lofi_resource_(false),
ignore_is_using_data_reduction_proxy_check_(false) {}
~TestLoFiDecider() override {}
@@ -152,6 +153,10 @@
should_be_client_lofi_ = should_be_client_lofi;
}
+ void SetIsClientLoFiAutoReload(bool should_be_client_lofi_auto_reload) {
+ should_be_client_lofi_auto_reload_ = should_be_client_lofi_auto_reload;
+ }
+
void MaybeSetAcceptTransformHeader(
const net::URLRequest& request,
bool is_previews_disabled,
@@ -200,12 +205,18 @@
return should_be_client_lofi_;
}
+ bool IsClientLoFiAutoReloadRequest(
+ const net::URLRequest& request) const override {
+ return should_be_client_lofi_auto_reload_;
+ }
+
void ignore_is_using_data_reduction_proxy_check() {
ignore_is_using_data_reduction_proxy_check_ = true;
}
private:
bool should_be_client_lofi_;
+ bool should_be_client_lofi_auto_reload_;
bool should_request_lofi_resource_;
bool ignore_is_using_data_reduction_proxy_check_;
};
@@ -255,6 +266,8 @@
DataReductionProxyNetworkDelegateTest()
: context_(true),
context_storage_(&context_),
+ lofi_decider_(nullptr),
+ lofi_ui_service_(nullptr),
ssl_socket_data_provider_(net::ASYNC, net::OK) {
ssl_socket_data_provider_.next_proto = net::kProtoHTTP11;
ssl_socket_data_provider_.cert = net::ImportCertFromFile(
@@ -1683,6 +1696,186 @@
FetchURLRequestAndVerifyECTHeader(effective_connection_types[1], true, true);
}
+class DataReductionProxyNetworkDelegateClientLoFiTest : public testing::Test {
+ public:
+ DataReductionProxyNetworkDelegateClientLoFiTest() : baseline_savings_(0) {}
+ ~DataReductionProxyNetworkDelegateClientLoFiTest() override;
+
+ void Reset() {
+ drp_test_context_.reset();
+ mock_socket_factory_.reset();
+ context_storage_.reset();
+
+ context_.reset(new net::TestURLRequestContext(true));
+ context_storage_.reset(new net::URLRequestContextStorage(context_.get()));
+ mock_socket_factory_.reset(new net::MockClientSocketFactory());
+ context_->set_client_socket_factory(mock_socket_factory_.get());
+
+ drp_test_context_ =
+ DataReductionProxyTestContext::Builder()
+ .WithURLRequestContext(context_.get())
+ .WithMockClientSocketFactory(mock_socket_factory_.get())
+ .Build();
+
+ drp_test_context_->AttachToURLRequestContext(context_storage_.get());
+ context_->Init();
+ base::RunLoop().RunUntilIdle();
+
+ baseline_savings_ =
+ drp_test_context()->settings()->GetTotalHttpContentLengthSaved();
+ }
+
+ void SetUpLoFiDecider(bool is_client_lofi_image,
+ bool is_client_lofi_auto_reload) const {
+ std::unique_ptr<TestLoFiDecider> lofi_decider(new TestLoFiDecider());
+ lofi_decider->SetIsUsingClientLoFi(is_client_lofi_image);
+ lofi_decider->SetIsClientLoFiAutoReload(is_client_lofi_auto_reload);
+ drp_test_context_->io_data()->set_lofi_decider(
+ std::unique_ptr<LoFiDecider>(std::move(lofi_decider)));
+ }
+
+ int64_t GetSavings() const {
+ return drp_test_context()->settings()->GetTotalHttpContentLengthSaved() -
+ baseline_savings_;
+ }
+
+ net::TestURLRequestContext* context() const { return context_.get(); }
+ net::MockClientSocketFactory* mock_socket_factory() const {
+ return mock_socket_factory_.get();
+ }
+ DataReductionProxyTestContext* drp_test_context() const {
+ return drp_test_context_.get();
+ }
+
+ private:
+ base::MessageLoopForIO loop;
+ std::unique_ptr<net::TestURLRequestContext> context_;
+ std::unique_ptr<net::URLRequestContextStorage> context_storage_;
+ std::unique_ptr<net::MockClientSocketFactory> mock_socket_factory_;
+ std::unique_ptr<DataReductionProxyTestContext> drp_test_context_;
+ int64_t baseline_savings_;
+};
+
+DataReductionProxyNetworkDelegateClientLoFiTest::
+ ~DataReductionProxyNetworkDelegateClientLoFiTest() {}
+
+TEST_F(DataReductionProxyNetworkDelegateClientLoFiTest, DataSavingsNonDRP) {
+ const char kSimple200ResponseHeaders[] =
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Length: 140\r\n\r\n";
+
+ const struct {
+ const char* headers;
+ size_t response_length;
+ bool is_client_lofi_image;
+ bool is_client_lofi_auto_reload;
+ int64_t expected_savings;
+ } tests[] = {
+ // 200 responses shouldn't see any savings.
+ {kSimple200ResponseHeaders, 140, false, false, 0},
+ {kSimple200ResponseHeaders, 140, true, false, 0},
+
+ // Client Lo-Fi Auto-reload responses should see negative savings.
+ {kSimple200ResponseHeaders, 140, false, true,
+ -(static_cast<int64_t>(sizeof(kSimple200ResponseHeaders) - 1) + 140)},
+ {kSimple200ResponseHeaders, 140, true, true,
+ -(static_cast<int64_t>(sizeof(kSimple200ResponseHeaders) - 1) + 140)},
+
+ // A range response that doesn't use Client Lo-Fi shouldn't see any
+ // savings.
+ {"HTTP/1.1 206 Partial Content\r\n"
+ "Content-Range: bytes 0-2047/10000\r\n"
+ "Content-Length: 2048\r\n\r\n",
+ 2048, false, false, 0},
+
+ // A Client Lo-Fi range response should see savings based on the
+ // Content-Range header.
+ {"HTTP/1.1 206 Partial Content\r\n"
+ "Content-Range: bytes 0-2047/10000\r\n"
+ "Content-Length: 2048\r\n\r\n",
+ 2048, true, false, 10000 - 2048},
+
+ // A Client Lo-Fi range response should see savings based on the
+ // Content-Range header, which in this case is 0 savings because the range
+ // response contained the entire resource.
+ {"HTTP/1.1 206 Partial Content\r\n"
+ "Content-Range: bytes 0-999/1000\r\n"
+ "Content-Length: 1000\r\n\r\n",
+ 1000, true, false, 0},
+
+ // Client Lo-Fi range responses that don't have a Content-Range with the
+ // full resource length shouldn't see any savings.
+ {"HTTP/1.1 206 Partial Content\r\n"
+ "Content-Length: 2048\r\n\r\n",
+ 2048, true, false, 0},
+ {"HTTP/1.1 206 Partial Content\r\n"
+ "Content-Range: bytes 0-2047/*\r\n"
+ "Content-Length: 2048\r\n\r\n",
+ 2048, true, false, 0},
+ {"HTTP/1.1 206 Partial Content\r\n"
+ "Content-Range: invalid_content_range\r\n"
+ "Content-Length: 2048\r\n\r\n",
+ 2048, true, false, 0},
+ };
+
+ for (const auto& test : tests) {
+ Reset();
+ SetUpLoFiDecider(test.is_client_lofi_image,
+ test.is_client_lofi_auto_reload);
+
+ std::string response_body(test.response_length, 'a');
+ net::MockRead reads[] = {net::MockRead(test.headers),
+ net::MockRead(response_body.c_str()),
+ net::MockRead(net::ASYNC, net::OK)};
+ net::StaticSocketDataProvider socket(reads, arraysize(reads), nullptr, 0);
+ mock_socket_factory()->AddSocketDataProvider(&socket);
+
+ net::TestDelegate test_delegate;
+ std::unique_ptr<net::URLRequest> request = context()->CreateRequest(
+ GURL("http://example.com"), net::RequestPriority::IDLE, &test_delegate);
+
+ request->Start();
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(test.expected_savings, GetSavings()) << (&test - tests);
+ }
+}
+
+TEST_F(DataReductionProxyNetworkDelegateClientLoFiTest, DataSavingsThroughDRP) {
+ Reset();
+ drp_test_context()->EnableDataReductionProxyWithSecureProxyCheckSuccess();
+ SetUpLoFiDecider(true, false);
+
+ const char kHeaders[] =
+ "HTTP/1.1 206 Partial Content\r\n"
+ "Content-Range: bytes 0-2047/10000\r\n"
+ "Content-Length: 2048\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n"
+ "X-Original-Content-Length: 3000\r\n\r\n";
+
+ std::string response_body(2048, 'a');
+ net::MockRead reads[] = {net::MockRead(kHeaders),
+ net::MockRead(response_body.c_str()),
+ net::MockRead(net::ASYNC, net::OK)};
+ net::StaticSocketDataProvider socket(reads, arraysize(reads), nullptr, 0);
+ mock_socket_factory()->AddSocketDataProvider(&socket);
+
+ net::TestDelegate test_delegate;
+ std::unique_ptr<net::URLRequest> request = context()->CreateRequest(
+ GURL("http://example.com"), net::RequestPriority::IDLE, &test_delegate);
+
+ request->Start();
+ base::RunLoop().RunUntilIdle();
+
+ // Since the Data Reduction Proxy is enabled, the length of the raw headers
+ // should be used in the estimated original size. The X-OCL should be ignored.
+ EXPECT_EQ(static_cast<int64_t>(net::HttpUtil::AssembleRawHeaders(
+ kHeaders, sizeof(kHeaders) - 1)
+ .size() +
+ 10000 - request->GetTotalReceivedBytes()),
+ GetSavings());
+}
+
} // namespace
} // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/common/lofi_decider.h b/components/data_reduction_proxy/core/common/lofi_decider.h
index c0b3858..867ecf50 100644
--- a/components/data_reduction_proxy/core/common/lofi_decider.h
+++ b/components/data_reduction_proxy/core/common/lofi_decider.h
@@ -67,6 +67,11 @@
// Returns whether the request was a client-side Lo-Fi image request.
virtual bool IsClientLoFiImageRequest(
const net::URLRequest& request) const = 0;
+
+ // Returns true if the request is for a client-side Lo-Fi image that is being
+ // automatically reloaded because of a decoding error.
+ virtual bool IsClientLoFiAutoReloadRequest(
+ const net::URLRequest& request) const = 0;
};
} // namespace data_reduction_proxy
diff --git a/content/public/common/previews_state.h b/content/public/common/previews_state.h
index 07ac08b..74e4f39b 100644
--- a/content/public/common/previews_state.h
+++ b/content/public/common/previews_state.h
@@ -27,19 +27,22 @@
// content of web pages to improve data savings and / or performance. This enum
// determines which Previews types to request.
enum PreviewsTypes {
- PREVIEWS_UNSPECIFIED = 0, // Let the browser process decide whether or
- // not to request Preview types.
- SERVER_LOFI_ON = 1 << 0, // Request a Lo-Fi version of the resource
- // from the server.
- CLIENT_LOFI_ON = 1 << 1, // Request a Lo-Fi version of the resource
- // from the client.
- SERVER_LITE_PAGE_ON = 1 << 2, // Request a Lite Page version of the
- // resource from the server.
- PREVIEWS_NO_TRANSFORM = 1 << 3, // Explicitly forbid Previews
- // transformations.
- PREVIEWS_OFF = 1 << 4, // Request a normal (non-Preview) version of
- // the resource. Server transformations may
- // still happen if the page is heavy.
+ PREVIEWS_UNSPECIFIED = 0, // Let the browser process decide whether or
+ // not to request Preview types.
+ SERVER_LOFI_ON = 1 << 0, // Request a Lo-Fi version of the resource
+ // from the server.
+ CLIENT_LOFI_ON = 1 << 1, // Request a Lo-Fi version of the resource
+ // from the client.
+ CLIENT_LOFI_AUTO_RELOAD = 1 << 2, // Request the original version of the
+ // resource after a decoding error occurred
+ // when attempting to use Client Lo-Fi.
+ SERVER_LITE_PAGE_ON = 1 << 3, // Request a Lite Page version of the
+ // resource from the server.
+ PREVIEWS_NO_TRANSFORM = 1 << 4, // Explicitly forbid Previews
+ // transformations.
+ PREVIEWS_OFF = 1 << 5, // Request a normal (non-Preview) version of
+ // the resource. Server transformations may
+ // still happen if the page is heavy.
PREVIEWS_STATE_LAST = PREVIEWS_OFF
};
@@ -51,6 +54,8 @@
blink::WebURLRequest::kServerLoFiOn);
STATIC_ASSERT_PREVIEWS_ENUM(CLIENT_LOFI_ON,
blink::WebURLRequest::kClientLoFiOn);
+STATIC_ASSERT_PREVIEWS_ENUM(CLIENT_LOFI_AUTO_RELOAD,
+ blink::WebURLRequest::kClientLoFiAutoReload);
STATIC_ASSERT_PREVIEWS_ENUM(SERVER_LITE_PAGE_ON,
blink::WebURLRequest::kServerLitePageOn);
STATIC_ASSERT_PREVIEWS_ENUM(PREVIEWS_NO_TRANSFORM,
diff --git a/third_party/WebKit/Source/core/loader/resource/ImageResource.cpp b/third_party/WebKit/Source/core/loader/resource/ImageResource.cpp
index 0537ade..c5c664d4 100644
--- a/third_party/WebKit/Source/core/loader/resource/ImageResource.cpp
+++ b/third_party/WebKit/Source/core/loader/resource/ImageResource.cpp
@@ -494,7 +494,20 @@
SetCachePolicyBypassingCache();
- SetPreviewsStateNoTransform();
+ // The reloaded image should not use any previews transformations.
+ WebURLRequest::PreviewsState previews_state_for_reload =
+ WebURLRequest::kPreviewsNoTransform;
+
+ if (policy == kReloadIfNeeded && (GetResourceRequest().GetPreviewsState() &
+ WebURLRequest::kClientLoFiOn)) {
+ // If the image attempted to use Client LoFi, but encountered a decoding
+ // error and is being automatically reloaded, then also set the appropriate
+ // PreviewsState bit for that. This allows the embedder to count the
+ // bandwidth used for this reload against the data savings of the initial
+ // response.
+ previews_state_for_reload |= WebURLRequest::kClientLoFiAutoReload;
+ }
+ SetPreviewsState(previews_state_for_reload);
if (placeholder_option_ != PlaceholderOption::kDoNotReloadPlaceholder)
ClearRangeRequestHeader();
diff --git a/third_party/WebKit/Source/core/loader/resource/ImageResourceTest.cpp b/third_party/WebKit/Source/core/loader/resource/ImageResourceTest.cpp
index 67a803a..065b2d2 100644
--- a/third_party/WebKit/Source/core/loader/resource/ImageResourceTest.cpp
+++ b/third_party/WebKit/Source/core/loader/resource/ImageResourceTest.cpp
@@ -1245,50 +1245,69 @@
}
TEST(ImageResourceTest, FetchAllowPlaceholderPartialContentWithoutDimensions) {
- KURL test_url(kParsedURLString, kTestURL);
- ScopedMockedURLLoad scoped_mocked_url_load(test_url, GetTestFilePath());
+ const struct {
+ WebURLRequest::PreviewsState initial_previews_state;
+ WebURLRequest::PreviewsState expected_reload_previews_state;
+ } tests[] = {
+ {WebURLRequest::kPreviewsUnspecified,
+ WebURLRequest::kPreviewsNoTransform},
+ {WebURLRequest::kClientLoFiOn, WebURLRequest::kPreviewsNoTransform |
+ WebURLRequest::kClientLoFiAutoReload},
+ };
- FetchParameters params{ResourceRequest(test_url), FetchInitiatorInfo()};
- params.SetAllowImagePlaceholder();
- ImageResource* image_resource = ImageResource::Fetch(params, CreateFetcher());
- EXPECT_EQ(FetchParameters::kAllowPlaceholder,
- params.GetPlaceholderImageRequestType());
- EXPECT_EQ("bytes=0-2047",
- image_resource->GetResourceRequest().HttpHeaderField("range"));
- EXPECT_TRUE(image_resource->ShouldShowPlaceholder());
- std::unique_ptr<MockImageResourceObserver> observer =
- MockImageResourceObserver::Create(image_resource->GetContent());
+ for (const auto& test : tests) {
+ KURL test_url(kParsedURLString, kTestURL);
+ ScopedMockedURLLoad scoped_mocked_url_load(test_url, GetTestFilePath());
- // TODO(hiroshige): Make the range request header and partial content length
- // consistent. https://crbug.com/689760.
- ResourceResponse partial_response(test_url, "image/jpeg",
- kJpegImageSubrangeWithoutDimensionsLength,
- g_null_atom);
- partial_response.SetHTTPStatusCode(206);
- partial_response.SetHTTPHeaderField(
- "content-range",
- BuildContentRange(kJpegImageSubrangeWithoutDimensionsLength,
- sizeof(kJpegImage)));
+ ResourceRequest resource_request(test_url);
+ resource_request.SetPreviewsState(test.initial_previews_state);
+ FetchParameters params{resource_request, FetchInitiatorInfo()};
- image_resource->Loader()->DidReceiveResponse(
- WrappedResourceResponse(partial_response));
- image_resource->Loader()->DidReceiveData(
- reinterpret_cast<const char*>(kJpegImage),
- kJpegImageSubrangeWithoutDimensionsLength);
+ params.SetAllowImagePlaceholder();
+ ImageResource* image_resource =
+ ImageResource::Fetch(params, CreateFetcher());
+ EXPECT_EQ(FetchParameters::kAllowPlaceholder,
+ params.GetPlaceholderImageRequestType());
+ EXPECT_EQ("bytes=0-2047",
+ image_resource->GetResourceRequest().HttpHeaderField("range"));
+ EXPECT_TRUE(image_resource->ShouldShowPlaceholder());
+ std::unique_ptr<MockImageResourceObserver> observer =
+ MockImageResourceObserver::Create(image_resource->GetContent());
- EXPECT_EQ(0, observer->ImageChangedCount());
+ // TODO(hiroshige): Make the range request header and partial content length
+ // consistent. https://crbug.com/689760.
+ ResourceResponse partial_response(test_url, "image/jpeg",
+ kJpegImageSubrangeWithoutDimensionsLength,
+ g_null_atom);
+ partial_response.SetHTTPStatusCode(206);
+ partial_response.SetHTTPHeaderField(
+ "content-range",
+ BuildContentRange(kJpegImageSubrangeWithoutDimensionsLength,
+ sizeof(kJpegImage)));
- image_resource->Loader()->DidFinishLoading(
- 0.0, kJpegImageSubrangeWithoutDimensionsLength,
- kJpegImageSubrangeWithoutDimensionsLength,
- kJpegImageSubrangeWithoutDimensionsLength);
+ image_resource->Loader()->DidReceiveResponse(
+ WrappedResourceResponse(partial_response));
+ image_resource->Loader()->DidReceiveData(
+ reinterpret_cast<const char*>(kJpegImage),
+ kJpegImageSubrangeWithoutDimensionsLength);
- EXPECT_FALSE(observer->ImageNotifyFinishedCalled());
- EXPECT_EQ(2, observer->ImageChangedCount());
+ EXPECT_EQ(0, observer->ImageChangedCount());
- TestThatReloadIsStartedThenServeReload(
- test_url, image_resource, image_resource->GetContent(), observer.get(),
- WebCachePolicy::kBypassingCache);
+ image_resource->Loader()->DidFinishLoading(
+ 0.0, kJpegImageSubrangeWithoutDimensionsLength,
+ kJpegImageSubrangeWithoutDimensionsLength,
+ kJpegImageSubrangeWithoutDimensionsLength);
+
+ EXPECT_FALSE(observer->ImageNotifyFinishedCalled());
+ EXPECT_EQ(2, observer->ImageChangedCount());
+
+ TestThatReloadIsStartedThenServeReload(
+ test_url, image_resource, image_resource->GetContent(), observer.get(),
+ WebCachePolicy::kBypassingCache);
+
+ EXPECT_EQ(test.expected_reload_previews_state,
+ image_resource->GetResourceRequest().GetPreviewsState());
+ }
}
TEST(ImageResourceTest, FetchAllowPlaceholderThenDisallowPlaceholder) {
diff --git a/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp b/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp
index 8d71536..ec544791 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp
@@ -922,8 +922,8 @@
resource_request_.SetCachePolicy(WebCachePolicy::kBypassingCache);
}
-void Resource::SetPreviewsStateNoTransform() {
- resource_request_.SetPreviewsState(WebURLRequest::kPreviewsNoTransform);
+void Resource::SetPreviewsState(WebURLRequest::PreviewsState previews_state) {
+ resource_request_.SetPreviewsState(previews_state);
}
void Resource::ClearRangeRequestHeader() {
diff --git a/third_party/WebKit/Source/platform/loader/fetch/Resource.h b/third_party/WebKit/Source/platform/loader/fetch/Resource.h
index c4ae381..2f4bcad 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/Resource.h
+++ b/third_party/WebKit/Source/platform/loader/fetch/Resource.h
@@ -406,7 +406,7 @@
}
void SetCachePolicyBypassingCache();
- void SetPreviewsStateNoTransform();
+ void SetPreviewsState(WebURLRequest::PreviewsState);
void ClearRangeRequestHeader();
SharedBuffer* Data() const { return data_.Get(); }
diff --git a/third_party/WebKit/public/platform/WebURLRequest.h b/third_party/WebKit/public/platform/WebURLRequest.h
index e559ac77..ba9dcb8 100644
--- a/third_party/WebKit/public/platform/WebURLRequest.h
+++ b/third_party/WebKit/public/platform/WebURLRequest.h
@@ -150,19 +150,22 @@
// The Previews types which determines whether to request a Preview version of
// the resource.
enum PreviewsTypes {
- kPreviewsUnspecified = 0, // Let the browser process decide whether or
- // not to request Preview types.
- kServerLoFiOn = 1 << 0, // Request a Lo-Fi version of the resource
- // from the server.
- kClientLoFiOn = 1 << 1, // Request a Lo-Fi version of the resource
- // from the client.
- kServerLitePageOn = 1 << 2, // Request a Lite Page version of the
- // resource from the server.
- kPreviewsNoTransform = 1 << 3, // Explicitly forbid Previews
- // transformations.
- kPreviewsOff = 1 << 4, // Request a normal (non-Preview) version of
- // the resource. Server transformations may
- // still happen if the page is heavy.
+ kPreviewsUnspecified = 0, // Let the browser process decide whether or
+ // not to request Preview types.
+ kServerLoFiOn = 1 << 0, // Request a Lo-Fi version of the resource
+ // from the server.
+ kClientLoFiOn = 1 << 1, // Request a Lo-Fi version of the resource
+ // from the client.
+ kClientLoFiAutoReload = 1 << 2, // Request the original version of the
+ // resource after a decoding error occurred
+ // when attempting to use Client Lo-Fi.
+ kServerLitePageOn = 1 << 3, // Request a Lite Page version of the
+ // resource from the server.
+ kPreviewsNoTransform = 1 << 4, // Explicitly forbid Previews
+ // transformations.
+ kPreviewsOff = 1 << 5, // Request a normal (non-Preview) version of
+ // the resource. Server transformations may
+ // still happen if the page is heavy.
kPreviewsStateLast = kPreviewsOff
};