// 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.
#ifndef COMPONENTS_SEARCH_PROVIDER_LOGOS_LOGO_CACHE_H_
#define COMPONENTS_SEARCH_PROVIDER_LOGOS_LOGO_CACHE_H_
#include <string>
#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/gtest_prod_util.h"
#include "base/memory/ref_counted.h"
#include "base/memory/ref_counted_memory.h"
#include "base/memory/scoped_ptr.h"
#include "base/threading/thread_checker.h"
#include "components/search_provider_logos/logo_common.h"
namespace search_provider_logos {
// A file-based cache for the search provider's logo. This allows clients to
// store and retrieve a logo (of type EncodedLogo) and its associated metadata
// (of type LogoMetadata). Metadata can be updated independently from the logo
// to handle cases where, e.g. the expiration date changes, but the logo stays
// the same. If corruption is detected in the metadata or logo, the cache will
// be cleared.
//
// Note: this class must only be used on a single thread. All methods are
// are blocking, so this should not be used on the UI thread.
//
// The logo and its metadata are stored in files, so they persist even when
// Chrome is closed. Once loaded from disk, the metadata is kept in memory to
// enable quick retrieval. The logo is not kept around in memory because of its
// size.
class LogoCache {
public:
// Constructs a logo cache that stores data in |cache_directory|.
// |cache_directory| will be created if it does not already exist.
explicit LogoCache(const base::FilePath& cache_directory);
virtual ~LogoCache();
// Updates the metadata for the cached logo.
virtual void UpdateCachedLogoMetadata(const LogoMetadata& metadata);
// Returns metadata for the cached logo, or NULL if logo is cached.
virtual const LogoMetadata* GetCachedLogoMetadata();
// Sets the cached logo and metadata. |logo| may be NULL, in which case the
// cached logo and metadata will be cleared.
virtual void SetCachedLogo(const EncodedLogo* logo);
// Returns the cached logo, or NULL if no logo is cached or the cached logo is
// corrupt.
virtual scoped_ptr<EncodedLogo> GetCachedLogo();
private:
FRIEND_TEST_ALL_PREFIXES(LogoCacheSerializationTest, SerializeMetadata);
FRIEND_TEST_ALL_PREFIXES(LogoCacheSerializationTest,
DeserializeCorruptMetadata);
FRIEND_TEST_ALL_PREFIXES(LogoCacheTest, StoreAndRetrieveMetadata);
FRIEND_TEST_ALL_PREFIXES(LogoCacheTest, RetrieveCorruptMetadata);
FRIEND_TEST_ALL_PREFIXES(LogoCacheTest, RetrieveCorruptLogo);
// Converts string |str| to a LogoMetadata object and returns it. Returns NULL
// if |str| cannot be converted.
static scoped_ptr<LogoMetadata> LogoMetadataFromString(
const std::string& str, int* logo_num_bytes);
// Converts |metadata| to a string and stores it in |str|.
static void LogoMetadataToString(const LogoMetadata& metadata,
int logo_num_bytes,
std::string* str);
// Returns the path where the cached logo will be saved.
base::FilePath GetLogoPath();
// Returns the path where the metadata for the cached logo will be saved.
base::FilePath GetMetadataPath();
// Updates the in-memory metadata.
void UpdateMetadata(scoped_ptr<LogoMetadata> metadata);
// If the cached logo's metadata isn't available in memory (i.e.
// |metadata_is_valid_| is false), reads it from disk and stores it in
// |metadata_|. If no logo is cached, |metadata_| will be updated to NULL.
void ReadMetadataIfNeeded();
// Writes the metadata for the cached logo to disk.
void WriteMetadata();
// Writes |metadata_| to the cached metadata file and |encoded_image| to the
// cached logo file.
void WriteLogo(scoped_refptr<base::RefCountedMemory> encoded_image);
// Deletes all the cache files.
void DeleteLogoAndMetadata();
// Tries to create the cache directory if it does not already exist. Returns
// whether the cache directory exists.
bool EnsureCacheDirectoryExists();
// The directory in which the cached logo and metadata will be saved.
base::FilePath cache_directory_;
// The metadata describing the cached logo, or NULL if no logo is cached. This
// value is meaningful iff |metadata_is_valid_| is true; otherwise, the
// metadata must be read from file and |metadata_| will be NULL.
// Note: Once read from file, metadata will be stored in memory indefinitely.
scoped_ptr<LogoMetadata> metadata_;
bool metadata_is_valid_;
// The number of bytes in the logo file, as recorded in the metadata file.
// Valid iff |metadata_is_valid_|. This is used to verify that the logo file
// is complete and corresponds to the current metadata file.
int logo_num_bytes_;
// Ensure LogoCache is only used on a single thread.
base::ThreadChecker thread_checker_;
DISALLOW_COPY_AND_ASSIGN(LogoCache);
};
} // namespace search_provider_logos
#endif // COMPONENTS_SEARCH_PROVIDER_LOGOS_LOGO_CACHE_H_