Add new certificateProvider extension API.
[chromium-blink-merge.git] / chrome / browser / ui / webui / print_preview / extension_printer_handler.cc
blob8866763fed7f500349b60aeb7c383351df9eff29
1 // Copyright 2015 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.
5 #include "chrome/browser/ui/webui/print_preview/extension_printer_handler.h"
7 #include <algorithm>
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/files/file.h"
12 #include "base/files/file_path.h"
13 #include "base/files/file_util.h"
14 #include "base/location.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/memory/ref_counted_memory.h"
17 #include "base/strings/string_split.h"
18 #include "base/task_runner_util.h"
19 #include "chrome/browser/local_discovery/pwg_raster_converter.h"
20 #include "components/cloud_devices/common/cloud_device_description.h"
21 #include "components/cloud_devices/common/printer_description.h"
22 #include "device/core/device_client.h"
23 #include "device/usb/usb_device.h"
24 #include "device/usb/usb_service.h"
25 #include "extensions/browser/api/device_permissions_manager.h"
26 #include "extensions/browser/api/printer_provider/printer_provider_api.h"
27 #include "extensions/browser/api/printer_provider/printer_provider_api_factory.h"
28 #include "extensions/browser/api/printer_provider/printer_provider_print_job.h"
29 #include "extensions/browser/extension_registry.h"
30 #include "extensions/common/api/printer_provider/usb_printer_manifest_data.h"
31 #include "extensions/common/permissions/permissions_data.h"
32 #include "extensions/common/permissions/usb_device_permission.h"
33 #include "extensions/common/permissions/usb_device_permission_data.h"
34 #include "extensions/common/value_builder.h"
35 #include "printing/pdf_render_settings.h"
36 #include "printing/pwg_raster_settings.h"
38 using device::UsbDevice;
39 using extensions::DevicePermissionsManager;
40 using extensions::DictionaryBuilder;
41 using extensions::Extension;
42 using extensions::ExtensionRegistry;
43 using extensions::ListBuilder;
44 using extensions::UsbPrinterManifestData;
45 using local_discovery::PWGRasterConverter;
47 namespace {
49 const char kContentTypePdf[] = "application/pdf";
50 const char kContentTypePWGRaster[] = "image/pwg-raster";
51 const char kContentTypeAll[] = "*/*";
53 const char kInvalidDataPrintError[] = "INVALID_DATA";
54 const char kInvalidTicketPrintError[] = "INVALID_TICKET";
56 const char kProvisionalUsbLabel[] = "provisional-usb";
58 // Updates |job| with raster file path, size and last modification time.
59 // Returns the updated print job.
60 scoped_ptr<extensions::PrinterProviderPrintJob> UpdateJobFileInfoOnWorkerThread(
61 const base::FilePath& raster_path,
62 scoped_ptr<extensions::PrinterProviderPrintJob> job) {
63 if (base::GetFileInfo(raster_path, &job->file_info))
64 job->document_path = raster_path;
65 return job.Pass();
68 // Callback to PWG raster conversion.
69 // Posts a task to update print job with info about file containing converted
70 // PWG raster data. The task is posted to |slow_task_runner|.
71 void UpdateJobFileInfo(
72 scoped_ptr<extensions::PrinterProviderPrintJob> job,
73 const scoped_refptr<base::TaskRunner>& slow_task_runner,
74 const ExtensionPrinterHandler::PrintJobCallback& callback,
75 bool success,
76 const base::FilePath& pwg_file_path) {
77 if (!success) {
78 callback.Run(job.Pass());
79 return;
82 base::PostTaskAndReplyWithResult(
83 slow_task_runner.get(), FROM_HERE,
84 base::Bind(&UpdateJobFileInfoOnWorkerThread, pwg_file_path,
85 base::Passed(&job)),
86 callback);
89 bool HasUsbPrinterProviderPermissions(const Extension* extension) {
90 return extension->permissions_data() &&
91 extension->permissions_data()->HasAPIPermission(
92 extensions::APIPermission::kPrinterProvider) &&
93 extension->permissions_data()->HasAPIPermission(
94 extensions::APIPermission::kUsb);
97 std::string GenerateProvisionalUsbPrinterId(const Extension* extension,
98 const UsbDevice* device) {
99 return base::StringPrintf("%s:%s:%s", kProvisionalUsbLabel,
100 extension->id().c_str(), device->guid().c_str());
103 bool ParseProvisionalUsbPrinterId(const std::string& printer_id,
104 std::string* extension_id,
105 std::string* device_guid) {
106 std::vector<std::string> components = base::SplitString(
107 printer_id, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
109 if (components.size() != 3)
110 return false;
112 if (components[0] != kProvisionalUsbLabel)
113 return false;
115 *extension_id = components[1];
116 *device_guid = components[2];
117 return true;
120 } // namespace
122 ExtensionPrinterHandler::ExtensionPrinterHandler(
123 content::BrowserContext* browser_context,
124 const scoped_refptr<base::TaskRunner>& slow_task_runner)
125 : browser_context_(browser_context),
126 slow_task_runner_(slow_task_runner),
127 weak_ptr_factory_(this) {
130 ExtensionPrinterHandler::~ExtensionPrinterHandler() {
133 void ExtensionPrinterHandler::Reset() {
134 // TODO(tbarzic): Keep track of pending request ids issued by |this| and
135 // cancel them from here.
136 pending_enumeration_count_ = 0;
137 weak_ptr_factory_.InvalidateWeakPtrs();
140 void ExtensionPrinterHandler::StartGetPrinters(
141 const PrinterHandler::GetPrintersCallback& callback) {
142 // Assume that there can only be one printer enumeration occuring at once.
143 DCHECK_EQ(pending_enumeration_count_, 0);
144 pending_enumeration_count_ = 1;
146 bool extension_supports_usb_printers = false;
147 ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_);
148 for (const auto& extension : registry->enabled_extensions()) {
149 if (UsbPrinterManifestData::Get(extension.get()) &&
150 HasUsbPrinterProviderPermissions(extension.get())) {
151 extension_supports_usb_printers = true;
152 break;
156 if (extension_supports_usb_printers) {
157 device::UsbService* service = device::DeviceClient::Get()->GetUsbService();
158 pending_enumeration_count_++;
159 service->GetDevices(
160 base::Bind(&ExtensionPrinterHandler::OnUsbDevicesEnumerated,
161 weak_ptr_factory_.GetWeakPtr(), callback));
164 extensions::PrinterProviderAPIFactory::GetInstance()
165 ->GetForBrowserContext(browser_context_)
166 ->DispatchGetPrintersRequested(
167 base::Bind(&ExtensionPrinterHandler::WrapGetPrintersCallback,
168 weak_ptr_factory_.GetWeakPtr(), callback));
171 void ExtensionPrinterHandler::StartGetCapability(
172 const std::string& destination_id,
173 const PrinterHandler::GetCapabilityCallback& callback) {
174 extensions::PrinterProviderAPIFactory::GetInstance()
175 ->GetForBrowserContext(browser_context_)
176 ->DispatchGetCapabilityRequested(
177 destination_id,
178 base::Bind(&ExtensionPrinterHandler::WrapGetCapabilityCallback,
179 weak_ptr_factory_.GetWeakPtr(), callback, destination_id));
182 void ExtensionPrinterHandler::StartPrint(
183 const std::string& destination_id,
184 const std::string& capability,
185 const base::string16& job_title,
186 const std::string& ticket_json,
187 const gfx::Size& page_size,
188 const scoped_refptr<base::RefCountedMemory>& print_data,
189 const PrinterHandler::PrintCallback& callback) {
190 scoped_ptr<extensions::PrinterProviderPrintJob> print_job(
191 new extensions::PrinterProviderPrintJob());
192 print_job->printer_id = destination_id;
193 print_job->job_title = job_title;
194 print_job->ticket_json = ticket_json;
196 cloud_devices::CloudDeviceDescription printer_description;
197 printer_description.InitFromString(capability);
199 cloud_devices::printer::ContentTypesCapability content_types;
200 content_types.LoadFrom(printer_description);
202 const bool kUsePdf = content_types.Contains(kContentTypePdf) ||
203 content_types.Contains(kContentTypeAll);
205 if (kUsePdf) {
206 // TODO(tbarzic): Consider writing larger PDF to disk and provide the data
207 // the same way as it's done with PWG raster.
208 print_job->content_type = kContentTypePdf;
209 print_job->document_bytes = print_data;
210 DispatchPrintJob(callback, print_job.Pass());
211 return;
214 cloud_devices::CloudDeviceDescription ticket;
215 if (!ticket.InitFromString(ticket_json)) {
216 WrapPrintCallback(callback, false, kInvalidTicketPrintError);
217 return;
220 print_job->content_type = kContentTypePWGRaster;
221 ConvertToPWGRaster(print_data, printer_description, ticket, page_size,
222 print_job.Pass(),
223 base::Bind(&ExtensionPrinterHandler::DispatchPrintJob,
224 weak_ptr_factory_.GetWeakPtr(), callback));
227 void ExtensionPrinterHandler::StartGrantPrinterAccess(
228 const std::string& printer_id,
229 const PrinterHandler::GetPrinterInfoCallback& callback) {
230 std::string extension_id;
231 std::string device_guid;
232 if (!ParseProvisionalUsbPrinterId(printer_id, &extension_id, &device_guid)) {
233 callback.Run(base::DictionaryValue());
234 return;
237 device::UsbService* service = device::DeviceClient::Get()->GetUsbService();
238 scoped_refptr<UsbDevice> device = service->GetDevice(device_guid);
239 if (!device) {
240 callback.Run(base::DictionaryValue());
241 return;
244 DevicePermissionsManager* permissions_manager =
245 DevicePermissionsManager::Get(browser_context_);
246 permissions_manager->AllowUsbDevice(extension_id, device);
248 extensions::PrinterProviderAPIFactory::GetInstance()
249 ->GetForBrowserContext(browser_context_)
250 ->DispatchGetUsbPrinterInfoRequested(
251 extension_id, device,
252 base::Bind(&ExtensionPrinterHandler::WrapGetPrinterInfoCallback,
253 weak_ptr_factory_.GetWeakPtr(), callback));
256 void ExtensionPrinterHandler::SetPwgRasterConverterForTesting(
257 scoped_ptr<local_discovery::PWGRasterConverter> pwg_raster_converter) {
258 pwg_raster_converter_ = pwg_raster_converter.Pass();
261 void ExtensionPrinterHandler::ConvertToPWGRaster(
262 const scoped_refptr<base::RefCountedMemory>& data,
263 const cloud_devices::CloudDeviceDescription& printer_description,
264 const cloud_devices::CloudDeviceDescription& ticket,
265 const gfx::Size& page_size,
266 scoped_ptr<extensions::PrinterProviderPrintJob> job,
267 const ExtensionPrinterHandler::PrintJobCallback& callback) {
268 if (!pwg_raster_converter_) {
269 pwg_raster_converter_ = PWGRasterConverter::CreateDefault();
271 pwg_raster_converter_->Start(
272 data.get(),
273 PWGRasterConverter::GetConversionSettings(printer_description, page_size),
274 PWGRasterConverter::GetBitmapSettings(printer_description, ticket),
275 base::Bind(&UpdateJobFileInfo, base::Passed(&job), slow_task_runner_,
276 callback));
279 void ExtensionPrinterHandler::DispatchPrintJob(
280 const PrinterHandler::PrintCallback& callback,
281 scoped_ptr<extensions::PrinterProviderPrintJob> print_job) {
282 if (print_job->document_path.empty() && !print_job->document_bytes) {
283 WrapPrintCallback(callback, false, kInvalidDataPrintError);
284 return;
287 extensions::PrinterProviderAPIFactory::GetInstance()
288 ->GetForBrowserContext(browser_context_)
289 ->DispatchPrintRequested(
290 *print_job, base::Bind(&ExtensionPrinterHandler::WrapPrintCallback,
291 weak_ptr_factory_.GetWeakPtr(), callback));
294 void ExtensionPrinterHandler::WrapGetPrintersCallback(
295 const PrinterHandler::GetPrintersCallback& callback,
296 const base::ListValue& printers,
297 bool done) {
298 DCHECK_GT(pending_enumeration_count_, 0);
299 if (done)
300 pending_enumeration_count_--;
302 callback.Run(printers, pending_enumeration_count_ == 0);
305 void ExtensionPrinterHandler::WrapGetCapabilityCallback(
306 const PrinterHandler::GetCapabilityCallback& callback,
307 const std::string& destination_id,
308 const base::DictionaryValue& capability) {
309 callback.Run(destination_id, capability);
312 void ExtensionPrinterHandler::WrapPrintCallback(
313 const PrinterHandler::PrintCallback& callback,
314 bool success,
315 const std::string& status) {
316 callback.Run(success, status);
319 void ExtensionPrinterHandler::WrapGetPrinterInfoCallback(
320 const PrinterHandler::GetPrinterInfoCallback& callback,
321 const base::DictionaryValue& printer_info) {
322 callback.Run(printer_info);
325 void ExtensionPrinterHandler::OnUsbDevicesEnumerated(
326 const PrinterHandler::GetPrintersCallback& callback,
327 const std::vector<scoped_refptr<UsbDevice>>& devices) {
328 ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_);
329 DevicePermissionsManager* permissions_manager =
330 DevicePermissionsManager::Get(browser_context_);
332 ListBuilder printer_list;
334 for (const auto& extension : registry->enabled_extensions()) {
335 const UsbPrinterManifestData* manifest_data =
336 UsbPrinterManifestData::Get(extension.get());
337 if (!manifest_data || !HasUsbPrinterProviderPermissions(extension.get()))
338 continue;
340 const extensions::DevicePermissions* device_permissions =
341 permissions_manager->GetForExtension(extension->id());
342 for (const auto& device : devices) {
343 if (manifest_data->SupportsDevice(device)) {
344 extensions::UsbDevicePermission::CheckParam param(
345 device->vendor_id(), device->product_id(),
346 extensions::UsbDevicePermissionData::UNSPECIFIED_INTERFACE);
347 if (device_permissions->FindUsbDeviceEntry(device) ||
348 extension->permissions_data()->CheckAPIPermissionWithParam(
349 extensions::APIPermission::kUsbDevice, &param)) {
350 // Skip devices the extension already has permission to access.
351 continue;
354 printer_list.Append(
355 DictionaryBuilder()
356 .Set("id", GenerateProvisionalUsbPrinterId(extension.get(),
357 device.get()))
358 .Set("name",
359 DevicePermissionsManager::GetPermissionMessage(
360 device->vendor_id(), device->product_id(),
361 device->manufacturer_string(),
362 device->product_string(), base::string16(), false))
363 .Set("extensionId", extension->id())
364 .Set("extensionName", extension->name())
365 .Set("provisional", true));
370 DCHECK_GT(pending_enumeration_count_, 0);
371 pending_enumeration_count_--;
372 callback.Run(*printer_list.Build().get(), pending_enumeration_count_ == 0);