1 // Copyright (c) 2012 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 "chrome/browser/ui/webui/print_preview/print_preview_handler.h"
6 
7 #include <ctype.h>
8 #include <stddef.h>
9 
10 #include <memory>
11 #include <string>
12 #include <utility>
13 #include <vector>
14 
15 #include "base/base64.h"
16 #include "base/bind.h"
17 #include "base/bind_helpers.h"
18 #include "base/command_line.h"
19 #include "base/containers/flat_set.h"
20 #include "base/feature_list.h"
21 #include "base/i18n/number_formatting.h"
22 #include "base/json/json_reader.h"
23 #include "base/lazy_instance.h"
24 #include "base/macros.h"
25 #include "base/memory/ref_counted_memory.h"
26 #include "base/metrics/histogram_functions.h"
27 #include "base/metrics/histogram_macros.h"
28 #include "base/values.h"
29 #include "build/build_config.h"
30 #include "chrome/browser/app_mode/app_mode_utils.h"
31 #include "chrome/browser/bad_message.h"
32 #include "chrome/browser/browser_process.h"
33 #include "chrome/browser/printing/background_printing_manager.h"
34 #include "chrome/browser/printing/print_dialog_cloud.h"
35 #include "chrome/browser/printing/print_error_dialog.h"
36 #include "chrome/browser/printing/print_job_manager.h"
37 #include "chrome/browser/printing/print_preview_dialog_controller.h"
38 #include "chrome/browser/printing/print_preview_sticky_settings.h"
39 #include "chrome/browser/printing/print_view_manager.h"
40 #include "chrome/browser/printing/printer_manager_dialog.h"
41 #include "chrome/browser/profiles/profile.h"
42 #include "chrome/browser/signin/account_consistency_mode_manager.h"
43 #include "chrome/browser/signin/identity_manager_factory.h"
44 #include "chrome/browser/ui/browser_finder.h"
45 #include "chrome/browser/ui/browser_tabstrip.h"
46 #include "chrome/browser/ui/chrome_pages.h"
47 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
48 #include "chrome/browser/ui/webui/print_preview/pdf_printer_handler.h"
49 #include "chrome/browser/ui/webui/print_preview/policy_settings.h"
50 #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
51 #include "chrome/browser/ui/webui/print_preview/printer_handler.h"
52 #include "chrome/common/buildflags.h"
53 #include "chrome/common/chrome_features.h"
54 #include "chrome/common/chrome_switches.h"
55 #include "chrome/common/cloud_print/cloud_print_constants.h"
56 #include "chrome/common/crash_keys.h"
57 #include "chrome/common/pref_names.h"
58 #include "chrome/common/webui_url_constants.h"
59 #include "components/cloud_devices/common/cloud_device_description.h"
60 #include "components/cloud_devices/common/cloud_devices_urls.h"
61 #include "components/cloud_devices/common/printer_description.h"
62 #include "components/prefs/pref_service.h"
63 #include "components/printing/browser/printer_capabilities.h"
64 #include "components/printing/common/cloud_print_cdd_conversion.h"
65 #include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h"
66 #include "components/signin/public/identity_manager/primary_account_access_token_fetcher.h"
67 #include "components/url_formatter/url_formatter.h"
68 #include "content/public/browser/browser_context.h"
69 #include "content/public/browser/render_frame_host.h"
70 #include "content/public/browser/render_process_host.h"
71 #include "content/public/browser/web_contents.h"
72 #include "content/public/browser/web_ui.h"
73 #include "google_apis/gaia/gaia_auth_util.h"
74 #include "net/base/url_util.h"
75 #include "printing/backend/print_backend.h"
76 #include "printing/backend/print_backend_consts.h"
77 #include "printing/buildflags/buildflags.h"
78 #include "printing/print_settings.h"
79 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
80 #include "third_party/icu/source/i18n/unicode/ulocdata.h"
81 
82 #if defined(OS_CHROMEOS)
83 #include "chrome/browser/chromeos/account_manager/account_manager_util.h"
84 #include "chrome/browser/device_identity/device_oauth2_token_service.h"
85 #include "chrome/browser/device_identity/device_oauth2_token_service_factory.h"
86 #include "chrome/browser/ui/settings_window_manager_chromeos.h"
87 #include "chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.h"
88 #include "chromeos/printing/printer_configuration.h"
89 #include "components/signin/public/identity_manager/scope_set.h"
90 #endif
91 
92 using content::RenderFrameHost;
93 using content::WebContents;
94 
95 namespace printing {
96 
97 namespace {
98 
99 // Max size for PDFs sent to Cloud Print. Server side limit is currently 80MB
100 // but PDF will double in size when sent to JS. See crbug.com/793506 and
101 // crbug.com/372240.
102 constexpr size_t kMaxCloudPrintPdfDataSizeInBytes = 80 * 1024 * 1024 / 2;
103 
104 // This enum is used to back an UMA histogram, and should therefore be treated
105 // as append only.
106 enum UserActionBuckets {
107   PRINT_TO_PRINTER,
108   PRINT_TO_PDF,
109   CANCEL,
110   FALLBACK_TO_ADVANCED_SETTINGS_DIALOG,
111   PREVIEW_FAILED,
112   PREVIEW_STARTED,
113   INITIATOR_CRASHED_UNUSED,
114   INITIATOR_CLOSED,
115   PRINT_WITH_CLOUD_PRINT,
116   PRINT_WITH_PRIVET,
117   PRINT_WITH_EXTENSION,
118   OPEN_IN_MAC_PREVIEW,
119   PRINT_TO_GOOGLE_DRIVE,
120   USERACTION_BUCKET_BOUNDARY
121 };
122 
123 // This enum is used to back an UMA histogram, and should therefore be treated
124 // as append only.
125 enum PrintSettingsBuckets {
126   LANDSCAPE = 0,
127   PORTRAIT,
128   COLOR,
129   BLACK_AND_WHITE,
130   COLLATE,
131   SIMPLEX,
132   DUPLEX,
133   TOTAL,
134   HEADERS_AND_FOOTERS,
135   CSS_BACKGROUND,
136   SELECTION_ONLY,
137   EXTERNAL_PDF_PREVIEW_UNUSED,
138   PAGE_RANGE,
139   DEFAULT_MEDIA,
140   NON_DEFAULT_MEDIA,
141   COPIES,
142   NON_DEFAULT_MARGINS,
143   DISTILL_PAGE_UNUSED,
144   SCALING,
145   PRINT_AS_IMAGE,
146   PAGES_PER_SHEET,
147   FIT_TO_PAGE,
148   DEFAULT_DPI,
149   NON_DEFAULT_DPI,
150   PIN,
151   FIT_TO_PAPER,
152   PRINT_SETTINGS_BUCKET_BOUNDARY
153 };
154 
155 // This enum is used to back an UMA histogram, and should therefore be treated
156 // as append only.
157 enum PrintDocumentTypeBuckets {
158   HTML_DOCUMENT = 0,
159   PDF_DOCUMENT,
160   PRINT_DOCUMENT_TYPE_BUCKET_BOUNDARY
161 };
162 
ReportUserActionHistogram(UserActionBuckets event)163 void ReportUserActionHistogram(UserActionBuckets event) {
164   UMA_HISTOGRAM_ENUMERATION("PrintPreview.UserAction", event,
165                             USERACTION_BUCKET_BOUNDARY);
166 }
167 
ReportPrintSettingHistogram(PrintSettingsBuckets setting)168 void ReportPrintSettingHistogram(PrintSettingsBuckets setting) {
169   UMA_HISTOGRAM_ENUMERATION("PrintPreview.PrintSettings", setting,
170                             PRINT_SETTINGS_BUCKET_BOUNDARY);
171 }
172 
ReportPrintDocumentTypeAndSizeHistograms(PrintDocumentTypeBuckets doctype,size_t average_page_size_in_kb)173 void ReportPrintDocumentTypeAndSizeHistograms(PrintDocumentTypeBuckets doctype,
174                                               size_t average_page_size_in_kb) {
175   base::UmaHistogramEnumeration("PrintPreview.PrintDocumentType", doctype,
176                                 PRINT_DOCUMENT_TYPE_BUCKET_BOUNDARY);
177   switch (doctype) {
178     case HTML_DOCUMENT:
179       base::UmaHistogramMemoryKB("PrintPreview.PrintDocumentSize.HTML",
180                                  average_page_size_in_kb);
181       break;
182     case PDF_DOCUMENT:
183       base::UmaHistogramMemoryKB("PrintPreview.PrintDocumentSize.PDF",
184                                  average_page_size_in_kb);
185       break;
186     default:
187       NOTREACHED();
188       break;
189   }
190 }
191 
GetPrinterTypeForUserAction(UserActionBuckets user_action)192 PrinterType GetPrinterTypeForUserAction(UserActionBuckets user_action) {
193   switch (user_action) {
194     case PRINT_WITH_PRIVET:
195       return PrinterType::kPrivetPrinter;
196     case PRINT_WITH_EXTENSION:
197       return PrinterType::kExtensionPrinter;
198     case PRINT_TO_PDF:
199       return PrinterType::kPdfPrinter;
200     case PRINT_TO_PRINTER:
201     case FALLBACK_TO_ADVANCED_SETTINGS_DIALOG:
202     case OPEN_IN_MAC_PREVIEW:
203       return PrinterType::kLocalPrinter;
204     default:
205       NOTREACHED();
206       return PrinterType::kLocalPrinter;
207   }
208 }
209 
GetErrorValue(UserActionBuckets user_action,base::StringPiece description)210 base::Value GetErrorValue(UserActionBuckets user_action,
211                           base::StringPiece description) {
212   return user_action == PRINT_WITH_PRIVET ? base::Value(-1)
213                                           : base::Value(description);
214 }
215 
216 // Dictionary Fields for Print Preview initial settings. Keep in sync with
217 // field names for print_preview.NativeInitialSettings in
218 // chrome/browser/resources/print_preview/native_layer.js
219 //
220 // Name of a dictionary field specifying whether to print automatically in
221 // kiosk mode. See http://crbug.com/31395.
222 const char kIsInKioskAutoPrintMode[] = "isInKioskAutoPrintMode";
223 // Dictionary field to indicate whether Chrome is running in forced app (app
224 // kiosk) mode. It's not the same as desktop Chrome kiosk (the one above).
225 const char kIsInAppKioskMode[] = "isInAppKioskMode";
226 // Name of a dictionary field holding the UI locale.
227 const char kUiLocale[] = "uiLocale";
228 // Name of a dictionary field holding the thousands delimiter according to the
229 // locale.
230 const char kThousandsDelimiter[] = "thousandsDelimiter";
231 // Name of a dictionary field holding the decimal delimiter according to the
232 // locale.
233 const char kDecimalDelimiter[] = "decimalDelimiter";
234 // Name of a dictionary field holding the measurement system according to the
235 // locale.
236 const char kUnitType[] = "unitType";
237 // Name of a dictionary field holding the initiator title.
238 const char kDocumentTitle[] = "documentTitle";
239 // Name of a dictionary field holding the state of selection for document.
240 const char kDocumentHasSelection[] = "documentHasSelection";
241 // Name of a dictionary field holding saved print preview state
242 const char kAppState[] = "serializedAppStateStr";
243 // Name of a dictionary field holding the default destination selection rules.
244 const char kDefaultDestinationSelectionRules[] =
245     "serializedDefaultDestinationSelectionRulesStr";
246 // Name of a dictionary field holding policy values for printing settings.
247 const char kPolicies[] = "policies";
248 // Name of a dictionary field holding policy allowed mode value for the setting.
249 const char kAllowedMode[] = "allowedMode";
250 // Name of a dictionary field holding policy default mode value for the setting.
251 const char kDefaultMode[] = "defaultMode";
252 // Name of a dictionary pref holding the policy value for the header/footer
253 // checkbox.
254 const char kHeaderFooter[] = "headerFooter";
255 // Name of a dictionary pref holding the policy value for the background
256 // graphics checkbox.
257 const char kCssBackground[] = "cssBackground";
258 // Name of a dictionary field indicating whether the 'Save to PDF' destination
259 // is disabled.
260 const char kPdfPrinterDisabled[] = "pdfPrinterDisabled";
261 // Name of a dictionary field indicating whether the destinations are managed by
262 // the PrinterTypeDenyList enterprise policy.
263 const char kDestinationsManaged[] = "destinationsManaged";
264 // Name of a dictionary field holding the cloud print URL.
265 const char kCloudPrintURL[] = "cloudPrintURL";
266 // Name of a dictionary field holding the signed in user accounts.
267 const char kUserAccounts[] = "userAccounts";
268 // Name of a dictionary field indicating whether sync is available. If false,
269 // Print Preview will always send a request to the Google Cloud Print server on
270 // load, to check the user's sign in state.
271 const char kSyncAvailable[] = "syncAvailable";
272 
273 // Get the print job settings dictionary from |json_str|.
274 // Returns |base::Value()| on failure.
GetSettingsDictionary(const std::string & json_str)275 base::Value GetSettingsDictionary(const std::string& json_str) {
276   base::Optional<base::Value> settings = base::JSONReader::Read(json_str);
277   if (!settings || !settings->is_dict()) {
278     NOTREACHED() << "Print job settings must be a dictionary.";
279     return base::Value();
280   }
281 
282   if (settings->DictEmpty()) {
283     NOTREACHED() << "Print job settings dictionary is empty";
284     return base::Value();
285   }
286 
287   return std::move(*settings);
288 }
289 
290 // Track the popularity of print settings and report the stats.
ReportPrintSettingsStats(const base::Value & print_settings,const base::Value & preview_settings,bool is_pdf)291 void ReportPrintSettingsStats(const base::Value& print_settings,
292                               const base::Value& preview_settings,
293                               bool is_pdf) {
294   ReportPrintSettingHistogram(TOTAL);
295 
296   // Print settings can be categorized into 2 groups: settings that are applied
297   // via preview generation (page range, selection, headers/footers, background
298   // graphics, scaling, layout, page size, pages per sheet, fit to page,
299   // margins, rasterize), and settings that are applied at the printer (color,
300   // duplex, copies, collate, dpi). The former should be captured from the most
301   // recent preview request, as some of them are set to dummy values in the
302   // print ticket. Similarly, settings applied at the printer should be pulled
303   // from the print ticket, as they may have dummy values in the preview
304   // request.
305   const base::Value* page_range_array =
306       preview_settings.FindKey(kSettingPageRange);
307   if (page_range_array && page_range_array->is_list() &&
308       !page_range_array->GetList().empty()) {
309     ReportPrintSettingHistogram(PAGE_RANGE);
310   }
311 
312   const base::Value* media_size_value =
313       preview_settings.FindKey(kSettingMediaSize);
314   if (media_size_value && media_size_value->is_dict() &&
315       !media_size_value->DictEmpty()) {
316     if (media_size_value->FindBoolKey(kSettingMediaSizeIsDefault)
317             .value_or(false)) {
318       ReportPrintSettingHistogram(DEFAULT_MEDIA);
319     } else {
320       ReportPrintSettingHistogram(NON_DEFAULT_MEDIA);
321     }
322   }
323 
324   base::Optional<bool> landscape_opt =
325       preview_settings.FindBoolKey(kSettingLandscape);
326   if (landscape_opt)
327     ReportPrintSettingHistogram(landscape_opt.value() ? LANDSCAPE : PORTRAIT);
328 
329   if (print_settings.FindIntKey(kSettingCopies).value_or(1) > 1)
330     ReportPrintSettingHistogram(COPIES);
331 
332   if (preview_settings.FindIntKey(kSettingPagesPerSheet).value_or(1) != 1)
333     ReportPrintSettingHistogram(PAGES_PER_SHEET);
334 
335   if (print_settings.FindBoolKey(kSettingCollate).value_or(false))
336     ReportPrintSettingHistogram(COLLATE);
337 
338   base::Optional<int> duplex_mode_opt =
339       print_settings.FindIntKey(kSettingDuplexMode);
340   if (duplex_mode_opt)
341     ReportPrintSettingHistogram(duplex_mode_opt.value() ? DUPLEX : SIMPLEX);
342 
343   base::Optional<int> color_mode_opt = print_settings.FindIntKey(kSettingColor);
344   if (color_mode_opt.has_value()) {
345     bool unknown_color_model = color_mode_opt.value() == UNKNOWN_COLOR_MODEL;
346     if (!unknown_color_model) {
347       base::Optional<bool> is_color =
348           IsColorModelSelected(color_mode_opt.value());
349       ReportPrintSettingHistogram(is_color.value() ? COLOR : BLACK_AND_WHITE);
350     }
351 
352     // Record whether the printing backend does not understand the printer's
353     // color capabilities. Do this only once per device.
354     static base::NoDestructor<base::flat_set<std::string>> seen_devices;
355     auto result =
356         seen_devices->insert(*print_settings.FindStringKey(kSettingDeviceName));
357     bool is_new_device = result.second;
358     if (is_new_device) {
359       base::UmaHistogramBoolean("Printing.CUPS.UnknownPpdColorModel",
360                                 unknown_color_model);
361     }
362   }
363 
364   if (preview_settings.FindIntKey(kSettingMarginsType).value_or(0) != 0)
365     ReportPrintSettingHistogram(NON_DEFAULT_MARGINS);
366 
367   if (preview_settings.FindBoolKey(kSettingHeaderFooterEnabled).value_or(false))
368     ReportPrintSettingHistogram(HEADERS_AND_FOOTERS);
369 
370   if (preview_settings.FindBoolKey(kSettingShouldPrintBackgrounds)
371           .value_or(false)) {
372     ReportPrintSettingHistogram(CSS_BACKGROUND);
373   }
374 
375   if (preview_settings.FindBoolKey(kSettingShouldPrintSelectionOnly)
376           .value_or(false)) {
377     ReportPrintSettingHistogram(SELECTION_ONLY);
378   }
379 
380   if (preview_settings.FindBoolKey(kSettingRasterizePdf).value_or(false))
381     ReportPrintSettingHistogram(PRINT_AS_IMAGE);
382 
383   ScalingType scaling_type =
384       static_cast<ScalingType>(preview_settings.FindIntKey(kSettingScalingType)
385                                    .value_or(ScalingType::DEFAULT));
386   if (scaling_type == ScalingType::CUSTOM) {
387     ReportPrintSettingHistogram(SCALING);
388   }
389 
390   if (is_pdf) {
391     if (scaling_type == ScalingType::FIT_TO_PAGE)
392       ReportPrintSettingHistogram(FIT_TO_PAGE);
393     else if (scaling_type == ScalingType::FIT_TO_PAPER)
394       ReportPrintSettingHistogram(FIT_TO_PAPER);
395   }
396 
397   if (print_settings.FindIntKey(kSettingDpiHorizontal).value_or(0) > 0 &&
398       print_settings.FindIntKey(kSettingDpiVertical).value_or(0) > 0) {
399     base::Optional<bool> is_default_opt =
400         print_settings.FindBoolKey(kSettingDpiDefault);
401     if (is_default_opt) {
402       ReportPrintSettingHistogram(is_default_opt.value() ? DEFAULT_DPI
403                                                          : NON_DEFAULT_DPI);
404     }
405   }
406 
407 #if defined(OS_CHROMEOS)
408   if (print_settings.FindStringKey(kSettingPinValue))
409     ReportPrintSettingHistogram(PIN);
410 #endif  // defined(OS_CHROMEOS)
411 }
412 
DetermineUserAction(const base::Value & settings)413 UserActionBuckets DetermineUserAction(const base::Value& settings) {
414 #if defined(OS_MACOSX)
415   if (settings.FindKey(kSettingOpenPDFInPreview))
416     return OPEN_IN_MAC_PREVIEW;
417 #endif
418   // This needs to be checked before checking for a cloud print ID, since a
419   // print ticket for printing to Drive will also contain a cloud print ID.
420   if (settings.FindBoolKey(kSettingPrintToGoogleDrive).value_or(false))
421     return PRINT_TO_GOOGLE_DRIVE;
422   if (settings.FindKey(kSettingCloudPrintId))
423     return PRINT_WITH_CLOUD_PRINT;
424 
425   PrinterType type = static_cast<PrinterType>(
426       settings.FindIntKey(kSettingPrinterType).value());
427   switch (type) {
428     case kPrivetPrinter:
429       return PRINT_WITH_PRIVET;
430     case kExtensionPrinter:
431       return PRINT_WITH_EXTENSION;
432     case kPdfPrinter:
433       return PRINT_TO_PDF;
434     case kLocalPrinter:
435       break;
436     default:
437       NOTREACHED();
438       break;
439   }
440 
441   if (settings.FindBoolKey(kSettingShowSystemDialog).value_or(false))
442     return FALLBACK_TO_ADVANCED_SETTINGS_DIALOG;
443   return PRINT_TO_PRINTER;
444 }
445 
GetPolicies(const PrefService & prefs)446 base::Value GetPolicies(const PrefService& prefs) {
447   base::Value policies(base::Value::Type::DICTIONARY);
448 
449   base::Value header_footer_policy(base::Value::Type::DICTIONARY);
450   if (prefs.HasPrefPath(prefs::kPrintHeaderFooter)) {
451     if (prefs.IsManagedPreference(prefs::kPrintHeaderFooter)) {
452       header_footer_policy.SetBoolKey(
453           kAllowedMode, prefs.GetBoolean(prefs::kPrintHeaderFooter));
454     } else {
455       header_footer_policy.SetBoolKey(
456           kDefaultMode, prefs.GetBoolean(prefs::kPrintHeaderFooter));
457     }
458   }
459   if (!header_footer_policy.DictEmpty())
460     policies.SetKey(kHeaderFooter, std::move(header_footer_policy));
461 
462   base::Value background_graphics_policy(base::Value::Type::DICTIONARY);
463   if (prefs.HasPrefPath(prefs::kPrintingAllowedBackgroundGraphicsModes)) {
464     background_graphics_policy.SetIntKey(
465         kAllowedMode,
466         prefs.GetInteger(prefs::kPrintingAllowedBackgroundGraphicsModes));
467   }
468   if (prefs.HasPrefPath(prefs::kPrintingBackgroundGraphicsDefault)) {
469     background_graphics_policy.SetIntKey(
470         kDefaultMode,
471         prefs.GetInteger(prefs::kPrintingBackgroundGraphicsDefault));
472   }
473   if (!background_graphics_policy.DictEmpty())
474     policies.SetKey(kCssBackground, std::move(background_graphics_policy));
475 
476   return policies;
477 }
478 
479 }  // namespace
480 
481 #if defined(OS_CHROMEOS)
482 class PrintPreviewHandler::AccessTokenService
483     : public OAuth2AccessTokenManager::Consumer {
484  public:
AccessTokenService()485   AccessTokenService() : OAuth2AccessTokenManager::Consumer("print_preview") {}
486 
RequestToken(base::OnceCallback<void (const std::string &)> callback)487   void RequestToken(base::OnceCallback<void(const std::string&)> callback) {
488     // There can only be one pending request at a time. See
489     // cloud_print_interface_js.js.
490     const signin::ScopeSet scopes{cloud_devices::kCloudPrintAuthScope};
491     DCHECK(!device_request_callback_);
492 
493     DeviceOAuth2TokenService* token_service =
494         DeviceOAuth2TokenServiceFactory::Get();
495     device_request_ = token_service->StartAccessTokenRequest(scopes, this);
496     device_request_callback_ = std::move(callback);
497   }
498 
OnGetTokenSuccess(const OAuth2AccessTokenManager::Request * request,const OAuth2AccessTokenConsumer::TokenResponse & token_response)499   void OnGetTokenSuccess(
500       const OAuth2AccessTokenManager::Request* request,
501       const OAuth2AccessTokenConsumer::TokenResponse& token_response) override {
502     OnServiceResponse(request, token_response.access_token);
503   }
504 
OnGetTokenFailure(const OAuth2AccessTokenManager::Request * request,const GoogleServiceAuthError & error)505   void OnGetTokenFailure(const OAuth2AccessTokenManager::Request* request,
506                          const GoogleServiceAuthError& error) override {
507     OnServiceResponse(request, std::string());
508   }
509 
510  private:
OnServiceResponse(const OAuth2AccessTokenManager::Request * request,const std::string & access_token)511   void OnServiceResponse(const OAuth2AccessTokenManager::Request* request,
512                          const std::string& access_token) {
513     DCHECK_EQ(request, device_request_.get());
514     std::move(device_request_callback_).Run(access_token);
515     device_request_.reset();
516   }
517 
518   std::unique_ptr<OAuth2AccessTokenManager::Request> device_request_;
519   base::OnceCallback<void(const std::string&)> device_request_callback_;
520 
521   DISALLOW_COPY_AND_ASSIGN(AccessTokenService);
522 };
523 #endif  // defined(OS_CHROMEOS)
524 
PrintPreviewHandler()525 PrintPreviewHandler::PrintPreviewHandler()
526     : regenerate_preview_request_count_(0),
527       manage_printers_dialog_request_count_(0),
528       reported_failed_preview_(false),
529       has_logged_printers_count_(false),
530       identity_manager_(nullptr) {
531   ReportUserActionHistogram(PREVIEW_STARTED);
532 }
533 
~PrintPreviewHandler()534 PrintPreviewHandler::~PrintPreviewHandler() {
535   base::UmaHistogramCounts1M("PrintPreview.ManagePrinters",
536                              manage_printers_dialog_request_count_);
537   UnregisterForGaiaCookieChanges();
538 }
539 
RegisterMessages()540 void PrintPreviewHandler::RegisterMessages() {
541   web_ui()->RegisterMessageCallback(
542       "getPrinters",
543       base::BindRepeating(&PrintPreviewHandler::HandleGetPrinters,
544                           base::Unretained(this)));
545   web_ui()->RegisterMessageCallback(
546       "getPreview", base::BindRepeating(&PrintPreviewHandler::HandleGetPreview,
547                                         base::Unretained(this)));
548   web_ui()->RegisterMessageCallback(
549       "print", base::BindRepeating(&PrintPreviewHandler::HandlePrint,
550                                    base::Unretained(this)));
551   web_ui()->RegisterMessageCallback(
552       "getPrinterCapabilities",
553       base::BindRepeating(&PrintPreviewHandler::HandleGetPrinterCapabilities,
554                           base::Unretained(this)));
555   web_ui()->RegisterMessageCallback(
556       "setupPrinter",
557       base::BindRepeating(&PrintPreviewHandler::HandlePrinterSetup,
558                           base::Unretained(this)));
559 #if BUILDFLAG(ENABLE_BASIC_PRINT_DIALOG)
560   web_ui()->RegisterMessageCallback(
561       "showSystemDialog",
562       base::BindRepeating(&PrintPreviewHandler::HandleShowSystemDialog,
563                           base::Unretained(this)));
564 #endif
565   web_ui()->RegisterMessageCallback(
566       "signIn", base::BindRepeating(&PrintPreviewHandler::HandleSignin,
567                                     base::Unretained(this)));
568 #if defined(OS_CHROMEOS)
569   web_ui()->RegisterMessageCallback(
570       "getAccessToken",
571       base::BindRepeating(&PrintPreviewHandler::HandleGetAccessToken,
572                           base::Unretained(this)));
573 #endif
574   web_ui()->RegisterMessageCallback(
575       "closePrintPreviewDialog",
576       base::BindRepeating(&PrintPreviewHandler::HandleClosePreviewDialog,
577                           base::Unretained(this)));
578   web_ui()->RegisterMessageCallback(
579       "hidePreview",
580       base::BindRepeating(&PrintPreviewHandler::HandleHidePreview,
581                           base::Unretained(this)));
582   web_ui()->RegisterMessageCallback(
583       "cancelPendingPrintRequest",
584       base::BindRepeating(&PrintPreviewHandler::HandleCancelPendingPrintRequest,
585                           base::Unretained(this)));
586   web_ui()->RegisterMessageCallback(
587       "saveAppState",
588       base::BindRepeating(&PrintPreviewHandler::HandleSaveAppState,
589                           base::Unretained(this)));
590   web_ui()->RegisterMessageCallback(
591       "getInitialSettings",
592       base::BindRepeating(&PrintPreviewHandler::HandleGetInitialSettings,
593                           base::Unretained(this)));
594   web_ui()->RegisterMessageCallback(
595       "grantExtensionPrinterAccess",
596       base::BindRepeating(
597           &PrintPreviewHandler::HandleGrantExtensionPrinterAccess,
598           base::Unretained(this)));
599 #if defined(OS_CHROMEOS)
600   web_ui()->RegisterMessageCallback(
601       "openPrinterSettings",
602       base::BindRepeating(&PrintPreviewHandler::HandleOpenPrinterSettings,
603                           base::Unretained(this)));
604 
605   web_ui()->RegisterMessageCallback(
606       "getEulaUrl", base::BindRepeating(&PrintPreviewHandler::HandleGetEulaUrl,
607                                         base::Unretained(this)));
608 #endif
609 }
610 
OnJavascriptAllowed()611 void PrintPreviewHandler::OnJavascriptAllowed() {
612   print_preview_ui()->SetPreviewUIId();
613   // Now that the UI is initialized, any future account changes will require
614   // a printer list refresh.
615   ReadPrinterTypeDenyListFromPrefs();
616   RegisterForGaiaCookieChanges();
617 }
618 
OnJavascriptDisallowed()619 void PrintPreviewHandler::OnJavascriptDisallowed() {
620   // Normally the handler and print preview will be destroyed together, but
621   // this is necessary for refresh or navigation from the chrome://print page.
622   weak_factory_.InvalidateWeakPtrs();
623   print_preview_ui()->ClearPreviewUIId();
624   preview_callbacks_.clear();
625   preview_failures_.clear();
626   printer_type_deny_list_.clear();
627   UnregisterForGaiaCookieChanges();
628 }
629 
preview_web_contents() const630 WebContents* PrintPreviewHandler::preview_web_contents() const {
631   return web_ui()->GetWebContents();
632 }
633 
GetPrefs() const634 PrefService* PrintPreviewHandler::GetPrefs() const {
635   auto* prefs = Profile::FromWebUI(web_ui())->GetPrefs();
636   DCHECK(prefs);
637   return prefs;
638 }
639 
ReadPrinterTypeDenyListFromPrefs()640 void PrintPreviewHandler::ReadPrinterTypeDenyListFromPrefs() {
641   PrefService* prefs = GetPrefs();
642   if (!prefs->HasPrefPath(prefs::kPrinterTypeDenyList))
643     return;
644 
645   const base::Value* deny_list_types = prefs->Get(prefs::kPrinterTypeDenyList);
646   if (!deny_list_types || !deny_list_types->is_list())
647     return;
648 
649   for (const base::Value& deny_list_type : deny_list_types->GetList()) {
650     if (!deny_list_type.is_string())
651       continue;
652 
653     // The expected printer type strings are enumerated in
654     // components/policy/resources/policy_templates.json
655     const std::string& deny_list_str = deny_list_type.GetString();
656     if (deny_list_str == "privet")
657       printer_type_deny_list_.insert(kPrivetPrinter);
658     else if (deny_list_str == "extension")
659       printer_type_deny_list_.insert(kExtensionPrinter);
660     else if (deny_list_str == "pdf")
661       printer_type_deny_list_.insert(kPdfPrinter);
662     else if (deny_list_str == "local")
663       printer_type_deny_list_.insert(kLocalPrinter);
664     else if (deny_list_str == "cloud")
665       printer_type_deny_list_.insert(kCloudPrinter);
666   }
667 }
668 
print_preview_ui() const669 PrintPreviewUI* PrintPreviewHandler::print_preview_ui() const {
670   return static_cast<PrintPreviewUI*>(web_ui()->GetController());
671 }
672 
ShouldReceiveRendererMessage(int request_id)673 bool PrintPreviewHandler::ShouldReceiveRendererMessage(int request_id) {
674   if (!IsJavascriptAllowed()) {
675     BadMessageReceived();
676     return false;
677   }
678 
679   if (!base::Contains(preview_callbacks_, request_id)) {
680     BadMessageReceived();
681     return false;
682   }
683 
684   return true;
685 }
686 
GetCallbackId(int request_id)687 std::string PrintPreviewHandler::GetCallbackId(int request_id) {
688   std::string result;
689   if (!IsJavascriptAllowed()) {
690     BadMessageReceived();
691     return result;
692   }
693 
694   auto it = preview_callbacks_.find(request_id);
695   if (it == preview_callbacks_.end()) {
696     BadMessageReceived();
697     return result;
698   }
699   result = it->second;
700   preview_callbacks_.erase(it);
701   return result;
702 }
703 
HandleGetPrinters(const base::ListValue * args)704 void PrintPreviewHandler::HandleGetPrinters(const base::ListValue* args) {
705   std::string callback_id;
706   CHECK(args->GetString(0, &callback_id));
707   CHECK(!callback_id.empty());
708   int type;
709   CHECK(args->GetInteger(1, &type));
710   PrinterType printer_type = static_cast<PrinterType>(type);
711 
712   // Immediately resolve the callback without fetching printers if the printer
713   // type is on the deny list.
714   if (base::Contains(printer_type_deny_list_, printer_type)) {
715     ResolveJavascriptCallback(base::Value(callback_id), base::Value());
716     return;
717   }
718 
719   PrinterHandler* handler = GetPrinterHandler(printer_type);
720   if (!handler) {
721     RejectJavascriptCallback(base::Value(callback_id), base::Value());
722     return;
723   }
724   // Make sure all in progress requests are canceled before new printer search
725   // starts.
726   handler->Reset();
727   handler->StartGetPrinters(
728       base::BindRepeating(&PrintPreviewHandler::OnAddedPrinters,
729                           weak_factory_.GetWeakPtr(), printer_type),
730       base::BindOnce(&PrintPreviewHandler::OnGetPrintersDone,
731                      weak_factory_.GetWeakPtr(), callback_id));
732 }
733 
HandleGrantExtensionPrinterAccess(const base::ListValue * args)734 void PrintPreviewHandler::HandleGrantExtensionPrinterAccess(
735     const base::ListValue* args) {
736   std::string callback_id;
737   std::string printer_id;
738   bool ok = args->GetString(0, &callback_id) &&
739             args->GetString(1, &printer_id) && !callback_id.empty();
740   DCHECK(ok);
741 
742   GetPrinterHandler(PrinterType::kExtensionPrinter)
743       ->StartGrantPrinterAccess(
744           printer_id,
745           base::BindOnce(&PrintPreviewHandler::OnGotExtensionPrinterInfo,
746                          weak_factory_.GetWeakPtr(), callback_id));
747 }
748 
HandleGetPrinterCapabilities(const base::ListValue * args)749 void PrintPreviewHandler::HandleGetPrinterCapabilities(
750     const base::ListValue* args) {
751   std::string callback_id;
752   std::string printer_name;
753   int type;
754   if (!args->GetString(0, &callback_id) || !args->GetString(1, &printer_name) ||
755       !args->GetInteger(2, &type) || callback_id.empty() ||
756       printer_name.empty()) {
757     RejectJavascriptCallback(base::Value(callback_id), base::Value());
758     return;
759   }
760   PrinterType printer_type = static_cast<PrinterType>(type);
761 
762   // Reject the callback if the printer type is on the deny list.
763   if (base::Contains(printer_type_deny_list_, printer_type)) {
764     RejectJavascriptCallback(base::Value(callback_id), base::Value());
765     return;
766   }
767 
768   PrinterHandler* handler = GetPrinterHandler(printer_type);
769   if (!handler) {
770     RejectJavascriptCallback(base::Value(callback_id), base::Value());
771     return;
772   }
773 
774   handler->StartGetCapability(
775       printer_name,
776       base::BindOnce(&PrintPreviewHandler::SendPrinterCapabilities,
777                      weak_factory_.GetWeakPtr(), callback_id));
778 }
779 
HandleGetPreview(const base::ListValue * args)780 void PrintPreviewHandler::HandleGetPreview(const base::ListValue* args) {
781   DCHECK_EQ(2U, args->GetSize());
782   std::string callback_id;
783   std::string json_str;
784 
785   // All of the conditions below should be guaranteed by the print preview
786   // javascript.
787   args->GetString(0, &callback_id);
788   CHECK(!callback_id.empty());
789   args->GetString(1, &json_str);
790   base::Value settings = GetSettingsDictionary(json_str);
791   CHECK(settings.is_dict());
792   int request_id = settings.FindIntKey(kPreviewRequestID).value();
793   CHECK_GT(request_id, -1);
794 
795   CHECK(!base::Contains(preview_callbacks_, request_id));
796   preview_callbacks_[request_id] = callback_id;
797   print_preview_ui()->OnPrintPreviewRequest(request_id);
798   // Add an additional key in order to identify |print_preview_ui| later on
799   // when calling PrintPreviewUI::ShouldCancelRequest() on the IO thread.
800   settings.SetKey(
801       kPreviewUIID,
802       base::Value(print_preview_ui()->GetIDForPrintPreviewUI().value()));
803 
804   // Increment request count.
805   ++regenerate_preview_request_count_;
806 
807   WebContents* initiator = GetInitiator();
808   RenderFrameHost* rfh =
809       initiator
810           ? PrintViewManager::FromWebContents(initiator)->print_preview_rfh()
811           : nullptr;
812   if (!rfh) {
813     ReportUserActionHistogram(INITIATOR_CLOSED);
814     print_preview_ui()->OnClosePrintPreviewDialog();
815     return;
816   }
817 
818   // Retrieve the page title and url and send it to the renderer process if
819   // headers and footers are to be displayed.
820   base::Optional<bool> display_header_footer_opt =
821       settings.FindBoolKey(kSettingHeaderFooterEnabled);
822   DCHECK(display_header_footer_opt);
823   if (display_header_footer_opt.value_or(false)) {
824     settings.SetKey(kSettingHeaderFooterTitle,
825                     base::Value(initiator->GetTitle()));
826 
827     url::Replacements<char> url_sanitizer;
828     url_sanitizer.ClearUsername();
829     url_sanitizer.ClearPassword();
830     const GURL& initiator_url = initiator->GetLastCommittedURL();
831     settings.SetKey(kSettingHeaderFooterURL,
832                     base::Value(url_formatter::FormatUrl(
833                         initiator_url.ReplaceComponents(url_sanitizer))));
834   }
835 
836   VLOG(1) << "Print preview request start";
837 
838   if (!print_render_frame_.is_bound())
839     rfh->GetRemoteAssociatedInterfaces()->GetInterface(&print_render_frame_);
840 
841   print_render_frame_->PrintPreview(settings.Clone());
842   last_preview_settings_ = std::move(settings);
843 }
844 
HandlePrint(const base::ListValue * args)845 void PrintPreviewHandler::HandlePrint(const base::ListValue* args) {
846   // Record the number of times the user requests to regenerate preview data
847   // before printing.
848   base::UmaHistogramCounts1M(
849       "PrintPreview.RegeneratePreviewRequest.BeforePrint",
850       regenerate_preview_request_count_);
851   std::string callback_id;
852   CHECK(args->GetString(0, &callback_id));
853   CHECK(!callback_id.empty());
854   std::string json_str;
855   CHECK(args->GetString(1, &json_str));
856 
857   base::Value settings = GetSettingsDictionary(json_str);
858   if (!settings.is_dict()) {
859     RejectJavascriptCallback(base::Value(callback_id), base::Value(-1));
860     return;
861   }
862 
863   const UserActionBuckets user_action = DetermineUserAction(settings);
864 
865   int page_count = settings.FindIntKey(kSettingPreviewPageCount).value_or(-1);
866   if (page_count <= 0) {
867     RejectJavascriptCallback(base::Value(callback_id),
868                              GetErrorValue(user_action, "NO_PAGE_COUNT"));
869     return;
870   }
871 
872   scoped_refptr<base::RefCountedMemory> data;
873   print_preview_ui()->GetPrintPreviewDataForIndex(
874       COMPLETE_PREVIEW_DOCUMENT_INDEX, &data);
875   if (!data) {
876     // Nothing to print, no preview available.
877     RejectJavascriptCallback(base::Value(callback_id),
878                              GetErrorValue(user_action, "NO_DATA"));
879     return;
880   }
881   DCHECK(data->size());
882   DCHECK(data->front());
883 
884   // After validating |settings|, record metrics.
885   bool is_pdf = !print_preview_ui()->source_is_modifiable();
886   if (last_preview_settings_.is_dict())
887     ReportPrintSettingsStats(settings, last_preview_settings_, is_pdf);
888   {
889     PrintDocumentTypeBuckets doc_type = is_pdf ? PDF_DOCUMENT : HTML_DOCUMENT;
890     size_t average_page_size_in_kb = data->size() / page_count;
891     average_page_size_in_kb /= 1024;
892     ReportPrintDocumentTypeAndSizeHistograms(doc_type, average_page_size_in_kb);
893   }
894   ReportUserActionHistogram(user_action);
895 
896   if (user_action == PRINT_WITH_CLOUD_PRINT ||
897       user_action == PRINT_TO_GOOGLE_DRIVE) {
898     // Does not send the title like the other printer handler types below,
899     // because JS already has the document title from the initial settings.
900     SendCloudPrintJob(callback_id, data.get());
901     return;
902   }
903 
904   PrinterHandler* handler =
905       GetPrinterHandler(GetPrinterTypeForUserAction(user_action));
906   handler->StartPrint(print_preview_ui()->initiator_title(),
907                       std::move(settings), data,
908                       base::BindOnce(&PrintPreviewHandler::OnPrintResult,
909                                      weak_factory_.GetWeakPtr(), callback_id));
910 }
911 
HandleHidePreview(const base::ListValue *)912 void PrintPreviewHandler::HandleHidePreview(const base::ListValue* /*args*/) {
913   print_preview_ui()->OnHidePreviewDialog();
914 }
915 
HandleCancelPendingPrintRequest(const base::ListValue *)916 void PrintPreviewHandler::HandleCancelPendingPrintRequest(
917     const base::ListValue* /*args*/) {
918   WebContents* initiator = GetInitiator();
919   if (initiator)
920     ClearInitiatorDetails();
921   ShowPrintErrorDialog();
922 }
923 
HandleSaveAppState(const base::ListValue * args)924 void PrintPreviewHandler::HandleSaveAppState(const base::ListValue* args) {
925   std::string data_to_save;
926   PrintPreviewStickySettings* sticky_settings =
927       PrintPreviewStickySettings::GetInstance();
928   if (args->GetString(0, &data_to_save) && !data_to_save.empty())
929     sticky_settings->StoreAppState(data_to_save);
930   sticky_settings->SaveInPrefs(GetPrefs());
931 }
932 
933 // |args| is expected to contain a string with representing the callback id
934 // followed by a list of arguments the first of which should be the printer id.
HandlePrinterSetup(const base::ListValue * args)935 void PrintPreviewHandler::HandlePrinterSetup(const base::ListValue* args) {
936   std::string callback_id;
937   std::string printer_name;
938   if (!args->GetString(0, &callback_id) || !args->GetString(1, &printer_name) ||
939       callback_id.empty() || printer_name.empty()) {
940     RejectJavascriptCallback(base::Value(callback_id),
941                              base::Value(printer_name));
942     return;
943   }
944 
945   GetPrinterHandler(PrinterType::kLocalPrinter)
946       ->StartGetCapability(
947           printer_name, base::BindOnce(&PrintPreviewHandler::SendPrinterSetup,
948                                        weak_factory_.GetWeakPtr(), callback_id,
949                                        printer_name));
950 }
951 
HandleSignin(const base::ListValue * args)952 void PrintPreviewHandler::HandleSignin(const base::ListValue* args) {
953   bool add_account = false;
954   CHECK(args->GetBoolean(0, &add_account));
955 
956   Profile* profile = Profile::FromWebUI(web_ui());
957   DCHECK(profile);
958 
959 #if defined(OS_CHROMEOS)
960   if (chromeos::IsAccountManagerAvailable(profile)) {
961     // Chrome OS Account Manager is enabled on this Profile and hence, all
962     // account management flows will go through native UIs and not through a
963     // tabbed browser window.
964     if (add_account) {
965       chromeos::InlineLoginHandlerDialogChromeOS::Show();
966     } else {
967       chrome::SettingsWindowManager::GetInstance()->ShowOSSettings(
968           profile, chrome::kAccountManagerSubPage);
969     }
970     return;
971   }
972 #endif
973 
974   chrome::ScopedTabbedBrowserDisplayer displayer(profile);
975   print_dialog_cloud::CreateCloudPrintSigninTab(
976       displayer.browser(), add_account,
977       base::BindOnce(&PrintPreviewHandler::OnSignInTabClosed,
978                      weak_factory_.GetWeakPtr()));
979 }
980 
OnSignInTabClosed()981 void PrintPreviewHandler::OnSignInTabClosed() {
982   if (identity_manager_) {
983     // Sign in state will be reported in OnAccountsInCookieJarUpdated, so no
984     // need to do anything here.
985     return;
986   }
987   FireWebUIListener("check-for-account-update");
988 }
989 
990 #if defined(OS_CHROMEOS)
HandleGetAccessToken(const base::ListValue * args)991 void PrintPreviewHandler::HandleGetAccessToken(const base::ListValue* args) {
992   std::string callback_id;
993 
994   bool ok = args->GetString(0, &callback_id) && !callback_id.empty();
995   DCHECK(ok);
996 
997   if (!token_service_)
998     token_service_ = std::make_unique<AccessTokenService>();
999   token_service_->RequestToken(
1000       base::BindOnce(&PrintPreviewHandler::SendAccessToken,
1001                      weak_factory_.GetWeakPtr(), callback_id));
1002 }
1003 #endif
1004 
1005 #if BUILDFLAG(ENABLE_BASIC_PRINT_DIALOG)
HandleShowSystemDialog(const base::ListValue *)1006 void PrintPreviewHandler::HandleShowSystemDialog(
1007     const base::ListValue* /*args*/) {
1008   manage_printers_dialog_request_count_++;
1009   ReportUserActionHistogram(FALLBACK_TO_ADVANCED_SETTINGS_DIALOG);
1010 
1011   WebContents* initiator = GetInitiator();
1012   if (!initiator)
1013     return;
1014 
1015   auto* print_view_manager = PrintViewManager::FromWebContents(initiator);
1016   print_view_manager->PrintForSystemDialogNow(base::BindOnce(
1017       &PrintPreviewHandler::ClosePreviewDialog, weak_factory_.GetWeakPtr()));
1018 
1019   // Cancel the pending preview request if exists.
1020   print_preview_ui()->OnCancelPendingPreviewRequest();
1021 }
1022 #endif
1023 
HandleClosePreviewDialog(const base::ListValue *)1024 void PrintPreviewHandler::HandleClosePreviewDialog(
1025     const base::ListValue* /*args*/) {
1026   ReportUserActionHistogram(CANCEL);
1027 
1028   // Record the number of times the user requests to regenerate preview data
1029   // before cancelling.
1030   base::UmaHistogramCounts1M(
1031       "PrintPreview.RegeneratePreviewRequest.BeforeCancel",
1032       regenerate_preview_request_count_);
1033 }
1034 
1035 #if defined(OS_CHROMEOS)
HandleOpenPrinterSettings(const base::ListValue * args)1036 void PrintPreviewHandler::HandleOpenPrinterSettings(
1037     const base::ListValue* args) {
1038   chrome::SettingsWindowManager::GetInstance()->ShowOSSettings(
1039       Profile::FromWebUI(web_ui()), chrome::kNativePrintingSettingsSubPage);
1040 }
1041 
HandleGetEulaUrl(const base::ListValue * args)1042 void PrintPreviewHandler::HandleGetEulaUrl(const base::ListValue* args) {
1043   CHECK_EQ(2U, args->GetSize());
1044 
1045   const std::string& callback_id = args->GetList()[0].GetString();
1046   const std::string& destination_id = args->GetList()[1].GetString();
1047 
1048   PrinterHandler* handler = GetPrinterHandler(kLocalPrinter);
1049   if (!handler) {
1050     RejectJavascriptCallback(base::Value(callback_id), base::Value());
1051     return;
1052   }
1053 
1054   handler->StartGetEulaUrl(
1055       destination_id, base::BindOnce(&PrintPreviewHandler::SendEulaUrl,
1056                                      weak_factory_.GetWeakPtr(), callback_id));
1057 }
1058 #endif
1059 
GetLocaleInformation(base::Value * settings)1060 void PrintPreviewHandler::GetLocaleInformation(base::Value* settings) {
1061   // Getting the measurement system based on the locale.
1062   UErrorCode errorCode = U_ZERO_ERROR;
1063   const char* locale = g_browser_process->GetApplicationLocale().c_str();
1064   settings->SetStringKey(kUiLocale, std::string(locale));
1065   UMeasurementSystem system = ulocdata_getMeasurementSystem(locale, &errorCode);
1066   // On error, assume the units are SI.
1067   // Since the only measurement units print preview's WebUI cares about are
1068   // those for measuring distance, assume anything non-US is SI.
1069   if (errorCode > U_ZERO_ERROR || system != UMS_US)
1070     system = UMS_SI;
1071 
1072   // Getting the number formatting based on the locale and writing to
1073   // dictionary.
1074   base::string16 number_format = base::FormatDouble(123456.78, 2);
1075   size_t thousands_pos = number_format.find('3') + 1;
1076   base::string16 thousands_delimiter = number_format.substr(thousands_pos, 1);
1077   if (number_format[thousands_pos] == '4')
1078     thousands_delimiter.clear();
1079   size_t decimal_pos = number_format.find('6') + 1;
1080   DCHECK_NE(number_format[decimal_pos], '7');
1081   base::string16 decimal_delimiter = number_format.substr(decimal_pos, 1);
1082   settings->SetStringKey(kDecimalDelimiter, decimal_delimiter);
1083   settings->SetStringKey(kThousandsDelimiter, thousands_delimiter);
1084   settings->SetIntKey(kUnitType, system);
1085 }
1086 
HandleGetInitialSettings(const base::ListValue * args)1087 void PrintPreviewHandler::HandleGetInitialSettings(
1088     const base::ListValue* args) {
1089   std::string callback_id;
1090   CHECK(args->GetString(0, &callback_id));
1091   CHECK(!callback_id.empty());
1092 
1093   AllowJavascript();
1094 
1095   GetPrinterHandler(PrinterType::kLocalPrinter)
1096       ->GetDefaultPrinter(
1097           base::BindOnce(&PrintPreviewHandler::SendInitialSettings,
1098                          weak_factory_.GetWeakPtr(), callback_id));
1099 }
1100 
GetUserAccountList(base::Value * settings)1101 void PrintPreviewHandler::GetUserAccountList(base::Value* settings) {
1102   base::Value account_list(base::Value::Type::LIST);
1103   if (identity_manager_) {
1104     const std::vector<gaia::ListedAccount>& accounts =
1105         identity_manager_->GetAccountsInCookieJar().signed_in_accounts;
1106     for (const gaia::ListedAccount& account : accounts) {
1107       account_list.Append(account.email);
1108     }
1109     settings->SetKey(kSyncAvailable, base::Value(true));
1110   } else {
1111     settings->SetKey(kSyncAvailable, base::Value(false));
1112   }
1113   settings->SetKey(kUserAccounts, std::move(account_list));
1114 }
1115 
SendInitialSettings(const std::string & callback_id,const std::string & default_printer)1116 void PrintPreviewHandler::SendInitialSettings(
1117     const std::string& callback_id,
1118     const std::string& default_printer) {
1119   base::Value initial_settings(base::Value::Type::DICTIONARY);
1120   initial_settings.SetStringKey(kDocumentTitle,
1121                                 print_preview_ui()->initiator_title());
1122   initial_settings.SetBoolKey(kSettingPreviewModifiable,
1123                               print_preview_ui()->source_is_modifiable());
1124   initial_settings.SetBoolKey(kSettingPreviewIsFromArc,
1125                               print_preview_ui()->source_is_arc());
1126   initial_settings.SetBoolKey(kSettingPreviewIsPdf,
1127                               print_preview_ui()->source_is_pdf());
1128   initial_settings.SetStringKey(kSettingPrinterName, default_printer);
1129   initial_settings.SetBoolKey(kDocumentHasSelection,
1130                               print_preview_ui()->source_has_selection());
1131   initial_settings.SetBoolKey(kSettingShouldPrintSelectionOnly,
1132                               print_preview_ui()->print_selection_only());
1133   PrefService* prefs = GetPrefs();
1134   PrintPreviewStickySettings* sticky_settings =
1135       PrintPreviewStickySettings::GetInstance();
1136   sticky_settings->RestoreFromPrefs(prefs);
1137   if (sticky_settings->printer_app_state()) {
1138     initial_settings.SetStringKey(kAppState,
1139                                   *sticky_settings->printer_app_state());
1140   } else {
1141     initial_settings.SetKey(kAppState, base::Value());
1142   }
1143 
1144   base::Value policies = GetPolicies(*prefs);
1145   if (!policies.DictEmpty())
1146     initial_settings.SetKey(kPolicies, std::move(policies));
1147 
1148   if (IsCloudPrintEnabled() &&
1149       !base::FeatureList::IsEnabled(features::kCloudPrinterHandler)) {
1150     initial_settings.SetStringKey(
1151         kCloudPrintURL, GURL(cloud_devices::GetCloudPrintURL()).spec());
1152   }
1153 
1154   initial_settings.SetBoolKey(
1155       kPdfPrinterDisabled,
1156       base::Contains(printer_type_deny_list_, kPdfPrinter));
1157 
1158   const bool destinations_managed =
1159       !printer_type_deny_list_.empty() &&
1160       prefs->IsManagedPreference(prefs::kPrinterTypeDenyList);
1161   initial_settings.SetBoolKey(kDestinationsManaged, destinations_managed);
1162 
1163   base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
1164   initial_settings.SetBoolKey(kIsInKioskAutoPrintMode,
1165                               cmdline->HasSwitch(switches::kKioskModePrinting));
1166   initial_settings.SetBoolKey(kIsInAppKioskMode,
1167                               chrome::IsRunningInForcedAppMode());
1168   const std::string rules_str =
1169       prefs->GetString(prefs::kPrintPreviewDefaultDestinationSelectionRules);
1170   if (rules_str.empty()) {
1171     initial_settings.SetKey(kDefaultDestinationSelectionRules, base::Value());
1172   } else {
1173     initial_settings.SetStringKey(kDefaultDestinationSelectionRules, rules_str);
1174   }
1175 
1176   GetLocaleInformation(&initial_settings);
1177   if (IsCloudPrintEnabled()) {
1178     GetUserAccountList(&initial_settings);
1179   }
1180 
1181   ResolveJavascriptCallback(base::Value(callback_id), initial_settings);
1182 }
1183 
ClosePreviewDialog()1184 void PrintPreviewHandler::ClosePreviewDialog() {
1185   print_preview_ui()->OnClosePrintPreviewDialog();
1186 }
1187 
1188 #if defined(OS_CHROMEOS)
SendAccessToken(const std::string & callback_id,const std::string & access_token)1189 void PrintPreviewHandler::SendAccessToken(const std::string& callback_id,
1190                                           const std::string& access_token) {
1191   VLOG(1) << "Get getAccessToken finished";
1192   ResolveJavascriptCallback(base::Value(callback_id),
1193                             base::Value(access_token));
1194 }
1195 
SendEulaUrl(const std::string & callback_id,const std::string & eula_url)1196 void PrintPreviewHandler::SendEulaUrl(const std::string& callback_id,
1197                                       const std::string& eula_url) {
1198   VLOG(1) << "Get PPD license finished";
1199   ResolveJavascriptCallback(base::Value(callback_id), base::Value(eula_url));
1200 }
1201 #endif
1202 
SendPrinterCapabilities(const std::string & callback_id,base::Value settings_info)1203 void PrintPreviewHandler::SendPrinterCapabilities(
1204     const std::string& callback_id,
1205     base::Value settings_info) {
1206   // Check that |settings_info| is valid.
1207   if (settings_info.is_dict() &&
1208       settings_info.FindKeyOfType(kSettingCapabilities,
1209                                   base::Value::Type::DICTIONARY)) {
1210     VLOG(1) << "Get printer capabilities finished";
1211     ResolveJavascriptCallback(base::Value(callback_id), settings_info);
1212     return;
1213   }
1214 
1215   VLOG(1) << "Get printer capabilities failed";
1216   RejectJavascriptCallback(base::Value(callback_id), base::Value());
1217 }
1218 
SendPrinterSetup(const std::string & callback_id,const std::string & printer_name,base::Value destination_info)1219 void PrintPreviewHandler::SendPrinterSetup(const std::string& callback_id,
1220                                            const std::string& printer_name,
1221                                            base::Value destination_info) {
1222   base::Value response(base::Value::Type::DICTIONARY);
1223   base::Value* caps_value =
1224       destination_info.is_dict()
1225           ? destination_info.FindKeyOfType(kSettingCapabilities,
1226                                            base::Value::Type::DICTIONARY)
1227           : nullptr;
1228   response.SetKey("printerId", base::Value(printer_name));
1229   response.SetKey("success", base::Value(!!caps_value));
1230   response.SetKey("capabilities",
1231                   caps_value ? std::move(*caps_value)
1232                              : base::Value(base::Value::Type::DICTIONARY));
1233   if (caps_value) {
1234     base::Value* printer =
1235         destination_info.FindKeyOfType(kPrinter, base::Value::Type::DICTIONARY);
1236     if (printer) {
1237       base::Value* policies_value = printer->FindKeyOfType(
1238           kSettingPolicies, base::Value::Type::DICTIONARY);
1239       if (policies_value)
1240         response.SetKey("policies", std::move(*policies_value));
1241     }
1242   } else {
1243     LOG(WARNING) << "Printer setup failed";
1244   }
1245   ResolveJavascriptCallback(base::Value(callback_id), response);
1246 }
1247 
SendCloudPrintJob(const std::string & callback_id,const base::RefCountedMemory * data)1248 void PrintPreviewHandler::SendCloudPrintJob(
1249     const std::string& callback_id,
1250     const base::RefCountedMemory* data) {
1251   // BASE64 encode the job data.
1252   const base::StringPiece raw_data(data->front_as<char>(), data->size());
1253   std::string base64_data;
1254   base::Base64Encode(raw_data, &base64_data);
1255 
1256   if (base64_data.size() >= kMaxCloudPrintPdfDataSizeInBytes) {
1257     RejectJavascriptCallback(base::Value(callback_id),
1258                              base::Value("OVERSIZED_PDF"));
1259     return;
1260   }
1261   ResolveJavascriptCallback(base::Value(callback_id), base::Value(base64_data));
1262 }
1263 
GetInitiator() const1264 WebContents* PrintPreviewHandler::GetInitiator() const {
1265   PrintPreviewDialogController* dialog_controller =
1266       PrintPreviewDialogController::GetInstance();
1267   if (!dialog_controller)
1268     return NULL;
1269   return dialog_controller->GetInitiator(preview_web_contents());
1270 }
1271 
OnAccountsInCookieUpdated(const signin::AccountsInCookieJarInfo & accounts_in_cookie_jar_info,const GoogleServiceAuthError & error)1272 void PrintPreviewHandler::OnAccountsInCookieUpdated(
1273     const signin::AccountsInCookieJarInfo& accounts_in_cookie_jar_info,
1274     const GoogleServiceAuthError& error) {
1275   base::Value account_list(base::Value::Type::LIST);
1276   const std::vector<gaia::ListedAccount>& accounts =
1277       accounts_in_cookie_jar_info.signed_in_accounts;
1278   for (const auto& account : accounts) {
1279     account_list.Append(account.email);
1280   }
1281   FireWebUIListener("user-accounts-updated", std::move(account_list));
1282 }
1283 
OnPrintPreviewReady(int preview_uid,int request_id)1284 void PrintPreviewHandler::OnPrintPreviewReady(int preview_uid, int request_id) {
1285   std::string callback_id = GetCallbackId(request_id);
1286   if (callback_id.empty())
1287     return;
1288 
1289   ResolveJavascriptCallback(base::Value(callback_id), base::Value(preview_uid));
1290 }
1291 
OnPrintPreviewFailed(int request_id)1292 void PrintPreviewHandler::OnPrintPreviewFailed(int request_id) {
1293   WebContents* initiator = GetInitiator();
1294   if (!initiator || initiator->IsBeingDestroyed())
1295     return;  // Drop notification if fired during destruction sequence.
1296 
1297   std::string callback_id = GetCallbackId(request_id);
1298   if (callback_id.empty())
1299     return;
1300 
1301   if (!reported_failed_preview_) {
1302     reported_failed_preview_ = true;
1303     ReportUserActionHistogram(PREVIEW_FAILED);
1304   }
1305 
1306   // Keep track of failures.
1307   bool inserted = preview_failures_.insert(request_id).second;
1308   DCHECK(inserted);
1309   RejectJavascriptCallback(base::Value(callback_id),
1310                            base::Value("PREVIEW_FAILED"));
1311 }
1312 
OnInvalidPrinterSettings(int request_id)1313 void PrintPreviewHandler::OnInvalidPrinterSettings(int request_id) {
1314   std::string callback_id = GetCallbackId(request_id);
1315   if (callback_id.empty())
1316     return;
1317 
1318   RejectJavascriptCallback(base::Value(callback_id),
1319                            base::Value("SETTINGS_INVALID"));
1320 }
1321 
SendPrintPresetOptions(bool disable_scaling,int copies,int duplex,int request_id)1322 void PrintPreviewHandler::SendPrintPresetOptions(bool disable_scaling,
1323                                                  int copies,
1324                                                  int duplex,
1325                                                  int request_id) {
1326   if (!ShouldReceiveRendererMessage(request_id))
1327     return;
1328 
1329   FireWebUIListener("print-preset-options", base::Value(disable_scaling),
1330                     base::Value(copies), base::Value(duplex));
1331 }
1332 
SendPageCountReady(int page_count,int fit_to_page_scaling,int request_id)1333 void PrintPreviewHandler::SendPageCountReady(int page_count,
1334                                              int fit_to_page_scaling,
1335                                              int request_id) {
1336   if (!ShouldReceiveRendererMessage(request_id))
1337     return;
1338 
1339   FireWebUIListener("page-count-ready", base::Value(page_count),
1340                     base::Value(request_id), base::Value(fit_to_page_scaling));
1341 }
1342 
SendPageLayoutReady(const base::DictionaryValue & layout,bool has_custom_page_size_style,int request_id)1343 void PrintPreviewHandler::SendPageLayoutReady(
1344     const base::DictionaryValue& layout,
1345     bool has_custom_page_size_style,
1346     int request_id) {
1347   if (!ShouldReceiveRendererMessage(request_id))
1348     return;
1349 
1350   FireWebUIListener("page-layout-ready", layout,
1351                     base::Value(has_custom_page_size_style));
1352 }
1353 
SendPagePreviewReady(int page_index,int preview_uid,int preview_request_id)1354 void PrintPreviewHandler::SendPagePreviewReady(int page_index,
1355                                                int preview_uid,
1356                                                int preview_request_id) {
1357   // With print compositing, by the time compositing finishes and this method
1358   // gets called, the print preview may have failed. Since the failure message
1359   // may have arrived first, check for this case and bail out instead of
1360   // thinking this may be a bad IPC message.
1361   if (base::Contains(preview_failures_, preview_request_id))
1362     return;
1363 
1364   if (!ShouldReceiveRendererMessage(preview_request_id))
1365     return;
1366 
1367   FireWebUIListener("page-preview-ready", base::Value(page_index),
1368                     base::Value(preview_uid), base::Value(preview_request_id));
1369 }
1370 
OnPrintPreviewCancelled(int request_id)1371 void PrintPreviewHandler::OnPrintPreviewCancelled(int request_id) {
1372   std::string callback_id = GetCallbackId(request_id);
1373   if (callback_id.empty())
1374     return;
1375 
1376   RejectJavascriptCallback(base::Value(callback_id), base::Value("CANCELLED"));
1377 }
1378 
OnPrintRequestCancelled()1379 void PrintPreviewHandler::OnPrintRequestCancelled() {
1380   HandleCancelPendingPrintRequest(nullptr);
1381 }
1382 
ClearInitiatorDetails()1383 void PrintPreviewHandler::ClearInitiatorDetails() {
1384   WebContents* initiator = GetInitiator();
1385   if (!initiator)
1386     return;
1387 
1388   // We no longer require the initiator details. Remove those details associated
1389   // with the preview dialog to allow the initiator to create another preview
1390   // dialog.
1391   PrintPreviewDialogController* dialog_controller =
1392       PrintPreviewDialogController::GetInstance();
1393   if (dialog_controller)
1394     dialog_controller->EraseInitiatorInfo(preview_web_contents());
1395 }
1396 
GetPrinterHandler(PrinterType printer_type)1397 PrinterHandler* PrintPreviewHandler::GetPrinterHandler(
1398     PrinterType printer_type) {
1399   if (printer_type == PrinterType::kExtensionPrinter) {
1400     if (!extension_printer_handler_) {
1401       extension_printer_handler_ = PrinterHandler::CreateForExtensionPrinters(
1402           Profile::FromWebUI(web_ui()));
1403     }
1404     return extension_printer_handler_.get();
1405   }
1406 #if BUILDFLAG(ENABLE_SERVICE_DISCOVERY)
1407   if (printer_type == PrinterType::kPrivetPrinter) {
1408     if (!privet_printer_handler_) {
1409       privet_printer_handler_ =
1410           PrinterHandler::CreateForPrivetPrinters(Profile::FromWebUI(web_ui()));
1411     }
1412     return privet_printer_handler_.get();
1413   }
1414 #endif
1415   if (printer_type == PrinterType::kPdfPrinter) {
1416     if (!pdf_printer_handler_) {
1417       pdf_printer_handler_ = PrinterHandler::CreateForPdfPrinter(
1418           Profile::FromWebUI(web_ui()), preview_web_contents(),
1419           PrintPreviewStickySettings::GetInstance());
1420     }
1421     return pdf_printer_handler_.get();
1422   }
1423   if (printer_type == PrinterType::kLocalPrinter) {
1424     if (!local_printer_handler_) {
1425       local_printer_handler_ = PrinterHandler::CreateForLocalPrinters(
1426           preview_web_contents(), Profile::FromWebUI(web_ui()));
1427     }
1428     return local_printer_handler_.get();
1429   }
1430   if (printer_type == PrinterType::kCloudPrinter) {
1431     // This printer handler is currently experimental. Ensure it is never
1432     // created unless the flag is enabled.
1433     CHECK(base::FeatureList::IsEnabled(features::kCloudPrinterHandler));
1434     if (!cloud_printer_handler_)
1435       cloud_printer_handler_ = PrinterHandler::CreateForCloudPrinters();
1436     return cloud_printer_handler_.get();
1437   }
1438   NOTREACHED();
1439   return nullptr;
1440 }
1441 
GetPdfPrinterHandler()1442 PdfPrinterHandler* PrintPreviewHandler::GetPdfPrinterHandler() {
1443   return static_cast<PdfPrinterHandler*>(
1444       GetPrinterHandler(PrinterType::kPdfPrinter));
1445 }
1446 
OnAddedPrinters(PrinterType printer_type,const base::ListValue & printers)1447 void PrintPreviewHandler::OnAddedPrinters(PrinterType printer_type,
1448                                           const base::ListValue& printers) {
1449   DCHECK(printer_type == PrinterType::kExtensionPrinter ||
1450          printer_type == PrinterType::kPrivetPrinter ||
1451          printer_type == PrinterType::kLocalPrinter);
1452   DCHECK(!printers.empty());
1453   FireWebUIListener("printers-added", base::Value(printer_type), printers);
1454 
1455   if (printer_type == PrinterType::kLocalPrinter &&
1456       !has_logged_printers_count_) {
1457     UMA_HISTOGRAM_COUNTS_1M("PrintPreview.NumberOfPrinters",
1458                             printers.GetSize());
1459     has_logged_printers_count_ = true;
1460   }
1461 }
1462 
OnGetPrintersDone(const std::string & callback_id)1463 void PrintPreviewHandler::OnGetPrintersDone(const std::string& callback_id) {
1464   ResolveJavascriptCallback(base::Value(callback_id), base::Value());
1465 }
1466 
OnGotExtensionPrinterInfo(const std::string & callback_id,const base::DictionaryValue & printer_info)1467 void PrintPreviewHandler::OnGotExtensionPrinterInfo(
1468     const std::string& callback_id,
1469     const base::DictionaryValue& printer_info) {
1470   if (printer_info.empty()) {
1471     RejectJavascriptCallback(base::Value(callback_id), base::Value());
1472     return;
1473   }
1474   ResolveJavascriptCallback(base::Value(callback_id), printer_info);
1475 }
1476 
OnPrintResult(const std::string & callback_id,const base::Value & error)1477 void PrintPreviewHandler::OnPrintResult(const std::string& callback_id,
1478                                         const base::Value& error) {
1479   if (error.is_none())
1480     ResolveJavascriptCallback(base::Value(callback_id), error);
1481   else
1482     RejectJavascriptCallback(base::Value(callback_id), error);
1483   // Remove the preview dialog from the background printing manager if it is
1484   // being stored there. Since the PDF has been sent and the callback is
1485   // resolved or rejected, it is no longer needed and can be destroyed.
1486   BackgroundPrintingManager* background_printing_manager =
1487       g_browser_process->background_printing_manager();
1488   if (background_printing_manager->HasPrintPreviewDialog(
1489           preview_web_contents())) {
1490     background_printing_manager->OnPrintRequestCancelled(
1491         preview_web_contents());
1492   }
1493 }
1494 
RegisterForGaiaCookieChanges()1495 void PrintPreviewHandler::RegisterForGaiaCookieChanges() {
1496   DCHECK(!identity_manager_);
1497   cloud_print_enabled_ =
1498       !base::Contains(printer_type_deny_list_, kCloudPrinter) &&
1499       GetPrefs()->GetBoolean(prefs::kCloudPrintSubmitEnabled);
1500 
1501   if (!cloud_print_enabled_)
1502     return;
1503 
1504   Profile* profile = Profile::FromWebUI(web_ui());
1505   if (!AccountConsistencyModeManager::IsMirrorEnabledForProfile(profile) &&
1506       !AccountConsistencyModeManager::IsDiceEnabledForProfile(profile)) {
1507     return;
1508   }
1509 
1510   identity_manager_ = IdentityManagerFactory::GetForProfile(profile);
1511   identity_manager_->AddObserver(this);
1512 }
1513 
UnregisterForGaiaCookieChanges()1514 void PrintPreviewHandler::UnregisterForGaiaCookieChanges() {
1515   if (!identity_manager_)
1516     return;
1517 
1518   identity_manager_->RemoveObserver(this);
1519   identity_manager_ = nullptr;
1520   cloud_print_enabled_ = false;
1521 }
1522 
IsCloudPrintEnabled()1523 bool PrintPreviewHandler::IsCloudPrintEnabled() {
1524   return cloud_print_enabled_;
1525 }
1526 
BadMessageReceived()1527 void PrintPreviewHandler::BadMessageReceived() {
1528   bad_message::ReceivedBadMessage(
1529       GetInitiator()->GetMainFrame()->GetProcess(),
1530       bad_message::BadMessageReason::PPH_EXTRA_PREVIEW_MESSAGE);
1531 }
1532 
FileSelectedForTesting(const base::FilePath & path,int index,void * params)1533 void PrintPreviewHandler::FileSelectedForTesting(const base::FilePath& path,
1534                                                  int index,
1535                                                  void* params) {
1536   GetPdfPrinterHandler()->FileSelected(path, index, params);
1537 }
1538 
SetPdfSavedClosureForTesting(base::OnceClosure closure)1539 void PrintPreviewHandler::SetPdfSavedClosureForTesting(
1540     base::OnceClosure closure) {
1541   GetPdfPrinterHandler()->SetPdfSavedClosureForTesting(std::move(closure));
1542 }
1543 
SendEnableManipulateSettingsForTest()1544 void PrintPreviewHandler::SendEnableManipulateSettingsForTest() {
1545   FireWebUIListener("enable-manipulate-settings-for-test", base::Value());
1546 }
1547 
SendManipulateSettingsForTest(const base::DictionaryValue & settings)1548 void PrintPreviewHandler::SendManipulateSettingsForTest(
1549     const base::DictionaryValue& settings) {
1550   FireWebUIListener("manipulate-settings-for-test", settings);
1551 }
1552 
1553 }  // namespace printing
1554