Index: chromeos/printing/ppd_cache.cc |
diff --git a/chromeos/printing/ppd_cache.cc b/chromeos/printing/ppd_cache.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..8584ea20b5a8f190bb96c2357913f7fa82d8b0a0 |
--- /dev/null |
+++ b/chromeos/printing/ppd_cache.cc |
@@ -0,0 +1,170 @@ |
+// Copyright 2016 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 "chromeos/printing/ppd_cache.h" |
+ |
+#include "base/files/file_util.h" |
+#include "base/memory/ptr_util.h" |
+#include "base/path_service.h" |
+#include "base/strings/stringprintf.h" |
+#include "chromeos/chromeos_paths.h" |
+ |
+using base::FilePath; |
+using base::Optional; |
+using std::string; |
+using std::unique_ptr; |
+ |
+namespace chromeos { |
+namespace printing { |
+namespace { |
+ |
+// Limits on key strings we'll accept. This limit is pretty arbitrary, we |
+// just don't want to accept strings that are so long they might cause |
+// memory pressure or somesuch. |
+constexpr int kKeySizeLimit = 512; |
+ |
+// "Manufacturer" used when storing and retrieving locally-keyed |
+// files. |
+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
|
+ |
+// Placeholder cache. |
+class PPDCacheImpl : public PPDCache { |
+ public: |
+ PPDCacheImpl(const PPDCache::Options& options) |
+ : cache_base_dir_(GetCacheBaseDirOrDie()) {} |
+ ~PPDCacheImpl() override {} |
+ |
+ // Public API functions. |
+ Optional<FilePath> Find(const string& manufacturer, |
+ const string& model) const override { |
+ Optional<FilePath> ret; |
+ if (model == kLocalModel) { |
+ 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
|
+ return ret; |
+ } |
+ 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
|
+ KeyIsValid("Printer model", model))) { |
+ return ret; |
+ } |
+ |
+ FilePath contents_path = GetCachePath(manufacturer, model); |
+ if (base::PathExists(contents_path)) { |
+ ret = contents_path; |
+ } |
+ return ret; |
+ } |
+ |
+ Optional<FilePath> FindLocal(const string& key) const override { |
+ Optional<FilePath> ret; |
+ if (!KeyIsValid("Printer identifier", key)) { |
+ return ret; |
+ } |
+ FilePath contents_path = GetCachePath(kLocalModel, key); |
+ if (base::PathExists(contents_path)) { |
+ ret = contents_path; |
+ } |
+ return ret; |
+ } |
+ |
+ // Store a ppd that was manually added by a user, using the given key. |
+ Optional<FilePath> StoreLocal( |
+ const string& key, |
+ const string& compressed_ppd_contents) override { |
+ if (!KeyIsValid("Printer identifier", key)) { |
+ return Optional<FilePath>(); |
+ } |
+ return StoreCommon(kLocalModel, key, compressed_ppd_contents); |
+ } |
+ |
+ Optional<FilePath> Store(const string& manufacturer, |
+ const string& model, |
+ const string& compressed_ppd_contents) override { |
+ if (model == kLocalModel) { |
+ LOG(ERROR) << "Denying attempt to store auto-ppd under local namespace"; |
+ return Optional<FilePath>(); |
+ } |
+ if (!(KeyIsValid("Printer manufacturer", manufacturer) && |
+ KeyIsValid("Printer model", model))) { |
+ return Optional<FilePath>(); |
+ } |
+ return StoreCommon(manufacturer, model, compressed_ppd_contents); |
+ } |
+ |
+ private: |
+ // Shared Store* functionality. This can assume that all arguments have been |
+ // pre-vetted and are valid. |
+ Optional<FilePath> StoreCommon(const string& manufacturer, |
+ const string& model, |
+ const string& compressed_ppd_contents) { |
+ Optional<FilePath> ret; |
+ FilePath contents_path = GetCachePath(manufacturer, model); |
+ if (base::WriteFile(contents_path, compressed_ppd_contents.data(), |
+ compressed_ppd_contents.size()) == |
+ static_cast<int>(compressed_ppd_contents.size())) { |
+ ret = contents_path; |
+ } else { |
+ LOG(ERROR) << "Failed to write " << compressed_ppd_contents.size() |
+ << " bytes to " << contents_path.LossyDisplayName(); |
+ // Try to clean up the file, as it may have partial contents. Note that |
+ // DeleteFile(nonexistant file) should return true, so failure here means |
+ // something is exceptionally hosed. |
+ if (!base::DeleteFile(contents_path, false)) { |
+ 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.
|
+ << contents_path.LossyDisplayName(); |
+ } |
+ } |
+ return ret; |
+ } |
+ |
+ // File paths are generated via hashes of the manufacturer/model strings. |
+ // This isn't because we're overly worried about collisions; rather, using the |
+ // hash instead of the strings directly means we don't have to do any fiddly |
+ // path escaping, stress about unicode concerns, or worry overmuch about path |
+ // length limits. |
+ FilePath GetCachePath(const string& manufacturer, const string& model) const { |
+ size_t h = base::HashInts64(std::hash<std::string>()(manufacturer), |
+ std::hash<std::string>()(model)); |
+ 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.
|
+ } |
+ |
+ // Return whether or not the given cache key is valid. Log an error |
+ // describing the problem if it's not valid. |
+ 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
|
+ if (key.empty()) { |
+ LOG(ERROR) << key_name << " cannot be empty."; |
+ return false; |
+ } |
+ if (key.size() > kKeySizeLimit) { |
+ LOG(ERROR) << key_name << " is too long. Limit is " << kKeySizeLimit; |
+ return false; |
+ } |
+ return true; |
+ } |
+ |
+ // Retrieve the printer cache filepath from PathService, or die trying. |
+ FilePath GetCacheBaseDirOrDie() const { |
+ FilePath ret; |
+ if (!PathService::Get(::chromeos::DIR_PRINTER_DRIVERS_CACHE, &ret)) { |
+ LOG(FATAL) << "Failed to get printer cache directory."; |
+ } |
+ return ret; |
+ } |
+ |
+ const FilePath cache_base_dir_; |
+}; |
+ |
+} // namespace |
+ |
+// static |
+unique_ptr<PPDCache> PPDCache::Create(const PPDCache::Options& options) { |
+ return ::base::MakeUnique<PPDCacheImpl>(options); |
+} |
+ |
+// static |
+unique_ptr<PPDCache> PPDCache::Create() { |
+ 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.
|
+} |
+ |
+} // namespace printing |
+} // namespace chromeos |