blob: 5c5ac8c7024ee890373e1d0e920edfcbebcac66d [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "printing/client_info_helpers.h"
#include "base/no_destructor.h"
#include "base/strings/strcat.h"
#include "base/strings/stringprintf.h"
#include "base/types/optional_util.h"
#include "printing/mojom/print.mojom.h"
#include "third_party/re2/src/re2/re2.h"
namespace printing {
namespace {
bool ValidateClientType(mojom::IppClientInfo::ClientType type) {
return type >= mojom::IppClientInfo::ClientType::kMinValue &&
type <= mojom::IppClientInfo::ClientType::kMaxValue;
}
bool ValidateStringMember(const std::string* value, size_t max_length) {
static const base::NoDestructor<RE2> kStringRegex("[a-zA-Z0-9_.-]*");
return value == nullptr ||
(value->size() <= max_length && RE2::FullMatch(*value, *kStringRegex));
}
// Returns true if all members of `client_info` are valid.
// String members are considered valid if they match the regex [a-zA-Z0-9_.-]*
// and do not exceed the maximum length specified for the respective IPP member
// attribute. The `client_type` member is valid if it is equal to one of the
// enum values defined for the `client-type` IPP attribute.
bool ValidateClientInfoItem(const mojom::IppClientInfo& client_info) {
return ValidateClientType(client_info.client_type) &&
ValidateStringMember(&client_info.client_name,
kClientInfoMaxNameLength) &&
ValidateStringMember(&client_info.client_string_version,
kClientInfoMaxStringVersionLength) &&
ValidateStringMember(base::OptionalToPtr(client_info.client_patches),
kClientInfoMaxPatchesLength) &&
ValidateStringMember(base::OptionalToPtr(client_info.client_version),
kClientInfoMaxVersionLength);
}
} // namespace
absl::optional<std::string> ClientInfoCollectionToCupsOptionValue(
const mojom::IppClientInfo& client_info) {
if (!ValidateClientInfoItem(client_info)) {
return absl::nullopt;
}
std::string name = base::StrCat({"client-name=", client_info.client_name});
std::string type = base::StringPrintf(
"client-type=%d", static_cast<int>(client_info.client_type));
std::string string_version = base::StrCat(
{"client-string-version=", client_info.client_string_version});
// Missing values for 'client-version' and 'client-patches' correspond to
// 'no-value' out-of-band IPP values. We omit them because there is no
// string encoding as a cups_option_t for them that CUPS understands.
std::string version;
if (client_info.client_version.has_value()) {
version =
base::StrCat({"client-version=", client_info.client_version.value()});
}
std::string patches;
if (client_info.client_patches.has_value()) {
patches =
base::StrCat({"client-patches=", client_info.client_patches.value()});
}
// The resulting string may have extra spaces between attributes because
// of missing member attributes which is okay because they are ignored
// by cupsParseOptions.
return base::StringPrintf("{%s %s %s %s %s}", name.c_str(), type.c_str(),
version.c_str(), string_version.c_str(),
patches.c_str());
}
} // namespace printing