summaryrefslogtreecommitdiff
path: root/chromium/components/image_fetcher
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/components/image_fetcher')
-rw-r--r--chromium/components/image_fetcher/core/BUILD.gn (renamed from chromium/components/image_fetcher/BUILD.gn)4
-rw-r--r--chromium/components/image_fetcher/core/image_data_fetcher.cc (renamed from chromium/components/image_fetcher/image_data_fetcher.cc)66
-rw-r--r--chromium/components/image_fetcher/core/image_data_fetcher.h (renamed from chromium/components/image_fetcher/image_data_fetcher.h)35
-rw-r--r--chromium/components/image_fetcher/core/image_data_fetcher_unittest.cc297
-rw-r--r--chromium/components/image_fetcher/core/image_decoder.h (renamed from chromium/components/image_fetcher/image_decoder.h)6
-rw-r--r--chromium/components/image_fetcher/core/image_fetcher.h (renamed from chromium/components/image_fetcher/image_fetcher.h)29
-rw-r--r--chromium/components/image_fetcher/core/image_fetcher_delegate.h (renamed from chromium/components/image_fetcher/image_fetcher_delegate.h)11
-rw-r--r--chromium/components/image_fetcher/core/image_fetcher_impl.cc (renamed from chromium/components/image_fetcher/image_fetcher_impl.cc)36
-rw-r--r--chromium/components/image_fetcher/core/image_fetcher_impl.h (renamed from chromium/components/image_fetcher/image_fetcher_impl.h)34
-rw-r--r--chromium/components/image_fetcher/core/request_metadata.cc (renamed from chromium/components/image_fetcher/request_metadata.cc)9
-rw-r--r--chromium/components/image_fetcher/core/request_metadata.h35
-rw-r--r--chromium/components/image_fetcher/core/request_metadata_unittest.cc57
-rw-r--r--chromium/components/image_fetcher/image_data_fetcher_unittest.cc167
-rw-r--r--chromium/components/image_fetcher/ios/BUILD.gn8
-rw-r--r--chromium/components/image_fetcher/ios/DEPS1
-rw-r--r--chromium/components/image_fetcher/ios/ios_image_data_fetcher_wrapper.h2
-rw-r--r--chromium/components/image_fetcher/ios/ios_image_decoder_impl.h23
-rw-r--r--chromium/components/image_fetcher/ios/ios_image_decoder_impl.mm106
-rw-r--r--chromium/components/image_fetcher/ios/ios_image_decoder_impl_unittest.mm112
-rw-r--r--chromium/components/image_fetcher/request_metadata.h24
-rw-r--r--chromium/components/image_fetcher/request_metadata_unittest.cc39
21 files changed, 796 insertions, 305 deletions
diff --git a/chromium/components/image_fetcher/BUILD.gn b/chromium/components/image_fetcher/core/BUILD.gn
index f911424ac1d..19d9cd4a7bd 100644
--- a/chromium/components/image_fetcher/BUILD.gn
+++ b/chromium/components/image_fetcher/core/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-static_library("image_fetcher") {
+static_library("core") {
sources = [
"image_data_fetcher.cc",
"image_data_fetcher.h",
@@ -31,7 +31,7 @@ source_set("unit_tests") {
"request_metadata_unittest.cc",
]
deps = [
- ":image_fetcher",
+ ":core",
"//net",
"//net:test_support",
"//testing/gmock",
diff --git a/chromium/components/image_fetcher/image_data_fetcher.cc b/chromium/components/image_fetcher/core/image_data_fetcher.cc
index 204fa95d7e8..3eac4508d21 100644
--- a/chromium/components/image_fetcher/image_data_fetcher.cc
+++ b/chromium/components/image_fetcher/core/image_data_fetcher.cc
@@ -2,19 +2,26 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/image_fetcher/image_data_fetcher.h"
+#include "components/image_fetcher/core/image_data_fetcher.h"
+
+#include <utility>
#include "net/base/load_flags.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_status_code.h"
#include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_status.h"
#include "url/gurl.h"
using data_use_measurement::DataUseUserData;
+namespace {
+
+const char kContentLocationHeader[] = "Content-Location";
+
+} // namespace
+
namespace image_fetcher {
// An active image URL fetcher request. The struct contains the related requests
@@ -22,8 +29,7 @@ namespace image_fetcher {
struct ImageDataFetcher::ImageDataFetcherRequest {
ImageDataFetcherRequest(const ImageDataFetcherCallback& callback,
std::unique_ptr<net::URLFetcher> url_fetcher)
- : callback(callback),
- url_fetcher(std::move(url_fetcher)) {}
+ : callback(callback), url_fetcher(std::move(url_fetcher)) {}
~ImageDataFetcherRequest() {}
@@ -47,6 +53,11 @@ void ImageDataFetcher::SetDataUseServiceName(
data_use_service_name_ = data_use_service_name;
}
+void ImageDataFetcher::SetImageDownloadLimit(
+ base::Optional<int64_t> max_download_bytes) {
+ max_download_bytes_ = max_download_bytes;
+}
+
void ImageDataFetcher::FetchImageData(
const GURL& image_url,
const ImageDataFetcherCallback& callback) {
@@ -70,32 +81,63 @@ void ImageDataFetcher::FetchImageData(
request->url_fetcher->SetRequestContext(url_request_context_getter_.get());
request->url_fetcher->SetReferrer(referrer);
request->url_fetcher->SetReferrerPolicy(referrer_policy);
+ request->url_fetcher->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
+ net::LOAD_DO_NOT_SAVE_COOKIES |
+ net::LOAD_DO_NOT_SEND_AUTH_DATA);
request->url_fetcher->Start();
pending_requests_[request->url_fetcher.get()] = std::move(request);
}
void ImageDataFetcher::OnURLFetchComplete(const net::URLFetcher* source) {
- auto request_iter = pending_requests_.find(source);
- DCHECK(request_iter != pending_requests_.end());
-
+ DCHECK(pending_requests_.find(source) != pending_requests_.end());
bool success = source->GetStatus().status() == net::URLRequestStatus::SUCCESS;
RequestMetadata metadata;
- metadata.response_code = RESPONSE_CODE_INVALID;
if (success && source->GetResponseHeaders()) {
source->GetResponseHeaders()->GetMimeType(&metadata.mime_type);
- metadata.response_code = source->GetResponseHeaders()->response_code();
- success &= (metadata.response_code == net::HTTP_OK);
+ metadata.http_response_code = source->GetResponseHeaders()->response_code();
+ // Just read the first value-pair for this header (not caring about |iter|).
+ source->GetResponseHeaders()->EnumerateHeader(
+ /*iter=*/nullptr, kContentLocationHeader,
+ &metadata.content_location_header);
+ success &= (metadata.http_response_code == net::HTTP_OK);
}
+ metadata.from_http_cache = source->WasCached();
std::string image_data;
if (success) {
source->GetResponseAsString(&image_data);
}
- request_iter->second->callback.Run(image_data, metadata);
+ FinishRequest(source, metadata, image_data);
+}
+
+void ImageDataFetcher::OnURLFetchDownloadProgress(
+ const net::URLFetcher* source,
+ int64_t current,
+ int64_t total,
+ int64_t current_network_bytes) {
+ if (!max_download_bytes_.has_value()) {
+ return;
+ }
+ if (total <= max_download_bytes_.value() &&
+ current <= max_download_bytes_.value()) {
+ return;
+ }
+ DCHECK(pending_requests_.find(source) != pending_requests_.end());
+ DLOG(WARNING) << "Image data exceeded download size limit.";
+ RequestMetadata metadata;
+ metadata.http_response_code = net::URLFetcher::RESPONSE_CODE_INVALID;
- // Remove the finished request.
+ FinishRequest(source, metadata, /*image_data=*/std::string());
+}
+
+void ImageDataFetcher::FinishRequest(const net::URLFetcher* source,
+ const RequestMetadata& metadata,
+ const std::string& image_data) {
+ auto request_iter = pending_requests_.find(source);
+ DCHECK(request_iter != pending_requests_.end());
+ request_iter->second->callback.Run(image_data, metadata);
pending_requests_.erase(request_iter);
}
diff --git a/chromium/components/image_fetcher/image_data_fetcher.h b/chromium/components/image_fetcher/core/image_data_fetcher.h
index d05ec3d4bb5..169ad54d2ce 100644
--- a/chromium/components/image_fetcher/image_data_fetcher.h
+++ b/chromium/components/image_fetcher/core/image_data_fetcher.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_IMAGE_FETCHER_IMAGE_DATA_FETCHER_H_
-#define COMPONENTS_IMAGE_FETCHER_IMAGE_DATA_FETCHER_H_
+#ifndef COMPONENTS_IMAGE_FETCHER_CORE_IMAGE_DATA_FETCHER_H_
+#define COMPONENTS_IMAGE_FETCHER_CORE_IMAGE_DATA_FETCHER_H_
#include <map>
#include <memory>
@@ -12,9 +12,9 @@
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/optional.h"
#include "components/data_use_measurement/core/data_use_user_data.h"
-#include "components/image_fetcher/request_metadata.h"
-#include "net/url_request/url_fetcher.h"
+#include "components/image_fetcher/core/request_metadata.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "net/url_request/url_request.h"
#include "url/gurl.h"
@@ -28,14 +28,10 @@ namespace image_fetcher {
class ImageDataFetcher : public net::URLFetcherDelegate {
public:
- // Impossible http response code. Used to signal that no http response code
- // was received.
- enum ResponseCode {
- RESPONSE_CODE_INVALID = net::URLFetcher::RESPONSE_CODE_INVALID
- };
-
// Callback with the |image_data|. If an error prevented a http response,
// |request_metadata.response_code| will be RESPONSE_CODE_INVALID.
+ // TODO(treib): Pass |image_data| out by value, or use RefCountedBytes, to
+ // avoid copying.
using ImageDataFetcherCallback =
base::Callback<void(const std::string& image_data,
const RequestMetadata& request_metadata)>;
@@ -49,6 +45,10 @@ class ImageDataFetcher : public net::URLFetcherDelegate {
// Sets a service name against which to track data usage.
void SetDataUseServiceName(DataUseServiceName data_use_service_name);
+ // Sets an upper limit for image downloads.
+ // Already running downloads are affected.
+ void SetImageDownloadLimit(base::Optional<int64_t> max_download_bytes);
+
// Fetches the raw image bytes from the given |image_url| and calls the given
// |callback|. The callback is run even if fetching the URL fails. In case
// of an error an empty string is passed to the callback.
@@ -64,8 +64,16 @@ class ImageDataFetcher : public net::URLFetcherDelegate {
private:
struct ImageDataFetcherRequest;
- // Method inherited from URLFetcherDelegate
+ // Methods inherited from URLFetcherDelegate
void OnURLFetchComplete(const net::URLFetcher* source) override;
+ void OnURLFetchDownloadProgress(const net::URLFetcher* source,
+ int64_t current,
+ int64_t total,
+ int64_t current_network_bytes) override;
+
+ void FinishRequest(const net::URLFetcher* source,
+ const RequestMetadata& metadata,
+ const std::string& image_data);
// All active image url requests.
std::map<const net::URLFetcher*, std::unique_ptr<ImageDataFetcherRequest>>
@@ -82,9 +90,12 @@ class ImageDataFetcher : public net::URLFetcherDelegate {
// is not used.
int next_url_fetcher_id_;
+ // Upper limit for the number of bytes to download per image.
+ base::Optional<int64_t> max_download_bytes_;
+
DISALLOW_COPY_AND_ASSIGN(ImageDataFetcher);
};
} // namespace image_fetcher
-#endif // COMPONENTS_IMAGE_FETCHER_IMAGE_DATA_FETCHER_H_
+#endif // COMPONENTS_IMAGE_FETCHER_CORE_IMAGE_DATA_FETCHER_H_
diff --git a/chromium/components/image_fetcher/core/image_data_fetcher_unittest.cc b/chromium/components/image_fetcher/core/image_data_fetcher_unittest.cc
new file mode 100644
index 00000000000..de47936940e
--- /dev/null
+++ b/chromium/components/image_fetcher/core/image_data_fetcher_unittest.cc
@@ -0,0 +1,297 @@
+// 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 "components/image_fetcher/core/image_data_fetcher.h"
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.h"
+#include "net/base/load_flags.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_status_code.h"
+#include "net/url_request/test_url_fetcher_factory.h"
+#include "net/url_request/url_request_status.h"
+#include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char kImageURL[] = "http://www.example.com/image";
+const char kURLResponseData[] = "EncodedImageData";
+
+} // namespace
+
+namespace image_fetcher {
+
+class ImageDataFetcherTest : public testing::Test {
+ public:
+ ImageDataFetcherTest()
+ : test_request_context_getter_(
+ new net::TestURLRequestContextGetter(message_loop_.task_runner())),
+ image_data_fetcher_(test_request_context_getter_.get()) {}
+ ~ImageDataFetcherTest() override {}
+
+ MOCK_METHOD2(OnImageDataFetched,
+ void(const std::string&, const RequestMetadata&));
+
+ MOCK_METHOD2(OnImageDataFetchedFailedRequest,
+ void(const std::string&, const RequestMetadata&));
+
+ MOCK_METHOD2(OnImageDataFetchedMultipleRequests,
+ void(const std::string&, const RequestMetadata&));
+
+ protected:
+ base::MessageLoop message_loop_;
+
+ scoped_refptr<net::URLRequestContextGetter> test_request_context_getter_;
+
+ ImageDataFetcher image_data_fetcher_;
+
+ net::TestURLFetcherFactory fetcher_factory_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ImageDataFetcherTest);
+};
+
+TEST_F(ImageDataFetcherTest, FetchImageData) {
+ image_data_fetcher_.FetchImageData(
+ GURL(kImageURL), base::Bind(&ImageDataFetcherTest::OnImageDataFetched,
+ base::Unretained(this)));
+
+ RequestMetadata expected_metadata;
+ expected_metadata.mime_type = std::string("image/png");
+ expected_metadata.http_response_code = net::HTTP_OK;
+ EXPECT_CALL(*this, OnImageDataFetched(std::string(kURLResponseData),
+ expected_metadata));
+
+ // Get and configure the TestURLFetcher.
+ net::TestURLFetcher* test_url_fetcher = fetcher_factory_.GetFetcherByID(0);
+ ASSERT_NE(nullptr, test_url_fetcher);
+ EXPECT_TRUE(test_url_fetcher->GetLoadFlags() & net::LOAD_DO_NOT_SEND_COOKIES);
+ EXPECT_TRUE(test_url_fetcher->GetLoadFlags() & net::LOAD_DO_NOT_SAVE_COOKIES);
+ EXPECT_TRUE(test_url_fetcher->GetLoadFlags() &
+ net::LOAD_DO_NOT_SEND_AUTH_DATA);
+ test_url_fetcher->set_status(
+ net::URLRequestStatus(net::URLRequestStatus::SUCCESS, net::OK));
+ test_url_fetcher->SetResponseString(kURLResponseData);
+ test_url_fetcher->set_response_code(net::HTTP_OK);
+
+ std::string raw_header =
+ "HTTP/1.1 200 OK\n"
+ "Content-type: image/png\n\n";
+ std::replace(raw_header.begin(), raw_header.end(), '\n', '\0');
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(raw_header));
+ test_url_fetcher->set_response_headers(headers);
+
+ // Call the URLFetcher delegate to continue the test.
+ test_url_fetcher->delegate()->OnURLFetchComplete(test_url_fetcher);
+}
+
+TEST_F(ImageDataFetcherTest, FetchImageData_FromCache) {
+ image_data_fetcher_.FetchImageData(
+ GURL(kImageURL), base::Bind(&ImageDataFetcherTest::OnImageDataFetched,
+ base::Unretained(this)));
+
+ RequestMetadata expected_metadata;
+ expected_metadata.mime_type = std::string("image/png");
+ expected_metadata.http_response_code = net::HTTP_OK;
+ expected_metadata.from_http_cache = true;
+ EXPECT_CALL(*this, OnImageDataFetched(std::string(kURLResponseData),
+ expected_metadata));
+
+ // Get and configure the TestURLFetcher.
+ net::TestURLFetcher* test_url_fetcher = fetcher_factory_.GetFetcherByID(0);
+ ASSERT_NE(nullptr, test_url_fetcher);
+ test_url_fetcher->set_status(
+ net::URLRequestStatus(net::URLRequestStatus::SUCCESS, net::OK));
+ test_url_fetcher->SetResponseString(kURLResponseData);
+ test_url_fetcher->set_response_code(net::HTTP_OK);
+ test_url_fetcher->set_was_cached(true);
+
+ std::string raw_header =
+ "HTTP/1.1 200 OK\n"
+ "Content-type: image/png\n\n";
+ std::replace(raw_header.begin(), raw_header.end(), '\n', '\0');
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(raw_header));
+ test_url_fetcher->set_response_headers(headers);
+
+ // Call the URLFetcher delegate to continue the test.
+ test_url_fetcher->delegate()->OnURLFetchComplete(test_url_fetcher);
+}
+
+TEST_F(ImageDataFetcherTest, FetchImageData_NotFound) {
+ image_data_fetcher_.FetchImageData(
+ GURL(kImageURL), base::Bind(&ImageDataFetcherTest::OnImageDataFetched,
+ base::Unretained(this)));
+
+ RequestMetadata expected_metadata;
+ expected_metadata.mime_type = std::string("image/png");
+ expected_metadata.http_response_code = net::HTTP_NOT_FOUND;
+ // For 404, expect an empty result even though correct image data is sent.
+ EXPECT_CALL(*this, OnImageDataFetched(std::string(), expected_metadata));
+
+ // Get and configure the TestURLFetcher.
+ net::TestURLFetcher* test_url_fetcher = fetcher_factory_.GetFetcherByID(0);
+ ASSERT_NE(nullptr, test_url_fetcher);
+ test_url_fetcher->set_status(
+ net::URLRequestStatus(net::URLRequestStatus::SUCCESS, net::OK));
+ test_url_fetcher->SetResponseString(kURLResponseData);
+
+ std::string raw_header =
+ "HTTP/1.1 404 Not Found\n"
+ "Content-type: image/png\n\n";
+ std::replace(raw_header.begin(), raw_header.end(), '\n', '\0');
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(raw_header));
+ test_url_fetcher->set_response_headers(headers);
+
+ // Call the URLFetcher delegate to continue the test.
+ test_url_fetcher->delegate()->OnURLFetchComplete(test_url_fetcher);
+}
+
+TEST_F(ImageDataFetcherTest, FetchImageData_WithContentLocation) {
+ image_data_fetcher_.FetchImageData(
+ GURL(kImageURL), base::Bind(&ImageDataFetcherTest::OnImageDataFetched,
+ base::Unretained(this)));
+
+ RequestMetadata expected_metadata;
+ expected_metadata.mime_type = std::string("image/png");
+ expected_metadata.http_response_code = net::HTTP_NOT_FOUND;
+ expected_metadata.content_location_header = "http://test-location/image.png";
+ // For 404, expect an empty result even though correct image data is sent.
+ EXPECT_CALL(*this, OnImageDataFetched(std::string(), expected_metadata));
+
+ // Get and configure the TestURLFetcher.
+ net::TestURLFetcher* test_url_fetcher = fetcher_factory_.GetFetcherByID(0);
+ ASSERT_NE(nullptr, test_url_fetcher);
+ test_url_fetcher->set_status(
+ net::URLRequestStatus(net::URLRequestStatus::SUCCESS, net::OK));
+ test_url_fetcher->SetResponseString(kURLResponseData);
+
+ std::string raw_header =
+ "HTTP/1.1 404 Not Found\n"
+ "Content-type: image/png\n"
+ "Content-location: http://test-location/image.png\n\n";
+ std::replace(raw_header.begin(), raw_header.end(), '\n', '\0');
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(raw_header));
+ test_url_fetcher->set_response_headers(headers);
+
+ // Call the URLFetcher delegate to continue the test.
+ test_url_fetcher->delegate()->OnURLFetchComplete(test_url_fetcher);
+}
+
+TEST_F(ImageDataFetcherTest, FetchImageData_FailedRequest) {
+ image_data_fetcher_.FetchImageData(
+ GURL(kImageURL),
+ base::Bind(&ImageDataFetcherTest::OnImageDataFetchedFailedRequest,
+ base::Unretained(this)));
+
+ RequestMetadata expected_metadata;
+ expected_metadata.http_response_code = net::URLFetcher::RESPONSE_CODE_INVALID;
+ EXPECT_CALL(
+ *this, OnImageDataFetchedFailedRequest(std::string(), expected_metadata));
+
+ // Get and configure the TestURLFetcher.
+ net::TestURLFetcher* test_url_fetcher = fetcher_factory_.GetFetcherByID(0);
+ ASSERT_NE(nullptr, test_url_fetcher);
+ test_url_fetcher->set_status(net::URLRequestStatus(
+ net::URLRequestStatus::FAILED, net::ERR_INVALID_URL));
+
+ // Call the URLFetcher delegate to continue the test.
+ test_url_fetcher->delegate()->OnURLFetchComplete(test_url_fetcher);
+}
+
+TEST_F(ImageDataFetcherTest, FetchImageData_MultipleRequests) {
+ ImageDataFetcher::ImageDataFetcherCallback callback =
+ base::Bind(&ImageDataFetcherTest::OnImageDataFetchedMultipleRequests,
+ base::Unretained(this));
+ EXPECT_CALL(*this, OnImageDataFetchedMultipleRequests(testing::_, testing::_))
+ .Times(2);
+
+ image_data_fetcher_.FetchImageData(GURL(kImageURL), callback);
+ image_data_fetcher_.FetchImageData(GURL(kImageURL), callback);
+
+ // Multiple calls to FetchImageData for the same URL will result in
+ // multiple URLFetchers being created.
+ net::TestURLFetcher* test_url_fetcher = fetcher_factory_.GetFetcherByID(0);
+ ASSERT_NE(nullptr, test_url_fetcher);
+ test_url_fetcher->delegate()->OnURLFetchComplete(test_url_fetcher);
+
+ test_url_fetcher = fetcher_factory_.GetFetcherByID(1);
+ ASSERT_NE(nullptr, test_url_fetcher);
+ test_url_fetcher->delegate()->OnURLFetchComplete(test_url_fetcher);
+}
+
+TEST_F(ImageDataFetcherTest, FetchImageData_CancelFetchIfImageExceedsMaxSize) {
+ // In order to know whether the fetcher was canceled, it must notify about its
+ // deletion.
+ fetcher_factory_.set_remove_fetcher_on_delete(true);
+
+ const int64_t kMaxDownloadBytes = 1024 * 1024;
+ image_data_fetcher_.SetImageDownloadLimit(kMaxDownloadBytes);
+ image_data_fetcher_.FetchImageData(
+ GURL(kImageURL), base::Bind(&ImageDataFetcherTest::OnImageDataFetched,
+ base::Unretained(this)));
+
+ // Fetching an oversized image will behave like any other failed request.
+ // There will be exactly one call to OnImageDataFetched containing a response
+ // code that would be impossible for a completed fetch.
+ RequestMetadata expected_metadata;
+ expected_metadata.http_response_code = net::URLFetcher::RESPONSE_CODE_INVALID;
+ EXPECT_CALL(*this, OnImageDataFetched(std::string(), expected_metadata));
+
+ // Get and configure the TestURLFetcher.
+ net::TestURLFetcher* test_url_fetcher = fetcher_factory_.GetFetcherByID(0);
+ ASSERT_NE(nullptr, test_url_fetcher);
+
+ // Create a completely valid response that is never used. This is to make sure
+ // that the answer isn't accidentally invalid but intentionally.
+ test_url_fetcher->set_status(
+ net::URLRequestStatus(net::URLRequestStatus::SUCCESS, net::OK));
+ test_url_fetcher->SetResponseString(kURLResponseData);
+ test_url_fetcher->set_response_code(net::HTTP_OK);
+ std::string raw_header =
+ "HTTP/1.1 200 OK\n"
+ "Content-type: image/png\n\n";
+ std::replace(raw_header.begin(), raw_header.end(), '\n', '\0');
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(raw_header));
+ test_url_fetcher->set_response_headers(headers);
+
+ test_url_fetcher->delegate()->OnURLFetchDownloadProgress(
+ test_url_fetcher,
+ /*current=*/0, // Bytes received up to the call.
+ /*total=*/-1, // not determined
+ /*current_network_bytes=*/0); // not relevant
+ // The URL fetch should be running ...
+ ASSERT_NE(nullptr, fetcher_factory_.GetFetcherByID(0));
+
+ test_url_fetcher->delegate()->OnURLFetchDownloadProgress(
+ test_url_fetcher,
+ 768 * 1024, // Current bytes are not exeeding the limit.
+ /*total=*/-1, /*current_network_bytes=*/0);
+ // ... and running ...
+ ASSERT_NE(nullptr, fetcher_factory_.GetFetcherByID(0));
+
+ test_url_fetcher->delegate()->OnURLFetchDownloadProgress(
+ test_url_fetcher, kMaxDownloadBytes, // Still not exeeding the limit.
+ /*total=*/-1, /*current_network_bytes=*/0);
+ // ... and running ...
+ ASSERT_NE(nullptr, fetcher_factory_.GetFetcherByID(0));
+
+ test_url_fetcher->delegate()->OnURLFetchDownloadProgress(
+ test_url_fetcher, kMaxDownloadBytes + 1, // Limits are exceeded.
+ /*total=*/-1, /*current_network_bytes=*/0);
+ // ... and be canceled.
+ EXPECT_EQ(nullptr, fetcher_factory_.GetFetcherByID(0));
+}
+
+} // namespace image_fetcher
diff --git a/chromium/components/image_fetcher/image_decoder.h b/chromium/components/image_fetcher/core/image_decoder.h
index b5589f17b4a..5f03db12d4c 100644
--- a/chromium/components/image_fetcher/image_decoder.h
+++ b/chromium/components/image_fetcher/core/image_decoder.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_IMAGE_FETCHER_IMAGE_DECODER_H_
-#define COMPONENTS_IMAGE_FETCHER_IMAGE_DECODER_H_
+#ifndef COMPONENTS_IMAGE_FETCHER_CORE_IMAGE_DECODER_H_
+#define COMPONENTS_IMAGE_FETCHER_CORE_IMAGE_DECODER_H_
#include <string>
@@ -43,4 +43,4 @@ class ImageDecoder {
} // namespace image_fetcher
-#endif // COMPONENTS_IMAGE_FETCHER_IMAGE_DECODER_H_
+#endif // COMPONENTS_IMAGE_FETCHER_CORE_IMAGE_DECODER_H_
diff --git a/chromium/components/image_fetcher/image_fetcher.h b/chromium/components/image_fetcher/core/image_fetcher.h
index 3626c3af704..0284aee9f25 100644
--- a/chromium/components/image_fetcher/image_fetcher.h
+++ b/chromium/components/image_fetcher/core/image_fetcher.h
@@ -2,15 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_IMAGE_FETCHER_IMAGE_FETCHER_H_
-#define COMPONENTS_IMAGE_FETCHER_IMAGE_FETCHER_H_
+#ifndef COMPONENTS_IMAGE_FETCHER_CORE_IMAGE_FETCHER_H_
+#define COMPONENTS_IMAGE_FETCHER_CORE_IMAGE_FETCHER_H_
#include <string>
#include "base/callback.h"
#include "base/macros.h"
+#include "base/optional.h"
#include "components/data_use_measurement/core/data_use_user_data.h"
-#include "components/image_fetcher/image_fetcher_delegate.h"
+#include "components/image_fetcher/core/image_fetcher_delegate.h"
#include "url/gurl.h"
namespace gfx {
@@ -20,6 +21,10 @@ class Size;
namespace image_fetcher {
+class ImageDecoder;
+
+struct RequestMetadata;
+
// A class used to fetch server images. It can be called from any thread and the
// callback will be called on the thread which initiated the fetch.
class ImageFetcher {
@@ -27,6 +32,11 @@ class ImageFetcher {
ImageFetcher() {}
virtual ~ImageFetcher() {}
+ using ImageFetcherCallback =
+ base::Callback<void(const std::string& id,
+ const gfx::Image& image,
+ const RequestMetadata& metadata)>;
+
using DataUseServiceName = data_use_measurement::DataUseUserData::ServiceName;
virtual void SetImageFetcherDelegate(ImageFetcherDelegate* delegate) = 0;
@@ -35,6 +45,12 @@ class ImageFetcher {
virtual void SetDataUseServiceName(
DataUseServiceName data_use_service_name) = 0;
+ // Sets an upper limit for image downloads that is by default disabled.
+ // Setting |max_download_bytes| to a negative value will disable the limit.
+ // Already running downloads are immediately affected.
+ virtual void SetImageDownloadLimit(
+ base::Optional<int64_t> max_download_bytes) = 0;
+
// Sets the desired size for images with multiple frames (like .ico files).
// By default, the image fetcher choses smaller images. Override to choose a
// frame with a size as close as possible to |size| (trying to take one in
@@ -48,10 +64,9 @@ class ImageFetcher {
virtual void StartOrQueueNetworkRequest(
const std::string& id,
const GURL& image_url,
- base::Callback<void(const std::string&, const gfx::Image&)> callback) = 0;
+ const ImageFetcherCallback& callback) = 0;
- // TODO(treib,markusheintz): Now that iOS uses the same ImageFetcherImpl (see
- // crbug.com/689020), add a getter for the ImageDecoder here.
+ virtual ImageDecoder* GetImageDecoder() = 0;
private:
DISALLOW_COPY_AND_ASSIGN(ImageFetcher);
@@ -59,4 +74,4 @@ class ImageFetcher {
} // namespace image_fetcher
-#endif // COMPONENTS_IMAGE_FETCHER_IMAGE_FETCHER_H_
+#endif // COMPONENTS_IMAGE_FETCHER_CORE_IMAGE_FETCHER_H_
diff --git a/chromium/components/image_fetcher/image_fetcher_delegate.h b/chromium/components/image_fetcher/core/image_fetcher_delegate.h
index 38d66b29543..fd9c362fcb9 100644
--- a/chromium/components/image_fetcher/image_fetcher_delegate.h
+++ b/chromium/components/image_fetcher/core/image_fetcher_delegate.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_IMAGE_FETCHER_IMAGE_FETCHER_DELEGATE_H_
-#define COMPONENTS_IMAGE_FETCHER_IMAGE_FETCHER_DELEGATE_H_
+#ifndef COMPONENTS_IMAGE_FETCHER_CORE_IMAGE_FETCHER_DELEGATE_H_
+#define COMPONENTS_IMAGE_FETCHER_CORE_IMAGE_FETCHER_DELEGATE_H_
#include <string>
@@ -24,13 +24,12 @@ class ImageFetcherDelegate {
// stores (generally compressed) image data owned by the caller, and can be
// empty if the fetch failed.
virtual void OnImageDataFetched(const std::string& id,
- const std::string& data) {};
+ const std::string& data) {}
// Called when an image was fetched and decoded. |id| is an identifier for the
// fetch (as passed to ImageFetcher::StartOrQueueNetworkRequest); |image|
// stores image data owned by the caller, and can be an empty gfx::Image.
- virtual void OnImageFetched(const std::string& id,
- const gfx::Image& image) {};
+ virtual void OnImageFetched(const std::string& id, const gfx::Image& image) {}
protected:
virtual ~ImageFetcherDelegate() {}
@@ -40,4 +39,4 @@ class ImageFetcherDelegate {
} // namespace image_fetcher
-#endif // COMPONENTS_IMAGE_FETCHER_IMAGE_FETCHER_DELEGATE_H_
+#endif // COMPONENTS_IMAGE_FETCHER_CORE_IMAGE_FETCHER_DELEGATE_H_
diff --git a/chromium/components/image_fetcher/image_fetcher_impl.cc b/chromium/components/image_fetcher/core/image_fetcher_impl.cc
index f65155c65e7..567928c9a6d 100644
--- a/chromium/components/image_fetcher/image_fetcher_impl.cc
+++ b/chromium/components/image_fetcher/core/image_fetcher_impl.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/image_fetcher/image_fetcher_impl.h"
+#include "components/image_fetcher/core/image_fetcher_impl.h"
#include <string>
@@ -15,10 +15,10 @@ namespace image_fetcher {
ImageFetcherImpl::ImageFetcherImpl(
std::unique_ptr<ImageDecoder> image_decoder,
net::URLRequestContextGetter* url_request_context)
- : delegate_(nullptr), url_request_context_(url_request_context),
+ : delegate_(nullptr),
+ url_request_context_(url_request_context),
image_decoder_(std::move(image_decoder)),
- image_data_fetcher_(new ImageDataFetcher(url_request_context_.get())) {
-}
+ image_data_fetcher_(new ImageDataFetcher(url_request_context_.get())) {}
ImageFetcherImpl::~ImageFetcherImpl() {}
@@ -27,7 +27,7 @@ ImageFetcherImpl::ImageRequest::ImageRequest() {}
ImageFetcherImpl::ImageRequest::ImageRequest(const ImageRequest& other) =
default;
-ImageFetcherImpl::ImageRequest::~ImageRequest() { }
+ImageFetcherImpl::ImageRequest::~ImageRequest() {}
void ImageFetcherImpl::SetImageFetcherDelegate(ImageFetcherDelegate* delegate) {
DCHECK(delegate);
@@ -43,10 +43,15 @@ void ImageFetcherImpl::SetDesiredImageFrameSize(const gfx::Size& size) {
desired_image_frame_size_ = size;
}
+void ImageFetcherImpl::SetImageDownloadLimit(
+ base::Optional<int64_t> max_download_bytes) {
+ image_data_fetcher_->SetImageDownloadLimit(max_download_bytes);
+}
+
void ImageFetcherImpl::StartOrQueueNetworkRequest(
const std::string& id,
const GURL& image_url,
- base::Callback<void(const std::string&, const gfx::Image&)> callback) {
+ const ImageFetcherCallback& callback) {
// Before starting to fetch the image. Look for a request in progress for
// |image_url|, and queue if appropriate.
ImageRequestMap::iterator it = pending_net_requests_.find(image_url);
@@ -57,9 +62,8 @@ void ImageFetcherImpl::StartOrQueueNetworkRequest(
pending_net_requests_[image_url].swap(&request);
image_data_fetcher_->FetchImageData(
- image_url,
- base::Bind(&ImageFetcherImpl::OnImageURLFetched,
- base::Unretained(this), image_url));
+ image_url, base::Bind(&ImageFetcherImpl::OnImageURLFetched,
+ base::Unretained(this), image_url));
} else {
// Request in progress. Register as an interested callback.
it->second.callbacks.push_back(callback);
@@ -76,12 +80,14 @@ void ImageFetcherImpl::OnImageURLFetched(const GURL& image_url,
delegate_->OnImageDataFetched(it->second.id, image_data);
}
- image_decoder_->DecodeImage(image_data, desired_image_frame_size_,
- base::Bind(&ImageFetcherImpl::OnImageDecoded,
- base::Unretained(this), image_url));
+ image_decoder_->DecodeImage(
+ image_data, desired_image_frame_size_,
+ base::Bind(&ImageFetcherImpl::OnImageDecoded, base::Unretained(this),
+ image_url, metadata));
}
void ImageFetcherImpl::OnImageDecoded(const GURL& image_url,
+ const RequestMetadata& metadata,
const gfx::Image& image) {
// Get request for the given image_url from the request queue.
ImageRequestMap::iterator image_iter = pending_net_requests_.find(image_url);
@@ -90,7 +96,7 @@ void ImageFetcherImpl::OnImageDecoded(const GURL& image_url,
// Run all callbacks
for (const auto& callback : request->callbacks) {
- callback.Run(request->id, image);
+ callback.Run(request->id, image, metadata);
}
// Inform the ImageFetcherDelegate.
@@ -102,4 +108,8 @@ void ImageFetcherImpl::OnImageDecoded(const GURL& image_url,
pending_net_requests_.erase(image_iter);
}
+ImageDecoder* ImageFetcherImpl::GetImageDecoder() {
+ return image_decoder_.get();
+}
+
} // namespace image_fetcher
diff --git a/chromium/components/image_fetcher/image_fetcher_impl.h b/chromium/components/image_fetcher/core/image_fetcher_impl.h
index 16b348f854e..697217c7f79 100644
--- a/chromium/components/image_fetcher/image_fetcher_impl.h
+++ b/chromium/components/image_fetcher/core/image_fetcher_impl.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_IMAGE_FETCHER_IMAGE_FETCHER_IMPL_H_
-#define COMPONENTS_IMAGE_FETCHER_IMAGE_FETCHER_IMPL_H_
+#ifndef COMPONENTS_IMAGE_FETCHER_CORE_IMAGE_FETCHER_IMPL_H_
+#define COMPONENTS_IMAGE_FETCHER_CORE_IMAGE_FETCHER_IMPL_H_
#include <map>
#include <memory>
@@ -13,9 +13,9 @@
#include "base/callback.h"
#include "base/macros.h"
-#include "components/image_fetcher/image_data_fetcher.h"
-#include "components/image_fetcher/image_decoder.h"
-#include "components/image_fetcher/image_fetcher.h"
+#include "components/image_fetcher/core/image_data_fetcher.h"
+#include "components/image_fetcher/core/image_decoder.h"
+#include "components/image_fetcher/core/image_fetcher.h"
#include "ui/gfx/geometry/size.h"
#include "url/gurl.h"
@@ -32,9 +32,8 @@ namespace image_fetcher {
// The standard (non-test) implementation of ImageFetcher.
class ImageFetcherImpl : public image_fetcher::ImageFetcher {
public:
- ImageFetcherImpl(
- std::unique_ptr<ImageDecoder> image_decoder,
- net::URLRequestContextGetter* url_request_context);
+ ImageFetcherImpl(std::unique_ptr<ImageDecoder> image_decoder,
+ net::URLRequestContextGetter* url_request_context);
~ImageFetcherImpl() override;
// Sets the |delegate| of the ImageFetcherImpl. The |delegate| has to be alive
@@ -47,16 +46,17 @@ class ImageFetcherImpl : public image_fetcher::ImageFetcher {
void SetDesiredImageFrameSize(const gfx::Size& size) override;
+ void SetImageDownloadLimit(
+ base::Optional<int64_t> max_download_bytes) override;
+
void StartOrQueueNetworkRequest(
const std::string& id,
const GURL& image_url,
- base::Callback<void(const std::string&, const gfx::Image&)> callback)
- override;
+ const ImageFetcherCallback& callback) override;
- private:
- using CallbackVector =
- std::vector<base::Callback<void(const std::string&, const gfx::Image&)>>;
+ ImageDecoder* GetImageDecoder() override;
+ private:
// State related to an image fetch (id, pending callbacks).
struct ImageRequest {
ImageRequest();
@@ -71,7 +71,7 @@ class ImageFetcherImpl : public image_fetcher::ImageFetcher {
std::string id;
// Queue for pending callbacks, which may accumulate while the request is in
// flight.
- CallbackVector callbacks;
+ std::vector<ImageFetcherCallback> callbacks;
};
using ImageRequestMap = std::map<const GURL, ImageRequest>;
@@ -84,7 +84,9 @@ class ImageFetcherImpl : public image_fetcher::ImageFetcher {
// Processes image decoded events. This is the continuation method used for
// creating callbacks that are passed to the ImageDecoder.
- void OnImageDecoded(const GURL& image_url, const gfx::Image& image);
+ void OnImageDecoded(const GURL& image_url,
+ const RequestMetadata& metadata,
+ const gfx::Image& image);
ImageFetcherDelegate* delegate_;
@@ -105,4 +107,4 @@ class ImageFetcherImpl : public image_fetcher::ImageFetcher {
} // namespace image_fetcher
-#endif // COMPONENTS_IMAGE_FETCHER_IMAGE_FETCHER_IMPL_H_
+#endif // COMPONENTS_IMAGE_FETCHER_CORE_IMAGE_FETCHER_IMPL_H_
diff --git a/chromium/components/image_fetcher/request_metadata.cc b/chromium/components/image_fetcher/core/request_metadata.cc
index 172dc5c2ab1..13ffadaa357 100644
--- a/chromium/components/image_fetcher/request_metadata.cc
+++ b/chromium/components/image_fetcher/core/request_metadata.cc
@@ -2,13 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/image_fetcher/request_metadata.h"
+#include "components/image_fetcher/core/request_metadata.h"
namespace image_fetcher {
+RequestMetadata::RequestMetadata()
+ : http_response_code(RESPONSE_CODE_INVALID), from_http_cache(false) {}
+
bool operator==(const RequestMetadata& lhs, const RequestMetadata& rhs) {
return lhs.mime_type == rhs.mime_type &&
- lhs.response_code == rhs.response_code;
+ lhs.http_response_code == rhs.http_response_code &&
+ lhs.from_http_cache == rhs.from_http_cache &&
+ lhs.content_location_header == rhs.content_location_header;
}
bool operator!=(const RequestMetadata& lhs, const RequestMetadata& rhs) {
diff --git a/chromium/components/image_fetcher/core/request_metadata.h b/chromium/components/image_fetcher/core/request_metadata.h
new file mode 100644
index 00000000000..630ffc6956c
--- /dev/null
+++ b/chromium/components/image_fetcher/core/request_metadata.h
@@ -0,0 +1,35 @@
+// Copyright 2017 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 COMPONENTS_IMAGE_FETCHER_CORE_REQUEST_METADATA_H_
+#define COMPONENTS_IMAGE_FETCHER_CORE_REQUEST_METADATA_H_
+
+#include <string>
+
+#include "net/url_request/url_fetcher.h"
+
+namespace image_fetcher {
+
+// Metadata for a URL request.
+struct RequestMetadata {
+ // Impossible http response code. Used to signal that no http response code
+ // was received.
+ enum ResponseCode {
+ RESPONSE_CODE_INVALID = net::URLFetcher::RESPONSE_CODE_INVALID
+ };
+
+ RequestMetadata();
+
+ std::string mime_type;
+ int http_response_code;
+ bool from_http_cache;
+ std::string content_location_header;
+};
+
+bool operator==(const RequestMetadata& lhs, const RequestMetadata& rhs);
+bool operator!=(const RequestMetadata& lhs, const RequestMetadata& rhs);
+
+} // namespace image_fetcher
+
+#endif // COMPONENTS_IMAGE_FETCHER_CORE_REQUEST_METADATA_H_
diff --git a/chromium/components/image_fetcher/core/request_metadata_unittest.cc b/chromium/components/image_fetcher/core/request_metadata_unittest.cc
new file mode 100644
index 00000000000..ea0d00f4e5c
--- /dev/null
+++ b/chromium/components/image_fetcher/core/request_metadata_unittest.cc
@@ -0,0 +1,57 @@
+// Copyright 2017 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 "components/image_fetcher/core/request_metadata.h"
+
+#include "base/memory/ref_counted.h"
+#include "net/http/http_response_headers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace image_fetcher {
+
+TEST(RequestMetadataTest, Equality) {
+ RequestMetadata rhs;
+ RequestMetadata lhs;
+ rhs.mime_type = "testMimeType";
+ lhs.mime_type = "testMimeType";
+ rhs.http_response_code = 1;
+ lhs.http_response_code = 1;
+ rhs.from_http_cache = true;
+ lhs.from_http_cache = true;
+ lhs.content_location_header = "http://test-location.com/image.png";
+ rhs.content_location_header = "http://test-location.com/image.png";
+
+ EXPECT_EQ(rhs, lhs);
+}
+
+TEST(RequestMetadataTest, NoEquality) {
+ RequestMetadata rhs;
+ RequestMetadata lhs;
+ rhs.mime_type = "testMimeType";
+ lhs.mime_type = "testMimeType";
+ rhs.http_response_code = 1;
+ lhs.http_response_code = 1;
+ rhs.from_http_cache = true;
+ lhs.from_http_cache = true;
+ lhs.content_location_header = "http://test-location.com/image.png";
+ rhs.content_location_header = "http://test-location.com/image.png";
+
+ lhs.mime_type = "testOtherMimeType";
+ EXPECT_NE(rhs, lhs);
+ lhs.mime_type = "testMimeType";
+
+ lhs.http_response_code = 2;
+ EXPECT_NE(rhs, lhs);
+ lhs.http_response_code = 1;
+
+ lhs.from_http_cache = false;
+ EXPECT_NE(rhs, lhs);
+ lhs.from_http_cache = true;
+
+ lhs.content_location_header = "http://other.test-location.com/image.png";
+ EXPECT_NE(rhs, lhs);
+ lhs.content_location_header = "http://test-location.com/image.png";
+}
+
+} // namespace image_fetcher
diff --git a/chromium/components/image_fetcher/image_data_fetcher_unittest.cc b/chromium/components/image_fetcher/image_data_fetcher_unittest.cc
deleted file mode 100644
index 15039781fb4..00000000000
--- a/chromium/components/image_fetcher/image_data_fetcher_unittest.cc
+++ /dev/null
@@ -1,167 +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 "components/image_fetcher/image_data_fetcher.h"
-
-#include <memory>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
-#include "net/http/http_response_headers.h"
-#include "net/http/http_status_code.h"
-#include "net/url_request/test_url_fetcher_factory.h"
-#include "net/url_request/url_request_status.h"
-#include "net/url_request/url_request_test_util.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-const char kImageURL[] = "http://www.example.com/image";
-const char kURLResponseData[] = "EncodedImageData";
-
-} // namespace
-
-namespace image_fetcher {
-
-class ImageDataFetcherTest : public testing::Test {
- public:
- ImageDataFetcherTest()
- : test_request_context_getter_(
- new net::TestURLRequestContextGetter(message_loop_.task_runner())),
- image_data_fetcher_(test_request_context_getter_.get()) {}
- ~ImageDataFetcherTest() override {}
-
- MOCK_METHOD2(OnImageDataFetched,
- void(const std::string&, const RequestMetadata&));
-
- MOCK_METHOD2(OnImageDataFetchedFailedRequest,
- void(const std::string&, const RequestMetadata&));
-
- MOCK_METHOD2(OnImageDataFetchedMultipleRequests,
- void(const std::string&, const RequestMetadata&));
-
- protected:
- base::MessageLoop message_loop_;
-
- scoped_refptr<net::URLRequestContextGetter> test_request_context_getter_;
-
- ImageDataFetcher image_data_fetcher_;
-
- net::TestURLFetcherFactory fetcher_factory_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ImageDataFetcherTest);
-};
-
-TEST_F(ImageDataFetcherTest, FetchImageData) {
- image_data_fetcher_.FetchImageData(
- GURL(kImageURL),
- base::Bind(&ImageDataFetcherTest::OnImageDataFetched,
- base::Unretained(this)));
-
- RequestMetadata expected_metadata;
- expected_metadata.mime_type = std::string("image/png");
- expected_metadata.response_code = net::HTTP_OK;
- EXPECT_CALL(*this, OnImageDataFetched(std::string(kURLResponseData),
- expected_metadata));
-
- // Get and configure the TestURLFetcher.
- net::TestURLFetcher* test_url_fetcher = fetcher_factory_.GetFetcherByID(0);
- ASSERT_NE(nullptr, test_url_fetcher);
- test_url_fetcher->set_status(
- net::URLRequestStatus(net::URLRequestStatus::SUCCESS, net::OK));
- test_url_fetcher->SetResponseString(kURLResponseData);
- test_url_fetcher->set_response_code(net::HTTP_OK);
-
- std::string raw_header =
- "HTTP/1.1 200 OK\n"
- "Content-type: image/png\n\n";
- std::replace(raw_header.begin(), raw_header.end(), '\n', '\0');
- scoped_refptr<net::HttpResponseHeaders> headers(
- new net::HttpResponseHeaders(raw_header));
-
- test_url_fetcher->set_response_headers(headers);
-
- // Call the URLFetcher delegate to continue the test.
- test_url_fetcher->delegate()->OnURLFetchComplete(test_url_fetcher);
-}
-
-TEST_F(ImageDataFetcherTest, FetchImageData_NotFound) {
- image_data_fetcher_.FetchImageData(
- GURL(kImageURL), base::Bind(&ImageDataFetcherTest::OnImageDataFetched,
- base::Unretained(this)));
-
- RequestMetadata expected_metadata;
- expected_metadata.mime_type = std::string("image/png");
- expected_metadata.response_code = net::HTTP_NOT_FOUND;
- // For 404, expect an empty result even though correct image data is sent.
- EXPECT_CALL(*this, OnImageDataFetched(std::string(), expected_metadata));
-
- // Get and configure the TestURLFetcher.
- net::TestURLFetcher* test_url_fetcher = fetcher_factory_.GetFetcherByID(0);
- ASSERT_NE(nullptr, test_url_fetcher);
- test_url_fetcher->set_status(
- net::URLRequestStatus(net::URLRequestStatus::SUCCESS, net::OK));
- test_url_fetcher->SetResponseString(kURLResponseData);
-
- std::string raw_header =
- "HTTP/1.1 404 Not Found\n"
- "Content-type: image/png\n\n";
- std::replace(raw_header.begin(), raw_header.end(), '\n', '\0');
- scoped_refptr<net::HttpResponseHeaders> headers(
- new net::HttpResponseHeaders(raw_header));
-
- test_url_fetcher->set_response_headers(headers);
-
- // Call the URLFetcher delegate to continue the test.
- test_url_fetcher->delegate()->OnURLFetchComplete(test_url_fetcher);
-}
-
-TEST_F(ImageDataFetcherTest, FetchImageData_FailedRequest) {
- image_data_fetcher_.FetchImageData(
- GURL(kImageURL),
- base::Bind(&ImageDataFetcherTest::OnImageDataFetchedFailedRequest,
- base::Unretained(this)));
-
- RequestMetadata expected_metadata;
- expected_metadata.response_code = net::URLFetcher::RESPONSE_CODE_INVALID;
- EXPECT_CALL(
- *this, OnImageDataFetchedFailedRequest(std::string(), expected_metadata));
-
- // Get and configure the TestURLFetcher.
- net::TestURLFetcher* test_url_fetcher = fetcher_factory_.GetFetcherByID(0);
- ASSERT_NE(nullptr, test_url_fetcher);
- test_url_fetcher->set_status(
- net::URLRequestStatus(net::URLRequestStatus::FAILED,
- net::ERR_INVALID_URL));
-
- // Call the URLFetcher delegate to continue the test.
- test_url_fetcher->delegate()->OnURLFetchComplete(test_url_fetcher);
-}
-
-TEST_F(ImageDataFetcherTest, FetchImageData_MultipleRequests) {
- ImageDataFetcher::ImageDataFetcherCallback callback =
- base::Bind(&ImageDataFetcherTest::OnImageDataFetchedMultipleRequests,
- base::Unretained(this));
- EXPECT_CALL(*this, OnImageDataFetchedMultipleRequests(testing::_, testing::_))
- .Times(2);
-
- image_data_fetcher_.FetchImageData(GURL(kImageURL), callback);
- image_data_fetcher_.FetchImageData(GURL(kImageURL), callback);
-
- // Multiple calls to FetchImageData for the same URL will result in
- // multiple URLFetchers being created.
- net::TestURLFetcher* test_url_fetcher = fetcher_factory_.GetFetcherByID(0);
- ASSERT_NE(nullptr, test_url_fetcher);
- test_url_fetcher->delegate()->OnURLFetchComplete(test_url_fetcher);
-
- test_url_fetcher = fetcher_factory_.GetFetcherByID(1);
- ASSERT_NE(nullptr, test_url_fetcher);
- test_url_fetcher->delegate()->OnURLFetchComplete(test_url_fetcher);
-}
-
-} // namespace image_fetcher
diff --git a/chromium/components/image_fetcher/ios/BUILD.gn b/chromium/components/image_fetcher/ios/BUILD.gn
index 88d514b151f..9ad5c7edc70 100644
--- a/chromium/components/image_fetcher/ios/BUILD.gn
+++ b/chromium/components/image_fetcher/ios/BUILD.gn
@@ -6,14 +6,18 @@ source_set("ios") {
sources = [
"ios_image_data_fetcher_wrapper.h",
"ios_image_data_fetcher_wrapper.mm",
+ "ios_image_decoder_impl.h",
+ "ios_image_decoder_impl.mm",
"webp_decoder.h",
"webp_decoder.mm",
]
deps = [
"//base",
- "//components/image_fetcher",
+ "//components/image_fetcher/core",
+ "//ios/web",
"//net",
"//third_party/libwebp:libwebp_dec",
+ "//ui/gfx",
]
configs += [ "//build/config/compiler:enable_arc" ]
}
@@ -22,6 +26,7 @@ source_set("unit_tests") {
testonly = true
sources = [
"ios_image_data_fetcher_wrapper_unittest.mm",
+ "ios_image_decoder_impl_unittest.mm",
"webp_decoder_unittest.mm",
]
deps = [
@@ -32,6 +37,7 @@ source_set("unit_tests") {
"//net:test_support",
"//testing/gmock",
"//testing/gtest",
+ "//ui/gfx",
]
configs += [ "//build/config/compiler:enable_arc" ]
}
diff --git a/chromium/components/image_fetcher/ios/DEPS b/chromium/components/image_fetcher/ios/DEPS
index d2f380fdf1b..dc46f3b0b57 100644
--- a/chromium/components/image_fetcher/ios/DEPS
+++ b/chromium/components/image_fetcher/ios/DEPS
@@ -1,5 +1,6 @@
include_rules = [
"+ios/web/public",
+ "+ui/gfx",
# Only WebP decoding is allowed (no encoding).
"+third_party/libwebp/webp/decode.h",
diff --git a/chromium/components/image_fetcher/ios/ios_image_data_fetcher_wrapper.h b/chromium/components/image_fetcher/ios/ios_image_data_fetcher_wrapper.h
index 4b6e0b67ef1..57806b0adba 100644
--- a/chromium/components/image_fetcher/ios/ios_image_data_fetcher_wrapper.h
+++ b/chromium/components/image_fetcher/ios/ios_image_data_fetcher_wrapper.h
@@ -9,7 +9,7 @@
#include "base/memory/ref_counted.h"
#include "components/data_use_measurement/core/data_use_user_data.h"
-#include "components/image_fetcher/image_data_fetcher.h"
+#include "components/image_fetcher/core/image_data_fetcher.h"
namespace base {
class TaskRunner;
diff --git a/chromium/components/image_fetcher/ios/ios_image_decoder_impl.h b/chromium/components/image_fetcher/ios/ios_image_decoder_impl.h
new file mode 100644
index 00000000000..2bb5db145d5
--- /dev/null
+++ b/chromium/components/image_fetcher/ios/ios_image_decoder_impl.h
@@ -0,0 +1,23 @@
+// 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 COMPONENTS_IMAGE_FETCHER_IOS_IMAGE_DECODER_IMPL_H_
+#define COMPONENTS_IMAGE_FETCHER_IOS_IMAGE_DECODER_IMPL_H_
+
+#include "base/memory/ref_counted.h"
+#include "components/image_fetcher/core/image_decoder.h"
+
+namespace base {
+class TaskRunner;
+}
+
+namespace image_fetcher {
+
+// Factory for iOS specific implementation of ImageDecoder.
+std::unique_ptr<ImageDecoder> CreateIOSImageDecoder(
+ scoped_refptr<base::TaskRunner> task_runner);
+
+} // namespace image_fetcher
+
+#endif // COMPONENTS_IMAGE_FETCHER_IOS_IMAGE_DECODER_IMPL_H_
diff --git a/chromium/components/image_fetcher/ios/ios_image_decoder_impl.mm b/chromium/components/image_fetcher/ios/ios_image_decoder_impl.mm
new file mode 100644
index 00000000000..ba32199f114
--- /dev/null
+++ b/chromium/components/image_fetcher/ios/ios_image_decoder_impl.mm
@@ -0,0 +1,106 @@
+// 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 "components/image_fetcher/ios/ios_image_decoder_impl.h"
+
+#import <UIKit/UIKit.h>
+
+#include "base/callback.h"
+#import "base/mac/bind_objc_block.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/weak_ptr.h"
+#import "components/image_fetcher/ios/webp_decoder.h"
+#include "ios/web/public/web_thread.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/image/image.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace image_fetcher {
+
+class IOSImageDecoderImpl : public ImageDecoder {
+ public:
+ explicit IOSImageDecoderImpl(scoped_refptr<base::TaskRunner> task_runner);
+ ~IOSImageDecoderImpl() override;
+
+ // Note, that |desired_image_frame_size| is not supported
+ // (http://crbug/697596).
+ void DecodeImage(const std::string& image_data,
+ const gfx::Size& desired_image_frame_size,
+ const ImageDecodedCallback& callback) override;
+
+ private:
+ void CreateUIImageAndRunCallback(const ImageDecodedCallback& callback,
+ NSData* image_data);
+
+ // The task runner used to decode images if necessary.
+ const scoped_refptr<base::TaskRunner> task_runner_;
+
+ // The WeakPtrFactory is used to cancel callbacks if ImageFetcher is
+ // destroyed during WebP decoding.
+ base::WeakPtrFactory<IOSImageDecoderImpl> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(IOSImageDecoderImpl);
+};
+
+IOSImageDecoderImpl::IOSImageDecoderImpl(
+ scoped_refptr<base::TaskRunner> task_runner)
+ : task_runner_(std::move(task_runner)), weak_factory_(this) {
+ DCHECK(task_runner_.get());
+}
+
+IOSImageDecoderImpl::~IOSImageDecoderImpl() {}
+
+void IOSImageDecoderImpl::DecodeImage(const std::string& image_data,
+ const gfx::Size& desired_image_frame_size,
+ const ImageDecodedCallback& callback) {
+ // Convert the |image_data| std::string to an NSData buffer.
+ // The data is copied as it may have to outlive the caller in
+ // PostTaskAndReplyWithResult.
+ NSData* data =
+ [NSData dataWithBytes:image_data.data() length:image_data.size()];
+
+ // The WebP image format is not supported by iOS natively. Therefore WebP
+ // images need to be decoded explicitly,
+ if (webp_transcode::WebpDecoder::IsWebpImage(image_data)) {
+ base::PostTaskAndReplyWithResult(
+ task_runner_.get(), FROM_HERE, base::BindBlockArc(^NSData*() {
+ return webp_transcode::WebpDecoder::DecodeWebpImage(data);
+ }),
+ base::Bind(&IOSImageDecoderImpl::CreateUIImageAndRunCallback,
+ weak_factory_.GetWeakPtr(), callback));
+ } else {
+ CreateUIImageAndRunCallback(callback, data);
+ }
+}
+
+void IOSImageDecoderImpl::CreateUIImageAndRunCallback(
+ const ImageDecodedCallback& callback,
+ NSData* image_data) {
+ // Decode the image data using UIImage.
+ if (image_data) {
+ // "Most likely" always returns 1x images.
+ UIImage* ui_image = [UIImage imageWithData:image_data scale:1];
+ if (ui_image) {
+ // This constructor does not retain the image, but expects to take the
+ // ownership, therefore, |ui_image| is retained here, but not released
+ // afterwards.
+ gfx::Image gfx_image(ui_image, base::scoped_policy::RETAIN);
+ callback.Run(gfx_image);
+ return;
+ }
+ }
+ gfx::Image empty_image;
+ callback.Run(empty_image);
+}
+
+std::unique_ptr<ImageDecoder> CreateIOSImageDecoder(
+ scoped_refptr<base::TaskRunner> task_runner) {
+ return base::MakeUnique<IOSImageDecoderImpl>(std::move(task_runner));
+}
+
+} // namespace image_fetcher
diff --git a/chromium/components/image_fetcher/ios/ios_image_decoder_impl_unittest.mm b/chromium/components/image_fetcher/ios/ios_image_decoder_impl_unittest.mm
new file mode 100644
index 00000000000..b83a127b3aa
--- /dev/null
+++ b/chromium/components/image_fetcher/ios/ios_image_decoder_impl_unittest.mm
@@ -0,0 +1,112 @@
+// Copyright 2011 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 "components/image_fetcher/ios/ios_image_decoder_impl.h"
+
+#import <UIKit/UIKit.h>
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/image/image.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+
+static unsigned char kJPGImage[] = {
+ 255, 216, 255, 224, 0, 16, 74, 70, 73, 70, 0, 1, 1, 1, 0,
+ 72, 0, 72, 0, 0, 255, 254, 0, 19, 67, 114, 101, 97, 116, 101,
+ 100, 32, 119, 105, 116, 104, 32, 71, 73, 77, 80, 255, 219, 0, 67,
+ 0, 5, 3, 4, 4, 4, 3, 5, 4, 4, 4, 5, 5, 5, 6,
+ 7, 12, 8, 7, 7, 7, 7, 15, 11, 11, 9, 12, 17, 15, 18,
+ 18, 17, 15, 17, 17, 19, 22, 28, 23, 19, 20, 26, 21, 17, 17,
+ 24, 33, 24, 26, 29, 29, 31, 31, 31, 19, 23, 34, 36, 34, 30,
+ 36, 28, 30, 31, 30, 255, 219, 0, 67, 1, 5, 5, 5, 7, 6,
+ 7, 14, 8, 8, 14, 30, 20, 17, 20, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 255,
+ 192, 0, 17, 8, 0, 1, 0, 1, 3, 1, 34, 0, 2, 17, 1,
+ 3, 17, 1, 255, 196, 0, 21, 0, 1, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 255, 196, 0, 20,
+ 16, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 255, 196, 0, 20, 1, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 196, 0, 20, 17,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 255, 218, 0, 12, 3, 1, 0, 2, 17, 3, 17, 0, 63,
+ 0, 178, 192, 7, 255, 217};
+
+static unsigned char kWEBPImage[] = {
+ 82, 73, 70, 70, 74, 0, 0, 0, 87, 69, 66, 80, 86, 80, 56, 88, 10,
+ 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 76, 80, 72,
+ 12, 0, 0, 0, 1, 7, 16, 17, 253, 15, 68, 68, 255, 3, 0, 0, 86,
+ 80, 56, 32, 24, 0, 0, 0, 48, 1, 0, 157, 1, 42, 1, 0, 1, 0,
+ 3, 0, 52, 37, 164, 0, 3, 112, 0, 254, 251, 253, 80, 0};
+
+} // namespace
+
+namespace image_fetcher {
+
+class IOSImageDecoderImplTest : public PlatformTest {
+ public:
+ void OnImageDecoded(const gfx::Image& image) { decoded_image_ = image; }
+
+ protected:
+ IOSImageDecoderImplTest()
+ : pool_(new base::SequencedWorkerPool(2,
+ "TestPool",
+ base::TaskPriority::USER_VISIBLE)) {
+ ios_image_decoder_impl_ = CreateIOSImageDecoder(pool_);
+ }
+
+ ~IOSImageDecoderImplTest() override { pool_->Shutdown(); }
+
+ base::MessageLoop loop_;
+ scoped_refptr<base::SequencedWorkerPool> pool_;
+ std::unique_ptr<ImageDecoder> ios_image_decoder_impl_;
+
+ gfx::Image decoded_image_;
+};
+
+TEST_F(IOSImageDecoderImplTest, JPGImage) {
+ ASSERT_TRUE(decoded_image_.IsEmpty());
+
+ std::string image_data =
+ std::string(reinterpret_cast<char*>(kJPGImage), sizeof(kJPGImage));
+ ios_image_decoder_impl_->DecodeImage(
+ image_data, gfx::Size(),
+ base::Bind(&IOSImageDecoderImplTest::OnImageDecoded,
+ base::Unretained(this)));
+
+ pool_->FlushForTesting();
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_FALSE(decoded_image_.IsEmpty());
+}
+
+TEST_F(IOSImageDecoderImplTest, WebpImage) {
+ ASSERT_TRUE(decoded_image_.IsEmpty());
+
+ std::string image_data =
+ std::string(reinterpret_cast<char*>(kWEBPImage), sizeof(kWEBPImage));
+ ios_image_decoder_impl_->DecodeImage(
+ image_data, gfx::Size(),
+ base::Bind(&IOSImageDecoderImplTest::OnImageDecoded,
+ base::Unretained(this)));
+
+ pool_->FlushForTesting();
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_FALSE(decoded_image_.IsEmpty());
+}
+
+} // namespace image_fetcher
diff --git a/chromium/components/image_fetcher/request_metadata.h b/chromium/components/image_fetcher/request_metadata.h
deleted file mode 100644
index 6b41e2d3c31..00000000000
--- a/chromium/components/image_fetcher/request_metadata.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2017 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 COMPONENTS_IMAGE_FETCHER_REQUEST_METADATA_H_
-#define COMPONENTS_IMAGE_FETCHER_REQUEST_METADATA_H_
-
-#include <string>
-
-namespace image_fetcher {
-
-// Metadata for a URL request.
-struct RequestMetadata {
- std::string mime_type;
- // HTTP response code.
- int response_code;
-};
-
-bool operator==(const RequestMetadata& lhs, const RequestMetadata& rhs);
-bool operator!=(const RequestMetadata& lhs, const RequestMetadata& rhs);
-
-} // namespace image_fetcher
-
-#endif // COMPONENTS_IMAGE_FETCHER_REQUEST_METADATA_H_
diff --git a/chromium/components/image_fetcher/request_metadata_unittest.cc b/chromium/components/image_fetcher/request_metadata_unittest.cc
deleted file mode 100644
index ba87ba08d8f..00000000000
--- a/chromium/components/image_fetcher/request_metadata_unittest.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2017 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 "components/image_fetcher/request_metadata.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace image_fetcher {
-
-TEST(RequestMetadataTest, Equality) {
- RequestMetadata rhs;
- RequestMetadata lhs;
- rhs.mime_type = "testMimeType";
- lhs.mime_type = "testMimeType";
- rhs.response_code = 1;
- lhs.response_code = 1;
-
- EXPECT_EQ(rhs, lhs);
-}
-
-TEST(RequestMetadataTest, NoEquality) {
- RequestMetadata rhs;
- RequestMetadata lhs;
- rhs.mime_type = "testMimeType";
- lhs.mime_type = "testMimeType";
- rhs.response_code = 1;
- lhs.response_code = 1;
-
- lhs.mime_type = "testOtherMimeType";
- EXPECT_NE(rhs, lhs);
- lhs.mime_type = "testMimeType";
-
- lhs.response_code = 2;
- EXPECT_NE(rhs, lhs);
- lhs.response_code = 1;
-}
-
-} // namespace image_fetcher