Windows WinHTTP (system services, BITS)
Used by: Windows services, BITS, apps using WinHTTP.
Helper library
Emulated helper library (CC0-1.0).
Version ranges and quirks
Windows 11 WinHTTP
| Behaviour | Value | Source |
|---|---|---|
| alert() output | ignored | lab, verified 2026-10-11 |
| Non-ASCII result rejected | false | lab, verified 2026-10-11 |
| shExpMatch is case-sensitive | true | lab, verified 2026-10-11 |
| dnsResolve is IPv4 only | true | lab, verified 2026-10-11 |
| JavaScript level accepted | 2017 | lab, verified 2026-10-11 |
| Calls FindProxyForURLEx if defined | true | lab, verified 2026-10-11 |
| Microsoft *Ex functions | true | lab, verified 2026-10-11 |
| Global variables persist between calls | true | lab, verified 2026-10-11 |
| IPv6 host passed in brackets | true | lab, verified 2026-10-11 |
| Host lower-cased by the engine | false | lab, verified 2026-10-11 |
| Largest PAC file accepted (bytes) | 1048576 | lab, verified 2026-10-11 |
| Functions built into the engine (native) | isPlainHostName, dnsDomainIs, localHostOrDomainIs, isResolvable, isInNet, dnsResolve, myIpAddress, dnsDomainLevels, shExpMatch, weekdayRange, dateRange, timeRange, alert, isResolvableEx, isInNetEx, dnsResolveEx, myIpAddressEx, sortIpAddressList, getClientVersion | lab, verified 2026-10-11 |
| On exception | error | lab, verified 2026-10-11 |
| On non-string / undefined result | stringify | lab, verified 2026-10-11 |
| How the returned string is read | windows | lab, verified 2026-10-11 |
| Proxy keywords understood | PROXY, HTTPS, SOCKS, DIRECT | lab, verified 2026-10-11 |
| URL passed to FindProxyForURL | https_to_origin | lab, verified 2026-10-11 |
Function availability
| Function | chromium | chromium | firefox | pacparser | pacparser | winhttp | wininet | reference |
|---|---|---|---|---|---|---|---|---|
isPlainHostName | yes | yes | yes | yes | yes | yes | yes | yes |
dnsDomainIs | yes | yes | yes | yes | yes | yes | yes | yes |
localHostOrDomainIs | yes | yes | yes | yes | yes | yes | yes | yes |
isResolvable | yes | yes | yes | yes | yes | yes | yes | yes |
isInNet | yes | yes | yes | yes | yes | yes | yes | yes |
dnsResolve | yes | yes | yes | yes | yes | yes | yes | yes |
myIpAddress | yes | yes | yes | yes | yes | yes | yes | yes |
dnsDomainLevels | yes | yes | yes | yes | yes | yes | yes | yes |
shExpMatch | yes | yes | yes | yes | yes | yes | yes | yes |
weekdayRange | yes | yes | yes | yes | yes | yes | yes | yes |
dateRange | yes | yes | yes | yes | yes | yes | yes | yes |
timeRange | yes | yes | yes | yes | yes | yes | yes | yes |
alert | yes | yes | yes | no | yes | yes | yes | yes |
dnsResolveEx | yes | yes | no | yes | yes | yes | yes | no |
myIpAddressEx | yes | yes | no | yes | yes | yes | yes | no |
isResolvableEx | yes | yes | no | yes | yes | yes | yes | no |
isInNetEx | yes | yes | no | yes | yes | yes | yes | no |
sortIpAddressList | yes | yes | no | no | no | yes | yes | no |
Rules with notes for winhttp
- PAC-C001Hostname pattern applied to url instead of host
https URLs are cut to scheme://host:port/ (path, query and user name removed); http URLs are passed whole. Later requests to the same host and scheme with a different path or port could get an earlier, cached answer. lab, verified 2026-10-11
- PAC-C018Upper-case letters in a hostname pattern
host keeps its case (Example.COM arrives as Example.COM, also from BITS). dnsDomainIs and shExpMatch compare case-sensitively; localHostOrDomainIs ignores case. lab, verified 2026-10-11
- PAC-C031IP address written with leading zeros, in hex, as one number or in short form
Passes the host as written; reads leading zeros as octal in isInNet; dnsResolve returns address-like text unchanged; returns a proxy entry unchanged, and the Windows address lookup reads the forms like the browsers. lab, verified 2026-10-11
- PAC-D006Large PAC served without compression
A PAC sent gzip-compressed (Content-Encoding: gzip) failed to load. lab, verified 2026-10-11
- PAC-D007PAC distributed via WPAD DNS discovery
Without a suffix search list: wpad under the primary DNS suffix, then under the connection's own suffix, then wpad.local by multicast DNS, WPAD by NetBIOS and wpad by LLMNR. With a suffix search list: wpad under each listed suffix in order, and no multicast, NetBIOS or LLMNR queries. No DHCP packet was seen during these detection runs. lab, verified 2026-10-11
- PAC-D009PAC loaded from a file path or SMB share
A file:// PAC URL was rejected; no PAC was loaded. lab, verified 2026-10-11
- PAC-D010PAC URL does not return 200
Only status 200 is accepted; 203, 204, 404 and 500 all failed. A 302 redirect to the PAC was followed. A 401 answer (Basic or NTLM) failed. A server that took 29 seconds to answer still worked; one that took 40 seconds failed after about 30 seconds. lab, verified 2026-10-11
- PAC-E001PAC file does not parse
A file that does not compile gives the calling program an error instead of a proxy list; what happens next depends on the program. lab, verified 2026-10-11
- PAC-E002No FindProxyForURL function
A file whose function is spelled findProxyForURL fails with an error to the calling program. A file that defines only FindProxyForURLEx works. lab, verified 2026-10-11
- PAC-E006Evaluation throws an exception
An exception gives the calling program an error instead of a proxy list. .NET Framework and .NET 8 programs then connected directly without showing an error. lab, verified 2026-10-11
- PAC-E007Evaluation did not finish within the time limit
No time limit was observed: a script with an endless loop blocked the calling program for more than 18 minutes, and the script kept running after that program was ended. No memory limit was observed either: a script that kept allocating memory grew to 2.9 GiB. lab, verified 2026-10-11
- PAC-E008Loop without a reachable exit
An endless loop was not stopped: it blocked the calling program for more than 18 minutes and kept running after that program was ended. lab, verified 2026-10-11
- PAC-E010isInNet called with an invalid address, mask or argument count
Own implementation without a check of the mask; answers short masks, leading zeros and a missing mask differently from the browsers. lab, verified 2026-10-11
- PAC-E011Return value is not a valid proxy string
Lenient and different from Chromium: "PROXY a:3128 DIRECT" (no ';') and a tab between entries give DIRECT; lower-case "proxy" or "direct" is ignored; a ',' also separates entries; one empty entry ("PROXY ; PROXY b:1") removes the whole list; the keyword HTTP gives no entries; an unknown keyword is skipped; "PROXY DIRECTORY:80" is read as DIRECT; "PROXY http://a:8080" becomes the proxy "http" on port 80; an IPv6 proxy without brackets is cut at the first ':'. undefined, null and a number give no entries. lab, verified 2026-10-11
- PAC-E012Proxy port out of range or not numeric
The entry is kept with a different port: 99999 became 34463, -1 became 65535, 0 became 80 and "80abc" became 80. lab, verified 2026-10-11
- PAC-E013File saved as UTF-16 instead of UTF-8 or ASCII
A UTF-8 file with or without a byte order mark loads normally. A UTF-16 file and a gzip-compressed response fail to load; a Latin-1 file loads, but its non-ASCII characters are garbled. lab, verified 2026-10-11
- PAC-E017PAC helper called with the wrong number of arguments
isPlainHostName, isInNet and weekdayRange raised an error that ends the script when an argument was missing, extra or null, for example isPlainHostName(), isPlainHostName("a", "b"), isInNet with two or four arguments and weekdayRange(null). dateRange() and timeRange() without arguments returned false. lab, verified 2026-10-11
- PAC-E018Browser or Node.js objects used in the PAC
window and navigator are undefined; using them throws. lab, verified 2026-10-11
- PAC-K001ES2015 to ES2017 syntax (let, const, arrow functions, template literals)
About ES2017. let, const, arrow functions, classes, template strings, destructuring, array spread, async functions and generators work; optional chaining (?.), ??, object spread, BigInt literals, regular-expression lookbehind and named groups are syntax errors, and then the whole file fails to load. lab, verified 2026-10-11
- PAC-K002alert() used in the PAC
alert exists and returns false, with or without arguments; the script continues. lab, verified 2026-10-11
- PAC-K003IPv6 extension functions (isInNetEx, dnsResolveEx, myIpAddressEx)
All six are present (isResolvableEx, isInNetEx, dnsResolveEx, myIpAddressEx, sortIpAddressList, getClientVersion). dnsResolveEx lists IPv4 and IPv6 addresses separated by ';' with IPv6 in brackets, and returns false for a name that does not resolve; isInNetEx needs a prefix such as /8, does not look up host names and is false for /0; getClientVersion returns "1.0". lab, verified 2026-10-11
- PAC-K004FindProxyForURLEx entry point
When both functions are defined, FindProxyForURLEx decides; a file that defines only FindProxyForURLEx works. lab, verified 2026-10-11
- PAC-K005SOCKS keywords mean different versions on different engines
"SOCKS s:1080" is returned as a SOCKS entry; a missing port becomes 1080. "SOCKS5 s:1080" and "SOCKS4 s:1080" are misread as a plain SOCKS entry with the broken host name "5 s" or "4 s". .NET Framework and .NET 8 programs went direct instead of using a SOCKS entry. lab, verified 2026-10-11
- PAC-K006HTTPS proxy keyword without a PROXY fallback
The HTTPS entry is returned to the program unchanged. A .NET Framework program turned it into a broken proxy address and the request failed; a .NET 8 program skipped it for http requests and used no proxy. lab, verified 2026-10-11
- PAC-K007Time functions that answer differently per engine (weekdayRange, dateRange, timeRange)
dateRange and timeRange always return false, whatever the arguments. weekdayRange works with upper-case day names and wraps (FRI to MON); lower-case names raise an error or give false. lab, verified 2026-10-11
- PAC-K008Mutable state outside FindProxyForURL
Top-level variables keep their values between calls; a counter increased by FindProxyForURL gave a different answer on the second call. lab, verified 2026-10-11
- PAC-K009Case-sensitive host comparisons without lower-casing host
The host is passed with the case the program used (Example.COM stays Example.COM); BITS showed the same. An IPv6 host arrives in brackets with its case kept. lab, verified 2026-10-11
- PAC-K010ES2015+ library methods (startsWith, flat, replaceAll, globalThis)
Present: Array includes, String padStart, Object.entries, Map, Set, Promise, Symbol, Proxy, Reflect. Missing (undefined, so a call throws): Array flat, Object.fromEntries, String replaceAll, Array at, globalThis. lab, verified 2026-10-11
- PAC-K013Routing decided by myIpAddress()
myIpAddress returned the machine's IPv4 address, and myIpAddressEx a list of a link-local IPv6 address in brackets followed by the IPv4 address. How Windows chooses among several adapters was not measured. lab, verified 2026-10-11
- PAC-K015Regular-expression syntax inside a shExpMatch pattern
Only * and ? are wildcards; [ ] + ( ) | { } $ are matched literally, so regex alternation never matches. A ^ in the pattern changes the match (shExpMatch("x^", "x^") is false). Matching is case-sensitive. lab, verified 2026-10-11
- PAC-K020JavaScript syntax newer than ES2017 (?., ??, object spread)
Optional chaining (?.), ??, object spread, BigInt literals, regular-expression lookbehind and named groups are syntax errors, and then the whole file fails to load. ES2015 to ES2017 syntax (let, const, arrow functions, classes, template strings, array spread, async functions, generators, **) works. lab, verified 2026-10-11
- PAC-K021Decision depends on the URL path or query
https URLs reach the script as https://host:port/. http URLs reach it whole, but later requests to the same host and scheme, also with another path or port, got an answer that the script had given for an earlier request. lab, verified 2026-10-11
- PAC-K022console used in the PAC
console is undefined; a call throws and the request is handled as a script failure. lab, verified 2026-10-11
- PAC-P006PAC file is large
A PAC body of 1,048,576 bytes (1 MiB) loads; one byte more and the download fails, so the file is not used. lab, verified 2026-10-11
- PAC-X001No unconditional return at the end of FindProxyForURL
undefined, null or a number as the result gives an empty list, so the program uses no proxy. lab, verified 2026-10-11
- PAC-X013PROXY entry without a port
A missing port becomes 80; the entry is kept, not rejected. lab, verified 2026-10-11
- PAC-X014DIRECT as fallback after a proxy
Windows returns the whole list, DIRECT included. Older Windows programs (.NET Framework, .NET 8) get only the entries before the first DIRECT: .NET Framework programs then added a DIRECT of their own after the last proxy, even where the PAC returned no DIRECT, while .NET 8 programs did not fall back to DIRECT at all. lab, verified 2026-10-11