123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459 |
- // 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_cache.h"
- #include <stddef.h>
- #include <stdint.h>
- #include <memory>
- #include <utility>
- #include "base/files/file_util.h"
- #include "base/json/json_reader.h"
- #include "base/json/json_writer.h"
- #include "base/logging.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/values.h"
- namespace search_provider_logos {
- namespace {
- // The cached logo metadata is persisted as JSON using these keys.
- const char kSourceUrlKey[] = "url";
- const char kExpirationTimeKey[] = "expiration_time";
- const char kCanShowAfterExpirationKey[] = "can_show_after_expiration";
- const char kFingerprintKey[] = "fingerprint";
- const char kTypeKey[] = "type";
- const char kOnClickURLKey[] = "on_click_url";
- const char kFullPageURLKey[] = "full_page_url";
- const char kAltTextKey[] = "alt_text";
- const char kMimeTypeKey[] = "mime_type";
- const char kDarkMimeTypeKey[] = "dark_mime_type";
- const char kNumBytesKey[] = "num_bytes";
- const char kDarkNumBytesKey[] = "dark_num_bytes";
- const char kAnimatedUrlKey[] = "animated_url";
- const char kDarkAnimatedUrlKey[] = "dark_animated_url";
- const char kLogUrlKey[] = "log_url";
- const char kDarkLogUrlKey[] = "dark_log_url";
- const char kCtaLogUrlKey[] = "cta_log_url";
- const char kDarkCtaLogUrlKey[] = "dark_cta_log_url";
- const char kShortLinkKey[] = "short_link";
- const char kWidthPx[] = "width_px";
- const char kHeightPx[] = "height_px";
- const char kDarkWidthPx[] = "dark_width_px";
- const char kDarkHeightPx[] = "dark_height_px";
- const char kIframeWidthPx[] = "iframe_width_px";
- const char kIframeHeightPx[] = "iframe_height_px";
- const char kDarkBackgroundColorKey[] = "dark_background_color";
- const char kShareButtonX[] = "share_button_x";
- const char kShareButtonY[] = "share_button_y";
- const char kShareButtonOpacity[] = "share_button_opacity";
- const char kShareButtonIcon[] = "share_button_icon";
- const char kShareButtonBg[] = "share_button_bg";
- const char kDarkShareButtonX[] = "dark_share_button_x";
- const char kDarkShareButtonY[] = "dark_share_button_y";
- const char kDarkShareButtonOpacity[] = "dark_share_button_opacity";
- const char kDarkShareButtonIcon[] = "dark_share_button_icon";
- const char kDarkShareButtonBg[] = "dark_share_button_bg";
- const char kSimpleType[] = "SIMPLE";
- const char kAnimatedType[] = "ANIMATED";
- const char kInteractiveType[] = "INTERACTIVE";
- bool GetTimeValue(const base::DictionaryValue& dict,
- const std::string& key,
- base::Time* time) {
- std::string str;
- int64_t internal_time_value;
- if (dict.GetString(key, &str) &&
- base::StringToInt64(str, &internal_time_value)) {
- *time = base::Time::FromInternalValue(internal_time_value);
- return true;
- }
- return false;
- }
- void SetTimeValue(base::DictionaryValue& dict,
- const std::string& key,
- const base::Time& time) {
- int64_t internal_time_value = time.ToInternalValue();
- dict.SetStringKey(key, base::NumberToString(internal_time_value));
- }
- LogoType LogoTypeFromString(base::StringPiece type) {
- if (type == kSimpleType) {
- return LogoType::SIMPLE;
- }
- if (type == kAnimatedType) {
- return LogoType::ANIMATED;
- }
- if (type == kInteractiveType) {
- return LogoType::INTERACTIVE;
- }
- LOG(WARNING) << "invalid type " << type;
- return LogoType::SIMPLE;
- }
- std::string LogoTypeToString(LogoType type) {
- switch (type) {
- case LogoType::SIMPLE:
- return kSimpleType;
- case LogoType::ANIMATED:
- return kAnimatedType;
- case LogoType::INTERACTIVE:
- return kInteractiveType;
- }
- NOTREACHED();
- return "";
- }
- } // namespace
- LogoCache::LogoCache(const base::FilePath& cache_directory)
- : cache_directory_(cache_directory),
- metadata_is_valid_(false) {
- // The LogoCache can be constructed on any thread, as long as it's used
- // on a single sequence after construction.
- DETACH_FROM_SEQUENCE(sequence_checker_);
- }
- LogoCache::~LogoCache() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- }
- void LogoCache::UpdateCachedLogoMetadata(const LogoMetadata& metadata) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(metadata_);
- DCHECK_EQ(metadata_->fingerprint, metadata.fingerprint);
- UpdateMetadata(std::make_unique<LogoMetadata>(metadata));
- WriteMetadata();
- }
- const LogoMetadata* LogoCache::GetCachedLogoMetadata() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- ReadMetadataIfNeeded();
- return metadata_.get();
- }
- void LogoCache::SetCachedLogo(const EncodedLogo* logo) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (!logo) {
- UpdateMetadata(nullptr);
- DeleteLogoAndMetadata();
- return;
- }
- logo_num_bytes_ =
- logo->encoded_image ? static_cast<int>(logo->encoded_image->size()) : 0;
- dark_logo_num_bytes_ =
- logo->dark_encoded_image
- ? static_cast<int>(logo->dark_encoded_image->size())
- : 0;
- UpdateMetadata(std::make_unique<LogoMetadata>(logo->metadata));
- WriteLogo(logo->encoded_image, logo->dark_encoded_image);
- }
- std::unique_ptr<EncodedLogo> LogoCache::GetCachedLogo() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- ReadMetadataIfNeeded();
- if (!metadata_)
- return nullptr;
- base::FilePath logo_path = GetLogoPath();
- base::FilePath dark_logo_path = GetDarkLogoPath();
- scoped_refptr<base::RefCountedString> encoded_image;
- if (logo_num_bytes_ != 0) {
- encoded_image = new base::RefCountedString();
- if (!base::ReadFileToString(logo_path, &encoded_image->data())) {
- UpdateMetadata(nullptr);
- return nullptr;
- }
- if (encoded_image->size() != static_cast<size_t>(logo_num_bytes_)) {
- // Delete corrupt metadata and logo.
- DeleteLogoAndMetadata();
- UpdateMetadata(nullptr);
- return nullptr;
- }
- }
- scoped_refptr<base::RefCountedString> dark_encoded_image;
- if (dark_logo_num_bytes_ != 0) {
- dark_encoded_image = new base::RefCountedString();
- if (!base::ReadFileToString(dark_logo_path, &dark_encoded_image->data())) {
- UpdateMetadata(nullptr);
- return nullptr;
- }
- if (dark_encoded_image->size() !=
- static_cast<size_t>(dark_logo_num_bytes_)) {
- // Delete corrupt metadata and logo.
- DeleteLogoAndMetadata();
- UpdateMetadata(nullptr);
- return nullptr;
- }
- }
- std::unique_ptr<EncodedLogo> logo(new EncodedLogo());
- logo->encoded_image = encoded_image;
- logo->dark_encoded_image = dark_encoded_image;
- logo->metadata = *metadata_;
- return logo;
- }
- // static
- std::unique_ptr<LogoMetadata> LogoCache::LogoMetadataFromString(
- const std::string& str,
- int* logo_num_bytes,
- int* dark_logo_num_bytes) {
- std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(str);
- base::DictionaryValue* dict;
- if (!value || !value->GetAsDictionary(&dict))
- return nullptr;
- // These helpers replace the deprecated analogous methods on
- // base::DictionaryValue, so as to maintain the early exit behavior in the if
- // predicate below.
- auto get_string = [dict](const char* key, std::string* ret) -> bool {
- const std::string* v = dict->FindStringKey(key);
- if (v)
- *ret = *v;
- return v != nullptr;
- };
- auto get_boolean = [dict](const char* key, bool* ret) -> bool {
- absl::optional<bool> v = dict->FindBoolKey(key);
- if (v.has_value())
- *ret = v.value();
- return v.has_value();
- };
- auto get_integer = [dict](const char* key, int* ret) -> bool {
- absl::optional<int> v = dict->FindIntKey(key);
- if (v.has_value())
- *ret = v.value();
- return v.has_value();
- };
- auto get_double = [dict](const char* key, double* ret) -> bool {
- absl::optional<double> v = dict->FindDoubleKey(key);
- if (v.has_value())
- *ret = v.value();
- return v.has_value();
- };
- std::unique_ptr<LogoMetadata> metadata(new LogoMetadata());
- std::string source_url;
- std::string type;
- std::string on_click_url;
- std::string full_page_url;
- std::string animated_url;
- std::string dark_animated_url;
- std::string log_url;
- std::string dark_log_url;
- std::string cta_log_url;
- std::string dark_cta_log_url;
- std::string short_link;
- if (!get_string(kSourceUrlKey, &source_url) ||
- !get_string(kFingerprintKey, &metadata->fingerprint) ||
- !get_string(kTypeKey, &type) ||
- !get_string(kOnClickURLKey, &on_click_url) ||
- !get_string(kFullPageURLKey, &full_page_url) ||
- !get_string(kAltTextKey, &metadata->alt_text) ||
- !get_string(kAnimatedUrlKey, &animated_url) ||
- !get_string(kDarkAnimatedUrlKey, &dark_animated_url) ||
- !get_string(kLogUrlKey, &log_url) ||
- !get_string(kDarkLogUrlKey, &dark_log_url) ||
- !get_string(kCtaLogUrlKey, &cta_log_url) ||
- !get_string(kDarkCtaLogUrlKey, &dark_cta_log_url) ||
- !get_string(kShortLinkKey, &short_link) ||
- !get_string(kMimeTypeKey, &metadata->mime_type) ||
- !get_string(kDarkMimeTypeKey, &metadata->dark_mime_type) ||
- !get_boolean(kCanShowAfterExpirationKey,
- &metadata->can_show_after_expiration) ||
- !get_integer(kNumBytesKey, logo_num_bytes) ||
- !get_integer(kDarkNumBytesKey, dark_logo_num_bytes) ||
- !get_integer(kShareButtonX, &metadata->share_button_x) ||
- !get_integer(kShareButtonY, &metadata->share_button_y) ||
- !get_double(kShareButtonOpacity, &metadata->share_button_opacity) ||
- !get_string(kShareButtonIcon, &metadata->share_button_icon) ||
- !get_string(kShareButtonBg, &metadata->share_button_bg) ||
- !get_integer(kDarkShareButtonX, &metadata->dark_share_button_x) ||
- !get_integer(kDarkShareButtonY, &metadata->dark_share_button_y) ||
- !get_double(kDarkShareButtonOpacity,
- &metadata->dark_share_button_opacity) ||
- !get_string(kDarkShareButtonIcon, &metadata->dark_share_button_icon) ||
- !get_string(kDarkShareButtonBg, &metadata->dark_share_button_bg) ||
- !get_integer(kWidthPx, &metadata->width_px) ||
- !get_integer(kHeightPx, &metadata->height_px) ||
- !get_integer(kDarkWidthPx, &metadata->dark_width_px) ||
- !get_integer(kDarkHeightPx, &metadata->dark_height_px) ||
- !get_integer(kIframeWidthPx, &metadata->iframe_width_px) ||
- !get_integer(kIframeHeightPx, &metadata->iframe_height_px) ||
- !get_string(kDarkBackgroundColorKey, &metadata->dark_background_color) ||
- !GetTimeValue(*dict, kExpirationTimeKey, &metadata->expiration_time)) {
- return nullptr;
- }
- metadata->type = LogoTypeFromString(type);
- metadata->source_url = GURL(source_url);
- metadata->on_click_url = GURL(on_click_url);
- metadata->full_page_url = GURL(full_page_url);
- metadata->animated_url = GURL(animated_url);
- metadata->dark_animated_url = GURL(dark_animated_url);
- metadata->log_url = GURL(log_url);
- metadata->dark_log_url = GURL(dark_log_url);
- metadata->cta_log_url = GURL(cta_log_url);
- metadata->dark_cta_log_url = GURL(dark_cta_log_url);
- metadata->short_link = GURL(short_link);
- return metadata;
- }
- // static
- void LogoCache::LogoMetadataToString(const LogoMetadata& metadata,
- int num_bytes,
- int dark_num_bytes,
- std::string* str) {
- base::DictionaryValue dict;
- dict.SetStringKey(kSourceUrlKey, metadata.source_url.spec());
- dict.SetStringKey(kFingerprintKey, metadata.fingerprint);
- dict.SetStringKey(kTypeKey, LogoTypeToString(metadata.type));
- dict.SetStringKey(kOnClickURLKey, metadata.on_click_url.spec());
- dict.SetStringKey(kFullPageURLKey, metadata.full_page_url.spec());
- dict.SetStringKey(kAltTextKey, metadata.alt_text);
- dict.SetStringKey(kAnimatedUrlKey, metadata.animated_url.spec());
- dict.SetStringKey(kDarkAnimatedUrlKey, metadata.dark_animated_url.spec());
- dict.SetStringKey(kLogUrlKey, metadata.log_url.spec());
- dict.SetStringKey(kDarkLogUrlKey, metadata.dark_log_url.spec());
- dict.SetStringKey(kCtaLogUrlKey, metadata.cta_log_url.spec());
- dict.SetStringKey(kDarkCtaLogUrlKey, metadata.dark_cta_log_url.spec());
- dict.SetStringKey(kShortLinkKey, metadata.short_link.spec());
- dict.SetStringKey(kMimeTypeKey, metadata.mime_type);
- dict.SetStringKey(kDarkMimeTypeKey, metadata.dark_mime_type);
- dict.SetBoolKey(kCanShowAfterExpirationKey,
- metadata.can_show_after_expiration);
- dict.SetIntKey(kNumBytesKey, num_bytes);
- dict.SetIntKey(kDarkNumBytesKey, dark_num_bytes);
- dict.SetIntKey(kShareButtonX, metadata.share_button_x);
- dict.SetIntKey(kShareButtonY, metadata.share_button_y);
- dict.SetDoubleKey(kShareButtonOpacity, metadata.share_button_opacity);
- dict.SetStringKey(kShareButtonIcon, metadata.share_button_icon);
- dict.SetStringKey(kShareButtonBg, metadata.share_button_bg);
- dict.SetIntKey(kDarkShareButtonX, metadata.dark_share_button_x);
- dict.SetIntKey(kDarkShareButtonY, metadata.dark_share_button_y);
- dict.SetDoubleKey(kDarkShareButtonOpacity,
- metadata.dark_share_button_opacity);
- dict.SetStringKey(kDarkShareButtonIcon, metadata.dark_share_button_icon);
- dict.SetStringKey(kDarkShareButtonBg, metadata.dark_share_button_bg);
- dict.SetIntKey(kWidthPx, metadata.width_px);
- dict.SetIntKey(kHeightPx, metadata.height_px);
- dict.SetIntKey(kDarkWidthPx, metadata.dark_width_px);
- dict.SetIntKey(kDarkHeightPx, metadata.dark_height_px);
- dict.SetIntKey(kIframeWidthPx, metadata.iframe_width_px);
- dict.SetIntKey(kIframeHeightPx, metadata.iframe_height_px);
- dict.SetStringKey(kDarkBackgroundColorKey, metadata.dark_background_color);
- SetTimeValue(dict, kExpirationTimeKey, metadata.expiration_time);
- base::JSONWriter::Write(dict, str);
- }
- base::FilePath LogoCache::GetLogoPath() {
- return cache_directory_.Append(FILE_PATH_LITERAL("logo"));
- }
- base::FilePath LogoCache::GetDarkLogoPath() {
- return cache_directory_.Append(FILE_PATH_LITERAL("dark_logo"));
- }
- base::FilePath LogoCache::GetMetadataPath() {
- return cache_directory_.Append(FILE_PATH_LITERAL("metadata"));
- }
- void LogoCache::UpdateMetadata(std::unique_ptr<LogoMetadata> metadata) {
- metadata_ = std::move(metadata);
- metadata_is_valid_ = true;
- }
- void LogoCache::ReadMetadataIfNeeded() {
- if (metadata_is_valid_)
- return;
- std::unique_ptr<LogoMetadata> metadata;
- base::FilePath metadata_path = GetMetadataPath();
- std::string str;
- if (base::ReadFileToString(metadata_path, &str)) {
- metadata =
- LogoMetadataFromString(str, &logo_num_bytes_, &dark_logo_num_bytes_);
- if (!metadata) {
- // Delete corrupt metadata and logo.
- DeleteLogoAndMetadata();
- }
- }
- UpdateMetadata(std::move(metadata));
- }
- void LogoCache::WriteMetadata() {
- if (!EnsureCacheDirectoryExists())
- return;
- std::string str;
- LogoMetadataToString(*metadata_, logo_num_bytes_, dark_logo_num_bytes_, &str);
- base::WriteFile(GetMetadataPath(), str.data(), static_cast<int>(str.size()));
- }
- void LogoCache::WriteLogo(
- scoped_refptr<base::RefCountedMemory> encoded_image,
- scoped_refptr<base::RefCountedMemory> dark_encoded_image) {
- if (!EnsureCacheDirectoryExists())
- return;
- if (!metadata_) {
- DeleteLogoAndMetadata();
- return;
- }
- // To minimize the chances of ending up in an undetectably broken state:
- // First, delete the metadata file, then update the logo file, then update the
- // metadata file.
- base::FilePath logo_path = GetLogoPath();
- base::FilePath dark_logo_path = GetDarkLogoPath();
- base::FilePath metadata_path = GetMetadataPath();
- if (!base::DeleteFile(metadata_path))
- return;
- if (encoded_image &&
- base::WriteFile(logo_path, encoded_image->front_as<char>(),
- static_cast<int>(encoded_image->size())) == -1) {
- base::DeleteFile(logo_path);
- return;
- }
- if (dark_encoded_image &&
- base::WriteFile(dark_logo_path, dark_encoded_image->front_as<char>(),
- static_cast<int>(dark_encoded_image->size())) == -1) {
- base::DeleteFile(logo_path);
- base::DeleteFile(dark_logo_path);
- return;
- }
- WriteMetadata();
- }
- void LogoCache::DeleteLogoAndMetadata() {
- base::DeleteFile(GetLogoPath());
- base::DeleteFile(GetDarkLogoPath());
- base::DeleteFile(GetMetadataPath());
- }
- bool LogoCache::EnsureCacheDirectoryExists() {
- if (base::DirectoryExists(cache_directory_))
- return true;
- return base::CreateDirectory(cache_directory_);
- }
- } // namespace search_provider_logos
|