Don't show supervised user as "already on this device" while they're being imported.
[chromium-blink-merge.git] / extensions / browser / api / printer_provider / printer_provider_api.cc
blobcf1fda6ed4e7fde4a6d74c021b97c39b830ad54b
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"
7 #include <map>
8 #include <set>
9 #include <utility>
10 #include <vector>
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 {
33 namespace {
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);
47 return result;
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)
58 return false;
59 *extension_id = printer_id.substr(0, separator);
60 *internal_printer_id = printer_id.substr(separator + 1);
61 return true;
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
67 // the event.
68 class GetPrintersRequest {
69 public:
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
75 // to the event.
76 void AddSource(const std::string& extension_id);
78 // Whether all extensions have responded to the event.
79 bool IsDone() const;
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);
86 private:
87 // Callback reporting event result for an extension. Called once for each
88 // extension.
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
96 // requests.
97 class PendingGetPrintersRequests {
98 public:
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,
109 int request_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
118 // to the event.
119 bool AddSource(int request_id, const std::string& extension_id);
121 private:
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 {
131 public:
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.
145 void FailAll();
147 private:
148 int last_request_id_;
149 std::map<int, PrinterProviderAPI::GetCapabilityCallback> pending_requests_;
152 // Keeps track of pending chrome.printerProvider.ontPrintRequested requests
153 // for an extension.
154 class PendingPrintRequests {
155 public:
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
172 // pending requests.
173 void FailAll();
175 private:
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 {
189 public:
190 explicit PrinterProviderAPIImpl(content::BrowserContext* browser_context);
191 ~PrinterProviderAPIImpl() override;
193 private:
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,
209 int request_id,
210 const PrinterProviderInternalAPIObserver::PrinterInfoVector& result)
211 override;
212 void OnGetCapabilityResult(const Extension* extension,
213 int request_id,
214 const base::DictionaryValue& result) override;
215 void OnPrintResult(
216 const Extension* extension,
217 int request_id,
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
229 // with the event.
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,
290 int request_id,
291 const base::ListValue& result) {
292 auto it = pending_requests_.find(request_id);
293 if (it == pending_requests_.end())
294 return false;
296 it->second.ReportForExtension(extension_id, result);
297 if (it->second.IsDone()) {
298 pending_requests_.erase(it);
300 return true;
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.
310 ++it;
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())
319 return false;
321 it->second.AddSource(extension_id);
322 return true;
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(
339 int request_id,
340 const base::DictionaryValue& response) {
341 auto it = pending_requests_.find(request_id);
342 if (it == pending_requests_.end())
343 return false;
345 PrinterProviderAPI::GetCapabilityCallback callback = it->second;
346 pending_requests_.erase(it);
348 callback.Run(response);
349 return true;
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;
369 request.job = job;
370 pending_requests_[++last_request_id_] = request;
371 return last_request_id_;
374 bool PendingPrintRequests::Complete(int request_id,
375 bool success,
376 const std::string& response) {
377 auto it = pending_requests_.find(request_id);
378 if (it == pending_requests_.end())
379 return false;
381 PrinterProviderAPI::PrintCallback callback = it->second.callback;
382 pending_requests_.erase(it);
384 callback.Run(success, response);
385 return true;
388 const PrinterProviderPrintJob* PendingPrintRequests::GetPrintJob(
389 int request_id) const {
390 auto it = pending_requests_.find(request_id);
391 if (it == pending_requests_.end())
392 return nullptr;
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 */);
423 return;
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
433 // custom bindings.
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());
455 return;
458 EventRouter* event_router = EventRouter::Get(browser_context_);
459 if (!event_router->ExtensionHasEventListener(
460 extension_id,
461 core_api::printer_provider::OnGetCapabilityRequested::kEventName)) {
462 callback.Run(base::DictionaryValue());
463 return;
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
470 // custom bindings.
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());
488 return;
491 EventRouter* event_router = EventRouter::Get(browser_context_);
492 if (!event_router->ExtensionHasEventListener(
493 extension_id,
494 core_api::printer_provider::OnPrintRequested::kEventName)) {
495 callback.Run(false, PrinterProviderAPI::GetDefaultPrintError());
496 return;
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));
504 if (!ticket_value ||
505 !core_api::printer_provider::PrintJob::Ticket::Populate(
506 *ticket_value, &print_job.ticket)) {
507 callback.Run(false,
508 core_api::printer_provider::ToString(
509 core_api::printer_provider::PRINT_ERROR_INVALID_TICKET));
510 return;
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
519 // custom bindings.
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())
533 return nullptr;
534 return it->second.GetPrintJob(request_id);
537 void PrinterProviderAPIImpl::OnGetPrintersResult(
538 const Extension* extension,
539 int request_id,
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,
575 int request_id,
576 const base::DictionaryValue& result) {
577 pending_capability_requests_[extension->id()].Complete(request_id, result);
580 void PrinterProviderAPIImpl::OnPrintResult(
581 const Extension* extension,
582 int request_id,
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,
590 error_str);
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(
613 int request_id,
614 content::BrowserContext* browser_context,
615 const Extension* extension,
616 base::ListValue* args) {
617 if (!extension)
618 return false;
619 EventRouter* event_router = EventRouter::Get(browser_context_);
620 if (!event_router->ExtensionHasEventListener(
621 extension->id(),
622 core_api::printer_provider::OnGetPrintersRequested::kEventName)) {
623 return false;
626 return pending_get_printers_requests_.AddSource(request_id, extension->id());
629 } // namespace
631 // static
632 PrinterProviderAPI* PrinterProviderAPI::Create(
633 content::BrowserContext* context) {
634 return new PrinterProviderAPIImpl(context);
637 // static
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