summaryrefslogtreecommitdiff
path: root/chromium/components/search_provider_logos/logo_tracker.cc
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2016-05-09 14:22:11 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2016-05-09 15:11:45 +0000
commit2ddb2d3e14eef3de7dbd0cef553d669b9ac2361c (patch)
treee75f511546c5fd1a173e87c1f9fb11d7ac8d1af3 /chromium/components/search_provider_logos/logo_tracker.cc
parenta4f3d46271c57e8155ba912df46a05559d14726e (diff)
downloadqtwebengine-chromium-2ddb2d3e14eef3de7dbd0cef553d669b9ac2361c.tar.gz
BASELINE: Update Chromium to 51.0.2704.41
Also adds in all smaller components by reversing logic for exclusion. Change-Id: Ibf90b506e7da088ea2f65dcf23f2b0992c504422 Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>
Diffstat (limited to 'chromium/components/search_provider_logos/logo_tracker.cc')
-rw-r--r--chromium/components/search_provider_logos/logo_tracker.cc332
1 files changed, 332 insertions, 0 deletions
diff --git a/chromium/components/search_provider_logos/logo_tracker.cc b/chromium/components/search_provider_logos/logo_tracker.cc
new file mode 100644
index 00000000000..c50b42ceb36
--- /dev/null
+++ b/chromium/components/search_provider_logos/logo_tracker.cc
@@ -0,0 +1,332 @@
+// Copyright 2014 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/search_provider_logos/logo_tracker.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/task_runner_util.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/time/default_clock.h"
+#include "net/http/http_response_headers.h"
+#include "net/url_request/url_fetcher.h"
+#include "net/url_request/url_request_context_getter.h"
+#include "net/url_request/url_request_status.h"
+
+namespace search_provider_logos {
+
+namespace {
+
+const int64_t kMaxDownloadBytes = 1024 * 1024;
+
+//const int kDecodeLogoTimeoutSeconds = 30;
+
+// Returns whether the metadata for the cached logo indicates that the logo is
+// OK to show, i.e. it's not expired or it's allowed to be shown temporarily
+// after expiration.
+bool IsLogoOkToShow(const LogoMetadata& metadata, base::Time now) {
+ base::TimeDelta offset =
+ base::TimeDelta::FromMilliseconds(kMaxTimeToLiveMS * 3 / 2);
+ base::Time distant_past = now - offset;
+ base::Time distant_future = now + offset;
+ // Sanity check so logos aren't accidentally cached forever.
+ if (metadata.expiration_time < distant_past ||
+ metadata.expiration_time > distant_future) {
+ return false;
+ }
+ return metadata.can_show_after_expiration || metadata.expiration_time >= now;
+}
+
+// Reads the logo from the cache and returns it. Returns NULL if the cache is
+// empty, corrupt, expired, or doesn't apply to the current logo URL.
+scoped_ptr<EncodedLogo> GetLogoFromCacheOnFileThread(LogoCache* logo_cache,
+ const GURL& logo_url,
+ base::Time now) {
+ const LogoMetadata* metadata = logo_cache->GetCachedLogoMetadata();
+ if (!metadata)
+ return scoped_ptr<EncodedLogo>();
+
+ if (metadata->source_url != logo_url.spec() ||
+ !IsLogoOkToShow(*metadata, now)) {
+ logo_cache->SetCachedLogo(NULL);
+ return scoped_ptr<EncodedLogo>();
+ }
+
+ return logo_cache->GetCachedLogo();
+}
+
+void DeleteLogoCacheOnFileThread(LogoCache* logo_cache) {
+ delete logo_cache;
+}
+
+} // namespace
+
+LogoTracker::LogoTracker(
+ base::FilePath cached_logo_directory,
+ scoped_refptr<base::SequencedTaskRunner> file_task_runner,
+ scoped_refptr<base::TaskRunner> background_task_runner,
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter,
+ scoped_ptr<LogoDelegate> delegate)
+ : is_idle_(true),
+ is_cached_logo_valid_(false),
+ logo_delegate_(std::move(delegate)),
+ logo_cache_(new LogoCache(cached_logo_directory)),
+ clock_(new base::DefaultClock()),
+ file_task_runner_(file_task_runner),
+ background_task_runner_(background_task_runner),
+ request_context_getter_(request_context_getter),
+ weak_ptr_factory_(this) {}
+
+LogoTracker::~LogoTracker() {
+ ReturnToIdle(kDownloadOutcomeNotTracked);
+ file_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&DeleteLogoCacheOnFileThread, logo_cache_));
+ logo_cache_ = NULL;
+}
+
+void LogoTracker::SetServerAPI(
+ const GURL& logo_url,
+ const ParseLogoResponse& parse_logo_response_func,
+ const AppendQueryparamsToLogoURL& append_queryparams_func,
+ bool wants_cta) {
+ if (logo_url == logo_url_)
+ return;
+
+ ReturnToIdle(kDownloadOutcomeNotTracked);
+
+ logo_url_ = logo_url;
+ parse_logo_response_func_ = parse_logo_response_func;
+ append_queryparams_func_ = append_queryparams_func;
+ wants_cta_ = wants_cta;
+}
+
+void LogoTracker::GetLogo(LogoObserver* observer) {
+ DCHECK(!logo_url_.is_empty());
+ logo_observers_.AddObserver(observer);
+
+ if (is_idle_) {
+ is_idle_ = false;
+ base::PostTaskAndReplyWithResult(
+ file_task_runner_.get(),
+ FROM_HERE,
+ base::Bind(&GetLogoFromCacheOnFileThread,
+ logo_cache_,
+ logo_url_,
+ clock_->Now()),
+ base::Bind(&LogoTracker::OnCachedLogoRead,
+ weak_ptr_factory_.GetWeakPtr()));
+ } else if (is_cached_logo_valid_) {
+ observer->OnLogoAvailable(cached_logo_.get(), true);
+ }
+}
+
+void LogoTracker::RemoveObserver(LogoObserver* observer) {
+ logo_observers_.RemoveObserver(observer);
+}
+
+void LogoTracker::SetLogoCacheForTests(scoped_ptr<LogoCache> cache) {
+ DCHECK(cache);
+ file_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&DeleteLogoCacheOnFileThread, logo_cache_));
+ logo_cache_ = cache.release();
+}
+
+void LogoTracker::SetClockForTests(scoped_ptr<base::Clock> clock) {
+ clock_ = std::move(clock);
+}
+
+void LogoTracker::ReturnToIdle(int outcome) {
+ if (outcome != kDownloadOutcomeNotTracked) {
+ UMA_HISTOGRAM_ENUMERATION("NewTabPage.LogoDownloadOutcome", outcome,
+ DOWNLOAD_OUTCOME_COUNT);
+ }
+ // Cancel the current asynchronous operation, if any.
+ fetcher_.reset();
+ weak_ptr_factory_.InvalidateWeakPtrs();
+
+ // Reset state.
+ is_idle_ = true;
+ cached_logo_.reset();
+ is_cached_logo_valid_ = false;
+
+ // Clear obsevers.
+ FOR_EACH_OBSERVER(LogoObserver, logo_observers_, OnObserverRemoved());
+ logo_observers_.Clear();
+}
+
+void LogoTracker::OnCachedLogoRead(scoped_ptr<EncodedLogo> cached_logo) {
+ DCHECK(!is_idle_);
+
+ if (cached_logo) {
+ logo_delegate_->DecodeUntrustedImage(
+ cached_logo->encoded_image,
+ base::Bind(&LogoTracker::OnCachedLogoAvailable,
+ weak_ptr_factory_.GetWeakPtr(),
+ cached_logo->metadata));
+ } else {
+ OnCachedLogoAvailable(LogoMetadata(), SkBitmap());
+ }
+}
+
+void LogoTracker::OnCachedLogoAvailable(const LogoMetadata& metadata,
+ const SkBitmap& image) {
+ DCHECK(!is_idle_);
+
+ if (!image.isNull()) {
+ cached_logo_.reset(new Logo());
+ cached_logo_->metadata = metadata;
+ cached_logo_->image = image;
+ }
+ is_cached_logo_valid_ = true;
+ Logo* logo = cached_logo_.get();
+ FOR_EACH_OBSERVER(LogoObserver, logo_observers_, OnLogoAvailable(logo, true));
+ FetchLogo();
+}
+
+void LogoTracker::SetCachedLogo(scoped_ptr<EncodedLogo> logo) {
+ file_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&LogoCache::SetCachedLogo,
+ base::Unretained(logo_cache_),
+ base::Owned(logo.release())));
+}
+
+void LogoTracker::SetCachedMetadata(const LogoMetadata& metadata) {
+ file_task_runner_->PostTask(FROM_HERE,
+ base::Bind(&LogoCache::UpdateCachedLogoMetadata,
+ base::Unretained(logo_cache_),
+ metadata));
+}
+
+void LogoTracker::FetchLogo() {
+ DCHECK(!fetcher_);
+ DCHECK(!is_idle_);
+
+ GURL url;
+ std::string fingerprint;
+ if (cached_logo_ && !cached_logo_->metadata.fingerprint.empty() &&
+ cached_logo_->metadata.expiration_time >= clock_->Now()) {
+ fingerprint = cached_logo_->metadata.fingerprint;
+ }
+ url = append_queryparams_func_.Run(logo_url_, fingerprint, wants_cta_);
+
+ fetcher_ = net::URLFetcher::Create(url, net::URLFetcher::GET, this);
+ fetcher_->SetRequestContext(request_context_getter_.get());
+ fetcher_->Start();
+ logo_download_start_time_ = base::TimeTicks::Now();
+}
+
+void LogoTracker::OnFreshLogoParsed(bool* parsing_failed,
+ scoped_ptr<EncodedLogo> logo) {
+ DCHECK(!is_idle_);
+
+ if (logo)
+ logo->metadata.source_url = logo_url_.spec();
+
+ if (!logo || !logo->encoded_image.get()) {
+ OnFreshLogoAvailable(std::move(logo), *parsing_failed, SkBitmap());
+ } else {
+ // Store the value of logo->encoded_image for use below. This ensures that
+ // logo->encoded_image is evaulated before base::Passed(&logo), which sets
+ // logo to NULL.
+ scoped_refptr<base::RefCountedString> encoded_image = logo->encoded_image;
+ logo_delegate_->DecodeUntrustedImage(
+ encoded_image,
+ base::Bind(&LogoTracker::OnFreshLogoAvailable,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::Passed(&logo),
+ *parsing_failed));
+ }
+}
+
+void LogoTracker::OnFreshLogoAvailable(scoped_ptr<EncodedLogo> encoded_logo,
+ bool parsing_failed,
+ const SkBitmap& image) {
+ DCHECK(!is_idle_);
+
+ int download_outcome = kDownloadOutcomeNotTracked;
+
+ if (encoded_logo && !encoded_logo->encoded_image.get() && cached_logo_ &&
+ !encoded_logo->metadata.fingerprint.empty() &&
+ encoded_logo->metadata.fingerprint ==
+ cached_logo_->metadata.fingerprint) {
+ // The cached logo was revalidated, i.e. its fingerprint was verified.
+ // mime_type isn't sent when revalidating, so copy it from the cached logo.
+ encoded_logo->metadata.mime_type = cached_logo_->metadata.mime_type;
+ SetCachedMetadata(encoded_logo->metadata);
+ download_outcome = DOWNLOAD_OUTCOME_LOGO_REVALIDATED;
+ } else if (encoded_logo && image.isNull()) {
+ // Image decoding failed. Do nothing.
+ download_outcome = DOWNLOAD_OUTCOME_DECODING_FAILED;
+ } else {
+ scoped_ptr<Logo> logo;
+ // Check if the server returned a valid, non-empty response.
+ if (encoded_logo) {
+ DCHECK(!image.isNull());
+ logo.reset(new Logo());
+ logo->metadata = encoded_logo->metadata;
+ logo->image = image;
+ }
+
+ if (logo) {
+ download_outcome = DOWNLOAD_OUTCOME_NEW_LOGO_SUCCESS;
+ } else {
+ if (parsing_failed)
+ download_outcome = DOWNLOAD_OUTCOME_PARSING_FAILED;
+ else
+ download_outcome = DOWNLOAD_OUTCOME_NO_LOGO_TODAY;
+ }
+
+ // Notify observers if a new logo was fetched, or if the new logo is NULL
+ // but the cached logo was non-NULL.
+ if (logo || cached_logo_) {
+ FOR_EACH_OBSERVER(LogoObserver,
+ logo_observers_,
+ OnLogoAvailable(logo.get(), false));
+ SetCachedLogo(std::move(encoded_logo));
+ }
+ }
+
+ DCHECK(download_outcome != kDownloadOutcomeNotTracked);
+ ReturnToIdle(download_outcome);
+}
+
+void LogoTracker::OnURLFetchComplete(const net::URLFetcher* source) {
+ DCHECK(!is_idle_);
+ scoped_ptr<net::URLFetcher> cleanup_fetcher(fetcher_.release());
+
+ if (!source->GetStatus().is_success() || (source->GetResponseCode() != 200)) {
+ ReturnToIdle(DOWNLOAD_OUTCOME_DOWNLOAD_FAILED);
+ return;
+ }
+
+ UMA_HISTOGRAM_TIMES("NewTabPage.LogoDownloadTime",
+ base::TimeTicks::Now() - logo_download_start_time_);
+
+ scoped_ptr<std::string> response(new std::string());
+ source->GetResponseAsString(response.get());
+ base::Time response_time = clock_->Now();
+
+ bool* parsing_failed = new bool(false);
+ base::PostTaskAndReplyWithResult(
+ background_task_runner_.get(), FROM_HERE,
+ base::Bind(parse_logo_response_func_, base::Passed(&response),
+ response_time, parsing_failed),
+ base::Bind(&LogoTracker::OnFreshLogoParsed,
+ weak_ptr_factory_.GetWeakPtr(), base::Owned(parsing_failed)));
+}
+
+void LogoTracker::OnURLFetchDownloadProgress(const net::URLFetcher* source,
+ int64_t current,
+ int64_t total) {
+ if (total > kMaxDownloadBytes || current > kMaxDownloadBytes) {
+ LOG(WARNING) << "Search provider logo exceeded download size limit";
+ ReturnToIdle(DOWNLOAD_OUTCOME_DOWNLOAD_FAILED);
+ }
+}
+
+} // namespace search_provider_logos