Add more checks to investigate SupervisedUserPrefStore crash at startup.
[chromium-blink-merge.git] / extensions / browser / api / printer_provider / printer_provider_api.cc
blobda66224ae389f20db920bca627fefba0d88a3a11
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 <utility>
8 #include <vector>
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 {
24 namespace {
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);
41 return result;
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)
52 return false;
53 *extension_id = printer_id.substr(0, separator);
54 *internal_printer_id = printer_id.substr(separator + 1);
55 return true;
58 } // namespace
60 PrinterProviderAPI::PrintJob::PrintJob() {
63 PrinterProviderAPI::PrintJob::~PrintJob() {
66 // static
67 BrowserContextKeyedAPIFactory<PrinterProviderAPI>*
68 PrinterProviderAPI::GetFactoryInstance() {
69 return g_api_factory.Pointer();
72 // static
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 */);
96 return;
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
106 // custom bindings.
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());
129 return;
132 EventRouter* event_router = EventRouter::Get(browser_context_);
133 if (!event_router->ExtensionHasEventListener(
134 extension_id,
135 core_api::printer_provider::OnGetCapabilityRequested::kEventName)) {
136 callback.Run(base::DictionaryValue());
137 return;
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
144 // custom bindings.
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());
162 return;
165 EventRouter* event_router = EventRouter::Get(browser_context_);
166 if (!event_router->ExtensionHasEventListener(
167 extension_id,
168 core_api::printer_provider::OnPrintRequested::kEventName)) {
169 callback.Run(false, GetDefaultPrintError());
170 return;
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));
178 if (!ticket_value ||
179 !core_api::printer_provider::PrintJob::Ticket::Populate(
180 *ticket_value, &print_job.ticket)) {
181 callback.Run(false,
182 core_api::printer_provider::ToString(
183 core_api::printer_provider::PRINT_ERROR_INVALID_TICKET));
184 return;
187 // TODO(tbarzic): Figure out how to support huge documents.
188 if (job.document_bytes->size() > PrinterProviderAPI::kMaxDocumentSize) {
189 callback.Run(false,
190 core_api::printer_provider::ToString(
191 core_api::printer_provider::PRINT_ERROR_INVALID_DATA));
192 return;
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
204 // custom bindings.
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,
254 int request_id,
255 const base::ListValue& result) {
256 auto it = pending_requests_.find(request_id);
257 if (it == pending_requests_.end())
258 return false;
260 it->second.ReportForExtension(extension_id, result);
261 if (it->second.IsDone()) {
262 pending_requests_.erase(it);
264 return true;
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.
274 ++it;
275 CompleteForExtension(extension_id, request_id, base::ListValue());
279 bool PrinterProviderAPI::PendingGetPrintersRequests::AddSource(
280 int request_id,
281 const std::string& extension_id) {
282 auto it = pending_requests_.find(request_id);
283 if (it == pending_requests_.end())
284 return false;
286 it->second.AddSource(extension_id);
287 return true;
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(
305 int request_id,
306 const base::DictionaryValue& response) {
307 auto it = pending_requests_.find(request_id);
308 if (it == pending_requests_.end())
309 return false;
311 GetCapabilityCallback callback = it->second;
312 pending_requests_.erase(it);
314 callback.Run(response);
315 return true;
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(
338 int request_id,
339 bool success,
340 const std::string& response) {
341 auto it = pending_requests_.find(request_id);
342 if (it == pending_requests_.end())
343 return false;
345 PrintCallback callback = it->second;
346 pending_requests_.erase(it);
348 callback.Run(success, response);
349 return true;
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,
360 int request_id,
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,
382 int request_id,
383 const base::DictionaryValue& result) {
384 pending_capability_requests_[extension->id()].Complete(request_id, result);
387 void PrinterProviderAPI::OnPrintResult(
388 const Extension* extension,
389 int request_id,
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,
397 error_str);
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(
420 int request_id,
421 content::BrowserContext* browser_context,
422 const Extension* extension,
423 base::ListValue* args) {
424 if (!extension)
425 return false;
426 EventRouter* event_router = EventRouter::Get(browser_context_);
427 if (!event_router->ExtensionHasEventListener(
428 extension->id(),
429 core_api::printer_provider::OnGetPrintersRequested::kEventName)) {
430 return false;
433 return pending_get_printers_requests_.AddSource(request_id, extension->id());
436 template <>
437 void BrowserContextKeyedAPIFactory<
438 PrinterProviderAPI>::DeclareFactoryDependencies() {
439 DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
440 DependsOn(PrinterProviderInternalAPI::GetFactoryInstance());
441 DependsOn(ExtensionRegistryFactory::GetInstance());
444 } // namespace extensions