1 # Proxy support in Chrome
3 This document establishes basic proxy terminology and describes Chrome-specific
8 ## Proxy server identifiers
10 A proxy server is an intermediary used for network requests. A proxy server can
11 be described by its address, along with the proxy scheme that should be used to
14 This can be written as a string using either the "PAC format" or the "URI
17 The PAC format is how one names a proxy server in [Proxy
18 auto-config](https://en.wikipedia.org/wiki/Proxy_auto-config) scripts. For
24 The "URI format" instead encodes the information as a URL. For example:
30 The port number is optional in both formats. When omitted, a per-scheme default
33 See the [Proxy server schemes](#Proxy-server-schemes) section for details on
34 what schemes Chrome supports, and how to write them in the PAC and URI formats.
36 Most UI surfaces in Chrome (including command lines and policy) expect URI
37 formatted proxy server identifiers. However outside of Chrome, proxy servers
38 are generally identified less precisely by just an address -- the proxy
39 scheme is assumed based on context.
41 In Windows' proxy settings there are host and port fields for the
42 "HTTP", "Secure", "FTP", and "SOCKS" proxy. With the exception of "SOCKS",
43 those are all identifiers for insecure HTTP proxy servers (proxy scheme is
48 Proxying in Chrome is done at the URL level.
50 When the browser is asked to fetch a URL, it needs to decide which IP endpoint
51 to send the request to. This can be either a proxy server, or the target host.
53 This is called proxy resolution. The input to proxy resolution is a URL, and
54 the output is an ordered list of [proxy server
55 identifiers](#Proxy-server-identifiers).
57 What proxies to use can be described using either:
59 * [Manual proxy settings](#Manual-proxy-settings) - proxy resolution is defined
60 using a declarative set of rules. These rules are expressed as a mapping from
61 URL scheme to proxy server identifier(s), and a list of proxy bypass rules for
62 when to go DIRECT instead of using the mapped proxy.
64 * PAC script - proxy resolution is defined using a JavaScript program, that is
65 invoked whenever fetching a URL to get the list of proxy server identifiers
68 * Auto-detect - the WPAD protocol is used to probe the network (using DHCP/DNS)
69 and possibly discover the URL of a PAC script.
71 ## Proxy server schemes
73 When using an explicit proxy in the browser, multiple layers of the network
74 request are impacted, depending on the scheme that is used. Some implications
75 of the proxy scheme are:
77 * Is communication to the proxy done over a secure channel?
78 * Is name resolution (ex: DNS) done client side, or proxy side?
79 * What authentication schemes to the proxy server are supported?
80 * What network traffic can be sent through the proxy?
82 Chrome supports these proxy server schemes:
84 * [DIRECT](#DIRECT-proxy-scheme)
85 * [HTTP](#HTTP-proxy-scheme)
86 * [HTTPS](#HTTPS-proxy-scheme)
87 * [SOCKSv4](#SOCKSv4-proxy-scheme)
88 * [SOCKSv5](#SOCKSv5-proxy-scheme)
89 * [QUIC](#QUIC-proxy-scheme)
91 ### DIRECT proxy scheme
93 * Default port: N/A (neither host nor port are applicable)
94 * Example identifier (PAC): `DIRECT`
95 * Example identifier (URI): `direct://`
97 This is a pseudo proxy scheme that indicates instead of using a proxy we are
98 sending the request directly to the target server.
100 It is imprecise to call this a "proxy server", but it is a convenient abstraction.
102 ### HTTP proxy scheme
105 * Example identifier (PAC): `PROXY proxy:8080`, `proxy` (non-standard; don't use)
106 * Example identifiers (URI): `http://proxy:8080`, `proxy:8080` (can omit scheme)
108 Generally when one refers to a "proxy server" or "web proxy", they are talking
111 When using an HTTP proxy in Chrome, name resolution is always deferred to the
112 proxy. HTTP proxies can proxy `http://`, `https://`, `ws://` and `wss://` URLs.
113 (Chrome's FTP support is deprecated, and HTTP proxies cannot proxy `ftp://` anymore)
115 Communication to HTTP proxy servers is insecure, meaning proxied `http://`
116 requests are sent in the clear. When proxying `https://` requests through an
117 HTTP proxy, the TLS exchange is forwarded through the proxy using the `CONNECT`
118 method, so end-to-end encryption is not broken. However when establishing the
119 tunnel, the hostname of the target URL is sent to the proxy server in the
122 HTTP proxies in Chrome support the same HTTP authentiation schemes as for
123 target servers: Basic, Digest, Negotiate, NTLM.
125 ### HTTPS proxy scheme
128 * Example identifier (PAC): `HTTPS proxy:8080`
129 * Example identifier (URI): `https://proxy:8080`
131 This works like an [HTTP proxy](#HTTP-proxy-scheme), except the
132 communication to the proxy server is protected by TLS, and may negotiate
133 HTTP/2 (but not QUIC).
135 Because the connection to the proxy server is secure, https:// requests
136 sent through the proxy are not sent in the clear as with an HTTP proxy.
137 Similarly, since CONNECT requests are sent over a protected channel, the
138 hostnames for proxied https:// URLs is also not revealed.
140 In addition to the usual HTTP authentication methods, HTTPS proxies also
141 support client certificates.
143 HTTPS proxies using HTTP/2 can offer better performance in Chrome than a
144 regular HTTP proxy due to higher connection limits (HTTP/1.1 proxies in Chrome
145 are limited to 32 simultaneous connections across all domains).
147 Chrome, Firefox, and Opera support HTTPS proxies; however, most older HTTP
150 Specifying an HTTPS proxy is generally not possible through system proxy
151 settings. Instead, one must use either a PAC script or a Chrome proxy setting
152 (command line, extension, or policy).
154 See the dev.chromium.org document on [secure web
155 proxies](http://dev.chromium.org/developers/design-documents/secure-web-proxy)
156 for tips on how to run and test against an HTTPS proxy.
158 ### SOCKSv4 proxy scheme
161 * Example identifiers (PAC): `SOCKS4 proxy:8080`, `SOCKS proxy:8080`
162 * Example identifier (URI): `socks4://proxy:8080`
164 SOCKSv4 is a simple transport layer proxy that wraps a TCP socket. Its use
165 is transparent to the rest of the protocol stack; after an initial
166 handshake when connecting the TCP socket (to the proxy), the rest of the
167 loading stack is unchanged.
169 No proxy authentication methods are supported for SOCKSv4.
171 When using a SOCKSv4 proxy, name resolution for target hosts is always done
172 client side, and moreover must resolve to an IPv4 address (SOCKSv4 encodes
173 target address as 4 octets, so IPv6 targets are not possible).
175 There are extensions to SOCKSv4 that allow for proxy side name resolution, and
176 IPv6, namely SOCKSv4a. However Chrome does not allow configuring, or falling
179 A better alternative is to just use the newer version of the protocol, SOCKSv5
180 (which is still 20+ years old).
182 ### SOCKSv5 proxy scheme
185 * Example identifier (PAC): `SOCKS5 proxy:8080`
186 * Example identifiers (URI): `socks://proxy:8080`, `socks5://proxy:8080`
188 [SOCKSv5](https://tools.ietf.org/html/rfc1928) is a transport layer proxy that
189 wraps a TCP socket, and allows for name resolution to be deferred to the proxy.
191 In Chrome when a proxy's scheme is set to SOCKSv5, name resolution is always
192 done proxy side (even though the protocol allows for client side as well). In
193 Firefox client side vs proxy side name resolution can be configured with
194 `network.proxy.socks_remote_dns`; Chrome has no equivalent option and will
195 always use proxy side resolution.
197 No authentication methods are supported for SOCKSv5 in Chrome (although some do
198 exist for the protocol).
200 A handy way to create a SOCKSv5 proxy is with `ssh -D`, which can be used to
201 tunnel web traffic to a remote host over SSH.
203 In Chrome SOCKSv5 is only used to proxy TCP-based URL requests. It cannot be
204 used to relay UDP traffic.
206 ### QUIC proxy scheme
208 * Default (UDP) port: 443
209 * Example identifier (PAC): `QUIC proxy:8080`
210 * Example identifier (URI): `quic://proxy:8080`
212 A QUIC proxy uses QUIC (UDP) as the underlying transport, but otherwise
213 behaves as an HTTP proxy. It has similar properties to an [HTTPS
214 proxy](#HTTPS-proxy-scheme), in that the connection to the proxy server
215 is secure, and connection limits are less restrictive.
217 Support for QUIC proxies in Chrome is currently experimental and not
218 ready for production use. In particular, sending https:// and wss://
219 URLs through a QUIC proxy is [disabled by
220 default](https://bugs.chromium.org/p/chromium/issues/detail?id=969859).
222 Another caveat is that QUIC does not currently support
223 client certificates since it does not use a TLS
224 handshake. This may change in future versions.
226 ## Manual proxy settings
228 The simplest way to configure proxy resolution is by providing a static list of
231 1. A mapping of URL schemes to [proxy server identifiers](#Proxy-server-identifiers).
232 2. A list of [proxy bypass rules](#Proxy-bypass-rules)
234 We refer to this mode of configuration as "manual proxy settings".
236 Manual proxy settings can succinctly describe setups like:
238 * Use proxy `http://foo:8080` for all requests
239 * Use proxy `http://foo:8080` for all requests except those to a `google.com`
241 * Use proxy `http://foo:8080` for all `https://` requests, and proxy
242 `socsk5://mysocks:90` for everything else
244 Although manual proxy settings are a ubiquituous way to configure proxies
245 across platforms, there is no standard representation or feature set.
247 Chrome's manual proxy settings most closely resembles that of WinInet. But it
248 also supports idioms from other platforms -- for instance KDE's notion of
249 reversing the bypass list, or Gnome's interpretation of bypass patterns as
252 When defining manual proxy settings in Chrome, we specify three (possibly
253 empty) lists of [proxy server identifiers](#Proxy-server-identifiers).
255 * proxies for HTTP - A list of proxy server identifiers to use for `http://`
256 requests, if non-empty.
257 * proxies for HTTPS - A list of proxy server identifiers to use for
258 `https://` requests, if non-empty.
259 * other proxies - A list of proxy server identifiers to use for everything
260 else (whatever isn't matched by the other two lists)
262 There are a lot of ways to end up with manual proxy settings in Chrome
263 (discussed in other sections).
265 The following examples will use the command line method. Launching Chrome with
266 `--proxy-server=XXX` (and optionally `--proxy-bypass-list=YYY`)
268 Example: To use proxy `http://foo:8080` for all requests we can launch
269 Chrome with `--proxy-server="http://foo:8080"`. This translates to:
271 * proxies for HTTP - *empty*
272 * proxies for HTTPS - *empty*
273 * other proxies - `http://foo:8080`
275 With the above configuration, if the proxy server was unreachable all requests
276 would fail with `ERR_PROXY_CONNECTION_FAILED`. To address this we could add a
277 fallback to `DIRECT` by launching using
278 `--proxy-server="http://foo:8080,direct://"` (note the comma separated list).
279 This command line means:
281 * proxies for HTTP - *empty*
282 * proxies for HTTPS - *empty*
283 * other proxies - `http://foo:8080`, `direct://`
285 If instead we wanted to proxy only `http://` URLs through the
286 HTTPS proxy `https://foo:443`, and have everything else use the SOCKSv5 proxy
287 `socks5://mysocks:1080` we could launch Chrome with
288 `--proxy-server="http=https://foo:443;socks=socks5://mysocks:1080"`. This now
291 * proxies for HTTP - `https://foo:443`
292 * proxies for HTTPS - *empty*
293 * other proxies - `socks5://mysocks:1080`
295 The command line above uses WinInet's proxy map format, with some additional
298 * Instead of naming proxy servers by just a hostname:port, you can use Chrome's
299 URI format for proxy server identifiers. In other words, you can prefix the
300 proxy scheme so it doesn't default to HTTP.
301 * The `socks=` mapping is understood more broadly as "other proxies". The
302 subsequent proxy list can include proxies of any scheme, however if the
303 scheme is omitted it will be understood as SOCKSv4 rather than HTTP.
305 ### Mapping WebSockets URLs to a proxy
307 [Manual proxy settings](#Manual-proxy-settings) don't have mappings for `ws://`
310 Selecting a proxy for these URL schemes is a bit different from other URL
311 schemes. The algorithm that Chrome uses is:
313 * If "other proxies" is non-empty use it
314 * If "proxies for HTTPS" is non-empty use it
315 * Otherwise use "proxies for HTTP"
317 This is per the recommendation in section 4.1.3 of [RFC
318 6455](https://tools.ietf.org/html/rfc6455).
320 It is possible to route `ws://` and `wss://` separately using a PAC script.
322 ### Proxy credentials in manual proxy settings
324 Most platforms' [manual proxy settings](#Manual-proxy-settings) allow
325 specifying a cleartext username/password for proxy sign in. Chrome does not
326 implement this, and will not use any credentials embedded in the proxy
329 Proxy authentication will instead go through the ordinary flow to find
332 ## Proxy bypass rules
334 In addition to specifying three lists of [proxy server
335 identifiers](#proxy-server-identifiers), Chrome's [manual proxy
336 settings](#Manual-proxy-settings) lets you specify a list of "proxy bypass
339 This ruleset determines whether a given URL should skip use of a proxy all
340 together, even when a proxy is otherwise defined for it.
342 This concept is also known by names like "exception list", "exclusion list" or
345 Proxy bypass rules can be written as an ordered list of strings. Ordering
346 generally doesn't matter, but may when using subtractive rules.
348 When manual proxy settings are specified from the command line, the
349 `--proxy-bypass-list="RULES"` switch can be used, where `RULES` is a semicolon
350 or comma separated list of bypass rules.
352 Following are the string constructions for the bypass rules that Chrome
353 supports. They can be used when defining a Chrome manual proxy settings from
354 command line flags, extensions, or policy.
356 When using system proxy settings, one should use the platform's rule format and
359 ### Bypass rule: Hostname
362 [ URL_SCHEME "://" ] HOSTNAME_PATTERN [ ":" <port> ]
365 Matches a hostname using a wildcard pattern, and an optional scheme and port
370 * `foobar.com` - Matches URL of any scheme and port, whose normalized host is
372 * `*foobar.com` - Matches URL of any scheme and port, whose normalized host
373 ends with `foobar.com` (for instance `blahfoobar.com` and `foo.foobar.com`).
374 * `*.org:443` - Matches URLs of any scheme, using port 443 and whose top level
376 * `https://x.*.y.com:99` - Matches https:// URLs on port 99 whose normalized
377 hostname matches `x.*.y.com`
379 ### Bypass rule: Subdomain
382 [ URL_SCHEME "://" ] "." HOSTNAME_SUFFIX_PATTERN [ ":" PORT ]
385 Hostname patterns that start with a dot are special cased to mean a subdomain
386 matches. `.foo.com` is effectively another way of writing `*.foo.com`.
390 * `.google.com` - Matches `calendar.google.com` and `foo.bar.google.com`, but
392 * `http://.google.com` - Matches only http:// URLs that are a subdomain of `google.com`.
394 ### Bypass rule: IP literal
397 [ SCHEME "://" ] IP_LITERAL [ ":" PORT ]
400 Matches URLs that are IP address literals, and optional scheme and port
401 restrictions. This is a special case of hostname matching that takes into
402 account IP literal canonicalization. For example the rules `[0:0:0::1]` and
403 `[::1]` are equivalent (both represent the same IPv6 address).
409 * `[::1]` - Matches any URL to the IPv6 loopback address.
410 * `[0:0::1]` - Same as above
411 * `http://[::1]:99` - Matches any http:// URL to the IPv6 loopback on port 99
413 ### Bypass rule: IPv4 address range
416 IPV4_LITERAL "/" PREFIX_LENGTH_IN_BITS
419 Matches any URL whose hostname is an IPv4 literal, and falls between the given
422 Note this [only applies to URLs that are IP
423 literals](#Meaning-of-IP-address-range-bypass-rules).
429 ### Bypass rule: IPv6 address range
432 IPV6_LITERAL "/" PREFIX_LENGTH_IN_BITS
435 Matches any URL that is an IPv6 literal that falls between the given range.
436 Note that IPv6 literals must *not* be bracketed.
438 Note this [only applies to URLs that are IP
439 literals](#Meaning-of-IP-address-range-bypass-rules).
444 * `[fefe::]/40` -- WRONG! IPv6 literals must not be bracketed.
446 ### Bypass rule: Simple hostnames
452 Matches hostnames without a period in them, and that are not IP literals. This
453 is a naive string search -- meaning that periods appearing *anywhere* count
454 (including trailing dots!).
456 This rule corresponds to the "Exclude simple hostnames" checkbox on macOS and
457 the "Don't use proxy server for local (intranet) addresses" on Windows.
459 The rule name comes from WinInet, and can easily be confused with the concept
460 of localhost. However the two concepts are completely orthogonal. In practice
461 one wouldn't add rules to bypass localhost, as it is [already done
462 implicitly](#Implicit-bypass-rules).
464 ### Bypass rule: Subtract implicit rules
470 *Subtracts* the [implicit proxy bypass rules](#Implicit-bypass-rules)
471 (localhost and link local addresses). This is generally only needed for test
472 setups. Beware of the security implications to proxying localhost.
474 Whereas regular bypass rules instruct the browser about URLs that should *not*
475 use the proxy, this rule has the opposite effect and tells the browser to
476 instead *use* the proxy.
478 Ordering may matter when using a subtractive rule, as rules will be evaluated
479 in a left-to-right order. `<-loopback>;127.0.0.1` has a subtly different effect
480 than `127.0.0.1;<-loopback>`.
482 ### Meaning of IP address range bypass rules
484 The IP address range bypass rules in manual proxy settings applies only to URL
485 literals. This is not what one would intuitively expect.
489 Say we have have configured a proxy for all requests, but added a bypass rule
490 for `192.168.0.0.1/16`. If we now navigate to `http://foo` (which resolves
491 to `192.168.1.5` in our setup) will the browser connect directly (bypass proxy)
492 because we have indicated a bypass rule that includes this IP?
494 It will go through the proxy.
496 The bypass rule in this case is not applicable, since the browser never
497 actually does a name resolution for `foo`. Proxy resolution happens before
498 name resolution, and depending on what proxy scheme is subsequently chosen,
499 client side name resolution may never be performed.
501 The usefulness of IP range proxy bypass rules is rather limited, as they only
502 apply to requests whose URL was explicitly an IP literal.
504 If proxy decisions need to be made based on the resolved IP address(es) of a
505 URL's hostname, one must use a PAC script.
507 ## Implicit bypass rules
509 Requests to certain hosts will not be sent through a proxy, and will instead be
512 We call these the _implicit bypass rules_. The implicit bypass rules match URLs
513 whose host portion is either a localhost name or a link-local IP literal.
514 Essentially it matches:
525 The complete rules are slightly more complicated. For instance on
526 Windows we will also recognize `loopback`.
528 This concept of implicit proxy bypass rules is consistent with the
529 platform-level proxy support on Windows and macOS (albeit with some differences
530 due to their implementation quirks - see compatibility notes in
531 `net::ProxyBypassRules::MatchesImplicitRules`)
533 Why apply implicit proxy bypass rules in the first place? Certainly there are
534 considerations around ergonomics and user expectation, but the bigger problem
535 is security. Since the web platform treats `localhost` as a secure origin, the
536 ability to proxy it grants extra powers. This is [especially
537 problematic](https://bugs.chromium.org/p/chromium/issues/detail?id=899126) when
538 proxy settings are externally controllable, as when using PAC scripts.
540 Historical support in Chrome:
542 * Prior to M71 there were no implicit proxy bypass rules, except if using
543 [`--winhttp-proxy-resolver`](#winhttp_proxy_resolver-command-line-switch).
544 * In M71 Chrome applied implicit proxy bypass rules to PAC scripts
545 * In M72 Chrome generalized the implicit proxy bypass rules to manually
548 ### Overriding the implicit bypass rules
550 If you want traffic to `localhost` to be sent through a proxy despite the
551 security concerns, it can be done by adding the special proxy bypass rule
552 `<-loopback>`. This has the effect of _subtracting_ the implicit rules.
554 For instance, launch Chrome with the command line flag:
557 --proxy-bypass-list="<-loopback>"
560 Note that there currently is no mechanism to disable the implicit proxy bypass
561 rules when using a PAC script. Proxy bypass lists only apply to manual
562 settings, so the technique above cannot be used to let PAC scripts decide the
563 proxy for localhost URLs.
565 ## Evaluating proxy lists (proxy fallback)
567 Proxy resolution results in a _list_ of [proxy server
568 identifiers](#Proxy-server-identifiers) to use for a
569 given request, not just a single proxy server identifier.
571 For instance, consider this PAC script:
574 function FindProxyForURL(url, host) {
575 if (host == "www.example.com") {
576 return "PROXY proxy1; HTTPS proxy2; SOCKS5 proxy3";
583 What proxy will Chrome use for connections to `www.example.com`, given that
584 we have a choice of three separate proxy server identifiers to choose from
585 {`http://proxy1:80`, `https://proxy2:443`, `socks5://proxy3:1080`}?
587 Initially, Chrome will try the proxies in order. This means first attempting
588 the request through `http://proxy1:80`. If that "fails", the request is
589 next attempted through `https://proxy2:443`. Lastly if that fails, the
590 request is attempted through `socks5://proxy3:1080`.
592 This process is referred to as _proxy fallback_. What constitutes a
593 "failure" is described later.
595 Proxy fallback is stateful. The actual order of proxy attempts made be Chrome
596 is influenced by the past responsiveness of proxy servers.
598 Let's say we request `http://www.example.com/`. Per the PAC script this
599 resolves to a list of three proxy server identifiers:
601 {`http://proxy1:80`, `https://proxy2:443`, `socks5://proxy3:1080`}
603 Chrome will first attempt to issue the request through these proxies in the
606 Let's say that the attempt through `http://proxy1:80` fails, but then the
607 attempt through `https://proxy2:443` succeeds. Chrome will mark
608 `http://proxy1:80` as _bad_ for the next 5 minutes. Being marked as _bad_
609 means that `http://proxy1:80` is de-prioritized with respect to
610 other proxy server identifiers (including `direct://`) that are not marked as
613 That means the next time `http://www.example.com/` is requested, the effective
614 order for proxies to attempt will be:
616 {`https://proxy2:443`, `socks5://proxy3:1080`, `http://proxy1:80`}
618 Conceptually, _bad_ proxies are moved to the end of the list, rather than being
619 removed from consideration all together.
621 What constitutes a "failure" when it comes to triggering proxy fallback depends
622 on the proxy type. Generally speaking, only connection level failures
623 are deemed eligible for proxy fallback. This includes:
625 * Failure resolving the proxy server's DNS
626 * Failure connecting a TCP socket to the proxy server
628 (There are some caveats for how HTTPS and QUIC proxies count failures for
631 Prior to M67, Chrome would consider failures establishing a
632 CONNECT tunnel as an error eligible for proxy fallback. This policy [resulted
633 in problems](https://bugs.chromium.org/p/chromium/issues/detail?id=680837) for
634 deployments whose HTTP proxies intentionally failed certain https:// requests,
635 since that necessitates inducing a failure during the CONNECT tunnel
636 establishment. The problem would occur when a working proxy fallback option
637 like DIRECT was given, since the failing proxy would then be marked as bad.
639 Currently there are no options to configure proxy fallback (including disabling
640 the caching of bad proxies). Future versions of Chrome may [remove caching
641 of bad proxies](https://bugs.chromium.org/p/chromium/issues/detail?id=936130)
642 to make fallback predictable.
644 To investigate issues relating to proxy fallback, one can [collect a NetLog
646 chrome://net-export/](https://dev.chromium.org/for-testers/providing-network-details).
647 These logs can then be loaded with the [NetLog
648 viewer](https://netlog-viewer.appspot.com/).
650 There are a few things of interest in the logs:
652 * The "Proxy" tab will show which proxies (if any) were marked as bad at the
653 time the capture ended.
654 * The "Events" tab notes what the resolved proxy list was, and what the
655 re-ordered proxy list was after taking into account bad proxies.
656 * The "Events" tab notes when a proxy is marked as bad and why (provided the
657 event occurred while capturing was enabled).
659 When debugging issues with bad proxies, it is also useful to reset Chrome's
660 cache of bad proxies. This can be done by clicking the "Clear bad proxies"
662 [chrome://net-internals/#proxy](chrome://net-internals/#proxy). Note the UI
663 will not give feedback that the bad proxies were cleared, however capturing a
664 new NetLog dump can confirm it was cleared.
666 ## Arguments passed to FindProxyForURL() in PAC scripts
668 PAC scripts in Chrome are expected to define a JavaScript function
671 The historical signature for this function is:
674 function FindProxyForURL(url, host) {
679 Scripts can expect to be called with string arguments `url` and `host` such
682 * `url` is a *sanitized* version of the request's URL
683 * `host` is the unbracketed host portion of the origin.
685 Sanitization of the URL means that the path, query, fragment, and identity
686 portions of the URL are stripped. Effectively `url` will be
687 limited to a `scheme://host:port/` style URL
689 Examples of how `FindProxyForURL()` will be called:
692 // Actual URL: https://www.google.com/Foo
693 FindProxyForURL('https://www.google.com/', 'www.google.com')
695 // Actual URL: https://[dead::beef]/foo?bar
696 FindProxyForURL('https://[dead::beef]/', 'dead::beef')
698 // Actual URL: https://www.example.com:8080#search
699 FindProxyForURL('https://www.example.com:8080/', 'example.com')
701 // Actual URL: https://username:password@www.example.com
702 FindProxyForURL('https://www.example.com/', 'example.com')
705 Stripping the path and query from the `url` is a departure from the original
706 Netscape implementation of PAC. It was introduced in Chrome 52 for [security
707 reasons](https://bugs.chromium.org/p/chromium/issues/detail?id=593759).
709 There is currently no option to turn off sanitization of URLs passed to PAC
710 scripts (removed in Chrome 75).
712 The sanitization of http:// URLs currently has a different policy, and does not
713 strip query and path portions of the URL. That said, users are advised not to
714 depend on reading the query/path portion of any URL
715 type, since future versions of Chrome may [deprecate that
716 capability](https://bugs.chromium.org/p/chromium/issues/detail?id=882536) in
717 favor of a consistent policy.
719 ## Resolving client's IP address within a PAC script using myIpAddress()
721 PAC scripts can invoke `myIpAddress()` to obtain the client's IP address. This
722 function returns a single IP literal, or `"127.0.0.1"` on failure.
724 This API is [inherently ambiguous when used on multi-homed
725 hosts](#myIpAddress_myIpAddressEx_and-multi_homed-hosts), as such hosts can
726 have multiple IP addresses and yet the browser can pick just one to return.
728 Chrome's algorithm for `myIpAddress()` favors returning the IP that would be
729 used if we were to connect to the public internet, by executing the following
730 ordered steps and short-circuiting once the first candidate IP is found:
732 1. Select the IP of an interface that can route to public Internet:
733 * Probe for route to `8.8.8.8`.
734 * Probe for route to `2001:4860:4860::8888`.
735 2. Select an IP by doing a DNS resolve of the machine's hostname:
736 * Select the first IPv4 result if there is one.
737 * Select the first IP result if there is one.
738 3. Select the IP of an interface that can route to private IP space:
739 * Probe for route to `10.0.0.0`.
740 * Probe for route to `172.16.0.0`.
741 * Probe for route to `192.168.0.0`.
742 * Probe for route to `FC00::`.
744 Note that when searching for candidate IP addresses, link-local and loopback
745 addresses are skipped over. Link-local or loopback address will only be returned as a
746 last resort when no other IP address was found by following these steps.
748 This sequence of steps explicitly favors IPv4 over IPv6 results, to match
749 Internet Explorer's IPv6 support.
751 *Historical note*: Prior to M72, Chrome's implementation of `myIpAddress()` was
752 effectively just `getaddrinfo(gethostname)`. This is now step 2 of the heuristic.
754 ## Resolving client's IP address within a PAC script using myIpAddressEx()
756 Chrome supports the [Microsoft PAC
757 extension](https://docs.microsoft.com/en-us/windows/desktop/winhttp/myipaddressex)
760 This is like `myIpAddress()`, but instead of returning a single IP address, it
761 can return multiple IP addresses. It returns a string containing a semi-colon
762 separated list of addresses. On failure it returns an empty string to indicate
763 no results (whereas `myIpAddress()` returns `127.0.0.1`).
765 There are some differences with Chrome's implementation:
767 * In Chrome the function is unconditionally defined, whereas in Internet
768 Explorer one must have used the `FindProxyForURLEx` entrypoint.
769 * Chrome [does not necessarily enumerate all of the host's network
770 interfaces](#myIpAddress_myIpAddressEx_and-multi_homed-hosts)
771 * Chrome does not return link-local or loopback addresses (except if no other
772 addresses were found).
774 The algorithm that Chrome uses is nearly identical to that of `myIpAddress()`
775 described earlier, but in certain cases may return multiple IPs.
777 1. Select all the IPs of interfaces that can route to public Internet:
778 * Probe for route to `8.8.8.8`.
779 * Probe for route to `2001:4860:4860::8888`.
780 * If any IPs were found, return them, and finish.
781 2. Select an IP by doing a DNS resolve of the machine's hostname:
782 * If any IPs were found, return them, and finish.
783 3. Select the IP of an interface that can route to private IP space:
784 * Probe for route to `10.0.0.0`.
785 * Probe for route to `172.16.0.0`.
786 * Probe for route to `192.168.0.0`.
787 * Probe for route to `FC00::`.
788 * If any IPs were found, return them, and finish.
790 Note that short-circuiting happens whenever steps 1-3 find a candidate IP. So
791 for example if at least one IP address was discovered by checking routes to
792 public Internet, only those IPs will be returned, and steps 2-3 will not run.
794 ## myIpAddress() / myIpAddressEx() and multi-homed hosts
796 `myIpAddress()` is a poor API for hosts that have multiple IP addresses, as it
797 can only return a single IP, which may or may not be the one you wanted. Both
798 `myIpAddress()` and `myIpAddressEx()` favor returning the IP for the interface
799 that would be used to route to the public internet.
801 As an API, `myIpAddressEx()` offers more flexibility since it can return
802 multiple IP addresses. However Chrome's implementation restricts which IPs a
803 PAC script can see [due to privacy
804 concerns](https://bugs.chromium.org/p/chromium/issues/detail?id=905366). So
805 using `myIpAddressEx()` is not as powerful as enumerating all the host's IPs,
806 and may not address all use-cases.
808 A more reliable strategy for PAC scripts to check which network(s) a user is on
809 is to probe test domains using `dnsResolve()` / `dnsResolveEx()`.
811 Moreover, note that Chrome does not support the Firefox-specific
812 `pacUseMultihomedDNS` option, so adding that global to a PAC script has no
813 special side-effect in Chrome. Whereas in Firefox it reconfigures
814 `myIpAddress()` to be dependent on the target URL that `FindProxyForURL()` was
819 Proxy resolving via PAC works differently on Android than other desktop Chrome
822 * Android Chrome uses the same Chromium PAC resolver, however does not run it
823 out-of-process as on Desktop Chrome. This architectural difference is
824 due to the higher process cost on Android, and means Android Chrome is more
825 susceptible to malicious PAC scripts. The other consequence is that Android
826 Chrome can have distinct regressions from Desktop Chrome as the service setup
827 is quite different (and most `browser_tests` are not run on Android either).
829 * [WebView does not use Chrome's PAC
830 resolver](https://bugs.chromium.org/p/chromium/issues/detail?id=989667).
831 Instead Android WebView uses the Android system's PAC resolver, which is less
832 optimized and uses an old build of V8. When the system is configured to use
833 PAC, Android WebView's net code will see the proxy settings as being a
834 single HTTP proxy on `localhost`. The system localhost proxy will in turn
835 evaluate the PAC script and forward the HTTP request on to the resolved
836 proxy. This translation has a number of effects, including what proxy
837 schemes are supported, the maximum connection limits, how proxy fallback
838 works, and overall performance (the current Android PAC evaluator blocks on
841 * Android system log messages for `PacProcessor` are not related to Chrome or
842 its PAC evaluator. Rather, these are log messages generated by the Android
843 system's PAC implementation. This confusion can arise when users add
844 `alert()` to debug PAC script logic, and then refer to output in `logcat` to
845 try and diagnose a resolving issue in Android Chrome.
847 ## Downloading PAC scripts
849 When a network context is configured to use a PAC script, proxy resolution will
850 stall while downloading the PAC script.
852 Fetches for PAC URLs are initiated by the network stack, and behave differently
853 from ordinary web visible requests:
855 * Must complete within 30 seconds.
856 * Must complete with an HTTP response code of exactly 200.
857 * Must have an uncompressed body smaller than 1 MB.
858 * Do not follow ordinary HTTP caching semantics.
859 * Are never fetched through a proxy
860 * Are not visible to the WebRequest extension API, or to service workers.
861 * Do not support HTTP authentication (ambient authentication may work, but
862 cannot prompt UI for credentials).
863 * Do not support client certificates (including `AutoSelectCertificateForUrls`)
864 * Do not support auxiliary certificate network fetches (will only used cached
865 OCSP, AIA, and CRL responses during certificate verification).
867 ### Caching of successful PAC fetches
869 PAC URLs are always fetched from the network, and never from the HTTP cache.
870 After a PAC URL is successfully fetched, its contents (which are used to create
871 a long-lived Java Script context) will be assumed to be fresh until either:
873 * The network changes (IP address changes, DNS configuration changes)
874 * The response becomes older than 12 hours
875 * A user explicitly invalidates PAC through `chrome://net-internals#proxy`
877 Once considered stale, the PAC URL will be re-fetched the next time proxy
878 resolution is requested.
880 ### Fallback for failed PAC fetches
882 When the proxy settings are configured to use a PAC URL, and that PAC URL
883 cannot be fetched, proxy resolution will fallback to the next option, which is
886 * If using system proxy settings, and the platform supports fallback to manual
887 proxy settings (e.g. Windows), the specified manual proxy servers will be
888 used after the PAC fetch fails.
889 * If using Chrome's proxy settings, and the PAC script was marked as
890 [mandatory](https://developer.chrome.com/extensions/proxy), fallback to
891 `DIRECT` is not permitted. Subsequent network requests will fail proxy
892 resolution and complete with `ERR_MANDATORY_PROXY_CONFIGURATION_FAILED`.
893 * Otherwise proxy resolution will silently fall back to `DIRECT`.
895 ### Recovering from failed PAC fetches
897 When fetching an explicitly configured PAC URL fails, the browser will try to
900 * In exactly 8 seconds
901 * 32 seconds after that
902 * 2 minutes after that
903 * Every 4 hours thereafter
905 This background polling of the PAC URL is only initiated in response to an
906 incoming proxy resolution request, so it will not trigger work when the browser
909 Similarly to successful fetches, the PAC URL will be also be re-fetched
910 whenever the network changes, the proxy settings change, or it was manually
911 invalidated via `chrome://net-internals#proxy`.
915 Note that UTF-8 is *not* the default interpretation of PAC response bodies.
917 The priority for encoding is determined in this order:
919 1. The `charset` property of the HTTP response's `Content-Type`
920 2. Any BOM at the start of response body
921 3. Otherwise defaults to ISO-8859-1.
923 When setting the `Content-Type`, servers should prefer using a mime type of
924 `application/x-ns-proxy-autoconfig` or `application/x-javascript-config`.
925 However in practice, Chrome does not enforce the mime type.
927 ## Capturing a Net Log for debugging proxy resolution issues
929 Issues in proxy resolution are best investigated using a Net Log.
931 A good starting point is to follow the [general instructions for
932 net-export](https://www.chromium.org/for-testers/providing-network-details),
933 *and while the Net Log is being captured perform these steps*:
935 1. Reproduce the failure (ex: load a URL that fails)
936 2. If you can reproduce a success, do so (ex: load a different URL that succeeds).
937 3. In a new tab, navigate to `chrome://net-internals/#proxy` and click both
938 buttons ("Re-apply settings" and "Clear bad proxies").
940 5. Stop the Net Log and save the file.
942 The resulting Net Log should have enough information to diagnose common
943 problems. It can be attached to a bug report, or explored using the [Net Log
944 Viewer](https://netlog-viewer.appspot.com/). See the next section for some tips
947 ## Analyzing Net Logs for proxy issues
949 Load saved Net Logs using [Net Log Viewer](https://netlog-viewer.appspot.com/).
951 ### Proxy overview tab
953 Start by getting a big-picture view of the proxy settings by clicking to the
954 "Proxy" tab on the left. This summarizes the proxy settings at the time the
957 * Does the _original_ proxy settings match expectation?
958 The proxy settings might be coming from:
959 * Managed Chrome policy (chrome://policy)
960 * Command line flags (ex: `--proxy-server`)
961 * (per-profile) Chrome extensions (ex: [chrome.proxy](https://developer.chrome.com/extensions/proxy))
962 * (per-network) System proxy settings
964 * Was [proxy autodetect (WPAD)](#Web-Proxy-Auto_Discovery-WPAD) specified? In
965 this case the final URL probed will be reflected by the difference between
966 the "Effective" and "Original" settings.
968 * Internally, proxy settings are per-NetworkContext. The proxy
969 overview tab shows settings for a *particular* NetworkContext, namely the
970 one associated with the Profile used to navigate to `chrome://net-export`. For
971 instance if the net-export was initiated from an Incognito window, it may
972 show different proxy settings here than a net-export capture initiated by a
973 non-Incognito window. When the net-export was triggered from command line
974 (`--log-net-log`) no particular NetworkContext is associated with the
975 capture and hence no proxy settings will be shown in this overview.
977 * Were any proxies marked as bad?
981 Skim through the Import tab and look for relevant command line flags and active
982 field trials. A find-in-page for `proxy` is a good starting point. Be on the lookout for
983 [`--winhttp-proxy-resolver`](#winhttp_proxy_resolver-command-line-switch) which
984 has [known problems](https://bugs.chromium.org/p/chromium/issues/detail?id=644030).
988 To deep dive into proxy resolution, switch to the Events tab.
990 You can start by filtering on `type:URL_REQUEST` to see all the top level
991 requests, and then keep click through the dependency links to
992 trace the proxy resolution steps and outcome.
994 The most relevant events have either `PROXY_`, `PAC_`, or
995 `WPAD_` in their names. You can also try filtering for each of those.
997 Documentation on specific events is available in
998 [net_log_event_type_list.h](https://chromium.googlesource.com/chromium/src/+/HEAD/net/log/net_log_event_type_list.h).
1000 Network change events can also be key to understanding proxy issues. After
1001 switching networks (ex VPN), the effective proxy settings, as well as content
1002 of any PAC scripts/auto-detect can change.
1004 ## Web Proxy Auto-Discovery (WPAD)
1006 When configured to use WPAD (aka "autotmaticaly detect proxy settings"), Chrome
1009 1. DHCP-based WPAD (option 252)
1012 These are tried in order, however DHCP-based WPAD is only supported for Chrome
1013 on Windows and Chrome on Chrome OS.
1015 WPAD is the system default for many home and Enterprise users.
1017 ### Chrome on macOS support for DHCP-based WPAD
1019 Chrome on macOS does not support DHCP-based WPAD when configured to use
1022 However, macOS might perform DHCP-based WPAD and embed this discovered PAC URL
1023 as part of the system proxy settings. So effectively when Chrome is configured
1024 to "use system proxy settings" it may behave as if it supports DHCP-based WPAD.
1026 ### Dangers of DNS-based WPAD and DNS search suffix list
1028 DNS-based WPAD involves probing for the non-FQDN `wpad`. This means
1029 WPAD's performance and security is directly tied to the user's DNS search
1032 When resolving `wpad`, the host's DNS resolver will complete the hostname using
1033 each of the suffixes in the search list:
1035 1. If the suffix list is long this process can very slow, as it triggers a
1036 cascade of NXDOMAIN.
1037 2. If the suffix list includes domains *outside of the administrative domain*,
1038 WPAD may select an attacker controlled PAC server, and can subsequently
1039 funnel the user's traffic through a proxy server of their choice. The
1040 evolution of TLDs further increases this risk, since what were previously
1041 private suffixes used by an enterprise can become publicly registerable.
1042 See also [WPAD Name Collision
1043 Vulnerability](https://www.us-cert.gov/ncas/alerts/TA16-144A)
1045 ## --winhttp-proxy-resolver command line switch
1047 Passing the `--winhttp-proxy-resolver` command line argument instructs Chrome
1048 to use the system libraries for *one narrow part of proxy resolution*: evaluating
1051 Use of this flag is NOT a supported mode, and has [known
1052 problems](https://bugs.chromium.org/p/chromium/issues/detail?id=644030): It
1053 can break Chrome extensions (`chrome.proxy` API), the interpretation of
1054 Proxy policies, hurt performance, and doesn't ensure full fidelity
1055 interpretation of system proxy settings.
1057 Another oddity of this switch is that it actually gets interpreted with a
1058 smilar meaning on other platforms (macOS), despite its Windows-specific naming.
1060 This flag was historically exposed for debugging, and to mitigate unresolved
1061 policy differences in PAC execution. In the future this switch [will be
1062 removed](https://bugs.chromium.org/p/chromium/issues/detail?id=644030).
1064 Although Chrome would like full fidelity with Windows proxy settings, there are
1065 limits to those integrations. Dependencies like NRPT for proxy
1066 resolution necessitate using Windows proxy resolution libraries directly
1067 instead of Chrome's. We hope these less common use cases will be fully
1069 feature](https://bugs.chromium.org/p/chromium/issues/detail?id=1032820)