Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2016 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 #include "chromeos/printing/ppd_cache.h" | |
| 6 | |
| 7 #include "base/files/file_util.h" | |
| 8 #include "base/memory/ptr_util.h" | |
| 9 #include "base/path_service.h" | |
| 10 #include "base/strings/stringprintf.h" | |
| 11 #include "chromeos/chromeos_paths.h" | |
| 12 | |
| 13 using base::FilePath; | |
| 14 using base::Optional; | |
| 15 using std::string; | |
| 16 using std::unique_ptr; | |
| 17 | |
| 18 namespace chromeos { | |
| 19 namespace printing { | |
| 20 namespace { | |
| 21 | |
| 22 // Limits on key strings we'll accept. This limit is pretty arbitrary, we | |
| 23 // just don't want to accept strings that are so long they might cause | |
| 24 // memory pressure or somesuch. | |
| 25 constexpr int kKeySizeLimit = 512; | |
| 26 | |
| 27 // "Manufacturer" used when storing and retrieving locally-keyed | |
| 28 // files. | |
| 29 const char* kLocalModel = "local"; | |
|
skau
2016/10/07 16:29:06
const char[] for string constants
Carlson
2016/10/14 19:28:56
OK, but any particular reason why?
skau
2016/10/14 22:10:16
Consistency. It looks to be the common interpreta
| |
| 30 | |
| 31 // Placeholder cache. | |
| 32 class PPDCacheImpl : public PPDCache { | |
| 33 public: | |
| 34 PPDCacheImpl(const PPDCache::Options& options) | |
| 35 : cache_base_dir_(GetCacheBaseDirOrDie()) {} | |
| 36 ~PPDCacheImpl() override {} | |
| 37 | |
| 38 // Public API functions. | |
| 39 Optional<FilePath> Find(const string& manufacturer, | |
| 40 const string& model) const override { | |
| 41 Optional<FilePath> ret; | |
| 42 if (model == kLocalModel) { | |
| 43 LOG(ERROR) << "Denying attempt to store auto-ppd under local namespace"; | |
|
skau
2016/10/07 16:29:06
Denying attempt to retrieve local ppd from auto na
Carlson
2016/10/14 19:28:56
Obsolete
| |
| 44 return ret; | |
| 45 } | |
| 46 if (!(KeyIsValid("Printer manufacturer", manufacturer) && | |
|
skau
2016/10/07 16:29:06
Is "Printer manufacturer" a constant?
Carlson
2016/10/14 19:28:56
Obsolete
| |
| 47 KeyIsValid("Printer model", model))) { | |
| 48 return ret; | |
| 49 } | |
| 50 | |
| 51 FilePath contents_path = GetCachePath(manufacturer, model); | |
| 52 if (base::PathExists(contents_path)) { | |
| 53 ret = contents_path; | |
| 54 } | |
| 55 return ret; | |
| 56 } | |
| 57 | |
| 58 Optional<FilePath> FindLocal(const string& key) const override { | |
| 59 Optional<FilePath> ret; | |
| 60 if (!KeyIsValid("Printer identifier", key)) { | |
| 61 return ret; | |
| 62 } | |
| 63 FilePath contents_path = GetCachePath(kLocalModel, key); | |
| 64 if (base::PathExists(contents_path)) { | |
| 65 ret = contents_path; | |
| 66 } | |
| 67 return ret; | |
| 68 } | |
| 69 | |
| 70 // Store a ppd that was manually added by a user, using the given key. | |
| 71 Optional<FilePath> StoreLocal( | |
| 72 const string& key, | |
| 73 const string& compressed_ppd_contents) override { | |
| 74 if (!KeyIsValid("Printer identifier", key)) { | |
| 75 return Optional<FilePath>(); | |
| 76 } | |
| 77 return StoreCommon(kLocalModel, key, compressed_ppd_contents); | |
| 78 } | |
| 79 | |
| 80 Optional<FilePath> Store(const string& manufacturer, | |
| 81 const string& model, | |
| 82 const string& compressed_ppd_contents) override { | |
| 83 if (model == kLocalModel) { | |
| 84 LOG(ERROR) << "Denying attempt to store auto-ppd under local namespace"; | |
| 85 return Optional<FilePath>(); | |
| 86 } | |
| 87 if (!(KeyIsValid("Printer manufacturer", manufacturer) && | |
| 88 KeyIsValid("Printer model", model))) { | |
| 89 return Optional<FilePath>(); | |
| 90 } | |
| 91 return StoreCommon(manufacturer, model, compressed_ppd_contents); | |
| 92 } | |
| 93 | |
| 94 private: | |
| 95 // Shared Store* functionality. This can assume that all arguments have been | |
| 96 // pre-vetted and are valid. | |
| 97 Optional<FilePath> StoreCommon(const string& manufacturer, | |
| 98 const string& model, | |
| 99 const string& compressed_ppd_contents) { | |
| 100 Optional<FilePath> ret; | |
| 101 FilePath contents_path = GetCachePath(manufacturer, model); | |
| 102 if (base::WriteFile(contents_path, compressed_ppd_contents.data(), | |
| 103 compressed_ppd_contents.size()) == | |
| 104 static_cast<int>(compressed_ppd_contents.size())) { | |
| 105 ret = contents_path; | |
| 106 } else { | |
| 107 LOG(ERROR) << "Failed to write " << compressed_ppd_contents.size() | |
| 108 << " bytes to " << contents_path.LossyDisplayName(); | |
| 109 // Try to clean up the file, as it may have partial contents. Note that | |
| 110 // DeleteFile(nonexistant file) should return true, so failure here means | |
| 111 // something is exceptionally hosed. | |
| 112 if (!base::DeleteFile(contents_path, false)) { | |
| 113 LOG(FATAL) << "Failed to cleanup partially-written file " | |
|
skau
2016/10/07 16:29:06
LOG(FATAL) will crash Chrome and thus the entire U
Carlson
2016/10/14 19:28:56
Done.
| |
| 114 << contents_path.LossyDisplayName(); | |
| 115 } | |
| 116 } | |
| 117 return ret; | |
| 118 } | |
| 119 | |
| 120 // File paths are generated via hashes of the manufacturer/model strings. | |
| 121 // This isn't because we're overly worried about collisions; rather, using the | |
| 122 // hash instead of the strings directly means we don't have to do any fiddly | |
| 123 // path escaping, stress about unicode concerns, or worry overmuch about path | |
| 124 // length limits. | |
| 125 FilePath GetCachePath(const string& manufacturer, const string& model) const { | |
| 126 size_t h = base::HashInts64(std::hash<std::string>()(manufacturer), | |
| 127 std::hash<std::string>()(model)); | |
| 128 return cache_base_dir_.Append(base::StringPrintf("%zx", h)); | |
|
skau
2016/10/07 16:29:06
Can we attach an appropriate file extension like .
Carlson
2016/10/14 19:28:56
Done.
| |
| 129 } | |
| 130 | |
| 131 // Return whether or not the given cache key is valid. Log an error | |
| 132 // describing the problem if it's not valid. | |
| 133 bool KeyIsValid(const string& key_name, const string& key) const { | |
|
skau
2016/10/07 16:29:06
Is there a way to clarify that this validation is
Carlson
2016/10/14 19:28:56
Obsolete
| |
| 134 if (key.empty()) { | |
| 135 LOG(ERROR) << key_name << " cannot be empty."; | |
| 136 return false; | |
| 137 } | |
| 138 if (key.size() > kKeySizeLimit) { | |
| 139 LOG(ERROR) << key_name << " is too long. Limit is " << kKeySizeLimit; | |
| 140 return false; | |
| 141 } | |
| 142 return true; | |
| 143 } | |
| 144 | |
| 145 // Retrieve the printer cache filepath from PathService, or die trying. | |
| 146 FilePath GetCacheBaseDirOrDie() const { | |
| 147 FilePath ret; | |
| 148 if (!PathService::Get(::chromeos::DIR_PRINTER_DRIVERS_CACHE, &ret)) { | |
| 149 LOG(FATAL) << "Failed to get printer cache directory."; | |
| 150 } | |
| 151 return ret; | |
| 152 } | |
| 153 | |
| 154 const FilePath cache_base_dir_; | |
| 155 }; | |
| 156 | |
| 157 } // namespace | |
| 158 | |
| 159 // static | |
| 160 unique_ptr<PPDCache> PPDCache::Create(const PPDCache::Options& options) { | |
| 161 return ::base::MakeUnique<PPDCacheImpl>(options); | |
| 162 } | |
| 163 | |
| 164 // static | |
| 165 unique_ptr<PPDCache> PPDCache::Create() { | |
| 166 return ::base::MakeUnique<PPDCacheImpl>(PPDCache::Options()); | |
|
skau
2016/10/07 16:29:06
nit: If we're always passing an Options struct, we
Carlson
2016/10/14 19:28:56
Done.
| |
| 167 } | |
| 168 | |
| 169 } // namespace printing | |
| 170 } // namespace chromeos | |
| OLD | NEW |