| // 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<base::StringPiece>( |
| {"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 |