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 "extensions/browser/api/printer_provider/printer_provider_api.h"
12 #include "base/bind.h"
13 #include "base/i18n/rtl.h"
14 #include "base/json/json_string_value_serializer.h"
15 #include "base/macros.h"
16 #include "base/memory/ref_counted_memory.h"
17 #include "base/scoped_observer.h"
18 #include "base/strings/string16.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "base/values.h"
21 #include "extensions/browser/api/printer_provider/printer_provider_print_job.h"
22 #include "extensions/browser/api/printer_provider_internal/printer_provider_internal_api.h"
23 #include "extensions/browser/api/printer_provider_internal/printer_provider_internal_api_observer.h"
24 #include "extensions/browser/event_router.h"
25 #include "extensions/browser/extension_registry.h"
26 #include "extensions/browser/extension_registry_observer.h"
27 #include "extensions/common/api/printer_provider.h"
28 #include "extensions/common/api/printer_provider_internal.h"
29 #include "extensions/common/extension.h"
31 namespace extensions
{
35 // The separator between extension id and the extension's internal printer id
36 // used when generating a printer id unique across extensions.
37 const char kPrinterIdSeparator
= ':';
39 // Given an extension ID and an ID of a printer reported by the extension, it
40 // generates a ID for the printer unique across extensions (assuming that the
41 // printer id is unique in the extension's space).
42 std::string
GeneratePrinterId(const std::string
& extension_id
,
43 const std::string
& internal_printer_id
) {
44 std::string result
= extension_id
;
45 result
.append(1, kPrinterIdSeparator
);
46 result
.append(internal_printer_id
);
50 // Parses an ID created using |GeneratePrinterId| to it's components:
51 // the extension ID and the printer ID internal to the extension.
52 // Returns whenter the ID was succesfully parsed.
53 bool ParsePrinterId(const std::string
& printer_id
,
54 std::string
* extension_id
,
55 std::string
* internal_printer_id
) {
56 size_t separator
= printer_id
.find_first_of(kPrinterIdSeparator
);
57 if (separator
== std::string::npos
)
59 *extension_id
= printer_id
.substr(0, separator
);
60 *internal_printer_id
= printer_id
.substr(separator
+ 1);
64 // Holds information about a pending onGetPrintersRequested request;
65 // in particular, the list of extensions to which the event was dispatched but
66 // which haven't yet responded, and the |GetPrinters| callback associated with
68 class GetPrintersRequest
{
70 explicit GetPrintersRequest(
71 const PrinterProviderAPI::GetPrintersCallback
& callback
);
72 ~GetPrintersRequest();
74 // Adds an extension id to the list of the extensions that need to respond
76 void AddSource(const std::string
& extension_id
);
78 // Whether all extensions have responded to the event.
81 // Runs the callback for an extension and removes the extension from the
82 // list of extensions that still have to respond to the event.
83 void ReportForExtension(const std::string
& extension_id
,
84 const base::ListValue
& printers
);
87 // Callback reporting event result for an extension. Called once for each
89 PrinterProviderAPI::GetPrintersCallback callback_
;
91 // The list of extensions that still have to respond to the event.
92 std::set
<std::string
> extensions_
;
95 // Keeps track of pending chrome.printerProvider.onGetPrintersRequested
97 class PendingGetPrintersRequests
{
99 PendingGetPrintersRequests();
100 ~PendingGetPrintersRequests();
102 // Adds a new request to the set of pending requests. Returns the id
103 // assigned to the request.
104 int Add(const PrinterProviderAPI::GetPrintersCallback
& callback
);
106 // Completes a request for an extension. It runs the request callback with
107 // values reported by the extension.
108 bool CompleteForExtension(const std::string
& extension_id
,
110 const base::ListValue
& result
);
112 // Runs callbacks for the extension for all requests that are waiting for a
113 // response from the extension with the provided extension id. Callbacks are
114 // called as if the extension reported empty set of printers.
115 void FailAllForExtension(const std::string
& extension_id
);
117 // Adds an extension id to the list of the extensions that need to respond
119 bool AddSource(int request_id
, const std::string
& extension_id
);
122 int last_request_id_
;
123 std::map
<int, GetPrintersRequest
> pending_requests_
;
125 DISALLOW_COPY_AND_ASSIGN(PendingGetPrintersRequests
);
128 // Keeps track of pending chrome.printerProvider.onGetCapabilityRequested
129 // requests for an extension.
130 class PendingGetCapabilityRequests
{
132 PendingGetCapabilityRequests();
133 ~PendingGetCapabilityRequests();
135 // Adds a new request to the set. Only information needed is the callback
136 // associated with the request. Returns the id assigned to the request.
137 int Add(const PrinterProviderAPI::GetCapabilityCallback
& callback
);
139 // Completes the request with the provided request id. It runs the request
140 // callback and removes the request from the set.
141 bool Complete(int request_id
, const base::DictionaryValue
& result
);
143 // Runs all pending callbacks with empty capability value and clears the
144 // set of pending requests.
148 int last_request_id_
;
149 std::map
<int, PrinterProviderAPI::GetCapabilityCallback
> pending_requests_
;
152 // Keeps track of pending chrome.printerProvider.ontPrintRequested requests
154 class PendingPrintRequests
{
156 PendingPrintRequests();
157 ~PendingPrintRequests();
159 // Adds a new request to the set. Only information needed is the callback
160 // associated with the request. Returns the id assigned to the request.
161 int Add(const PrinterProviderPrintJob
& job
,
162 const PrinterProviderAPI::PrintCallback
& callback
);
164 // Gets print job associated with a request.
165 const PrinterProviderPrintJob
* GetPrintJob(int request_id
) const;
167 // Completes the request with the provided request id. It runs the request
168 // callback and removes the request from the set.
169 bool Complete(int request_id
, bool success
, const std::string
& result
);
171 // Runs all pending callbacks with ERROR_FAILED and clears the set of
176 struct PrintRequest
{
177 PrinterProviderAPI::PrintCallback callback
;
178 PrinterProviderPrintJob job
;
181 int last_request_id_
;
182 std::map
<int, PrintRequest
> pending_requests_
;
185 // Implements chrome.printerProvider API events.
186 class PrinterProviderAPIImpl
: public PrinterProviderAPI
,
187 public PrinterProviderInternalAPIObserver
,
188 public ExtensionRegistryObserver
{
190 explicit PrinterProviderAPIImpl(content::BrowserContext
* browser_context
);
191 ~PrinterProviderAPIImpl() override
;
194 // PrinterProviderAPI implementation:
195 void DispatchGetPrintersRequested(
196 const PrinterProviderAPI::GetPrintersCallback
& callback
) override
;
197 void DispatchGetCapabilityRequested(
198 const std::string
& printer_id
,
199 const PrinterProviderAPI::GetCapabilityCallback
& callback
) override
;
200 void DispatchPrintRequested(
201 const PrinterProviderPrintJob
& job
,
202 const PrinterProviderAPI::PrintCallback
& callback
) override
;
203 const PrinterProviderPrintJob
* GetPrintJob(const Extension
* extension
,
204 int request_id
) const override
;
206 // PrinterProviderInternalAPIObserver implementation:
207 void OnGetPrintersResult(
208 const Extension
* extension
,
210 const PrinterProviderInternalAPIObserver::PrinterInfoVector
& result
)
212 void OnGetCapabilityResult(const Extension
* extension
,
214 const base::DictionaryValue
& result
) override
;
216 const Extension
* extension
,
218 core_api::printer_provider_internal::PrintError error
) override
;
220 // ExtensionRegistryObserver implementation:
221 void OnExtensionUnloaded(content::BrowserContext
* browser_context
,
222 const Extension
* extension
,
223 UnloadedExtensionInfo::Reason reason
) override
;
225 // Called before chrome.printerProvider.onGetPrintersRequested event is
226 // dispatched to an extension. It returns whether the extension is interested
227 // in the event. If the extension listens to the event, it's added to the set
228 // of |request| sources. |request| is |GetPrintersRequest| object associated
230 bool WillRequestPrinters(int request_id
,
231 content::BrowserContext
* browser_context
,
232 const Extension
* extension
,
233 base::ListValue
* args
);
235 content::BrowserContext
* browser_context_
;
237 PendingGetPrintersRequests pending_get_printers_requests_
;
239 std::map
<std::string
, PendingPrintRequests
> pending_print_requests_
;
241 std::map
<std::string
, PendingGetCapabilityRequests
>
242 pending_capability_requests_
;
244 ScopedObserver
<PrinterProviderInternalAPI
, PrinterProviderInternalAPIObserver
>
245 internal_api_observer_
;
247 ScopedObserver
<ExtensionRegistry
, ExtensionRegistryObserver
>
248 extension_registry_observer_
;
250 DISALLOW_COPY_AND_ASSIGN(PrinterProviderAPIImpl
);
253 GetPrintersRequest::GetPrintersRequest(
254 const PrinterProviderAPI::GetPrintersCallback
& callback
)
255 : callback_(callback
) {
258 GetPrintersRequest::~GetPrintersRequest() {
261 void GetPrintersRequest::AddSource(const std::string
& extension_id
) {
262 extensions_
.insert(extension_id
);
265 bool GetPrintersRequest::IsDone() const {
266 return extensions_
.empty();
269 void GetPrintersRequest::ReportForExtension(const std::string
& extension_id
,
270 const base::ListValue
& printers
) {
271 if (extensions_
.erase(extension_id
) > 0)
272 callback_
.Run(printers
, IsDone());
275 PendingGetPrintersRequests::PendingGetPrintersRequests() : last_request_id_(0) {
278 PendingGetPrintersRequests::~PendingGetPrintersRequests() {
281 int PendingGetPrintersRequests::Add(
282 const PrinterProviderAPI::GetPrintersCallback
& callback
) {
283 pending_requests_
.insert(
284 std::make_pair(++last_request_id_
, GetPrintersRequest(callback
)));
285 return last_request_id_
;
288 bool PendingGetPrintersRequests::CompleteForExtension(
289 const std::string
& extension_id
,
291 const base::ListValue
& result
) {
292 auto it
= pending_requests_
.find(request_id
);
293 if (it
== pending_requests_
.end())
296 it
->second
.ReportForExtension(extension_id
, result
);
297 if (it
->second
.IsDone()) {
298 pending_requests_
.erase(it
);
303 void PendingGetPrintersRequests::FailAllForExtension(
304 const std::string
& extension_id
) {
305 auto it
= pending_requests_
.begin();
306 while (it
!= pending_requests_
.end()) {
307 int request_id
= it
->first
;
308 // |it| may get deleted during |CompleteForExtension|, so progress it to the
309 // next item before calling the method.
311 CompleteForExtension(extension_id
, request_id
, base::ListValue());
315 bool PendingGetPrintersRequests::AddSource(int request_id
,
316 const std::string
& extension_id
) {
317 auto it
= pending_requests_
.find(request_id
);
318 if (it
== pending_requests_
.end())
321 it
->second
.AddSource(extension_id
);
325 PendingGetCapabilityRequests::PendingGetCapabilityRequests()
326 : last_request_id_(0) {
329 PendingGetCapabilityRequests::~PendingGetCapabilityRequests() {
332 int PendingGetCapabilityRequests::Add(
333 const PrinterProviderAPI::GetCapabilityCallback
& callback
) {
334 pending_requests_
[++last_request_id_
] = callback
;
335 return last_request_id_
;
338 bool PendingGetCapabilityRequests::Complete(
340 const base::DictionaryValue
& response
) {
341 auto it
= pending_requests_
.find(request_id
);
342 if (it
== pending_requests_
.end())
345 PrinterProviderAPI::GetCapabilityCallback callback
= it
->second
;
346 pending_requests_
.erase(it
);
348 callback
.Run(response
);
352 void PendingGetCapabilityRequests::FailAll() {
353 for (auto& request
: pending_requests_
)
354 request
.second
.Run(base::DictionaryValue());
355 pending_requests_
.clear();
358 PendingPrintRequests::PendingPrintRequests() : last_request_id_(0) {
361 PendingPrintRequests::~PendingPrintRequests() {
364 int PendingPrintRequests::Add(
365 const PrinterProviderPrintJob
& job
,
366 const PrinterProviderAPI::PrintCallback
& callback
) {
367 PrintRequest request
;
368 request
.callback
= callback
;
370 pending_requests_
[++last_request_id_
] = request
;
371 return last_request_id_
;
374 bool PendingPrintRequests::Complete(int request_id
,
376 const std::string
& response
) {
377 auto it
= pending_requests_
.find(request_id
);
378 if (it
== pending_requests_
.end())
381 PrinterProviderAPI::PrintCallback callback
= it
->second
.callback
;
382 pending_requests_
.erase(it
);
384 callback
.Run(success
, response
);
388 const PrinterProviderPrintJob
* PendingPrintRequests::GetPrintJob(
389 int request_id
) const {
390 auto it
= pending_requests_
.find(request_id
);
391 if (it
== pending_requests_
.end())
394 return &it
->second
.job
;
397 void PendingPrintRequests::FailAll() {
398 for (auto& request
: pending_requests_
)
399 request
.second
.callback
.Run(false,
400 PrinterProviderAPI::GetDefaultPrintError());
401 pending_requests_
.clear();
404 PrinterProviderAPIImpl::PrinterProviderAPIImpl(
405 content::BrowserContext
* browser_context
)
406 : browser_context_(browser_context
),
407 internal_api_observer_(this),
408 extension_registry_observer_(this) {
409 internal_api_observer_
.Add(
410 PrinterProviderInternalAPI::GetFactoryInstance()->Get(browser_context
));
411 extension_registry_observer_
.Add(ExtensionRegistry::Get(browser_context
));
414 PrinterProviderAPIImpl::~PrinterProviderAPIImpl() {
417 void PrinterProviderAPIImpl::DispatchGetPrintersRequested(
418 const GetPrintersCallback
& callback
) {
419 EventRouter
* event_router
= EventRouter::Get(browser_context_
);
420 if (!event_router
->HasEventListener(
421 core_api::printer_provider::OnGetPrintersRequested::kEventName
)) {
422 callback
.Run(base::ListValue(), true /* done */);
426 // |pending_get_printers_requests_| take ownership of |request| which gets
427 // NULLed out. Save the pointer before passing it to the requests, as it will
428 // be needed later on.
429 int request_id
= pending_get_printers_requests_
.Add(callback
);
431 scoped_ptr
<base::ListValue
> internal_args(new base::ListValue
);
432 // Request id is not part of the public API, but it will be massaged out in
434 internal_args
->AppendInteger(request_id
);
436 scoped_ptr
<Event
> event(
437 new Event(core_api::printer_provider::OnGetPrintersRequested::kEventName
,
438 internal_args
.Pass()));
439 // This callback is called synchronously during |BroadcastEvent|, so
440 // Unretained is safe.
441 event
->will_dispatch_callback
=
442 base::Bind(&PrinterProviderAPIImpl::WillRequestPrinters
,
443 base::Unretained(this), request_id
);
445 event_router
->BroadcastEvent(event
.Pass());
448 void PrinterProviderAPIImpl::DispatchGetCapabilityRequested(
449 const std::string
& printer_id
,
450 const PrinterProviderAPI::GetCapabilityCallback
& callback
) {
451 std::string extension_id
;
452 std::string internal_printer_id
;
453 if (!ParsePrinterId(printer_id
, &extension_id
, &internal_printer_id
)) {
454 callback
.Run(base::DictionaryValue());
458 EventRouter
* event_router
= EventRouter::Get(browser_context_
);
459 if (!event_router
->ExtensionHasEventListener(
461 core_api::printer_provider::OnGetCapabilityRequested::kEventName
)) {
462 callback
.Run(base::DictionaryValue());
466 int request_id
= pending_capability_requests_
[extension_id
].Add(callback
);
468 scoped_ptr
<base::ListValue
> internal_args(new base::ListValue
);
469 // Request id is not part of the public API, but it will be massaged out in
471 internal_args
->AppendInteger(request_id
);
472 internal_args
->AppendString(internal_printer_id
);
474 scoped_ptr
<Event
> event(new Event(
475 core_api::printer_provider::OnGetCapabilityRequested::kEventName
,
476 internal_args
.Pass()));
478 event_router
->DispatchEventToExtension(extension_id
, event
.Pass());
481 void PrinterProviderAPIImpl::DispatchPrintRequested(
482 const PrinterProviderPrintJob
& job
,
483 const PrinterProviderAPI::PrintCallback
& callback
) {
484 std::string extension_id
;
485 std::string internal_printer_id
;
486 if (!ParsePrinterId(job
.printer_id
, &extension_id
, &internal_printer_id
)) {
487 callback
.Run(false, PrinterProviderAPI::GetDefaultPrintError());
491 EventRouter
* event_router
= EventRouter::Get(browser_context_
);
492 if (!event_router
->ExtensionHasEventListener(
494 core_api::printer_provider::OnPrintRequested::kEventName
)) {
495 callback
.Run(false, PrinterProviderAPI::GetDefaultPrintError());
499 core_api::printer_provider::PrintJob print_job
;
500 print_job
.printer_id
= internal_printer_id
;
502 JSONStringValueDeserializer
deserializer(job
.ticket_json
);
503 scoped_ptr
<base::Value
> ticket_value(deserializer
.Deserialize(NULL
, NULL
));
505 !core_api::printer_provider::PrintJob::Ticket::Populate(
506 *ticket_value
, &print_job
.ticket
)) {
508 core_api::printer_provider::ToString(
509 core_api::printer_provider::PRINT_ERROR_INVALID_TICKET
));
513 print_job
.content_type
= job
.content_type
;
514 print_job
.title
= base::UTF16ToUTF8(job
.job_title
);
515 int request_id
= pending_print_requests_
[extension_id
].Add(job
, callback
);
517 scoped_ptr
<base::ListValue
> internal_args(new base::ListValue
);
518 // Request id is not part of the public API and it will be massaged out in
520 internal_args
->AppendInteger(request_id
);
521 internal_args
->Append(print_job
.ToValue().release());
522 scoped_ptr
<Event
> event(
523 new Event(core_api::printer_provider::OnPrintRequested::kEventName
,
524 internal_args
.Pass()));
525 event_router
->DispatchEventToExtension(extension_id
, event
.Pass());
528 const PrinterProviderPrintJob
* PrinterProviderAPIImpl::GetPrintJob(
529 const Extension
* extension
,
530 int request_id
) const {
531 auto it
= pending_print_requests_
.find(extension
->id());
532 if (it
== pending_print_requests_
.end())
534 return it
->second
.GetPrintJob(request_id
);
537 void PrinterProviderAPIImpl::OnGetPrintersResult(
538 const Extension
* extension
,
540 const PrinterProviderInternalAPIObserver::PrinterInfoVector
& result
) {
541 base::ListValue printer_list
;
543 // Update some printer description properties to better identify the extension
544 // managing the printer.
545 for (size_t i
= 0; i
< result
.size(); ++i
) {
546 scoped_ptr
<base::DictionaryValue
> printer(result
[i
]->ToValue());
547 std::string internal_printer_id
;
548 CHECK(printer
->GetString("id", &internal_printer_id
));
549 printer
->SetString("id",
550 GeneratePrinterId(extension
->id(), internal_printer_id
));
551 printer
->SetString("extensionId", extension
->id());
552 printer
->SetString("extensionName", extension
->name());
554 base::string16 printer_name
;
555 if (printer
->GetString("name", &printer_name
) &&
556 base::i18n::AdjustStringForLocaleDirection(&printer_name
)) {
557 printer
->SetString("name", printer_name
);
560 base::string16 printer_description
;
561 if (printer
->GetString("description", &printer_description
) &&
562 base::i18n::AdjustStringForLocaleDirection(&printer_description
)) {
563 printer
->SetString("description", printer_description
);
566 printer_list
.Append(printer
.release());
569 pending_get_printers_requests_
.CompleteForExtension(extension
->id(),
570 request_id
, printer_list
);
573 void PrinterProviderAPIImpl::OnGetCapabilityResult(
574 const Extension
* extension
,
576 const base::DictionaryValue
& result
) {
577 pending_capability_requests_
[extension
->id()].Complete(request_id
, result
);
580 void PrinterProviderAPIImpl::OnPrintResult(
581 const Extension
* extension
,
583 core_api::printer_provider_internal::PrintError error
) {
584 const std::string error_str
=
585 error
== core_api::printer_provider_internal::PRINT_ERROR_NONE
586 ? PrinterProviderAPI::GetDefaultPrintError()
587 : core_api::printer_provider_internal::ToString(error
);
588 pending_print_requests_
[extension
->id()].Complete(
589 request_id
, error
== core_api::printer_provider_internal::PRINT_ERROR_OK
,
593 void PrinterProviderAPIImpl::OnExtensionUnloaded(
594 content::BrowserContext
* browser_context
,
595 const Extension
* extension
,
596 UnloadedExtensionInfo::Reason reason
) {
597 pending_get_printers_requests_
.FailAllForExtension(extension
->id());
599 auto print_it
= pending_print_requests_
.find(extension
->id());
600 if (print_it
!= pending_print_requests_
.end()) {
601 print_it
->second
.FailAll();
602 pending_print_requests_
.erase(print_it
);
605 auto capability_it
= pending_capability_requests_
.find(extension
->id());
606 if (capability_it
!= pending_capability_requests_
.end()) {
607 capability_it
->second
.FailAll();
608 pending_capability_requests_
.erase(capability_it
);
612 bool PrinterProviderAPIImpl::WillRequestPrinters(
614 content::BrowserContext
* browser_context
,
615 const Extension
* extension
,
616 base::ListValue
* args
) {
619 EventRouter
* event_router
= EventRouter::Get(browser_context_
);
620 if (!event_router
->ExtensionHasEventListener(
622 core_api::printer_provider::OnGetPrintersRequested::kEventName
)) {
626 return pending_get_printers_requests_
.AddSource(request_id
, extension
->id());
632 PrinterProviderAPI
* PrinterProviderAPI::Create(
633 content::BrowserContext
* context
) {
634 return new PrinterProviderAPIImpl(context
);
638 std::string
PrinterProviderAPI::GetDefaultPrintError() {
639 return core_api::printer_provider_internal::ToString(
640 core_api::printer_provider_internal::PRINT_ERROR_FAILED
);
643 } // namespace extensions