Skip to content

Commit 7a5460a

Browse files
authored
fix(devtools-proxy-agent): properly forward errors for Socks5 requests (#457)
1 parent f1fb92c commit 7a5460a

File tree

2 files changed

+50
-10
lines changed

2 files changed

+50
-10
lines changed

packages/devtools-proxy-support/src/socks5.spec.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,33 @@ describe('createSocks5Tunnel', function () {
208208
expect(await response.text()).to.equal('OK /hello');
209209
});
210210

211+
it('properly handles forwarding failures', async function () {
212+
tunnel = await setupSocks5Tunnel(
213+
{
214+
useEnvironmentVariableProxies: true,
215+
env: {
216+
MONGODB_PROXY: `http://foo:[email protected]:1`,
217+
},
218+
},
219+
{},
220+
'mongodb://'
221+
);
222+
if (!tunnel) {
223+
// regular conditional instead of assertion so that TS can follow it
224+
expect.fail('failed to create Socks5 tunnel');
225+
}
226+
227+
try {
228+
const fetch = createFetch({
229+
proxy: `socks5://@127.0.0.1:${tunnel.config.proxyPort}`,
230+
});
231+
await fetch('http://example.com/hello');
232+
expect.fail('missed exception');
233+
} catch (err: any) {
234+
expect(err.message).to.include('Socket closed');
235+
}
236+
});
237+
211238
context('with a non-HTTP target', function () {
212239
let netServer: Server;
213240
beforeEach(async function () {

packages/devtools-proxy-support/src/socks5.ts

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,28 @@ export async function connectThroughAgent({
9494
}): Promise<Duplex> {
9595
const channel = await new Promise<Duplex | undefined>((resolve, reject) => {
9696
const req = createFakeHttpClientRequest(dstAddr, dstPort, overrideProtocol);
97-
req.onSocket = (sock) => {
98-
if (sock) resolve(sock);
97+
req.on('error', reject);
98+
const done = (
99+
error: Error | null | undefined,
100+
sock: Duplex | undefined
101+
) => {
102+
req.off('error', reject);
103+
if (error) reject(error);
104+
else if (sock) resolve(sock);
105+
else
106+
reject(
107+
new Error(
108+
'Received neither error object nor socket from agent.createSocket()'
109+
)
110+
);
111+
};
112+
113+
// err isn't actually optional but not part of the Node.js typings
114+
req.onSocket = (
115+
sock: Duplex | undefined,
116+
err?: Error | null | undefined
117+
) => {
118+
done(err, sock);
99119
};
100120
agent.createSocket(
101121
req,
@@ -107,14 +127,7 @@ export async function connectThroughAgent({
107127
// Ideally, we would always be using this callback for retrieving the `sock`
108128
// instance. However, agent-base does not call the callback at all if
109129
// the agent resolved to another agent (as is the case for e.g. `ProxyAgent`).
110-
if (err) reject(err);
111-
else if (sock) resolve(sock);
112-
else
113-
reject(
114-
new Error(
115-
'Received neither error object nor socket from agent.createSocket()'
116-
)
117-
);
130+
done(err, sock);
118131
}
119132
);
120133
});

0 commit comments

Comments
 (0)