1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef COMPONENTS_SEARCH_PROVIDER_LOGOS_LOGO_CACHE_H_
6#define COMPONENTS_SEARCH_PROVIDER_LOGOS_LOGO_CACHE_H_
7
8#include <string>
9
10#include "base/callback.h"
11#include "base/files/file_path.h"
12#include "base/gtest_prod_util.h"
13#include "base/memory/ref_counted.h"
14#include "base/memory/ref_counted_memory.h"
15#include "base/memory/scoped_ptr.h"
16#include "base/threading/thread_checker.h"
17#include "components/search_provider_logos/logo_common.h"
18
19namespace search_provider_logos {
20
21// A file-based cache for the search provider's logo. This allows clients to
22// store and retrieve a logo (of type EncodedLogo) and its associated metadata
23// (of type LogoMetadata). Metadata can be updated independently from the logo
24// to handle cases where, e.g. the expiration date changes, but the logo stays
25// the same. If corruption is detected in the metadata or logo, the cache will
26// be cleared.
27//
28// Note: this class must only be used on a single thread. All methods are
29// are blocking, so this should not be used on the UI thread.
30//
31// The logo and its metadata are stored in files, so they persist even when
32// Chrome is closed. Once loaded from disk, the metadata is kept in memory to
33// enable quick retrieval. The logo is not kept around in memory because of its
34// size.
35class LogoCache {
36 public:
37  // Constructs a logo cache that stores data in |cache_directory|.
38  // |cache_directory| will be created if it does not already exist.
39  explicit LogoCache(const base::FilePath& cache_directory);
40  virtual ~LogoCache();
41
42  // Updates the metadata for the cached logo.
43  virtual void UpdateCachedLogoMetadata(const LogoMetadata& metadata);
44
45  // Returns metadata for the cached logo, or NULL if logo is cached.
46  virtual const LogoMetadata* GetCachedLogoMetadata();
47
48  // Sets the cached logo and metadata. |logo| may be NULL, in which case the
49  // cached logo and metadata will be cleared.
50  virtual void SetCachedLogo(const EncodedLogo* logo);
51
52  // Returns the cached logo, or NULL if no logo is cached or the cached logo is
53  // corrupt.
54  virtual scoped_ptr<EncodedLogo> GetCachedLogo();
55
56 private:
57  FRIEND_TEST_ALL_PREFIXES(LogoCacheSerializationTest, SerializeMetadata);
58  FRIEND_TEST_ALL_PREFIXES(LogoCacheSerializationTest,
59                           DeserializeCorruptMetadata);
60  FRIEND_TEST_ALL_PREFIXES(LogoCacheTest, StoreAndRetrieveMetadata);
61  FRIEND_TEST_ALL_PREFIXES(LogoCacheTest, RetrieveCorruptMetadata);
62  FRIEND_TEST_ALL_PREFIXES(LogoCacheTest, RetrieveCorruptLogo);
63
64  // Converts string |str| to a LogoMetadata object and returns it. Returns NULL
65  // if |str| cannot be converted.
66  static scoped_ptr<LogoMetadata> LogoMetadataFromString(
67      const std::string& str, int* logo_num_bytes);
68
69  // Converts |metadata| to a string and stores it in |str|.
70  static void LogoMetadataToString(const LogoMetadata& metadata,
71                                   int logo_num_bytes,
72                                   std::string* str);
73
74  // Returns the path where the cached logo will be saved.
75  base::FilePath GetLogoPath();
76
77  // Returns the path where the metadata for the cached logo will be saved.
78  base::FilePath GetMetadataPath();
79
80  // Updates the in-memory metadata.
81  void UpdateMetadata(scoped_ptr<LogoMetadata> metadata);
82
83  // If the cached logo's metadata isn't available in memory (i.e.
84  // |metadata_is_valid_| is false), reads it from disk and stores it in
85  // |metadata_|. If no logo is cached, |metadata_| will be updated to NULL.
86  void ReadMetadataIfNeeded();
87
88  // Writes the metadata for the cached logo to disk.
89  void WriteMetadata();
90
91  // Writes |metadata_| to the cached metadata file and |encoded_image| to the
92  // cached logo file.
93  void WriteLogo(scoped_refptr<base::RefCountedMemory> encoded_image);
94
95  // Deletes all the cache files.
96  void DeleteLogoAndMetadata();
97
98  // Tries to create the cache directory if it does not already exist. Returns
99  // whether the cache directory exists.
100  bool EnsureCacheDirectoryExists();
101
102  // The directory in which the cached logo and metadata will be saved.
103  base::FilePath cache_directory_;
104
105  // The metadata describing the cached logo, or NULL if no logo is cached. This
106  // value is meaningful iff |metadata_is_valid_| is true; otherwise, the
107  // metadata must be read from file and |metadata_| will be NULL.
108  // Note: Once read from file, metadata will be stored in memory indefinitely.
109  scoped_ptr<LogoMetadata> metadata_;
110  bool metadata_is_valid_;
111
112  // The number of bytes in the logo file, as recorded in the metadata file.
113  // Valid iff |metadata_is_valid_|. This is used to verify that the logo file
114  // is complete and corresponds to the current metadata file.
115  int logo_num_bytes_;
116
117  // Ensure LogoCache is only used on a single thread.
118  base::ThreadChecker thread_checker_;
119
120  DISALLOW_COPY_AND_ASSIGN(LogoCache);
121};
122
123}  // namespace search_provider_logos
124
125#endif  // COMPONENTS_SEARCH_PROVIDER_LOGOS_LOGO_CACHE_H_
126