/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_netwerk_base_proxy_config_h #define mozilla_netwerk_base_proxy_config_h #include #include "nsCRT.h" #include "nsString.h" #include "nsTArray.h" // NOTE: This file is inspired by Chromium's code. // https://source.chromium.org/chromium/chromium/src/+/main:net/proxy_resolution/proxy_config.h. namespace mozilla { namespace net { // ProxyServer stores the {type, host, port} of a proxy server. // ProxyServer is immutable. class ProxyServer final { public: enum class ProxyType { DIRECT = 0, HTTP, HTTPS, SOCKS, SOCKS4, SOCKS5, FTP, // DEFAULT is a special type used on windows only. DEFAULT }; ProxyServer() = default; ProxyServer(ProxyType aType, const nsACString& aHost, int32_t aPort) : mType(aType), mHost(aHost), mPort(aPort) {} const nsCString& Host() const { return mHost; } int32_t Port() const { return mPort; } ProxyType Type() const { return mType; } void ToHostAndPortStr(nsACString& aOutput) { aOutput.Truncate(); if (mType == ProxyType::DIRECT) { return; } aOutput.Assign(mHost); if (mPort != -1) { aOutput.Append(':'); aOutput.AppendInt(mPort); } } bool operator==(const ProxyServer& aOther) const { return mType == aOther.mType && mHost == aOther.mHost && mPort == aOther.mPort; } bool operator!=(const ProxyServer& aOther) const { return !(*this == aOther); } private: ProxyType mType{ProxyType::DIRECT}; nsCString mHost; int32_t mPort{-1}; }; // This class includes the information about proxy configuration. // It contains enabled proxy servers, exception list, and the url of PAC // script. class ProxyConfig { public: struct ProxyRules { ProxyRules() = default; ~ProxyRules() = default; std::map mProxyServers; }; struct ProxyBypassRules { ProxyBypassRules() = default; ~ProxyBypassRules() = default; CopyableTArray mExceptions; }; ProxyConfig() = default; ProxyConfig(const ProxyConfig& config); ~ProxyConfig() = default; ProxyRules& Rules() { return mRules; } const ProxyRules& Rules() const { return mRules; } ProxyBypassRules& ByPassRules() { return mBypassRules; } const ProxyBypassRules& ByPassRules() const { return mBypassRules; } void SetPACUrl(const nsACString& aUrl) { mPACUrl = aUrl; } const nsCString& PACUrl() const { return mPACUrl; } static ProxyServer::ProxyType ToProxyType(const char* aType) { if (!aType) { return ProxyServer::ProxyType::DIRECT; } if (nsCRT::strcasecmp(aType, "http") == 0) { return ProxyServer::ProxyType::HTTP; } if (nsCRT::strcasecmp(aType, "https") == 0) { return ProxyServer::ProxyType::HTTPS; } if (nsCRT::strcasecmp(aType, "socks") == 0) { return ProxyServer::ProxyType::SOCKS; } if (nsCRT::strcasecmp(aType, "socks4") == 0) { return ProxyServer::ProxyType::SOCKS4; } if (nsCRT::strcasecmp(aType, "socks5") == 0) { return ProxyServer::ProxyType::SOCKS5; } if (nsCRT::strcasecmp(aType, "ftp") == 0) { return ProxyServer::ProxyType::FTP; } return ProxyServer::ProxyType::DIRECT; } static void SetProxyResult(const char* aType, const nsACString& aHostPort, nsACString& aResult) { aResult.AssignASCII(aType); aResult.Append(' '); aResult.Append(aHostPort); } static void SetProxyResultDirect(nsACString& aResult) { // For whatever reason, a proxy is not to be used. aResult.AssignLiteral("DIRECT"); } static void ProxyStrToResult(const nsACString& aSpecificProxy, const nsACString& aDefaultProxy, const nsACString& aSocksProxy, nsACString& aResult) { if (!aSpecificProxy.IsEmpty()) { SetProxyResult("PROXY", aSpecificProxy, aResult); // Protocol-specific proxy. } else if (!aDefaultProxy.IsEmpty()) { SetProxyResult("PROXY", aDefaultProxy, aResult); // Default proxy. } else if (!aSocksProxy.IsEmpty()) { SetProxyResult("SOCKS", aSocksProxy, aResult); // SOCKS proxy. } else { SetProxyResultDirect(aResult); // Direct connection. } } void GetProxyString(const nsACString& aScheme, nsACString& aResult) { SetProxyResultDirect(aResult); nsAutoCString specificProxy; nsAutoCString defaultProxy; nsAutoCString socksProxy; nsAutoCString prefix; ToLowerCase(aScheme, prefix); ProxyServer::ProxyType type = ProxyConfig::ToProxyType(prefix.get()); for (auto& [key, value] : mRules.mProxyServers) { // Break the loop if we found a specific proxy. if (key == type) { value.ToHostAndPortStr(specificProxy); break; } else if (key == ProxyServer::ProxyType::DEFAULT) { value.ToHostAndPortStr(defaultProxy); } else if (key == ProxyServer::ProxyType::SOCKS) { value.ToHostAndPortStr(socksProxy); } } ProxyStrToResult(specificProxy, defaultProxy, socksProxy, aResult); } private: nsCString mPACUrl; ProxyRules mRules; ProxyBypassRules mBypassRules; }; } // namespace net } // namespace mozilla #endif // mozilla_netwerk_base_proxy_config_h