ppd_provider.cc 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007
  1. // Copyright 2019 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. #include "chromeos/printing/ppd_provider.h"
  5. #include <algorithm>
  6. #include <string>
  7. #include <utility>
  8. #include <vector>
  9. #include "base/containers/queue.h"
  10. #include "base/files/file_path.h"
  11. #include "base/files/file_util.h"
  12. #include "base/memory/scoped_refptr.h"
  13. #include "base/notreached.h"
  14. #include "base/strings/strcat.h"
  15. #include "base/task/task_traits.h"
  16. #include "base/task/thread_pool.h"
  17. #include "base/threading/scoped_blocking_call.h"
  18. #include "base/time/time.h"
  19. #include "chromeos/printing/epson_driver_matching.h"
  20. #include "chromeos/printing/ppd_cache.h"
  21. #include "chromeos/printing/ppd_metadata_manager.h"
  22. #include "chromeos/printing/printer_config_cache.h"
  23. #include "chromeos/printing/printer_configuration.h"
  24. #include "chromeos/printing/printing_constants.h"
  25. #include "net/base/filename_util.h"
  26. namespace chromeos {
  27. namespace {
  28. // The exact queue length at which PpdProvider will begin to post
  29. // failure callbacks in response to its queue-able public methods.
  30. // Arbitrarily chosen.
  31. // See also: struct MethodDeferralContext
  32. constexpr size_t kMethodDeferralLimit = 20;
  33. // Age limit for time-sensitive API calls. Typically denotes "Please
  34. // respond with data no older than kMaxDataAge." Arbitrarily chosen.
  35. constexpr base::TimeDelta kMaxDataAge = base::Minutes(30LL);
  36. // Effective-make-and-model string that describes a printer capable of
  37. // using the generic Epson PPD.
  38. const char kEpsonGenericEmm[] = "epson generic escpr printer";
  39. bool PpdReferenceIsWellFormed(const Printer::PpdReference& reference) {
  40. int filled_fields = 0;
  41. if (!reference.user_supplied_ppd_url.empty()) {
  42. ++filled_fields;
  43. GURL tmp_url(reference.user_supplied_ppd_url);
  44. if (!tmp_url.is_valid() || !tmp_url.SchemeIs("file")) {
  45. LOG(ERROR) << "Invalid url for a user-supplied ppd: "
  46. << reference.user_supplied_ppd_url
  47. << " (must be a file:// URL)";
  48. return false;
  49. }
  50. }
  51. if (!reference.effective_make_and_model.empty()) {
  52. ++filled_fields;
  53. }
  54. // All effective-make-and-model strings should be lowercased, since v2.
  55. // Since make-and-model strings could include non-Latin chars, only checking
  56. // that it excludes all upper-case chars A-Z.
  57. if (!std::all_of(reference.effective_make_and_model.begin(),
  58. reference.effective_make_and_model.end(),
  59. [](char c) -> bool { return !base::IsAsciiUpper(c); })) {
  60. return false;
  61. }
  62. // Should have exactly one non-empty field.
  63. return filled_fields == 1;
  64. }
  65. std::string PpdPathInServingRoot(base::StringPiece ppd_basename) {
  66. return base::StrCat({"ppds_for_metadata_v3/", ppd_basename});
  67. }
  68. // Helper struct for PpdProviderImpl. Allows PpdProviderImpl to defer
  69. // its public method calls, which PpdProviderImpl will do when the
  70. // PpdMetadataManager is not ready to deal with locale-sensitive PPD
  71. // metadata.
  72. //
  73. // Note that the semantics of this struct demand two things of the
  74. // deferable public methods of PpdProviderImpl:
  75. // 1. that they check for its presence and
  76. // 2. that they check its |current_method_is_being_failed| member to
  77. // prevent infinite re-enqueueing of public methods once the queue
  78. // is full.
  79. struct MethodDeferralContext {
  80. MethodDeferralContext() = default;
  81. ~MethodDeferralContext() = default;
  82. // This struct is not copyable.
  83. MethodDeferralContext(const MethodDeferralContext&) = delete;
  84. MethodDeferralContext& operator=(const MethodDeferralContext&) = delete;
  85. // Pops the first entry from |deferred_methods| and synchronously runs
  86. // it with the intent to fail it.
  87. void FailOneEnqueuedMethod() {
  88. DCHECK(!current_method_is_being_failed);
  89. // Explicitly activates the failure codepath for whatever public
  90. // method of PpdProviderImpl that we'll now Run().
  91. current_method_is_being_failed = true;
  92. std::move(deferred_methods.front()).Run();
  93. deferred_methods.pop();
  94. current_method_is_being_failed = false;
  95. }
  96. // Fails all |deferred_methods| synchronously.
  97. void FailAllEnqueuedMethods() {
  98. while (!deferred_methods.empty()) {
  99. FailOneEnqueuedMethod();
  100. }
  101. }
  102. // Dequeues and posts all |deferred_methods| onto our sequence.
  103. void FlushAndPostAll() {
  104. while (!deferred_methods.empty()) {
  105. base::SequencedTaskRunnerHandle::Get()->PostTask(
  106. FROM_HERE, std::move(deferred_methods.front()));
  107. deferred_methods.pop();
  108. }
  109. }
  110. bool IsFull() { return deferred_methods.size() >= kMethodDeferralLimit; }
  111. // Whether an attempt to get the metadata locale is ongoing.
  112. bool metadata_locale_fetch_is_ongoing = false;
  113. // This bool is checked during execution of a queue-able public method
  114. // of PpdProviderImpl. If it is true, then
  115. // 1. the current queue-able public method was previously enqueued,
  116. // 2. the deferral queue is full, and so
  117. // 3. the current queue-able public method was posted for the sole
  118. // purpose of being _failed_, and should not be re-enqueued.
  119. bool current_method_is_being_failed = false;
  120. base::queue<base::OnceCallback<void()>> deferred_methods;
  121. };
  122. // This class implements the PpdProvider interface for the v3 metadata
  123. // (https://crbug.com/888189).
  124. class PpdProviderImpl : public PpdProvider {
  125. public:
  126. PpdProviderImpl(const base::Version& current_version,
  127. scoped_refptr<PpdCache> cache,
  128. std::unique_ptr<PpdMetadataManager> metadata_manager,
  129. std::unique_ptr<PrinterConfigCache> config_cache)
  130. : version_(current_version),
  131. ppd_cache_(cache),
  132. deferral_context_(std::make_unique<MethodDeferralContext>()),
  133. metadata_manager_(std::move(metadata_manager)),
  134. config_cache_(std::move(config_cache)),
  135. file_task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
  136. {base::TaskPriority::USER_VISIBLE, base::MayBlock(),
  137. base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})) {}
  138. void ResolveManufacturers(ResolveManufacturersCallback cb) override {
  139. // Do we need
  140. // 1. to defer this method?
  141. // 2. to fail this method (which was already previously deferred)?
  142. if (deferral_context_) {
  143. if (deferral_context_->current_method_is_being_failed) {
  144. auto failure_cb = base::BindOnce(
  145. std::move(cb), PpdProvider::CallbackResultCode::SERVER_ERROR,
  146. std::vector<std::string>());
  147. base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
  148. std::move(failure_cb));
  149. return;
  150. }
  151. if (deferral_context_->IsFull()) {
  152. deferral_context_->FailOneEnqueuedMethod();
  153. DCHECK(!deferral_context_->IsFull());
  154. }
  155. TryToGetMetadataManagerLocale();
  156. base::OnceCallback<void()> this_method =
  157. base::BindOnce(&PpdProviderImpl::ResolveManufacturers,
  158. weak_factory_.GetWeakPtr(), std::move(cb));
  159. deferral_context_->deferred_methods.push(std::move(this_method));
  160. return;
  161. }
  162. metadata_manager_->GetManufacturers(kMaxDataAge, std::move(cb));
  163. }
  164. void ResolvePrinters(const std::string& manufacturer,
  165. ResolvePrintersCallback cb) override {
  166. // Caller must not call ResolvePrinters() before a successful reply
  167. // from ResolveManufacturers(). ResolveManufacturers() cannot have
  168. // been successful if the |deferral_context_| still exists.
  169. if (deferral_context_) {
  170. auto failure_cb = base::BindOnce(
  171. std::move(cb), PpdProvider::CallbackResultCode::INTERNAL_ERROR,
  172. ResolvedPrintersList());
  173. base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
  174. std::move(failure_cb));
  175. return;
  176. }
  177. PpdMetadataManager::GetPrintersCallback manager_callback =
  178. base::BindOnce(&PpdProviderImpl::OnPrintersGotten,
  179. weak_factory_.GetWeakPtr(), std::move(cb));
  180. metadata_manager_->GetPrinters(manufacturer, kMaxDataAge,
  181. std::move(manager_callback));
  182. }
  183. // This method examines the members of |search_data| in turn and seeks
  184. // out an appropriate PPD from the serving root. The order is
  185. // 1. |search_data|::make_and_model - we seek out
  186. // effective-make-and-model strings from forward index metadata.
  187. // 2. |search_data|::usb_*_id - we seek out a device with a matching
  188. // ID from USB index metadata.
  189. // 3. |search_data|::make_and_model - we check if any among these
  190. // effective-make-and-model strings describe a printer for which
  191. // we can use the generic Epson PPD.
  192. //
  193. // * This method observes and honors PPD restrictions (furnished by
  194. // forward index metadata) and will ignore PPDs that are not
  195. // advertised to run with the current |version_|.
  196. // * This method is not locale-sensitive.
  197. void ResolvePpdReference(const PrinterSearchData& search_data,
  198. ResolvePpdReferenceCallback cb) override {
  199. // In v3 metadata, effective-make-and-model strings are only
  200. // expressed in lowercased ASCII.
  201. PrinterSearchData lowercased_search_data(search_data);
  202. for (std::string& emm : lowercased_search_data.make_and_model) {
  203. emm = base::ToLowerASCII(emm);
  204. }
  205. ResolvePpdReferenceContext context(lowercased_search_data, std::move(cb));
  206. // Initiate step 1 if possible.
  207. if (!lowercased_search_data.make_and_model.empty()) {
  208. auto callback = base::BindOnce(
  209. &PpdProviderImpl::TryToResolvePpdReferenceFromForwardIndices,
  210. weak_factory_.GetWeakPtr(), std::move(context));
  211. metadata_manager_->FindAllEmmsAvailableInIndex(
  212. lowercased_search_data.make_and_model, kMaxDataAge,
  213. std::move(callback));
  214. return;
  215. }
  216. // Otherwise, jump straight to step 2.
  217. TryToResolvePpdReferenceFromUsbIndices(std::move(context));
  218. }
  219. // This method invokes |cb| with the contents of a successfully
  220. // retrieved PPD appropriate for |reference|.
  221. //
  222. // As a side effect, this method may attempt
  223. // * to read a PPD from the user's files (if the PPD is
  224. // user-supplied) or
  225. // * to download a PPD from the serving root (if the PPD is not
  226. // user-supplied).
  227. void ResolvePpd(const Printer::PpdReference& reference,
  228. ResolvePpdCallback cb) override {
  229. // In v3 metadata, effective-make-and-model strings are only
  230. // expressed in lowercased ASCII.
  231. Printer::PpdReference lowercased_reference(reference);
  232. lowercased_reference.effective_make_and_model =
  233. base::ToLowerASCII(lowercased_reference.effective_make_and_model);
  234. if (!PpdReferenceIsWellFormed(lowercased_reference)) {
  235. base::SequencedTaskRunnerHandle::Get()->PostTask(
  236. FROM_HERE, base::BindOnce(std::move(cb),
  237. CallbackResultCode::INTERNAL_ERROR, ""));
  238. return;
  239. }
  240. if (!lowercased_reference.user_supplied_ppd_url.empty()) {
  241. ResolveUserSuppliedPpd(lowercased_reference, std::move(cb));
  242. return;
  243. }
  244. std::vector<std::string> target_emm = {
  245. lowercased_reference.effective_make_and_model};
  246. auto callback =
  247. base::BindOnce(&PpdProviderImpl::OnPpdBasenameSoughtFromForwardIndex,
  248. weak_factory_.GetWeakPtr(),
  249. std::move(lowercased_reference), std::move(cb));
  250. metadata_manager_->FindAllEmmsAvailableInIndex(target_emm, kMaxDataAge,
  251. std::move(callback));
  252. }
  253. void ReverseLookup(const std::string& effective_make_and_model,
  254. ReverseLookupCallback cb) override {
  255. // Do we need
  256. // 1. to defer this method?
  257. // 2. to fail this method (which was already previously deferred)?
  258. if (deferral_context_) {
  259. if (deferral_context_->current_method_is_being_failed) {
  260. auto failure_cb = base::BindOnce(
  261. std::move(cb), PpdProvider::CallbackResultCode::SERVER_ERROR, "",
  262. "");
  263. base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
  264. std::move(failure_cb));
  265. return;
  266. }
  267. if (deferral_context_->IsFull()) {
  268. deferral_context_->FailOneEnqueuedMethod();
  269. DCHECK(!deferral_context_->IsFull());
  270. }
  271. TryToGetMetadataManagerLocale();
  272. base::OnceCallback<void()> this_method = base::BindOnce(
  273. &PpdProviderImpl::ReverseLookup, weak_factory_.GetWeakPtr(),
  274. effective_make_and_model, std::move(cb));
  275. deferral_context_->deferred_methods.push(std::move(this_method));
  276. return;
  277. }
  278. // In v3 metadata, effective-make-and-model strings are only
  279. // expressed in lowercased ASCII.
  280. std::string lowercased_effective_make_and_model =
  281. base::ToLowerASCII(effective_make_and_model);
  282. // Delegates directly to the PpdMetadataManager.
  283. metadata_manager_->SplitMakeAndModel(lowercased_effective_make_and_model,
  284. kMaxDataAge, std::move(cb));
  285. }
  286. // This method depends on forward indices, which are not
  287. // locale-sensitive.
  288. void ResolvePpdLicense(base::StringPiece effective_make_and_model,
  289. ResolvePpdLicenseCallback cb) override {
  290. // In v3 metadata, effective-make-and-model strings are only
  291. // expressed in lowercased ASCII.
  292. const std::string lowercased_effective_make_and_model =
  293. base::ToLowerASCII(effective_make_and_model);
  294. auto callback = base::BindOnce(
  295. &PpdProviderImpl::FindLicenseForEmm, weak_factory_.GetWeakPtr(),
  296. lowercased_effective_make_and_model, std::move(cb));
  297. metadata_manager_->FindAllEmmsAvailableInIndex(
  298. {lowercased_effective_make_and_model}, kMaxDataAge,
  299. std::move(callback));
  300. }
  301. protected:
  302. ~PpdProviderImpl() override = default;
  303. private:
  304. // Convenience container used throughout ResolvePpdReference().
  305. struct ResolvePpdReferenceContext {
  306. ResolvePpdReferenceContext(const PrinterSearchData& search_data_arg,
  307. ResolvePpdReferenceCallback cb_arg)
  308. : search_data(search_data_arg), cb(std::move(cb_arg)) {}
  309. ~ResolvePpdReferenceContext() = default;
  310. // This container is not copyable and is move-only.
  311. ResolvePpdReferenceContext(ResolvePpdReferenceContext&& other) = default;
  312. ResolvePpdReferenceContext& operator=(ResolvePpdReferenceContext&& other) =
  313. default;
  314. PrinterSearchData search_data;
  315. ResolvePpdReferenceCallback cb;
  316. };
  317. // Used internally in ResolvePpd(). Describes the physical, bitwise
  318. // origin of a PPD.
  319. //
  320. // Example: a PPD previously downloaded from the serving root is saved
  321. // into the local PpdCache. A subsequent call to ResolvePpd() searches
  322. // the local PpdCache and returns this PPD. Internally, the methods
  323. // that comprise ResolvePpd() treat this as kFromPpdCache.
  324. enum class ResolvedPpdOrigin {
  325. kFromServingRoot,
  326. kFromUserSuppliedUrl,
  327. kFromPpdCache,
  328. };
  329. // Returns an empty string on failure.
  330. static std::string FetchFile(const GURL& ppd_url) {
  331. DCHECK(ppd_url.is_valid());
  332. DCHECK(ppd_url.SchemeIs("file"));
  333. base::ScopedBlockingCall scoped_blocking_call(
  334. FROM_HERE, base::BlockingType::MAY_BLOCK);
  335. base::FilePath path;
  336. if (!net::FileURLToFilePath(ppd_url, &path)) {
  337. LOG(ERROR) << "Not a valid file URL.";
  338. return "";
  339. }
  340. std::string file_contents;
  341. if (!base::ReadFileToString(path, &file_contents)) {
  342. return "";
  343. }
  344. return file_contents;
  345. }
  346. // Requests that |metadata_manager_| obtain a metadata locale so that
  347. // |this| can call its locale-sensitive methods.
  348. //
  349. // |this| is largely useless if its |metadata_manager_| is not ready
  350. // to traffick in locale-sensitive PPD metadata, so we want this
  351. // method to eventually succeed.
  352. void TryToGetMetadataManagerLocale() {
  353. if (deferral_context_->metadata_locale_fetch_is_ongoing) {
  354. return;
  355. }
  356. auto callback =
  357. base::BindOnce(&PpdProviderImpl::OnMetadataManagerLocaleGotten,
  358. weak_factory_.GetWeakPtr());
  359. metadata_manager_->GetLocale(std::move(callback));
  360. deferral_context_->metadata_locale_fetch_is_ongoing = true;
  361. }
  362. // Evaluates true if our |version_| falls within the bounds set by
  363. // |restrictions|.
  364. bool CurrentVersionSatisfiesRestrictions(
  365. const Restrictions& restrictions) const {
  366. if ((restrictions.min_milestone.has_value() &&
  367. restrictions.min_milestone.value().IsValid() &&
  368. version_ < restrictions.min_milestone) ||
  369. (restrictions.max_milestone.has_value() &&
  370. restrictions.max_milestone.value().IsValid() &&
  371. version_ > restrictions.max_milestone)) {
  372. return false;
  373. }
  374. return true;
  375. }
  376. // Callback fed to PpdMetadataManager::GetLocale().
  377. void OnMetadataManagerLocaleGotten(bool succeeded) {
  378. deferral_context_->metadata_locale_fetch_is_ongoing = false;
  379. if (!succeeded) {
  380. // Uh-oh, we concretely failed to get a metadata locale. We should
  381. // fail all outstanding deferred methods and let callers retry as
  382. // they see fit.
  383. deferral_context_->FailAllEnqueuedMethods();
  384. return;
  385. }
  386. deferral_context_->FlushAndPostAll();
  387. // It is no longer necessary to defer public method calls.
  388. deferral_context_.reset();
  389. }
  390. // Callback fed to PpdMetadataManager::GetPrinters().
  391. void OnPrintersGotten(ResolvePrintersCallback cb,
  392. bool succeeded,
  393. const ParsedPrinters& printers) {
  394. if (!succeeded) {
  395. base::SequencedTaskRunnerHandle::Get()->PostTask(
  396. FROM_HERE,
  397. base::BindOnce(std::move(cb), CallbackResultCode::SERVER_ERROR,
  398. ResolvedPrintersList()));
  399. return;
  400. }
  401. ResolvedPrintersList printers_available_to_our_version;
  402. for (const ParsedPrinter& printer : printers) {
  403. if (CurrentVersionSatisfiesRestrictions(printer.restrictions)) {
  404. Printer::PpdReference ppd_reference;
  405. ppd_reference.effective_make_and_model =
  406. printer.effective_make_and_model;
  407. printers_available_to_our_version.push_back(ResolvedPpdReference{
  408. printer.user_visible_printer_name, ppd_reference});
  409. }
  410. }
  411. base::SequencedTaskRunnerHandle::Get()->PostTask(
  412. FROM_HERE, base::BindOnce(std::move(cb), CallbackResultCode::SUCCESS,
  413. printers_available_to_our_version));
  414. }
  415. // Finds the first ParsedIndexLeaf keyed on |effective_make_and_model|
  416. // from |forward_index_subset| (a slice of forward index metadata)
  417. // that is allowed for use in our current |version_|.
  418. //
  419. // Note that |forward_index_subset| has the type returned by
  420. // PpdMetadataManager::FindAllEmmsAvailableInIndexCallback.
  421. const ParsedIndexLeaf* FirstAllowableParsedIndexLeaf(
  422. base::StringPiece effective_make_and_model,
  423. const base::flat_map<std::string, ParsedIndexValues>&
  424. forward_index_subset) const {
  425. const auto& iter = forward_index_subset.find(effective_make_and_model);
  426. if (iter == forward_index_subset.end()) {
  427. return nullptr;
  428. }
  429. for (const ParsedIndexLeaf& index_leaf : iter->second.values) {
  430. if (CurrentVersionSatisfiesRestrictions(index_leaf.restrictions)) {
  431. return &index_leaf;
  432. }
  433. }
  434. return nullptr;
  435. }
  436. static void SuccessfullyResolvePpdReferenceWithEmm(
  437. base::StringPiece effective_make_and_model,
  438. ResolvePpdReferenceCallback cb) {
  439. Printer::PpdReference reference;
  440. reference.effective_make_and_model = std::string(effective_make_and_model);
  441. base::SequencedTaskRunnerHandle::Get()->PostTask(
  442. FROM_HERE, base::BindOnce(std::move(cb), CallbackResultCode::SUCCESS,
  443. std::move(reference), /*manufacturer=*/""));
  444. }
  445. // Fails a prior call to ResolvePpdReference().
  446. // |usb_manufacturer| may be empty
  447. // * if we didn't find a manufacturer name for the given vendor ID or
  448. // * if we invoked this method directly with an empty manufacturer
  449. // name: "this wasn't a USB printer in the first place, so there's
  450. // no USB manufacturer to speak of."
  451. static void FailToResolvePpdReferenceWithUsbManufacturer(
  452. ResolvePpdReferenceCallback cb,
  453. const std::string& usb_manufacturer) {
  454. base::SequencedTaskRunnerHandle::Get()->PostTask(
  455. FROM_HERE, base::BindOnce(std::move(cb), CallbackResultCode::NOT_FOUND,
  456. Printer::PpdReference(), usb_manufacturer));
  457. }
  458. // Entry point to fail a prior call to ResolvePpdReference().
  459. void FailToResolvePpdReference(ResolvePpdReferenceContext context) {
  460. if (context.search_data.discovery_type ==
  461. PrinterSearchData::PrinterDiscoveryType::kUsb) {
  462. auto callback = base::BindOnce(
  463. &PpdProviderImpl::FailToResolvePpdReferenceWithUsbManufacturer,
  464. std::move(context.cb));
  465. metadata_manager_->GetUsbManufacturerName(
  466. context.search_data.usb_vendor_id, kMaxDataAge, std::move(callback));
  467. return;
  468. }
  469. // If |search_data| does not describe a USB printer, the |cb| is
  470. // posted in the same way, but with an empty USB manufacturer name.
  471. FailToResolvePpdReferenceWithUsbManufacturer(std::move(context.cb),
  472. /*manufacturer=*/"");
  473. }
  474. // Continues a prior call to ResolvePpdReference() (step 3).
  475. // This callback is fed to
  476. // PpdMetadataManager::FindAllEmmsAvailableInIndex(), as we treat the
  477. // hardcoded generic Epson effective-make-and-model string like any
  478. // other emm, duly verifying its presence in forward index metadata
  479. // and that it is not restricted from running in this |version_|.
  480. void OnForwardIndicesSearchedForGenericEpsonEmm(
  481. ResolvePpdReferenceContext context,
  482. const base::flat_map<std::string, ParsedIndexValues>&
  483. forward_index_results) {
  484. const ParsedIndexLeaf* const index_leaf =
  485. FirstAllowableParsedIndexLeaf(kEpsonGenericEmm, forward_index_results);
  486. if (index_leaf) {
  487. SuccessfullyResolvePpdReferenceWithEmm(kEpsonGenericEmm,
  488. std::move(context.cb));
  489. return;
  490. }
  491. // This really shouldn't happen, but we couldn't build a
  492. // PpdReference that would point to the generic Epson PPD.
  493. // (This might mean that the serving root is badly messed up in a
  494. // way that escaped the attention of the Chrome OS printing team.)
  495. FailToResolvePpdReference(std::move(context));
  496. }
  497. // Continues a prior call to ResolvePpdReference() (step 3).
  498. void TryToResolvePpdReferenceWithGenericEpsonPpd(
  499. ResolvePpdReferenceContext context) {
  500. if (CanUseEpsonGenericPPD(context.search_data)) {
  501. auto callback = base::BindOnce(
  502. &PpdProviderImpl::OnForwardIndicesSearchedForGenericEpsonEmm,
  503. weak_factory_.GetWeakPtr(), std::move(context));
  504. metadata_manager_->FindAllEmmsAvailableInIndex(
  505. {kEpsonGenericEmm}, kMaxDataAge, std::move(callback));
  506. return;
  507. }
  508. // At this point, we couldn't build a PpdReference using the
  509. // generic Epson PPD. ResolvePpdReference() can only fail now.
  510. FailToResolvePpdReference(std::move(context));
  511. }
  512. // Continues a prior call to ResolvePpdReference() (step 2).
  513. // This callback is fed to
  514. // PpdMetadataManager::FindAllEmmsAvailableInIndex().
  515. void OnForwardIndicesSearchedForUsbEmm(
  516. ResolvePpdReferenceContext context,
  517. const std::string& effective_make_and_model_from_usb_index,
  518. const base::flat_map<std::string, ParsedIndexValues>&
  519. forward_index_results) {
  520. const ParsedIndexLeaf* const index_leaf = FirstAllowableParsedIndexLeaf(
  521. effective_make_and_model_from_usb_index, forward_index_results);
  522. if (index_leaf) {
  523. SuccessfullyResolvePpdReferenceWithEmm(
  524. effective_make_and_model_from_usb_index, std::move(context.cb));
  525. return;
  526. }
  527. // At this point, we couldn't build a PpdReference from the
  528. // effective-make-and-model string sourced from the USB index.
  529. // ResolvePpdReference() continues to its next step.
  530. TryToResolvePpdReferenceWithGenericEpsonPpd(std::move(context));
  531. }
  532. // Continues a prior call to ResolvePpdReference() (step 2).
  533. // This callback is fed to PpdMetadataManager::FindDeviceInUsbIndex().
  534. void OnUsbIndicesSearched(ResolvePpdReferenceContext context,
  535. const std::string& effective_make_and_model) {
  536. if (!effective_make_and_model.empty()) {
  537. auto callback =
  538. base::BindOnce(&PpdProviderImpl::OnForwardIndicesSearchedForUsbEmm,
  539. weak_factory_.GetWeakPtr(), std::move(context),
  540. effective_make_and_model);
  541. metadata_manager_->FindAllEmmsAvailableInIndex(
  542. {effective_make_and_model}, kMaxDataAge, std::move(callback));
  543. return;
  544. }
  545. // At this point, we couldn't build a PpdReference from a USB index
  546. // search. ResolvePpdReference() continues to its next step.
  547. TryToResolvePpdReferenceWithGenericEpsonPpd(std::move(context));
  548. }
  549. // Continues a prior call to ResolvePpdReference() (step 2).
  550. void TryToResolvePpdReferenceFromUsbIndices(
  551. ResolvePpdReferenceContext context) {
  552. const int vendor_id = context.search_data.usb_vendor_id;
  553. const int product_id = context.search_data.usb_product_id;
  554. if (vendor_id && product_id) {
  555. auto callback =
  556. base::BindOnce(&PpdProviderImpl::OnUsbIndicesSearched,
  557. weak_factory_.GetWeakPtr(), std::move(context));
  558. metadata_manager_->FindDeviceInUsbIndex(vendor_id, product_id,
  559. kMaxDataAge, std::move(callback));
  560. return;
  561. }
  562. // At this point, we couldn't use |search_data| to search USB indices.
  563. // ResolvePpdReference() continues to its next step.
  564. TryToResolvePpdReferenceWithGenericEpsonPpd(std::move(context));
  565. }
  566. // Continues a prior call to ResolvePpdReference() (step 1).
  567. // This callback is fed to
  568. // PpdMetadataManager::FindAllEmmsAvailableInIndexCallback().
  569. void TryToResolvePpdReferenceFromForwardIndices(
  570. ResolvePpdReferenceContext context,
  571. const base::flat_map<std::string, ParsedIndexValues>&
  572. forward_index_results) {
  573. // Sweeps through the results of the forward index metadata search.
  574. // If any effective-make-and-model string advertises an available
  575. // PPD, we use that result to post |cb|.
  576. for (base::StringPiece effective_make_and_model :
  577. context.search_data.make_and_model) {
  578. const ParsedIndexLeaf* const index_leaf = FirstAllowableParsedIndexLeaf(
  579. effective_make_and_model, forward_index_results);
  580. if (!index_leaf) {
  581. continue;
  582. }
  583. SuccessfullyResolvePpdReferenceWithEmm(effective_make_and_model,
  584. std::move(context.cb));
  585. return;
  586. }
  587. // At this point, we couldn't build a PpdReference directly from a
  588. // forward index search. ResolvePpdReference() continues to step 2.
  589. TryToResolvePpdReferenceFromUsbIndices(std::move(context));
  590. }
  591. // Continues a prior call to ResolvePpd().
  592. //
  593. // Stores a PPD with |ppd_contents| in the PPD Cache.
  594. // Caller must provide nonempty |ppd_basename| when |ppd_origin|
  595. // identifies the PPD as coming from the the serving root.
  596. void StorePpdWithContents(const std::string& ppd_contents,
  597. absl::optional<std::string> ppd_basename,
  598. ResolvedPpdOrigin ppd_origin,
  599. Printer::PpdReference reference) {
  600. switch (ppd_origin) {
  601. case ResolvedPpdOrigin::kFromPpdCache:
  602. // This very PPD was retrieved from the local PpdCache; there's no
  603. // point in storing it again.
  604. return;
  605. case ResolvedPpdOrigin::kFromServingRoot:
  606. // To service the two-step "dereference" of resolving a PPD from
  607. // the serving root, we need to Store() the basename of this PPD
  608. // in the local PpdCache.
  609. DCHECK(ppd_basename.has_value());
  610. DCHECK(!ppd_basename->empty());
  611. DCHECK(!reference.effective_make_and_model.empty());
  612. ppd_cache_->Store(PpdBasenameToCacheKey(ppd_basename.value()),
  613. ppd_contents);
  614. ppd_cache_->Store(PpdReferenceToCacheKey(reference),
  615. ppd_basename.value());
  616. break;
  617. case ResolvedPpdOrigin::kFromUserSuppliedUrl:
  618. // No special considerations for a user-supplied PPD; we can
  619. // Store() it directly by mapping the user-supplied URI to the
  620. // PPD contents.
  621. DCHECK(!reference.user_supplied_ppd_url.empty());
  622. ppd_cache_->Store(PpdReferenceToCacheKey(reference), ppd_contents);
  623. break;
  624. }
  625. }
  626. // Continues a prior call to ResolvePpd().
  627. //
  628. // Called when we have the contents of the PPD being resolved; we are
  629. // on the cusp of being able to invoke the |cb|.
  630. void ResolvePpdWithContents(ResolvedPpdOrigin ppd_origin,
  631. absl::optional<std::string> ppd_basename,
  632. std::string ppd_contents,
  633. Printer::PpdReference reference,
  634. ResolvePpdCallback cb) {
  635. DCHECK(!ppd_contents.empty());
  636. if (ppd_contents.size() > kMaxPpdSizeBytes) {
  637. base::SequencedTaskRunnerHandle::Get()->PostTask(
  638. FROM_HERE,
  639. base::BindOnce(std::move(cb), CallbackResultCode::PPD_TOO_LARGE, ""));
  640. return;
  641. }
  642. StorePpdWithContents(ppd_contents, std::move(ppd_basename), ppd_origin,
  643. std::move(reference));
  644. base::SequencedTaskRunnerHandle::Get()->PostTask(
  645. FROM_HERE, base::BindOnce(std::move(cb), CallbackResultCode::SUCCESS,
  646. std::move(ppd_contents)));
  647. }
  648. // Continues a prior call to ResolvePpd().
  649. //
  650. // Called back by PrinterConfigCache::Fetch() when we've fetched
  651. // a PPD from the serving root.
  652. void OnPpdFetchedFromServingRoot(
  653. Printer::PpdReference reference,
  654. ResolvePpdCallback cb,
  655. const PrinterConfigCache::FetchResult& result) {
  656. if (!result.succeeded || result.contents.empty()) {
  657. base::SequencedTaskRunnerHandle::Get()->PostTask(
  658. FROM_HERE,
  659. base::BindOnce(std::move(cb), CallbackResultCode::SERVER_ERROR, ""));
  660. return;
  661. }
  662. ResolvePpdWithContents(ResolvedPpdOrigin::kFromServingRoot,
  663. /*ppd_basename=*/result.key,
  664. /*ppd_contents=*/result.contents,
  665. std::move(reference), std::move(cb));
  666. }
  667. // Continues a prior call to ResolvePpd().
  668. //
  669. // Called when we seek a mapping from an effective-make-and-model
  670. // string to a PPD basename by querying the local PpdCache.
  671. void OnPpdBasenameSoughtInPpdCache(Printer::PpdReference reference,
  672. ResolvePpdCallback cb,
  673. const PpdCache::FindResult& result) {
  674. if (!result.success || result.contents.empty()) {
  675. base::SequencedTaskRunnerHandle::Get()->PostTask(
  676. FROM_HERE,
  677. base::BindOnce(std::move(cb), CallbackResultCode::NOT_FOUND, ""));
  678. return;
  679. }
  680. std::string cache_key = PpdBasenameToCacheKey(result.contents);
  681. ppd_cache_->Find(
  682. cache_key,
  683. base::BindOnce(&PpdProviderImpl::OnPpdFromServingRootSoughtInPpdCache,
  684. weak_factory_.GetWeakPtr(),
  685. /*ppd_basename=*/result.contents, std::move(reference),
  686. std::move(cb)));
  687. }
  688. // Continues a prior call to ResolvePpd().
  689. //
  690. // Called when we have a PPD basename already and seek its contents
  691. // in the local PpdCache.
  692. void OnPpdFromServingRootSoughtInPpdCache(
  693. const std::string& ppd_basename,
  694. Printer::PpdReference reference,
  695. ResolvePpdCallback cb,
  696. const PpdCache::FindResult& result) {
  697. if (!result.success || result.contents.empty()) {
  698. // We have the PPD basename, but not the contents of the PPD
  699. // itself in our local PpdCache. We must seek out the contents
  700. // from the serving root.
  701. auto callback = base::BindOnce(
  702. &PpdProviderImpl::OnPpdFetchedFromServingRoot,
  703. weak_factory_.GetWeakPtr(), std::move(reference), std::move(cb));
  704. config_cache_->Fetch(PpdPathInServingRoot(ppd_basename), kMaxDataAge,
  705. std::move(callback));
  706. return;
  707. }
  708. ResolvePpdWithContents(ResolvedPpdOrigin::kFromPpdCache, ppd_basename,
  709. result.contents, std::move(reference),
  710. std::move(cb));
  711. }
  712. // Continues a prior call to ResolvePpd().
  713. //
  714. // Called back by PpdMetadataManager::FindAllEmmsAvailableInIndex().
  715. //
  716. // 1. Maps |reference|::effective_make_and_model to a PPD basename.
  717. // a. Attempts to do so with fresh forward index metadata if
  718. // possible, searching |forward_index_subset| for the best
  719. // available PPD.
  720. // b. Falls back to directly querying the local PpdCache instance,
  721. // e.g. if the network is unreachable.
  722. // 2. Uses basename derived in previous step to retrieve the
  723. // appropriate PPD from the local PpdCache instance.
  724. void OnPpdBasenameSoughtFromForwardIndex(
  725. Printer::PpdReference reference,
  726. ResolvePpdCallback cb,
  727. const base::flat_map<std::string, ParsedIndexValues>&
  728. forward_index_subset) {
  729. const ParsedIndexLeaf* const leaf = FirstAllowableParsedIndexLeaf(
  730. reference.effective_make_and_model, forward_index_subset);
  731. if (!leaf || leaf->ppd_basename.empty()) {
  732. // The forward index doesn't advise what the best fit PPD is for
  733. // |reference|::effective_make_and_model. We can look toward the
  734. // local PpdCache to see if we saved it previously.
  735. std::string cache_key = PpdReferenceToCacheKey(reference);
  736. ppd_cache_->Find(
  737. cache_key,
  738. base::BindOnce(&PpdProviderImpl::OnPpdBasenameSoughtInPpdCache,
  739. weak_factory_.GetWeakPtr(), std::move(reference),
  740. std::move(cb)));
  741. return;
  742. }
  743. // The forward index does advertise a best-fit PPD basename. We
  744. // check the local PpdCache to see if we already have it.
  745. ppd_cache_->Find(
  746. PpdBasenameToCacheKey(leaf->ppd_basename),
  747. base::BindOnce(&PpdProviderImpl::OnPpdFromServingRootSoughtInPpdCache,
  748. weak_factory_.GetWeakPtr(), leaf->ppd_basename,
  749. std::move(reference), std::move(cb)));
  750. }
  751. // Continues a prior call to ResolvePpd().
  752. //
  753. // Called when we finish searching the PpdCache for a user-supplied
  754. // PPD. This contrasts with the slightly more involved two-step
  755. // "dereference" process in searching the PpdCache for a PPD retrieved
  756. // from the serving root.
  757. void OnUserSuppliedPpdSoughtInPpdCache(Printer::PpdReference reference,
  758. ResolvePpdCallback cb,
  759. const PpdCache::FindResult& result) {
  760. if (!result.success) {
  761. base::SequencedTaskRunnerHandle::Get()->PostTask(
  762. FROM_HERE,
  763. base::BindOnce(std::move(cb), CallbackResultCode::NOT_FOUND, ""));
  764. return;
  765. }
  766. ResolvePpdWithContents(ResolvedPpdOrigin::kFromPpdCache,
  767. /*ppd_basename=*/absl::nullopt, result.contents,
  768. std::move(reference), std::move(cb));
  769. }
  770. // Continues a prior call to ResolvePpd().
  771. //
  772. // Called when we finish fetching a PPD file from device-local storage
  773. // (e.g. from the user's home directory, not from the PpdCache).
  774. void OnUserSuppliedPpdFetched(Printer::PpdReference reference,
  775. ResolvePpdCallback cb,
  776. const std::string& result) {
  777. if (result.empty()) {
  778. // We didn't find a nonempty PPD at the location specified by the
  779. // user. The next step is to try searching the PpdCache.
  780. std::string cache_key = PpdReferenceToCacheKey(reference);
  781. ppd_cache_->Find(
  782. cache_key,
  783. base::BindOnce(&PpdProviderImpl::OnUserSuppliedPpdSoughtInPpdCache,
  784. weak_factory_.GetWeakPtr(), std::move(reference),
  785. std::move(cb)));
  786. return;
  787. }
  788. ResolvePpdWithContents(ResolvedPpdOrigin::kFromUserSuppliedUrl,
  789. /*ppd_basename=*/absl::nullopt, result,
  790. std::move(reference), std::move(cb));
  791. }
  792. // Continues a prior call to ResolvePpd().
  793. //
  794. // 1. Attempts to invoke |cb| with the file named by
  795. // |reference|::user_suplied_ppd_url - i.e. a live fetch from
  796. // wherever the user saved the PPD.
  797. // 2. Attempts to search the local PpdCache instance for the file
  798. // whose cache key was built from
  799. // |reference|::user_supplied_ppd_url.
  800. void ResolveUserSuppliedPpd(Printer::PpdReference reference,
  801. ResolvePpdCallback cb) {
  802. DCHECK(!reference.user_supplied_ppd_url.empty());
  803. GURL url(reference.user_supplied_ppd_url);
  804. file_task_runner_->PostTaskAndReplyWithResult(
  805. FROM_HERE, base::BindOnce(&FetchFile, url),
  806. base::BindOnce(&PpdProviderImpl::OnUserSuppliedPpdFetched,
  807. weak_factory_.GetWeakPtr(), std::move(reference),
  808. std::move(cb)));
  809. }
  810. // Continues a prior call to ResolvePpdLicense().
  811. // This callback is fed to
  812. // PpdMetadataManager::FindAllEmmsAvailableInIndexCallback().
  813. void FindLicenseForEmm(const std::string& effective_make_and_model,
  814. ResolvePpdLicenseCallback cb,
  815. const base::flat_map<std::string, ParsedIndexValues>&
  816. forward_index_results) {
  817. const ParsedIndexLeaf* const index_leaf = FirstAllowableParsedIndexLeaf(
  818. effective_make_and_model, forward_index_results);
  819. if (!index_leaf) {
  820. // This particular |effective_make_and_model| is invisible to the
  821. // current |version_|; either it is restricted or it is missing
  822. // entirely from the forward indices.
  823. base::SequencedTaskRunnerHandle::Get()->PostTask(
  824. FROM_HERE,
  825. base::BindOnce(std::move(cb), CallbackResultCode::NOT_FOUND,
  826. /*license_name=*/""));
  827. return;
  828. }
  829. // Note that the license can also be empty; this denotes that
  830. // no license is associated with this particular
  831. // |effective_make_and_model| in this |version_|.
  832. base::SequencedTaskRunnerHandle::Get()->PostTask(
  833. FROM_HERE, base::BindOnce(std::move(cb), CallbackResultCode::SUCCESS,
  834. index_leaf->license));
  835. }
  836. // Current version used to filter restricted ppds
  837. const base::Version version_;
  838. // Provides PPD storage on-device.
  839. scoped_refptr<PpdCache> ppd_cache_;
  840. // Used to
  841. // 1. to determine if |this| should defer locale-sensitive public
  842. // method calls and
  843. // 2. to defer those method calls, if necessary.
  844. // These deferrals are only necessary before the |metadata_manager_|
  845. // is ready to deal with locale-sensitive PPD metadata. This member is
  846. // reset once deferrals are unnecessary.
  847. std::unique_ptr<MethodDeferralContext> deferral_context_;
  848. // Interacts with and controls PPD metadata.
  849. std::unique_ptr<PpdMetadataManager> metadata_manager_;
  850. // Fetches PPDs from the Chrome OS Printing team's serving root.
  851. std::unique_ptr<PrinterConfigCache> config_cache_;
  852. // Where to run disk operations.
  853. const scoped_refptr<base::SequencedTaskRunner> file_task_runner_;
  854. base::WeakPtrFactory<PpdProviderImpl> weak_factory_{this};
  855. };
  856. } // namespace
  857. PrinterSearchData::PrinterSearchData() = default;
  858. PrinterSearchData::PrinterSearchData(const PrinterSearchData& other) = default;
  859. PrinterSearchData::~PrinterSearchData() = default;
  860. // static
  861. //
  862. // Used in production but also exposed for testing.
  863. std::string PpdProvider::PpdReferenceToCacheKey(
  864. const Printer::PpdReference& reference) {
  865. DCHECK(PpdReferenceIsWellFormed(reference));
  866. // The key prefixes here are arbitrary, but ensure we can't have an (unhashed)
  867. // collision between keys generated from different PpdReference fields.
  868. if (!reference.effective_make_and_model.empty()) {
  869. return base::StrCat(
  870. {"emm_for_metadata_v3:", reference.effective_make_and_model});
  871. } else {
  872. // Retains the legacy salt from the v2 PpdProvider. This is done
  873. // to minimize user breakage when we roll out the v3 PpdProvider.
  874. return base::StrCat({"up:", reference.user_supplied_ppd_url});
  875. }
  876. }
  877. // static
  878. //
  879. // Used in production but also exposed for testing.
  880. std::string PpdProvider::PpdBasenameToCacheKey(base::StringPiece ppd_basename) {
  881. return base::StrCat({"ppd_basename_for_metadata_v3:", ppd_basename});
  882. }
  883. // static
  884. scoped_refptr<PpdProvider> PpdProvider::Create(
  885. const base::Version& current_version,
  886. scoped_refptr<PpdCache> cache,
  887. std::unique_ptr<PpdMetadataManager> metadata_manager,
  888. std::unique_ptr<PrinterConfigCache> config_cache) {
  889. return base::MakeRefCounted<PpdProviderImpl>(current_version, cache,
  890. std::move(metadata_manager),
  891. std::move(config_cache));
  892. }
  893. } // namespace chromeos