Commit d0add841 authored by Luum Habtemariam's avatar Luum Habtemariam Committed by Commit Bot

Convert cups_ipp_parser.mojom.Value to mojo_base.Value

Originally rolled my own value mojom representation, but have since
started maintaining the libCUPS ValueType separately, ergo rewrite.

Bug: chromium:945409
Test: unittests still pass
Change-Id: Ie8c2009f57b06930aa4d40e50b023aa71fa04e10
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1672488
Commit-Queue: Luum Habtemariam <luum@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarKen Rockot <rockot@google.com>
Reviewed-by: default avatarSean Kau <skau@chromium.org>
Cr-Commit-Position: refs/heads/master@{#676117}
parent 6ec8a181
......@@ -11,6 +11,7 @@
#include "base/strings/strcat.h"
#include "base/strings/string_split.h"
#include "base/values.h"
#include "net/http/http_util.h"
namespace ipp_converter {
......@@ -21,6 +22,8 @@ using ValueType = cups_ipp_parser::mojom::ValueType;
const char kStatusDelimiter[] = " ";
const char kHeaderDelimiter[] = ": ";
const size_t kIppDateSize = 11;
// Callback used with ippReadIO (libCUPS API),
// Repeatedly used to copy IPP request buffer -> ipp_t.
ssize_t IppRead(base::span<const uint8_t>* src,
......@@ -87,6 +90,7 @@ base::Optional<ValueType> ValueTagToType(const int value_tag) {
case IPP_TAG_DATE:
return ValueType::DATE;
case IPP_TAG_INTEGER:
case IPP_TAG_ENUM:
return ValueType::INTEGER;
// Below string cases take from libCUPS ippAttributeString API
......@@ -107,9 +111,44 @@ base::Optional<ValueType> ValueTagToType(const int value_tag) {
}
// Fail to convert any unrecognized types.
DVLOG(1) << "Failed to convert CUPS value tag, type " << value_tag;
return base::nullopt;
}
std::vector<bool> IppGetBools(ipp_attribute_t* attr) {
std::vector<bool> ret;
for (int i = 0; i < ippGetCount(attr); ++i) {
// No decipherable failure condition for this libCUPS method.
bool v = ippGetBoolean(attr, i);
ret.emplace_back(v);
}
return ret;
}
base::Optional<std::vector<int>> IppGetInts(ipp_attribute_t* attr) {
std::vector<int> ret;
for (int i = 0; i < ippGetCount(attr); ++i) {
int v = ippGetInteger(attr, i);
if (!v) {
return base::nullopt;
}
ret.emplace_back(v);
}
return ret;
}
base::Optional<std::vector<std::string>> IppGetStrings(ipp_attribute_t* attr) {
std::vector<std::string> ret;
for (int i = 0; i < ippGetCount(attr); ++i) {
const char* v = ippGetString(
attr, i, nullptr /* TODO(crbug.com/945409): figure out language */);
if (!v) {
return base::nullopt;
}
ret.emplace_back(v);
}
return ret;
}
} // namespace
base::Optional<std::vector<std::string>> ParseRequestLine(
......@@ -316,49 +355,41 @@ cups_ipp_parser::mojom::IppMessagePtr ConvertIppToMojo(ipp_t* ipp) {
}
attrptr->type = type.value();
std::vector<cups_ipp_parser::mojom::ValuePtr> values;
for (int i = 0; i < ippGetCount(attr); ++i) {
auto value = cups_ipp_parser::mojom::Value::New();
switch (attrptr->type) {
case ValueType::BOOLEAN: {
auto v = ippGetBoolean(attr, i);
if (!v) {
return nullptr;
}
value->set_bool_value(v);
break;
}
case ValueType::DATE: {
auto* v = ippGetDate(attr, i);
if (!v) {
return nullptr;
}
value->set_char_value(*v);
break;
attrptr->value = cups_ipp_parser::mojom::IppAttributeValue::New();
switch (attrptr->type) {
case ValueType::BOOLEAN: {
attrptr->value->set_bools(IppGetBools(attr));
break;
}
case ValueType::DATE: {
// Note: We never expect date-attributes to be single-valued.
const uint8_t* v =
reinterpret_cast<const uint8_t*>(ippGetDate(attr, 0));
if (!v) {
return nullptr;
}
case ValueType::INTEGER: {
auto v = ippGetInteger(attr, i);
if (!v) {
return nullptr;
}
value->set_int_value(v);
break;
attrptr->value->set_date(std::vector<uint8_t>(v, v + kIppDateSize));
break;
}
case ValueType::INTEGER: {
auto vals = IppGetInts(attr);
if (!vals.has_value()) {
return nullptr;
}
case ValueType::STRING: {
auto* v = ippGetString(
attr, i, NULL /* TODO(crbug/781061): figure out language */);
if (!v) {
return nullptr;
}
value->set_string_value(v);
break;
attrptr->value->set_ints(*vals);
break;
}
case ValueType::STRING: {
auto vals = IppGetStrings(attr);
if (!vals.has_value()) {
return nullptr;
}
default:
NOTREACHED();
attrptr->value->set_strings(*vals);
break;
}
values.emplace_back(std::move(value));
default:
NOTREACHED();
}
attrptr->values = std::move(values);
attributes.emplace_back(std::move(attrptr));
}
......
......@@ -16,11 +16,15 @@ enum ValueType {
STRING,
};
union Value {
bool bool_value;
int64 int_value;
uint8 char_value;
string string_value;
union IppAttributeValue {
array<bool> bools;
// Per the RFC1903 DateAndTime specification, date's are serialized as a
// string of 11 octets.
array<uint8> date;
array<int32> ints;
array<string> strings;
};
struct IppAttribute {
......@@ -28,7 +32,7 @@ struct IppAttribute {
int64 group_tag;
int64 value_tag;
ValueType type;
array<Value> values;
IppAttributeValue value;
};
struct IppMessage {
......
......@@ -29,57 +29,59 @@ namespace {
// TODO(crbug.com/945409): Extending to supporting arbitrary locales.
const char kLocaleEnglish[] = "en";
// Following ParseXxx methods translate mojom objects representing IPP
// attribute values to formats libCUPS APIs accept.
// Following ConvertXxx methods translate IPP attribute values to formats'
// libCUPS APIs accept.
// Converting to vector<char> for libCUPS API:
// ippAddBooleans(..., int num_values, const char *values)
// TODO(crbug.com/945409): Convert cups_ipp_parser::mojom::Value to using
// mojo_base::Value.
base::Optional<std::vector<char>> ParseBooleans(
const std::vector<cups_ipp_parser::mojom::ValuePtr>& values) {
std::vector<char> ConvertBooleans(std::vector<bool> bools) {
std::vector<char> ret;
for (auto& value : values) {
if (!value->is_bool_value()) {
return base::nullopt;
}
ret.push_back(value->get_bool_value() ? 1 : 0);
}
return ret;
}
// Converting to vector<int> for libCUPS API:
// ippAddIntegers(..., int num_values, const int *values)
base::Optional<std::vector<int>> ParseIntegers(
const std::vector<cups_ipp_parser::mojom::ValuePtr>& values) {
std::vector<int> ret;
for (auto& value : values) {
if (!value->is_int_value()) {
return base::nullopt;
}
ret.push_back(value->get_int_value());
for (bool value : bools) {
ret.push_back(value ? 1 : 0);
}
return ret;
}
// Converting to vector<const char*> for libCUPS API:
// ippAddStrings(..., int num_values, const char *const *values)
base::Optional<std::vector<const char*>> ParseStrings(
const std::vector<cups_ipp_parser::mojom::ValuePtr>& values) {
// Note: The values in the returned vector refer to |strings|; so |strings|
// must outlive them.
std::vector<const char*> ConvertStrings(
const std::vector<std::string>& strings) {
std::vector<const char*> ret;
for (auto& value : values) {
if (!value->is_string_value()) {
return base::nullopt;
}
// ret's cstrings reference |values| strings, so |values| MUST outlive it.
ret.push_back(value->get_string_value().c_str());
for (auto& value : strings) {
ret.push_back(value.c_str());
}
return ret;
}
// Depending on |type|, returns the number of values associated with
// |attr_value|.
size_t GetAttributeValuesSize(
const cups_ipp_parser::mojom::IppAttributePtr& attr) {
const auto& attr_value = attr->value;
switch (attr->type) {
case cups_ipp_parser::mojom::ValueType::DATE:
return 1;
case cups_ipp_parser::mojom::ValueType::BOOLEAN:
DCHECK(attr_value->is_bools());
return attr_value->get_bools().size();
case cups_ipp_parser::mojom::ValueType::INTEGER:
DCHECK(attr_value->is_ints());
return attr_value->get_ints().size();
case cups_ipp_parser::mojom::ValueType::STRING:
DCHECK(attr_value->is_strings());
return attr_value->get_strings().size();
default:
break;
}
DVLOG(1) << "Unknown CupsIppParser ValueType " << attr->type;
return 0;
}
} // namespace
// Verifies that |method|, |endpoint|, and |http_version| form a valid HTTP
......@@ -154,71 +156,71 @@ ipp_t* IppValidator::ValidateIppMessage(
cups_ipp_parser::mojom::IppAttributePtr attribute =
std::move(ipp_message->attributes[i]);
if (ValidateAttribute(ipp_oper_id, attribute->name, attribute->type,
attribute->values.size()))
size_t num_values = GetAttributeValuesSize(attribute);
if (!num_values) {
return nullptr;
}
if (!ValidateAttribute(ipp_oper_id, attribute->name, attribute->type,
num_values)) {
return nullptr;
}
switch (attribute->type) {
case cups_ipp_parser::mojom::ValueType::BOOLEAN: {
base::Optional<std::vector<char>> values =
ParseBooleans(attribute->values);
if (!values.has_value()) {
return nullptr;
}
DCHECK(attribute->value->is_bools());
std::vector<char> values =
ConvertBooleans(attribute->value->get_bools());
auto* attr = ippAddBooleans(
ipp.get(), static_cast<ipp_tag_t>(attribute->group_tag),
attribute->name.c_str(), values->size(), values->data());
attribute->name.c_str(), values.size(), values.data());
if (!attr) {
return nullptr;
}
break;
}
// TODO(crbug.com/945409): Include for multiple value checking.
case cups_ipp_parser::mojom::ValueType::DATE: {
if (!attribute->values.front()->is_char_value()) {
return nullptr;
}
auto date = attribute->values.front()->get_char_value();
auto* attr = ippAddDate(
ipp.get(), static_cast<ipp_tag_t>(attribute->group_tag),
attribute->name.c_str(), static_cast<ipp_uchar_t*>(&date));
DCHECK(attribute->value->is_date());
std::vector<uint8_t> date = attribute->value->get_date();
// Per RFC2910, ipp_uchar_t is defined as an OCTET, so below
// reinterpret_cast is safe.
auto* attr =
ippAddDate(ipp.get(), static_cast<ipp_tag_t>(attribute->group_tag),
attribute->name.c_str(),
reinterpret_cast<const ipp_uchar_t*>(date.data()));
if (!attr) {
return nullptr;
}
break;
}
case cups_ipp_parser::mojom::ValueType::INTEGER: {
base::Optional<std::vector<int>> values =
ParseIntegers(attribute->values);
if (!values.has_value()) {
return nullptr;
}
DCHECK(attribute->value->is_ints());
std::vector<int> values = attribute->value->get_ints();
auto* attr = ippAddIntegers(
ipp.get(), static_cast<ipp_tag_t>(attribute->group_tag),
static_cast<ipp_tag_t>(attribute->value_tag),
attribute->name.c_str(), values->size(), values->data());
attribute->name.c_str(), values.size(), values.data());
if (!attr) {
return nullptr;
}
break;
}
case cups_ipp_parser::mojom::ValueType::STRING: {
// Note: cstrings_values references attribute->values, i.e.
// cstrings_values MUST outlive attribute->values.
base::Optional<std::vector<const char*>> cstrings_values =
ParseStrings(attribute->values);
if (!cstrings_values.has_value()) {
return nullptr;
}
DCHECK(attribute->value->is_strings());
// Note: cstrings_values references attribute->value's strings, i.e.
// attribute->value MUST outlive cstrings_values.
std::vector<const char*> cstrings_values =
ConvertStrings(attribute->value->get_strings());
auto* attr = ippAddStrings(
ipp.get(), static_cast<ipp_tag_t>(attribute->group_tag),
static_cast<ipp_tag_t>(attribute->value_tag),
attribute->name.c_str(), cstrings_values->size(), kLocaleEnglish,
cstrings_values->data());
attribute->name.c_str(), cstrings_values.size(), kLocaleEnglish,
cstrings_values.data());
if (!attr) {
return nullptr;
}
......
......@@ -22,7 +22,6 @@ namespace {
using cups_ipp_parser::mojom::IppAttributePtr;
using cups_ipp_parser::mojom::IppMessagePtr;
using cups_ipp_parser::mojom::IppRequestPtr;
using cups_ipp_parser::mojom::Value;
using cups_ipp_parser::mojom::ValueType;
using Printer = chromeos::Printer;
......@@ -84,6 +83,7 @@ IppAttributePtr BuildAttributePtr(std::string name,
ret->name = name;
ret->group_tag = group_tag;
ret->value_tag = value_tag;
ret->value = cups_ipp_parser::mojom::IppAttributeValue::New();
return ret;
}
......@@ -116,12 +116,12 @@ IppRequestPtr GetBasicIppRequest() {
IppAttributePtr attr_charset = BuildAttributePtr(
"attributes-charset", IPP_TAG_OPERATION, IPP_TAG_CHARSET);
attr_charset->type = ValueType::STRING;
attr_charset->values.push_back(Value::NewStringValue("utf-8"));
attr_charset->value->set_strings({"utf-8"});
IppAttributePtr attr_natlang = BuildAttributePtr(
"attributes-natural-language", IPP_TAG_OPERATION, IPP_TAG_LANGUAGE);
attr_natlang->type = ValueType::STRING;
attr_natlang->values.push_back(Value::NewStringValue("en"));
attr_natlang->value->set_strings({"en"});
ipp_message->attributes.push_back(std::move(attr_charset));
ipp_message->attributes.push_back(std::move(attr_natlang));
......@@ -177,7 +177,7 @@ TEST_F(IppValidatorTest, MissingHeaderValue) {
EXPECT_TRUE(RunValidateIppRequest(request));
}
// TODO(luum): Test IPP validation.
// TODO(crbug.com/945409): Test IPP validation.
} // namespace
} // namespace cups_proxy
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