1 // Copyright 2018 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/http/proxy_fallback.h"
6
7 #include "net/base/net_errors.h"
8 #include "net/base/proxy_chain.h"
9 #include "net/base/proxy_server.h"
10
11 namespace net {
12
CanFalloverToNextProxy(const ProxyChain & proxy_chain,int error,int * final_error,bool is_for_ip_protection)13 NET_EXPORT bool CanFalloverToNextProxy(const ProxyChain& proxy_chain,
14 int error,
15 int* final_error,
16 bool is_for_ip_protection) {
17 *final_error = error;
18 auto proxy_servers = proxy_chain.proxy_servers();
19 bool has_quic_proxy = std::any_of(
20 proxy_servers.begin(), proxy_servers.end(),
21 [](const ProxyServer& proxy_server) { return proxy_server.is_quic(); });
22 if (!proxy_chain.is_direct() && has_quic_proxy) {
23 // The whole chain should be QUIC.
24 for (const auto& proxy_server : proxy_servers) {
25 CHECK(proxy_server.is_quic());
26 }
27 switch (error) {
28 case ERR_QUIC_PROTOCOL_ERROR:
29 case ERR_QUIC_HANDSHAKE_FAILED:
30 case ERR_MSG_TOO_BIG:
31 return true;
32 }
33 }
34
35 // TODO(eroman): Split up these error codes across the relevant proxy types.
36 //
37 // A failure to resolve the hostname or any error related to establishing a
38 // TCP connection could be grounds for trying a new proxy configuration.
39 //
40 // Why do this when a hostname cannot be resolved? Some URLs only make sense
41 // to proxy servers. The hostname in those URLs might fail to resolve if we
42 // are still using a non-proxy config. We need to check if a proxy config
43 // now exists that corresponds to a proxy server that could load the URL.
44
45 switch (error) {
46 case ERR_PROXY_CONNECTION_FAILED:
47 case ERR_NAME_NOT_RESOLVED:
48 case ERR_INTERNET_DISCONNECTED:
49 case ERR_ADDRESS_UNREACHABLE:
50 case ERR_CONNECTION_CLOSED:
51 case ERR_CONNECTION_TIMED_OUT:
52 case ERR_CONNECTION_RESET:
53 case ERR_CONNECTION_REFUSED:
54 case ERR_CONNECTION_ABORTED:
55 case ERR_TIMED_OUT:
56 case ERR_SOCKS_CONNECTION_FAILED:
57 // ERR_PROXY_CERTIFICATE_INVALID can happen in the case of trying to talk to
58 // a proxy using SSL, and ending up talking to a captive portal that
59 // supports SSL instead.
60 case ERR_PROXY_CERTIFICATE_INVALID:
61 // ERR_SSL_PROTOCOL_ERROR can happen when trying to talk SSL to a non-SSL
62 // server (like a captive portal).
63 case ERR_SSL_PROTOCOL_ERROR:
64 return true;
65
66 case ERR_SOCKS_CONNECTION_HOST_UNREACHABLE:
67 // Remap the SOCKS-specific "host unreachable" error to a more
68 // generic error code (this way consumers like the link doctor
69 // know to substitute their error page).
70 //
71 // Note that if the host resolving was done by the SOCKS5 proxy, we can't
72 // differentiate between a proxy-side "host not found" versus a proxy-side
73 // "address unreachable" error, and will report both of these failures as
74 // ERR_ADDRESS_UNREACHABLE.
75 *final_error = ERR_ADDRESS_UNREACHABLE;
76 return false;
77
78 case ERR_TUNNEL_CONNECTION_FAILED:
79 // A failure while establishing a tunnel to the proxy is only considered
80 // grounds for fallback when connecting to an IP Protection proxy. Other
81 // browsers similarly don't fallback, and some client's PAC configurations
82 // rely on this for some degree of content blocking. See
83 // https://crbug.com/680837 for details.
84 return is_for_ip_protection;
85 }
86 return false;
87 }
88
89 } // namespace net
90