chromium/chrome/browser/ui/webui/ash/settings/pages/printing/server_printer_url_util.cc

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/webui/ash/settings/pages/printing/server_printer_url_util.h"

#include "url/gurl.h"

namespace {

// Returns an updated |gurl| with the specified components from the params. If
// |scheme| is not empty, returns an updated GURL with the specified scheme. If
// |replace_port| is true, returns an updated GURL with 631 as the port. 631 is
// the default port for IPP.
GURL UpdateServerPrinterGURL(const GURL& gurl,
                             const std::string& scheme,
                             bool replace_ipp_port) {
  GURL::Replacements replacement;
  if (!scheme.empty()) {
    replacement.SetSchemeStr(scheme);
  }
  if (replace_ipp_port) {
    replacement.SetPortStr("631");
  }
  return gurl.ReplaceComponents(replacement);
}

}  // namespace

namespace ash::settings {

bool HasValidServerPrinterScheme(const GURL& gurl) {
  return gurl.SchemeIsHTTPOrHTTPS() || gurl.SchemeIs("ipp") ||
         gurl.SchemeIs("ipps");
}

std::optional<GURL> GenerateServerPrinterUrlWithValidScheme(
    const std::string& url) {
  std::optional<GURL> gurl = std::make_optional(GURL(url));
  if (!HasValidServerPrinterScheme(*gurl)) {
    // If we're missing a valid scheme, try querying with IPPS first.
    gurl = GURL("ipps://" + url);
  }

  if (!gurl->is_valid()) {
    return std::nullopt;
  }

  // Replaces IPP/IPPS by HTTP/HTTPS. IPP standard describes protocol built
  // on top of HTTP, so both types of addresses have the same meaning in the
  // context of IPP interface. Moreover, the URL must have HTTP/HTTPS scheme
  // to pass IsStandard() test from GURL library (see "Validation of the URL
  // address" below).
  if (gurl->SchemeIs("ipp")) {
    gurl = UpdateServerPrinterGURL(*gurl, "http",
                                   /*replace_ipp_port=*/false);
    // The default port for IPP is 631. If the schema IPP is replaced by HTTP
    // and the port is not explicitly defined in the URL, we have to overwrite
    // the default HTTP port with the default IPP port. For IPPS we do nothing
    // because implementers use the same port for IPPS and HTTPS.
    if (gurl->IntPort() == url::PORT_UNSPECIFIED) {
      gurl = UpdateServerPrinterGURL(*gurl, /*scheme=*/"",
                                     /*replace_ipp_port=*/true);
    }
  } else if (gurl->SchemeIs("ipps")) {
    gurl = UpdateServerPrinterGURL(*gurl, "https",
                                   /*replace_ipp_port=*/false);
  }

  // Check validation of the URL address and return |gurl| if valid.
  return gurl->IsStandard() ? gurl : std::nullopt;
}

}  // namespace ash::settings