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"
10 #include "base/bind.h"
11 #include "base/json/json_string_value_serializer.h"
12 #include "base/lazy_instance.h"
13 #include "base/values.h"
14 #include "extensions/browser/api/printer_provider_internal/printer_provider_internal_api.h"
15 #include "extensions/browser/event_router.h"
16 #include "extensions/browser/extension_registry.h"
17 #include "extensions/browser/extension_registry_factory.h"
18 #include "extensions/common/api/printer_provider.h"
19 #include "extensions/common/api/printer_provider_internal.h"
20 #include "extensions/common/extension.h"
22 namespace extensions
{
26 static base::LazyInstance
<BrowserContextKeyedAPIFactory
<PrinterProviderAPI
>>
27 g_api_factory
= LAZY_INSTANCE_INITIALIZER
;
29 // The separator between extension id and the extension's internal printer id
30 // used when generating a printer id unique across extensions.
31 const char kPrinterIdSeparator
= ':';
33 // Given an extension ID and an ID of a printer reported by the extension, it
34 // generates a ID for the printer unique across extensions (assuming that the
35 // printer id is unique in the extension's space).
36 std::string
GeneratePrinterId(const std::string
& extension_id
,
37 const std::string
& internal_printer_id
) {
38 std::string result
= extension_id
;
39 result
.append(1, kPrinterIdSeparator
);
40 result
.append(internal_printer_id
);
44 // Parses an ID created using |GeneratePrinterId| to it's components:
45 // the extension ID and the printer ID internal to the extension.
46 // Returns whenter the ID was succesfully parsed.
47 bool ParsePrinterId(const std::string
& printer_id
,
48 std::string
* extension_id
,
49 std::string
* internal_printer_id
) {
50 size_t separator
= printer_id
.find_first_of(kPrinterIdSeparator
);
51 if (separator
== std::string::npos
)
53 *extension_id
= printer_id
.substr(0, separator
);
54 *internal_printer_id
= printer_id
.substr(separator
+ 1);
60 PrinterProviderAPI::PrintJob::PrintJob() {
63 PrinterProviderAPI::PrintJob::~PrintJob() {
67 BrowserContextKeyedAPIFactory
<PrinterProviderAPI
>*
68 PrinterProviderAPI::GetFactoryInstance() {
69 return g_api_factory
.Pointer();
73 std::string
PrinterProviderAPI::GetDefaultPrintError() {
74 return core_api::printer_provider_internal::ToString(
75 core_api::printer_provider_internal::PRINT_ERROR_FAILED
);
78 PrinterProviderAPI::PrinterProviderAPI(content::BrowserContext
* browser_context
)
79 : browser_context_(browser_context
),
80 internal_api_observer_(this),
81 extension_registry_observer_(this) {
82 internal_api_observer_
.Add(
83 PrinterProviderInternalAPI::GetFactoryInstance()->Get(browser_context
));
84 extension_registry_observer_
.Add(ExtensionRegistry::Get(browser_context
));
87 PrinterProviderAPI::~PrinterProviderAPI() {
90 void PrinterProviderAPI::DispatchGetPrintersRequested(
91 const GetPrintersCallback
& callback
) {
92 EventRouter
* event_router
= EventRouter::Get(browser_context_
);
93 if (!event_router
->HasEventListener(
94 core_api::printer_provider::OnGetPrintersRequested::kEventName
)) {
95 callback
.Run(base::ListValue(), true /* done */);
99 // |pending_get_printers_requests_| take ownership of |request| which gets
100 // NULLed out. Save the pointer before passing it to the requests, as it will
101 // be needed later on.
102 int request_id
= pending_get_printers_requests_
.Add(callback
);
104 scoped_ptr
<base::ListValue
> internal_args(new base::ListValue
);
105 // Request id is not part of the public API, but it will be massaged out in
107 internal_args
->AppendInteger(request_id
);
109 scoped_ptr
<Event
> event(
110 new Event(core_api::printer_provider::OnGetPrintersRequested::kEventName
,
111 internal_args
.Pass()));
112 // This callback is called synchronously during |BroadcastEvent|, so
113 // Unretained is safe. Also, |raw_request_ptr| will stay valid at least until
114 // |BroadcastEvent| finishes.
115 event
->will_dispatch_callback
=
116 base::Bind(&PrinterProviderAPI::WillRequestPrinters
,
117 base::Unretained(this), request_id
);
119 event_router
->BroadcastEvent(event
.Pass());
122 void PrinterProviderAPI::DispatchGetCapabilityRequested(
123 const std::string
& printer_id
,
124 const PrinterProviderAPI::GetCapabilityCallback
& callback
) {
125 std::string extension_id
;
126 std::string internal_printer_id
;
127 if (!ParsePrinterId(printer_id
, &extension_id
, &internal_printer_id
)) {
128 callback
.Run(base::DictionaryValue());
132 EventRouter
* event_router
= EventRouter::Get(browser_context_
);
133 if (!event_router
->ExtensionHasEventListener(
135 core_api::printer_provider::OnGetCapabilityRequested::kEventName
)) {
136 callback
.Run(base::DictionaryValue());
140 int request_id
= pending_capability_requests_
[extension_id
].Add(callback
);
142 scoped_ptr
<base::ListValue
> internal_args(new base::ListValue
);
143 // Request id is not part of the public API, but it will be massaged out in
145 internal_args
->AppendInteger(request_id
);
146 internal_args
->AppendString(internal_printer_id
);
148 scoped_ptr
<Event
> event(new Event(
149 core_api::printer_provider::OnGetCapabilityRequested::kEventName
,
150 internal_args
.Pass()));
152 event_router
->DispatchEventToExtension(extension_id
, event
.Pass());
155 void PrinterProviderAPI::DispatchPrintRequested(
156 const PrinterProviderAPI::PrintJob
& job
,
157 const PrinterProviderAPI::PrintCallback
& callback
) {
158 std::string extension_id
;
159 std::string internal_printer_id
;
160 if (!ParsePrinterId(job
.printer_id
, &extension_id
, &internal_printer_id
)) {
161 callback
.Run(false, GetDefaultPrintError());
165 EventRouter
* event_router
= EventRouter::Get(browser_context_
);
166 if (!event_router
->ExtensionHasEventListener(
168 core_api::printer_provider::OnPrintRequested::kEventName
)) {
169 callback
.Run(false, GetDefaultPrintError());
173 core_api::printer_provider::PrintJob print_job
;
174 print_job
.printer_id
= internal_printer_id
;
176 JSONStringValueSerializer
serializer(job
.ticket_json
);
177 scoped_ptr
<base::Value
> ticket_value(serializer
.Deserialize(NULL
, NULL
));
179 !core_api::printer_provider::PrintJob::Ticket::Populate(
180 *ticket_value
, &print_job
.ticket
)) {
182 core_api::printer_provider::ToString(
183 core_api::printer_provider::PRINT_ERROR_INVALID_TICKET
));
187 // TODO(tbarzic): Figure out how to support huge documents.
188 if (job
.document_bytes
->size() > PrinterProviderAPI::kMaxDocumentSize
) {
190 core_api::printer_provider::ToString(
191 core_api::printer_provider::PRINT_ERROR_INVALID_DATA
));
195 print_job
.content_type
= job
.content_type
;
196 print_job
.document
= std::vector
<char>(
197 job
.document_bytes
->front(),
198 job
.document_bytes
->front() + job
.document_bytes
->size());
200 int request_id
= pending_print_requests_
[extension_id
].Add(callback
);
202 scoped_ptr
<base::ListValue
> internal_args(new base::ListValue
);
203 // Request id is not part of the public API and it will be massaged out in
205 internal_args
->AppendInteger(request_id
);
206 internal_args
->Append(print_job
.ToValue().release());
207 scoped_ptr
<Event
> event(
208 new Event(core_api::printer_provider::OnPrintRequested::kEventName
,
209 internal_args
.Pass()));
211 event_router
->DispatchEventToExtension(extension_id
, event
.Pass());
214 PrinterProviderAPI::GetPrintersRequest::GetPrintersRequest(
215 const GetPrintersCallback
& callback
)
216 : callback_(callback
) {
219 PrinterProviderAPI::GetPrintersRequest::~GetPrintersRequest() {
222 void PrinterProviderAPI::GetPrintersRequest::AddSource(
223 const std::string
& extension_id
) {
224 extensions_
.insert(extension_id
);
227 bool PrinterProviderAPI::GetPrintersRequest::IsDone() const {
228 return extensions_
.empty();
231 void PrinterProviderAPI::GetPrintersRequest::ReportForExtension(
232 const std::string
& extension_id
,
233 const base::ListValue
& printers
) {
234 if (extensions_
.erase(extension_id
) > 0)
235 callback_
.Run(printers
, IsDone());
238 PrinterProviderAPI::PendingGetPrintersRequests::PendingGetPrintersRequests()
239 : last_request_id_(0) {
242 PrinterProviderAPI::PendingGetPrintersRequests::~PendingGetPrintersRequests() {
245 int PrinterProviderAPI::PendingGetPrintersRequests::Add(
246 const GetPrintersCallback
& callback
) {
247 pending_requests_
.insert(
248 std::make_pair(++last_request_id_
, GetPrintersRequest(callback
)));
249 return last_request_id_
;
252 bool PrinterProviderAPI::PendingGetPrintersRequests::CompleteForExtension(
253 const std::string
& extension_id
,
255 const base::ListValue
& result
) {
256 auto it
= pending_requests_
.find(request_id
);
257 if (it
== pending_requests_
.end())
260 it
->second
.ReportForExtension(extension_id
, result
);
261 if (it
->second
.IsDone()) {
262 pending_requests_
.erase(it
);
267 void PrinterProviderAPI::PendingGetPrintersRequests::FailAllForExtension(
268 const std::string
& extension_id
) {
269 auto it
= pending_requests_
.begin();
270 while (it
!= pending_requests_
.end()) {
271 int request_id
= it
->first
;
272 // |it| may get deleted during |CompleteForExtension|, so progress it to the
273 // next item before calling the method.
275 CompleteForExtension(extension_id
, request_id
, base::ListValue());
279 bool PrinterProviderAPI::PendingGetPrintersRequests::AddSource(
281 const std::string
& extension_id
) {
282 auto it
= pending_requests_
.find(request_id
);
283 if (it
== pending_requests_
.end())
286 it
->second
.AddSource(extension_id
);
290 PrinterProviderAPI::PendingGetCapabilityRequests::PendingGetCapabilityRequests()
291 : last_request_id_(0) {
294 PrinterProviderAPI::PendingGetCapabilityRequests::
295 ~PendingGetCapabilityRequests() {
298 int PrinterProviderAPI::PendingGetCapabilityRequests::Add(
299 const PrinterProviderAPI::GetCapabilityCallback
& callback
) {
300 pending_requests_
[++last_request_id_
] = callback
;
301 return last_request_id_
;
304 bool PrinterProviderAPI::PendingGetCapabilityRequests::Complete(
306 const base::DictionaryValue
& response
) {
307 auto it
= pending_requests_
.find(request_id
);
308 if (it
== pending_requests_
.end())
311 GetCapabilityCallback callback
= it
->second
;
312 pending_requests_
.erase(it
);
314 callback
.Run(response
);
318 void PrinterProviderAPI::PendingGetCapabilityRequests::FailAll() {
319 for (auto& request
: pending_requests_
)
320 request
.second
.Run(base::DictionaryValue());
321 pending_requests_
.clear();
324 PrinterProviderAPI::PendingPrintRequests::PendingPrintRequests()
325 : last_request_id_(0) {
328 PrinterProviderAPI::PendingPrintRequests::~PendingPrintRequests() {
331 int PrinterProviderAPI::PendingPrintRequests::Add(
332 const PrinterProviderAPI::PrintCallback
& callback
) {
333 pending_requests_
[++last_request_id_
] = callback
;
334 return last_request_id_
;
337 bool PrinterProviderAPI::PendingPrintRequests::Complete(
340 const std::string
& response
) {
341 auto it
= pending_requests_
.find(request_id
);
342 if (it
== pending_requests_
.end())
345 PrintCallback callback
= it
->second
;
346 pending_requests_
.erase(it
);
348 callback
.Run(success
, response
);
352 void PrinterProviderAPI::PendingPrintRequests::FailAll() {
353 for (auto& request
: pending_requests_
)
354 request
.second
.Run(false, GetDefaultPrintError());
355 pending_requests_
.clear();
358 void PrinterProviderAPI::OnGetPrintersResult(
359 const Extension
* extension
,
361 const PrinterProviderInternalAPIObserver::PrinterInfoVector
& result
) {
362 base::ListValue printer_list
;
364 // Update some printer description properties to better identify the extension
365 // managing the printer.
366 for (size_t i
= 0; i
< result
.size(); ++i
) {
367 scoped_ptr
<base::DictionaryValue
> printer(result
[i
]->ToValue());
368 std::string internal_printer_id
;
369 CHECK(printer
->GetString("id", &internal_printer_id
));
370 printer
->SetString("id",
371 GeneratePrinterId(extension
->id(), internal_printer_id
));
372 printer
->SetString("extensionId", extension
->id());
373 printer_list
.Append(printer
.release());
376 pending_get_printers_requests_
.CompleteForExtension(extension
->id(),
377 request_id
, printer_list
);
380 void PrinterProviderAPI::OnGetCapabilityResult(
381 const Extension
* extension
,
383 const base::DictionaryValue
& result
) {
384 pending_capability_requests_
[extension
->id()].Complete(request_id
, result
);
387 void PrinterProviderAPI::OnPrintResult(
388 const Extension
* extension
,
390 core_api::printer_provider_internal::PrintError error
) {
391 const std::string error_str
=
392 error
== core_api::printer_provider_internal::PRINT_ERROR_NONE
393 ? GetDefaultPrintError()
394 : core_api::printer_provider_internal::ToString(error
);
395 pending_print_requests_
[extension
->id()].Complete(
396 request_id
, error
== core_api::printer_provider_internal::PRINT_ERROR_OK
,
400 void PrinterProviderAPI::OnExtensionUnloaded(
401 content::BrowserContext
* browser_context
,
402 const Extension
* extension
,
403 UnloadedExtensionInfo::Reason reason
) {
404 pending_get_printers_requests_
.FailAllForExtension(extension
->id());
406 auto print_it
= pending_print_requests_
.find(extension
->id());
407 if (print_it
!= pending_print_requests_
.end()) {
408 print_it
->second
.FailAll();
409 pending_print_requests_
.erase(print_it
);
412 auto capability_it
= pending_capability_requests_
.find(extension
->id());
413 if (capability_it
!= pending_capability_requests_
.end()) {
414 capability_it
->second
.FailAll();
415 pending_capability_requests_
.erase(capability_it
);
419 bool PrinterProviderAPI::WillRequestPrinters(
421 content::BrowserContext
* browser_context
,
422 const Extension
* extension
,
423 base::ListValue
* args
) {
426 EventRouter
* event_router
= EventRouter::Get(browser_context_
);
427 if (!event_router
->ExtensionHasEventListener(
429 core_api::printer_provider::OnGetPrintersRequested::kEventName
)) {
433 return pending_get_printers_requests_
.AddSource(request_id
, extension
->id());
437 void BrowserContextKeyedAPIFactory
<
438 PrinterProviderAPI
>::DeclareFactoryDependencies() {
439 DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
440 DependsOn(PrinterProviderInternalAPI::GetFactoryInstance());
441 DependsOn(ExtensionRegistryFactory::GetInstance());
444 } // namespace extensions