Commit 05d92917 authored by rbpotter's avatar rbpotter Committed by Commit Bot

Add validation for CDDs from extension and privet printers

To prevent JS console errors, ensure that all CDDs obtained from
extension and privet printers are sane. Do not need to check CDDs from
local printers, since they are generated by
SemanticCapsAndDefaultsToCdd.

Bug: None
Cq-Include-Trybots: master.tryserver.chromium.linux:closure_compilation
Change-Id: Idbbd9470cd966a47bb4b16472f05f30fe4990c4c
Reviewed-on: https://chromium-review.googlesource.com/679283
Commit-Queue: Rebekah Potter <rbpotter@chromium.org>
Reviewed-by: default avatarLei Zhang <thestig@chromium.org>
Cr-Commit-Position: refs/heads/master@{#510151}
parent 5dfbdc57
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "base/task_scheduler/post_task.h" #include "base/task_scheduler/post_task.h"
#include "chrome/browser/printing/pwg_raster_converter.h" #include "chrome/browser/printing/pwg_raster_converter.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/print_preview/printer_capabilities.h"
#include "components/cloud_devices/common/cloud_device_description.h" #include "components/cloud_devices/common/cloud_device_description.h"
#include "components/cloud_devices/common/printer_description.h" #include "components/cloud_devices/common/printer_description.h"
#include "device/base/device_client.h" #include "device/base/device_client.h"
...@@ -308,8 +309,11 @@ void ExtensionPrinterHandler::WrapGetCapabilityCallback( ...@@ -308,8 +309,11 @@ void ExtensionPrinterHandler::WrapGetCapabilityCallback(
const base::DictionaryValue& capability) { const base::DictionaryValue& capability) {
std::unique_ptr<base::DictionaryValue> capabilities = std::unique_ptr<base::DictionaryValue> capabilities =
std::make_unique<base::DictionaryValue>(); std::make_unique<base::DictionaryValue>();
if (!capability.empty()) // empty capability -> empty return dictionary std::unique_ptr<base::DictionaryValue> cdd =
capabilities->SetPath({printing::kSettingCapabilities}, capability.Clone()); printing::ValidateCddForPrintPreview(capability);
// TODO (thestig): Remove call to Clone().
if (!cdd->empty()) // empty capability -> empty return dictionary
capabilities->SetPath({printing::kSettingCapabilities}, cdd->Clone());
callback.Run(std::move(capabilities)); callback.Run(std::move(capabilities));
} }
......
...@@ -33,6 +33,17 @@ namespace printing { ...@@ -33,6 +33,17 @@ namespace printing {
const char kPrinter[] = "printer"; const char kPrinter[] = "printer";
// Keys for a dictionary specifying a custom vendor capability. See
// settings/advanced_settings/advanced_settings_item.js in
// chrome/browser/resources/print_preview.
const char kOptionKey[] = "option";
const char kSelectCapKey[] = "select_cap";
const char kSelectString[] = "SELECT";
const char kTypeKey[] = "type";
// The dictionary key for the CDD item containing custom vendor capabilities.
const char kVendorCapabilityKey[] = "vendor_capability";
namespace { namespace {
// Returns a dictionary representing printer capabilities as CDD. Returns // Returns a dictionary representing printer capabilities as CDD. Returns
...@@ -118,6 +129,39 @@ void PrintersToValues(const printing::PrinterList& printer_list, ...@@ -118,6 +129,39 @@ void PrintersToValues(const printing::PrinterList& printer_list,
} }
} }
template <typename Predicate>
base::Value GetFilteredList(const base::Value* list, Predicate pred) {
auto out_list = list->Clone();
base::EraseIf(out_list.GetList(), pred);
return out_list;
}
bool ValueIsNull(const base::Value& val) {
return val.is_none();
}
bool VendorCapabilityInvalid(const base::Value& val) {
if (!val.is_dict())
return true;
const base::Value* option_type =
val.FindPathOfType({kTypeKey}, base::Value::Type::STRING);
if (!option_type)
return true;
if (option_type->GetString() != kSelectString)
return false;
const base::Value* select_cap =
val.FindPathOfType({kSelectCapKey}, base::Value::Type::DICTIONARY);
if (!select_cap)
return true;
const base::Value* options_list =
select_cap->FindPathOfType({kOptionKey}, base::Value::Type::LIST);
if (!options_list || options_list->GetList().empty() ||
GetFilteredList(options_list, ValueIsNull).GetList().empty()) {
return true;
}
return false;
}
} // namespace } // namespace
std::pair<std::string, std::string> GetPrinterNameAndDescription( std::pair<std::string, std::string> GetPrinterNameAndDescription(
...@@ -181,4 +225,59 @@ void ConvertPrinterListForCallback( ...@@ -181,4 +225,59 @@ void ConvertPrinterListForCallback(
callback.Run(printers); callback.Run(printers);
done_callback.Run(); done_callback.Run();
} }
std::unique_ptr<base::DictionaryValue> ValidateCddForPrintPreview(
const base::DictionaryValue& cdd) {
auto out_final =
base::DictionaryValue::From(std::make_unique<base::Value>(cdd.Clone()));
const base::Value* caps = cdd.FindPath({kPrinter});
if (!caps || !caps->is_dict())
return out_final;
out_final->RemovePath({kPrinter});
auto out_caps = std::make_unique<base::DictionaryValue>();
for (const auto capability : caps->DictItems()) {
const auto& path = capability.first;
const base::Value* dict =
caps->FindPathOfType({path}, base::Value::Type::DICTIONARY);
const base::Value* list =
dict ? dict->FindPathOfType({kOptionKey}, base::Value::Type::LIST)
: caps->FindPathOfType({path}, base::Value::Type::LIST);
if (!list) {
out_caps->SetPath({path}, capability.second.Clone());
continue;
}
bool is_vendor_capability = path == kVendorCapabilityKey;
auto out_list = GetFilteredList(
list, is_vendor_capability ? VendorCapabilityInvalid : ValueIsNull);
if (out_list.GetList().empty()) // leave out empty lists.
continue;
if (is_vendor_capability) {
// Need to also filter the individual capability lists.
for (auto& vendor_option : out_list.GetList()) {
if (vendor_option.FindPathOfType({kTypeKey}, base::Value::Type::STRING)
->GetString() != kSelectString) {
continue;
}
base::Value* options_dict = vendor_option.FindPathOfType(
{kSelectCapKey}, base::Value::Type::DICTIONARY);
base::Value* options_list =
options_dict->FindPathOfType({kOptionKey}, base::Value::Type::LIST);
options_dict->SetPath({kOptionKey},
GetFilteredList(options_list, ValueIsNull));
}
}
if (dict) {
base::Value::DictStorage option_dict;
option_dict[kOptionKey] =
std::make_unique<base::Value>(std::move(out_list));
out_caps->SetPath({path}, base::Value(option_dict));
} else {
out_caps->SetPath({path}, std::move(out_list));
}
}
out_final->SetDictionary(kPrinter, std::move(out_caps));
return out_final;
}
} // namespace printing } // namespace printing
...@@ -17,6 +17,15 @@ namespace printing { ...@@ -17,6 +17,15 @@ namespace printing {
struct PrinterBasicInfo; struct PrinterBasicInfo;
// Printer capability setting keys.
extern const char kOptionKey[];
extern const char kPrinter[];
extern const char kTypeKey[];
extern const char kSelectCapKey[];
extern const char kSelectString[];
extern const char kTypeKey[];
extern const char kVendorCapabilityKey[];
// Extracts the printer display name and description from the // Extracts the printer display name and description from the
// appropriate fields in |printer| for the platform. // appropriate fields in |printer| for the platform.
std::pair<std::string, std::string> GetPrinterNameAndDescription( std::pair<std::string, std::string> GetPrinterNameAndDescription(
...@@ -35,6 +44,12 @@ void ConvertPrinterListForCallback( ...@@ -35,6 +44,12 @@ void ConvertPrinterListForCallback(
const PrinterHandler::AddedPrintersCallback& callback, const PrinterHandler::AddedPrintersCallback& callback,
const PrinterHandler::GetPrintersDoneCallback& done_callback, const PrinterHandler::GetPrintersDoneCallback& done_callback,
const printing::PrinterList& printer_list); const printing::PrinterList& printer_list);
// Returns a unique_ptr to a sanitized version of |cdd| to prevent possible JS
// errors in Print Preview. Will remove null items from lists or options lists
// and remove any lists/options that are empty or only contain null values.
std::unique_ptr<base::DictionaryValue> ValidateCddForPrintPreview(
const base::DictionaryValue& cdd);
} // namespace printing } // namespace printing
#endif // CHROME_BROWSER_UI_WEBUI_PRINT_PREVIEW_PRINTER_CAPABILITIES_H_ #endif // CHROME_BROWSER_UI_WEBUI_PRINT_PREVIEW_PRINTER_CAPABILITIES_H_
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/stl_util.h"
#include "base/test/values_test_util.h" #include "base/test/values_test_util.h"
#include "chrome/browser/ui/webui/print_preview/printer_capabilities.h" #include "chrome/browser/ui/webui/print_preview/printer_capabilities.h"
#include "content/public/test/test_browser_thread_bundle.h" #include "content/public/test/test_browser_thread_bundle.h"
...@@ -16,6 +17,212 @@ ...@@ -16,6 +17,212 @@
namespace printing { namespace printing {
namespace {
const char kCollate[] = "collate";
const char kDisplayName[] = "display_name";
const char kDpi[] = "dpi";
const char kId[] = "id";
const char kIsDefault[] = "is_default";
const char kMediaSizes[] = "media_sizes";
const char kPagesPerSheet[] = "Pages per sheet";
const char kPaperType[] = "Paper Type";
const char kValue[] = "value";
const char kVendorCapability[] = "vendor_capability";
base::DictionaryValue GetCapabilitiesFull() {
base::DictionaryValue printer;
base::Value::ListStorage list_media;
list_media.push_back(base::Value("Letter"));
list_media.push_back(base::Value("A4"));
printer.SetPath({kMediaSizes}, base::Value(list_media));
base::Value::ListStorage list_dpi;
list_dpi.push_back(base::Value(300));
list_dpi.push_back(base::Value(600));
base::Value::DictStorage options;
options[kOptionKey] = std::make_unique<base::Value>(list_dpi);
printer.SetPath({kDpi}, base::Value(options));
printer.SetPath({kCollate}, base::Value(true));
base::Value::ListStorage pages_per_sheet;
for (int i = 1; i <= 8; i *= 2) {
base::Value::DictStorage option;
option[kDisplayName] = std::make_unique<base::Value>(std::to_string(i));
option[kValue] = std::make_unique<base::Value>(i);
if (i == 1)
option[kIsDefault] = std::make_unique<base::Value>(true);
pages_per_sheet.push_back(base::Value(option));
}
base::Value::DictStorage pages_per_sheet_option;
pages_per_sheet_option[kOptionKey] =
std::make_unique<base::Value>(pages_per_sheet);
base::Value::DictStorage pages_per_sheet_capability;
pages_per_sheet_capability[kDisplayName] =
std::make_unique<base::Value>(kPagesPerSheet);
pages_per_sheet_capability[kId] =
std::make_unique<base::Value>(kPagesPerSheet);
pages_per_sheet_capability[kTypeKey] =
std::make_unique<base::Value>(kSelectString);
pages_per_sheet_capability[kSelectCapKey] =
std::make_unique<base::Value>(pages_per_sheet_option);
base::Value::ListStorage paper_types;
base::Value::DictStorage option1;
option1[kDisplayName] = std::make_unique<base::Value>("Plain");
option1[kValue] = std::make_unique<base::Value>("Plain");
option1[kIsDefault] = std::make_unique<base::Value>(true);
base::Value::DictStorage option2;
option2[kDisplayName] = std::make_unique<base::Value>("Photo");
option2[kValue] = std::make_unique<base::Value>("Photo");
paper_types.push_back(base::Value(option1));
paper_types.push_back(base::Value(option2));
base::Value::DictStorage paper_type_option;
paper_type_option[kOptionKey] = std::make_unique<base::Value>(paper_types);
base::Value::DictStorage paper_type_capability;
paper_type_capability[kDisplayName] =
std::make_unique<base::Value>(kPaperType);
paper_type_capability[kId] = std::make_unique<base::Value>(kPaperType);
paper_type_capability[kTypeKey] =
std::make_unique<base::Value>(kSelectString);
paper_type_capability[kSelectCapKey] =
std::make_unique<base::Value>(paper_type_option);
base::Value::ListStorage vendor_capabilities;
vendor_capabilities.push_back(base::Value(pages_per_sheet_capability));
vendor_capabilities.push_back(base::Value(paper_type_capability));
printer.SetPath({kVendorCapability}, base::Value(vendor_capabilities));
return printer;
}
base::Value ValidList(const base::Value* list) {
auto out_list = list->Clone();
base::EraseIf(out_list.GetList(),
[](const base::Value& v) { return v.is_none(); });
return out_list;
}
bool HasValidEntry(const base::Value* list) {
return list && !list->GetList().empty() && !ValidList(list).GetList().empty();
}
void CompareStringKeys(const base::Value& expected,
const base::Value& actual,
base::StringPiece key) {
EXPECT_EQ(*(expected.FindPathOfType({key}, base::Value::Type::STRING)),
*(actual.FindPathOfType({key}, base::Value::Type::STRING)));
}
void ValidateList(const base::Value* list_out, const base::Value* input_list) {
auto input_list_valid = ValidList(input_list);
ASSERT_EQ(list_out->GetList().size(), input_list_valid.GetList().size());
for (size_t index = 0; index < list_out->GetList().size(); index++) {
EXPECT_EQ(list_out->GetList()[index], input_list_valid.GetList()[index]);
}
}
void ValidateMedia(const base::Value* printer_out,
const base::Value* expected_list) {
const base::Value* media_out =
printer_out->FindPathOfType({kMediaSizes}, base::Value::Type::LIST);
if (!HasValidEntry(expected_list)) {
EXPECT_FALSE(media_out);
return;
}
ValidateList(media_out, expected_list);
}
void ValidateDpi(const base::Value* printer_out,
const base::Value* expected_dpi) {
const base::Value* dpi_option_out =
printer_out->FindPathOfType({kDpi}, base::Value::Type::DICTIONARY);
if (!expected_dpi) {
EXPECT_FALSE(dpi_option_out);
return;
}
const base::Value* dpi_list =
expected_dpi->FindPathOfType({kOptionKey}, base::Value::Type::LIST);
if (!HasValidEntry(dpi_list)) {
EXPECT_FALSE(dpi_option_out);
return;
}
ASSERT_TRUE(dpi_option_out);
const base::Value* dpi_list_out =
dpi_option_out->FindPathOfType({kOptionKey}, base::Value::Type::LIST);
ASSERT_TRUE(dpi_list_out);
ValidateList(dpi_list_out, dpi_list);
}
void ValidateCollate(const base::Value* printer_out) {
const base::Value* collate_out =
printer_out->FindPathOfType({kCollate}, base::Value::Type::BOOLEAN);
ASSERT_TRUE(collate_out);
}
void ValidateVendorCaps(const base::Value* printer_out,
const base::Value* input_vendor_caps) {
const base::Value* vendor_capability_out =
printer_out->FindPathOfType({kVendorCapability}, base::Value::Type::LIST);
if (!HasValidEntry(input_vendor_caps)) {
ASSERT_FALSE(vendor_capability_out);
return;
}
ASSERT_TRUE(vendor_capability_out);
size_t index = 0;
const base::Value::ListStorage& output_list =
vendor_capability_out->GetList();
for (const auto& input_entry : input_vendor_caps->GetList()) {
if (!HasValidEntry(
input_entry
.FindPathOfType({kSelectCapKey}, base::Value::Type::DICTIONARY)
->FindPathOfType({kOptionKey}, base::Value::Type::LIST))) {
continue;
}
CompareStringKeys(input_entry, output_list[index], kDisplayName);
CompareStringKeys(input_entry, output_list[index], kId);
CompareStringKeys(input_entry, output_list[index], kTypeKey);
const base::Value* select_cap = output_list[index].FindPathOfType(
{kSelectCapKey}, base::Value::Type::DICTIONARY);
ASSERT_TRUE(select_cap);
const base::Value* list =
select_cap->FindPathOfType({kOptionKey}, base::Value::Type::LIST);
ASSERT_TRUE(list);
ValidateList(
list,
input_entry
.FindPathOfType({kSelectCapKey}, base::Value::Type::DICTIONARY)
->FindPathOfType({kOptionKey}, base::Value::Type::LIST));
index++;
}
}
void ValidatePrinter(const base::DictionaryValue* cdd_out,
const base::DictionaryValue& printer) {
const base::Value* printer_out =
cdd_out->FindPathOfType({kPrinter}, base::Value::Type::DICTIONARY);
ASSERT_TRUE(printer_out);
const base::Value* media =
printer.FindPathOfType({kMediaSizes}, base::Value::Type::LIST);
ValidateMedia(printer_out, media);
const base::Value* dpi_dict =
printer.FindPathOfType({kDpi}, base::Value::Type::DICTIONARY);
ValidateDpi(printer_out, dpi_dict);
ValidateCollate(printer_out);
const base::Value* capabilities_list =
printer.FindPathOfType({kVendorCapability}, base::Value::Type::LIST);
ValidateVendorCaps(printer_out, capabilities_list);
}
} // namespace
class PrinterCapabilitiesTest : public testing::Test { class PrinterCapabilitiesTest : public testing::Test {
public: public:
PrinterCapabilitiesTest() {} PrinterCapabilitiesTest() {}
...@@ -66,12 +273,12 @@ TEST_F(PrinterCapabilitiesTest, ProvidedCapabilitiesUsed) { ...@@ -66,12 +273,12 @@ TEST_F(PrinterCapabilitiesTest, ProvidedCapabilitiesUsed) {
// verify capabilities and have one entry // verify capabilities and have one entry
base::DictionaryValue* cdd; base::DictionaryValue* cdd;
ASSERT_TRUE(settings_dictionary->GetDictionary("capabilities", &cdd)); ASSERT_TRUE(settings_dictionary->GetDictionary(kSettingCapabilities, &cdd));
// read the CDD for the dpi attribute. // read the CDD for the dpi attribute.
base::DictionaryValue* caps_dict; base::DictionaryValue* caps_dict;
ASSERT_TRUE(cdd->GetDictionary("printer", &caps_dict)); ASSERT_TRUE(cdd->GetDictionary(kPrinter, &caps_dict));
EXPECT_TRUE(caps_dict->HasKey("dpi")); EXPECT_TRUE(caps_dict->HasKey(kDpi));
} }
// Ensure that the capabilities dictionary is present but empty if the backend // Ensure that the capabilities dictionary is present but empty if the backend
...@@ -91,8 +298,105 @@ TEST_F(PrinterCapabilitiesTest, NullCapabilitiesExcluded) { ...@@ -91,8 +298,105 @@ TEST_F(PrinterCapabilitiesTest, NullCapabilitiesExcluded) {
// verify that capabilities is an empty dictionary // verify that capabilities is an empty dictionary
base::DictionaryValue* caps_dict; base::DictionaryValue* caps_dict;
ASSERT_TRUE(settings_dictionary->GetDictionary("capabilities", &caps_dict)); ASSERT_TRUE(
settings_dictionary->GetDictionary(kSettingCapabilities, &caps_dict));
EXPECT_TRUE(caps_dict->empty()); EXPECT_TRUE(caps_dict->empty());
} }
TEST_F(PrinterCapabilitiesTest, FullCddPassthrough) {
base::DictionaryValue printer = GetCapabilitiesFull();
base::DictionaryValue cdd;
cdd.SetPath({kPrinter}, printer.Clone());
auto cdd_out = ValidateCddForPrintPreview(cdd);
ValidatePrinter(cdd_out.get(), printer);
}
TEST_F(PrinterCapabilitiesTest, FilterBadList) {
base::DictionaryValue printer = GetCapabilitiesFull();
printer.RemovePath({kMediaSizes});
base::Value::ListStorage list_media;
list_media.push_back(base::Value());
list_media.push_back(base::Value());
printer.SetPath({kMediaSizes}, base::Value(list_media));
base::DictionaryValue cdd;
cdd.SetPath({kPrinter}, printer.Clone());
auto cdd_out = ValidateCddForPrintPreview(cdd);
ValidatePrinter(cdd_out.get(), printer);
}
TEST_F(PrinterCapabilitiesTest, FilterBadOptionOneElement) {
base::DictionaryValue printer = GetCapabilitiesFull();
printer.RemovePath({kDpi});
base::Value::DictStorage options;
base::Value::ListStorage list_dpi;
list_dpi.push_back(base::Value());
list_dpi.push_back(base::Value(600));
options[kOptionKey] = std::make_unique<base::Value>(list_dpi);
printer.SetPath({kDpi}, base::Value(options));
base::DictionaryValue cdd;
cdd.SetPath({kPrinter}, printer.Clone());
auto cdd_out = ValidateCddForPrintPreview(cdd);
ValidatePrinter(cdd_out.get(), printer);
}
TEST_F(PrinterCapabilitiesTest, FilterBadOptionAllElement) {
base::DictionaryValue printer = GetCapabilitiesFull();
printer.RemovePath({kDpi});
base::Value::DictStorage options;
base::Value::ListStorage list_dpi;
list_dpi.push_back(base::Value());
list_dpi.push_back(base::Value());
options[kOptionKey] = std::make_unique<base::Value>(list_dpi);
printer.SetPath({kDpi}, base::Value(options));
base::DictionaryValue cdd;
cdd.SetPath({kPrinter}, printer.Clone());
auto cdd_out = ValidateCddForPrintPreview(cdd);
ValidatePrinter(cdd_out.get(), printer);
}
TEST_F(PrinterCapabilitiesTest, FilterBadVendorCapabilityAllElement) {
base::DictionaryValue printer = GetCapabilitiesFull();
base::Value* select_cap_0 =
printer.FindPathOfType({kVendorCapability}, base::Value::Type::LIST)
->GetList()[0]
.FindPathOfType({kSelectCapKey}, base::Value::Type::DICTIONARY);
select_cap_0->RemovePath({kOptionKey});
base::Value::ListStorage option_list;
option_list.push_back(base::Value());
option_list.push_back(base::Value());
select_cap_0->SetPath({kOptionKey}, base::Value(option_list));
base::DictionaryValue cdd;
cdd.SetPath({kPrinter}, printer.Clone());
auto cdd_out = ValidateCddForPrintPreview(cdd);
ValidatePrinter(cdd_out.get(), printer);
}
TEST_F(PrinterCapabilitiesTest, FilterBadVendorCapabilityOneElement) {
base::DictionaryValue printer = GetCapabilitiesFull();
base::Value* vendor_dictionary =
printer.FindPathOfType({kVendorCapability}, base::Value::Type::LIST)
->GetList()[0]
.FindPathOfType({kSelectCapKey}, base::Value::Type::DICTIONARY);
vendor_dictionary->RemovePath({kOptionKey});
base::Value::ListStorage pages_per_sheet;
for (int i = 1; i <= 8; i *= 2) {
if (i == 2) {
pages_per_sheet.push_back(base::Value());
continue;
}
base::Value::DictStorage option;
option[kDisplayName] = std::make_unique<base::Value>(std::to_string(i));
option[kValue] = std::make_unique<base::Value>(i);
if (i == 1)
option[kIsDefault] = std::make_unique<base::Value>(true);
pages_per_sheet.push_back(base::Value(option));
}
vendor_dictionary->SetPath({kOptionKey}, base::Value(pages_per_sheet));
base::DictionaryValue cdd;
cdd.SetPath({kPrinter}, printer.Clone());
auto cdd_out = ValidateCddForPrintPreview(cdd);
ValidatePrinter(cdd_out.get(), printer);
}
} // namespace printing } // namespace printing
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "chrome/browser/printing/cloud_print/privet_constants.h" #include "chrome/browser/printing/cloud_print/privet_constants.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/signin_manager_factory.h" #include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/browser/ui/webui/print_preview/printer_capabilities.h"
#include "chrome/common/chrome_switches.h" #include "chrome/common/chrome_switches.h"
#include "components/signin/core/browser/signin_manager.h" #include "components/signin/core/browser/signin_manager.h"
#include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/size.h"
...@@ -190,14 +191,14 @@ void PrivetPrinterHandler::OnGotCapabilities( ...@@ -190,14 +191,14 @@ void PrivetPrinterHandler::OnGotCapabilities(
std::unique_ptr<base::DictionaryValue> printer_info = std::unique_ptr<base::DictionaryValue> printer_info =
std::make_unique<base::DictionaryValue>(); std::make_unique<base::DictionaryValue>();
FillPrinterDescription(name, *description, true, printer_info.get()); FillPrinterDescription(name, *description, true, printer_info.get());
std::unique_ptr<base::DictionaryValue> printer_info_and_caps = base::DictionaryValue printer_info_and_caps;
std::make_unique<base::DictionaryValue>(); printer_info_and_caps.SetDictionary(printing::kPrinter,
printer_info_and_caps->SetDictionary("printer", std::move(printer_info)); std::move(printer_info));
std::unique_ptr<base::DictionaryValue> capabilities_copy = std::unique_ptr<base::DictionaryValue> capabilities_copy =
capabilities->CreateDeepCopy(); capabilities->CreateDeepCopy();
printer_info_and_caps->SetDictionary("capabilities", printer_info_and_caps.SetDictionary(printing::kSettingCapabilities,
std::move(capabilities_copy)); std::move(capabilities_copy));
callback.Run(std::move(printer_info_and_caps)); callback.Run(printing::ValidateCddForPrintPreview(printer_info_and_caps));
privet_capabilities_operation_.reset(); privet_capabilities_operation_.reset();
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment