PAC-K008 · module-scope-state

Mutable state outside FindProxyForURL

low · Compatibility across engines

A top-level variable that FindProxyForURL writes to (a cache, a counter, a "first call" flag) assumes one persistent JavaScript context. Engines may run several contexts or recreate them, so the state is unreliable and behaviour becomes non-reproducible.

Why it matters

Engines are free to evaluate the PAC on more than one thread, to recreate the context after a re-fetch, or to keep it for the whole session. Code that memoises dnsResolve results in a top-level object or counts calls therefore works by accident, differs between engines and makes support cases impossible to reproduce. FindProxyForURL should be a pure function of its two arguments; hoisting within one call (PAC-P004) is fine, cross-call state is not. Draft: per-engine context lifetime has not been measured in the lab.

How to fix

Keep top-level declarations constant (lists, proxy strings) and do all per-request work inside the function.

Examples

Bad

var cache = {};
function FindProxyForURL(url, host) {
  if (!(host in cache)) {
    cache[host] = isInNet(dnsResolve(host), "10.0.0.0", "255.0.0.0");
  }
  return cache[host] ? "DIRECT" : "PROXY proxy.corp.example:8080";
}
Open bad example in checker

Good

var internalSuffixes = [".corp.example", ".lab.example"];
function FindProxyForURL(url, host) {
  for (var i = 0; i < internalSuffixes.length; i++) {
    if (dnsDomainIs(host, internalSuffixes[i])) {
      return "DIRECT";
    }
  }
  return "PROXY proxy.corp.example:8080";
}
Open good example in checker

Related rules