blob: f25bef2a2ae4224307cd5880c3c60f456d0d04bf [file] [log] [blame]
// 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 "net/proxy_resolution/win/windows_system_proxy_resolution_service.h"
#include <utility>
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/values.h"
#include "base/win/windows_version.h"
#include "net/base/net_errors.h"
#include "net/base/net_info_source_list.h"
#include "net/log/net_log.h"
#include "net/log/net_log_event_type.h"
#include "net/log/net_log_with_source.h"
#include "net/proxy_resolution/win/windows_system_proxy_resolution_request.h"
#include "net/proxy_resolution/win/windows_system_proxy_resolver.h"
namespace net {
// static
bool WindowsSystemProxyResolutionService::IsSupported() {
// The sandbox required to run the WinHttp functions used in the resolver is
// only supported in RS1 and later.
if (base::win::GetVersion() < base::win::Version::WIN10_RS1) {
LOG(WARNING) << "WindowsSystemProxyResolutionService is only supported for "
"Windows 10 Version 1607 (RS1) and later.";
return false;
}
return true;
}
// static
std::unique_ptr<WindowsSystemProxyResolutionService>
WindowsSystemProxyResolutionService::Create(
std::unique_ptr<WindowsSystemProxyResolver> windows_system_proxy_resolver,
NetLog* net_log) {
if (!IsSupported() || !windows_system_proxy_resolver)
return nullptr;
return base::WrapUnique(new WindowsSystemProxyResolutionService(
std::move(windows_system_proxy_resolver), net_log));
}
WindowsSystemProxyResolutionService::WindowsSystemProxyResolutionService(
std::unique_ptr<WindowsSystemProxyResolver> windows_system_proxy_resolver,
NetLog* net_log)
: windows_system_proxy_resolver_(std::move(windows_system_proxy_resolver)),
net_log_(net_log) {}
WindowsSystemProxyResolutionService::~WindowsSystemProxyResolutionService() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Cancel any in-progress requests.
// This cancels the internal requests, but leaves the responsibility of
// canceling the high-level ProxyResolutionRequest (by deleting it) to the
// client. Since |pending_requests_| might be modified in one of the requests'
// callbacks (if it deletes another request), iterating through the set in a
// for-loop will not work.
while (!pending_requests_.empty()) {
WindowsSystemProxyResolutionRequest* req = *pending_requests_.begin();
req->ProxyResolutionComplete(ProxyList(), WinHttpStatus::kAborted, 0);
pending_requests_.erase(req);
}
}
int WindowsSystemProxyResolutionService::ResolveProxy(
const GURL& url,
const std::string& method,
const NetworkAnonymizationKey& network_anonymization_key,
ProxyInfo* results,
CompletionOnceCallback callback,
std::unique_ptr<ProxyResolutionRequest>* request,
const NetLogWithSource& net_log,
RequestPriority priority) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!callback.is_null());
DCHECK(request);
net_log.BeginEvent(NetLogEventType::PROXY_RESOLUTION_SERVICE);
// Once it's created, the WindowsSystemProxyResolutionRequest immediately
// kicks off proxy resolution in a separate process.
auto req = std::make_unique<WindowsSystemProxyResolutionRequest>(
this, url, method, network_anonymization_key, results,
std::move(callback), net_log, windows_system_proxy_resolver_.get());
DCHECK(!ContainsPendingRequest(req.get()));
pending_requests_.insert(req.get());
// Completion will be notified through |callback|, unless the caller cancels
// the request using |request|.
*request = std::move(req);
return ERR_IO_PENDING;
}
void WindowsSystemProxyResolutionService::ReportSuccess(
const ProxyInfo& proxy_info) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
const ProxyRetryInfoMap& new_retry_info = proxy_info.proxy_retry_info();
ProxyResolutionService::ProcessProxyRetryInfo(
new_retry_info, proxy_retry_info_, proxy_delegate_);
}
void WindowsSystemProxyResolutionService::SetProxyDelegate(
ProxyDelegate* delegate) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!proxy_delegate_ || !delegate);
proxy_delegate_ = delegate;
}
void WindowsSystemProxyResolutionService::OnShutdown() {
// TODO(crbug.com/40111093): Add cleanup here as necessary. If cleanup
// is unnecessary, update the interface to not require an implementation for
// this so OnShutdown() can be removed.
}
void WindowsSystemProxyResolutionService::ClearBadProxiesCache() {
proxy_retry_info_.clear();
}
const ProxyRetryInfoMap& WindowsSystemProxyResolutionService::proxy_retry_info()
const {
return proxy_retry_info_;
}
base::Value::Dict WindowsSystemProxyResolutionService::GetProxyNetLogValues() {
base::Value::Dict net_info_dict;
// Log proxy settings - Windows system proxy uses the system configuration
{
base::Value::Dict dict;
dict.Set("source", "system");
dict.Set("description", "Windows system proxy configuration");
net_info_dict.Set(kNetInfoProxySettings, std::move(dict));
}
// Log Bad Proxies.
net_info_dict.Set(kNetInfoBadProxies, BuildBadProxiesList(proxy_retry_info_));
return net_info_dict;
}
bool WindowsSystemProxyResolutionService::
CastToConfiguredProxyResolutionService(
ConfiguredProxyResolutionService**
configured_proxy_resolution_service) {
*configured_proxy_resolution_service = nullptr;
return false;
}
bool WindowsSystemProxyResolutionService::ContainsPendingRequest(
WindowsSystemProxyResolutionRequest* req) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return pending_requests_.count(req) == 1;
}
void WindowsSystemProxyResolutionService::RemovePendingRequest(
WindowsSystemProxyResolutionRequest* req) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(ContainsPendingRequest(req));
pending_requests_.erase(req);
}
int WindowsSystemProxyResolutionService::DidFinishResolvingProxy(
const GURL& url,
const std::string& method,
const NetworkAnonymizationKey& network_anonymization_key,
ProxyInfo* result,
WinHttpStatus winhttp_status,
int windows_error,
const NetLogWithSource& net_log) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Log the diagnostic information about the WinHTTP resolution
net_log.AddEvent(
NetLogEventType::PROXY_RESOLUTION_SERVICE_RESOLVED_PROXY_LIST, [&] {
base::Value::Dict resolution_dict;
resolution_dict.Set("winhttp_status", static_cast<int>(winhttp_status));
resolution_dict.Set("windows_error", windows_error);
if (winhttp_status == WinHttpStatus::kOk) {
resolution_dict.Set("proxy_info", result->ToDebugString());
}
return resolution_dict;
});
if (winhttp_status == WinHttpStatus::kOk) {
if (proxy_delegate_) {
proxy_delegate_->OnResolveProxy(url, network_anonymization_key, method,
proxy_retry_info_, result);
}
DeprioritizeBadProxyChains(proxy_retry_info_, result, net_log);
} else {
result->UseDirect();
}
net_log.EndEvent(NetLogEventType::PROXY_RESOLUTION_SERVICE);
return OK;
}
} // namespace net