Skip to content

Commit

Permalink
fix: do not proxy traffic to sockets
Browse files Browse the repository at this point in the history
This commit implements a proxy-exception for traffic targeting local
sockets instead of a "host:port" combination. If such traffic would be
forwarded through the proxy, the socket destination info would be lost,
while a "localhost:80" destination would be added. This means that the
proxy cannot handle such requests correctly either way, which makes
sending traffic to the proxy pointless.

Because of that, if the agent receives traffic destined for a socket, it
will simply use the fallback agent to handle that traffic.
  • Loading branch information
tommyknows committed Oct 14, 2022
1 parent f82ad8a commit fe5ea15
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 10 deletions.
13 changes: 13 additions & 0 deletions src/classes/Agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,19 @@ abstract class Agent {
requestUrl = this.protocol + '//' + (configuration.hostname ?? configuration.host) + (configuration.port === 80 ?? configuration.port === 443 ? '' : ':' + configuration.port) + request.path;
}

// If a request should go to a local socket, proxying it through an HTTP
// server does not make sense as the information about the target socket
// will be lost and the proxy won't be able to correctly handle the request.
if (configuration.socketPath) {
log.trace({
destination: configuration.socketPath,
}, "not proxying request; destination is a socket");

// @ts-expect-error seems like we are using wrong type for fallbackAgent.
this.fallbackAgent.addRequest(request, configuration);
return;
}

if (!this.isProxyConfigured()) {
log.trace({
destination: requestUrl,
Expand Down
48 changes: 38 additions & 10 deletions test/global-agent/factories/createGlobalProxyAgent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,44 +270,72 @@ serial('proxies HTTPS request with dedicated proxy', async (t) => {
globalProxyAgent.HTTPS_PROXY = proxyServer.url;

const response: HttpResponseType = await new Promise((resolve) => {
https.get('https://127.0.0.1', {}, createHttpResponseResolver(resolve));
https.get("https://127.0.0.1", {}, createHttpResponseResolver(resolve));
});

t.is(response.body, 'OK');
t.is(response.body, "OK");
});

serial('ignores dedicated HTTPS proxy for HTTP urls', async (t) => {
serial("ignores dedicated HTTPS proxy for HTTP urls", async (t) => {
const globalProxyAgent = createGlobalProxyAgent();

const proxyServer = await createProxyServer();

globalProxyAgent.HTTP_PROXY = proxyServer.url;
globalProxyAgent.HTTPS_PROXY = 'http://example.org';
globalProxyAgent.HTTPS_PROXY = "http://example.org";

const response: HttpResponseType = await new Promise((resolve) => {
http.get('http://127.0.0.1', {}, createHttpResponseResolver(resolve));
http.get("http://127.0.0.1", {}, createHttpResponseResolver(resolve));
});

t.is(response.body, 'OK');
t.is(response.body, "OK");
});

serial('forwards requests matching NO_PROXY', async (t) => {
serial("forwards requests matching NO_PROXY", async (t) => {
const globalProxyAgent = createGlobalProxyAgent();

const proxyServer = await createProxyServer();
const httpServer = await createHttpServer();

globalProxyAgent.HTTP_PROXY = proxyServer.url;
globalProxyAgent.NO_PROXY = '127.0.0.1';
globalProxyAgent.NO_PROXY = "127.0.0.1";

const response: HttpResponseType = await new Promise((resolve) => {
http.get(httpServer.url, createHttpResponseResolver(resolve));
});

t.is(response.body, 'DIRECT');
t.is(response.body, "DIRECT");
});

serial("forwards requests that go to a socket", async (t) => {
const globalProxyAgent = createGlobalProxyAgent();

// not relevant as traffic shouldn't go through proxy
globalProxyAgent.HTTP_PROXY = "localhost:10324";

var server = http.createServer(function (req, res) {
res.writeHead(200);
res.write("OK");
res.end();
});

t.teardown(() => {
server.close();
});
server.listen("/tmp/test.sock");

const response: HttpResponseType = await new Promise((resolve) => {
http.get({
socketPath: "/tmp/test.sock",
path: "/endpoint",
method: "get",
}, createHttpResponseResolver(resolve)
);
});
t.is(response.body, "OK");
});

serial('proxies HTTP request (using http.get(host))', async (t) => {
serial("proxies HTTP request (using http.get(host))", async (t) => {
const globalProxyAgent = createGlobalProxyAgent();

const proxyServer = await createProxyServer();
Expand Down

0 comments on commit fe5ea15

Please sign in to comment.