chromium/chrome/browser/ash/crosapi/translate_crosapi_to_proxy_config.cc

// Copyright 2021 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/ash/crosapi/network_settings_translation.h"

#include "base/notreached.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "components/proxy_config/proxy_config_dictionary.h"
#include "components/proxy_config/proxy_config_pref_names.h"
#include "components/proxy_config/proxy_prefs.h"
#include "url/url_constants.h"

namespace {

// Some strings are not URL schemes, but they are given in the same spot in
// the proxy server specifier strings. So we return other strings in that
// case.
constexpr char kInvalidScheme[] = "invalid";
constexpr char kDirectScheme[] = "direct";
constexpr char kSocksScheme[] = "socks";
constexpr char kSocks5Scheme[] = "socks5";
constexpr char kQuicScheme[] = "quic";

// Format the proxy url. The request scheme is the scheme the request to the
// actual web server is using. The proxy scheme is the scheme the proxy is using
// to receive requests. For example a proxy receiving its request through http
// can forward requests going to an https server.
std::string FormatProxyUri(const char* request_scheme,
                           const crosapi::mojom::ProxyLocationPtr& proxy) {
  const char* proxy_scheme_string = url::kHttpScheme;

  switch (proxy->scheme) {
    // We map kUnknown to HTTP because this will make the proxy setting work for
    // most deployments with older ASH browser versions which do not support
    // sending the ProxyLocation::Scheme yet, as HTTP is the most commonly used
    // scheme for communicating with a HTTP proxy server.
    case crosapi::mojom::ProxyLocation::Scheme::kUnknown:
      proxy_scheme_string = url::kHttpScheme;
      break;
    case crosapi::mojom::ProxyLocation::Scheme::kInvalid:
      proxy_scheme_string = kInvalidScheme;
      break;
    case crosapi::mojom::ProxyLocation::Scheme::kDirect:
      proxy_scheme_string = kDirectScheme;
      break;
    case crosapi::mojom::ProxyLocation::Scheme::kHttp:
      proxy_scheme_string = url::kHttpScheme;
      break;
    case crosapi::mojom::ProxyLocation::Scheme::kSocks4:
      proxy_scheme_string = kSocksScheme;
      break;
    case crosapi::mojom::ProxyLocation::Scheme::kSocks5:
      proxy_scheme_string = kSocks5Scheme;
      break;
    case crosapi::mojom::ProxyLocation::Scheme::kHttps:
      proxy_scheme_string = url::kHttpsScheme;
      break;
    case crosapi::mojom::ProxyLocation::Scheme::kQuic:
      // Quic support on Chrome OS is experimental. Can be set by an extension
      // in the primary profile.
      proxy_scheme_string = kQuicScheme;
      break;
  }

  return base::StringPrintf("%s=%s://%s:%d", request_scheme,
                            proxy_scheme_string, proxy->host.c_str(),
                            proxy->port);
}

// See //net/docs/proxy.md and net::ProxyConfig::ProxyRules::ParseFromString()
// for translation rules.
base::Value::Dict TranslateManualProxySettings(
    crosapi::mojom::ProxySettingsManualPtr proxy_settings) {
  std::vector<std::string> proxy_server_specs;
  for (auto const& proxy : proxy_settings->http_proxies) {
    proxy_server_specs.push_back(FormatProxyUri(url::kHttpScheme, proxy));
  }
  for (auto const& proxy : proxy_settings->secure_http_proxies) {
    proxy_server_specs.push_back(FormatProxyUri(url::kHttpsScheme, proxy));
  }
  for (auto const& proxy : proxy_settings->socks_proxies) {
    proxy_server_specs.push_back(FormatProxyUri(kSocksScheme, proxy));
  }

  if (proxy_server_specs.empty()) {
    return ProxyConfigDictionary::CreateDirect();
  }
  return ProxyConfigDictionary::CreateFixedServers(
      base::JoinString(proxy_server_specs, ";"),
      base::JoinString(proxy_settings->exclude_domains, ";"));
}

base::Value::Dict TranslatePacProxySettings(
    crosapi::mojom::ProxySettingsPacPtr proxy_settings) {
  if (!proxy_settings->pac_url.is_valid())
    return ProxyConfigDictionary::CreateDirect();
  return ProxyConfigDictionary::CreatePacScript(proxy_settings->pac_url.spec(),
                                                proxy_settings->pac_mandatory);
}

base::Value::Dict TranslateWpadProxySettings(
    crosapi::mojom::ProxySettingsWpadPtr proxy_settings) {
  return ProxyConfigDictionary::CreateAutoDetect();
}

ProxyConfigDictionary DirectProxyConfig() {
  return ProxyConfigDictionary(ProxyConfigDictionary::CreateDirect());
}

}  // namespace

namespace crosapi {

ProxyConfigDictionary CrosapiProxyToProxyConfig(
    crosapi::mojom::ProxyConfigPtr crosapi_proxy) {
  if (!crosapi_proxy)
    return DirectProxyConfig();

  if (crosapi_proxy->proxy_settings->is_direct())
    return DirectProxyConfig();

  if (crosapi_proxy->proxy_settings->is_pac())
    return ProxyConfigDictionary(TranslatePacProxySettings(
        std::move(crosapi_proxy->proxy_settings->get_pac())));

  if (crosapi_proxy->proxy_settings->is_wpad())
    return ProxyConfigDictionary(TranslateWpadProxySettings(
        std::move(crosapi_proxy->proxy_settings->get_wpad())));

  if (crosapi_proxy->proxy_settings->is_manual())
    return ProxyConfigDictionary(TranslateManualProxySettings(
        std::move(crosapi_proxy->proxy_settings->get_manual())));

  NOTREACHED_IN_MIGRATION() << "Invalid crosapi proxy settings";
  return DirectProxyConfig();
}

}  // namespace crosapi