httptoolkit / mockttp

Powerful friendly HTTP mock server & proxy library
https://httptoolkit.com
Apache License 2.0
786 stars 88 forks source link

[BUG] Support for external PAC files #179

Closed smckee-r7 closed 1 month ago

smckee-r7 commented 2 months ago

Hey, So I've been trying to get proxyUrl to work with an external pac file but it doesn't seem to be working. Running the following script with the curl request shows the pac file is never fetched from the local server and mockttp fails to forward the request to the 2nd proxy with the log message, Failed to handle request: buildProxyAgent is not a function:

const mockttp = require("mockttp");

// start local server to host a pac file
const server = require("http").createServer((req, res) => {
  console.log("Request made to PAC file server");
  if (req.url === '/proxy.pac') {
    console.log("PAC file server response");
    res.writeHead(200, { 'Content-Type': 'text/javascript' });
    res.write(`
    function FindProxyForURL(url, host) {
      if (shExpMatch(url, '*www.bbc.com*')) {
        return "PROXY localhost:8096; DIRECT";
      }
      return "DIRECT";
    }`);
  }
  res.end();
});
server.listen(5010, 'localhost', () => console.log("Started PAC file server on localhost:5010"));

// Launch 2 proxies the first using a PAC file that redirects some requests to proxy 2
(async () => {
  const https = await mockttp.generateCACertificate();

  // Proxy 1
  const proxy1 = mockttp.getLocal({ debug: true, http2: false, https });
  await proxy1.start(8095);
  console.log('1st Proxy on 8095');

  await proxy1.forAnyRequest().thenPassThrough({
    beforeRequest: req => {
      console.log('Reached the 1st Proxy:', req.url)
      return req;
    },
    ignoreHostHttpsErrors: true,
    proxyConfig: {
      proxyUrl: 'pac+http://localhost:5010/proxy.pac'
    }
  });

  // Proxy 2
  const proxy2 = mockttp.getLocal({ debug: true, http2: false, https });
  await proxy2.start(8096);
  console.log('bbc.com requests only proxy on 8096');

  await proxy2.forAnyRequest().thenPassThrough({
    beforeRequest: req => {
      console.log('bbc.com request received:', req.url)
      return req;
    },
    ignoreHostHttpsErrors: true
  });
})();

Curl Request: curl -k -x "http://127.0.0.1:8095/" "https://www.bbc.com/" -A "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/81.0"

It looks like buildProxyAgent is an object containing a class rather than a function. This might be related to changes in pac-proxy-agent potentially?

pimterry commented 2 months ago

Hmm, yes that definitely seems broken, and it does look like somehow this doesn't have any existing tests either. Would you be interested in opening a PR? I expect the actual fix isn't too difficult (relevant code is here: https://github.com/httptoolkit/mockttp/blob/main/src/rules/http-agents.ts) and most of the test code we'll need is already in the example above.

smckee-r7 commented 1 month ago

Fixed in #181