// Copyright 2016 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chromeos/printing/printer_configuration.h" #include "base/containers/fixed_flat_set.h" #include "base/guid.h" #include "base/logging.h" #include "base/notreached.h" #include "base/strings/string_piece.h" #include "base/strings/string_util.h" #include "chromeos/printing/printing_constants.h" #include "chromeos/printing/uri.h" #include "net/base/ip_endpoint.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "url/third_party/mozilla/url_parse.h" #include "url/url_constants.h" namespace chromeos { namespace { std::string ToString(Uri::ParserStatus status) { switch (status) { case Uri::ParserStatus::kInvalidPercentEncoding: return "invalid percent encoding"; case Uri::ParserStatus::kDisallowedASCIICharacter: return "disallowed ASCII character"; case Uri::ParserStatus::kInvalidUTF8Character: return "invalid UTF-8 character"; case Uri::ParserStatus::kInvalidScheme: return "invalid scheme"; case Uri::ParserStatus::kInvalidPortNumber: return "invalid port number"; case Uri::ParserStatus::kRelativePathsNotAllowed: return "relative paths not allowed"; case Uri::ParserStatus::kEmptySegmentInPath: return "empty segment in path"; case Uri::ParserStatus::kEmptyParameterNameInQuery: return "empty parameter name in query"; case Uri::ParserStatus::kNoErrors: return "no errors"; } return "unknown error"; } } // namespace std::string ToString(PrinterClass pclass) { switch (pclass) { case PrinterClass::kEnterprise: return "Enterprise"; case PrinterClass::kAutomatic: return "Automatic"; case PrinterClass::kDiscovered: return "Discovered"; case PrinterClass::kSaved: return "Saved"; } NOTREACHED(); return ""; } bool IsValidPrinterUri(const Uri& uri, std::string* error_message) { static constexpr auto kKnownSchemes = base::MakeFixedFlatSet( {"http", "https", "ipp", "ipps", "ippusb", "lpd", "socket", "usb"}); static const std::string kPrefix = "Malformed printer URI: "; if (!kKnownSchemes.contains(uri.GetScheme())) { if (error_message) *error_message = kPrefix + "unknown or missing scheme"; return false; } // Only printer URIs with the lpd scheme are allowed to have Userinfo. if (!uri.GetUserinfo().empty() && uri.GetScheme() != "lpd") { if (error_message) *error_message = kPrefix + "user info is not allowed for this scheme"; return false; } if (uri.GetHost().empty()) { if (error_message) *error_message = kPrefix + "missing host"; return false; } if (uri.GetScheme() == "ippusb" || uri.GetScheme() == "usb") { if (uri.GetPort() > -1) { if (error_message) *error_message = kPrefix + "port is not allowed for this scheme"; return false; } if (uri.GetPath().empty()) { if (error_message) *error_message = kPrefix + "path is required for this scheme"; return false; } } if (uri.GetScheme() == "socket" && !uri.GetPath().empty()) { if (error_message) *error_message = kPrefix + "path is not allowed for this scheme"; return false; } if (!uri.GetFragment().empty()) { if (error_message) *error_message = kPrefix + "fragment is not allowed"; return false; } return true; } bool Printer::PpdReference::IsFilled() const { return autoconf || !user_supplied_ppd_url.empty() || !effective_make_and_model.empty(); } Printer::Printer() : id_(base::GenerateGUID()), source_(SRC_USER_PREFS) {} Printer::Printer(const std::string& id) : id_(id), source_(SRC_USER_PREFS) { if (id_.empty()) id_ = base::GenerateGUID(); } Printer::Printer(const Printer& other) = default; Printer& Printer::operator=(const Printer& other) = default; Printer::~Printer() = default; bool Printer::SetUri(const Uri& uri, std::string* error_message) { if (!IsValidPrinterUri(uri, error_message)) return false; uri_ = uri; return true; } bool Printer::SetUri(const std::string& uri, std::string* error_message) { Uri parsed_uri(uri); const Uri::ParserError& parser_status = parsed_uri.GetLastParsingError(); if (parser_status.status == Uri::ParserStatus::kNoErrors) return SetUri(parsed_uri, error_message); if (error_message) { *error_message = "Malformed URI: " + ToString(parser_status.status); } return false; } bool Printer::IsIppEverywhere() const { return ppd_reference_.autoconf; } net::HostPortPair Printer::GetHostAndPort() const { if (!HasUri()) { return net::HostPortPair(); } return net::HostPortPair(uri_.GetHost(), uri_.GetPort()); } Uri Printer::ReplaceHostAndPort(const net::IPEndPoint& ip) const { if (!HasUri()) { return Uri(); } const std::string host = ip.ToStringWithoutPort(); if (host.empty()) { return Uri(); } Uri uri = uri_; uri.SetHost(host); uri.SetPort(ip.port()); return uri; } Printer::PrinterProtocol Printer::GetProtocol() const { if (uri_.GetScheme() == "usb") return PrinterProtocol::kUsb; if (uri_.GetScheme() == "ipp") return PrinterProtocol::kIpp; if (uri_.GetScheme() == "ipps") return PrinterProtocol::kIpps; if (uri_.GetScheme() == "http") return PrinterProtocol::kHttp; if (uri_.GetScheme() == "https") return PrinterProtocol::kHttps; if (uri_.GetScheme() == "socket") return PrinterProtocol::kSocket; if (uri_.GetScheme() == "lpd") return PrinterProtocol::kLpd; if (uri_.GetScheme() == "ippusb") return PrinterProtocol::kIppUsb; return PrinterProtocol::kUnknown; } bool Printer::HasNetworkProtocol() const { Printer::PrinterProtocol current_protocol = GetProtocol(); switch (current_protocol) { case PrinterProtocol::kIpp: case PrinterProtocol::kIpps: case PrinterProtocol::kHttp: case PrinterProtocol::kHttps: case PrinterProtocol::kSocket: case PrinterProtocol::kLpd: return true; default: return false; } } bool Printer::IsUsbProtocol() const { Printer::PrinterProtocol current_protocol = GetProtocol(); switch (current_protocol) { case PrinterProtocol::kUsb: case PrinterProtocol::kIppUsb: return true; default: return false; } } bool Printer::HasSecureProtocol() const { Printer::PrinterProtocol current_protocol = GetProtocol(); switch (current_protocol) { case PrinterProtocol::kUsb: case PrinterProtocol::kIpps: case PrinterProtocol::kHttps: case PrinterProtocol::kIppUsb: return true; default: return false; } } bool Printer::IsZeroconf() const { return base::EndsWith(uri_.GetHost(), ".local"); } } // namespace chromeos