Skip to content

Commit a8344fb

Browse files
authored
fix: log error message on socket only when there are no other handlers (#623)
1 parent d178688 commit a8344fb

File tree

4 files changed

+85
-16
lines changed

4 files changed

+85
-16
lines changed

src/server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ export class Server extends EventEmitter {
249249
// See https://github.com/apify/proxy-chain/issues/53
250250
socket.on('error', (err) => {
251251
// Handle errors only if there's no other handler
252-
if (this.listenerCount('error') === 1) {
252+
if (socket.listenerCount('error') === 1) {
253253
this.log(socket.proxyChainId, `Source socket emitted error: ${err.stack || err}`);
254254
}
255255
});

test/Dockerfile

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,17 @@
11
FROM node:18.20.8-bookworm@sha256:c6ae79e38498325db67193d391e6ec1d224d96c693a8a4d943498556716d3783
22

3-
RUN apt-get update && apt-get install -y --no-install-recommends chromium=142.0.7444.134-1~deb12u1 \
3+
RUN apt-get update && apt-get install -y --no-install-recommends chromium \
44
&& rm -rf /var/lib/apt/lists/*
55

66
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
77
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
88

99
WORKDIR /home/node
1010

11-
COPY .. .
11+
COPY --chown=node:node package*.json ./
12+
RUN npm --quiet set progress=false && npm install --no-optional
13+
COPY --chown=node:node . .
1214

13-
RUN npm --quiet set progress=false \
14-
&& npm install --no-optional \
15-
&& echo "Installed NPM packages:" \
16-
&& npm list || true \
17-
&& echo "Node.js version:" \
18-
&& node --version \
19-
&& echo "NPM version:" \
20-
&& npm --version
15+
USER node
2116

22-
CMD ["npm", "test"]
17+
ENTRYPOINT [ "npm", "test", "--" ]

test/README.md

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,23 @@
55
Since Linux and macOS handle sockets differently, please run tests in a Docker container
66
to have a consistent Linux environment for running tests.
77

8-
```bash
9-
npm run test:docker
10-
```
8+
1. Run all tests
9+
10+
```bash
11+
npm run test:docker
12+
```
13+
14+
2. Run a specific test file
15+
16+
```bash
17+
npm run test:docker test/server.js
18+
```
19+
20+
3. Run all `direct ipv6` test cases across all tests
21+
22+
```bash
23+
npm run test:docker test/server.js -- --grep "direct ipv6"
24+
```
1125

1226
Note: for test in Docker no changes in `/etc/hosts` needed.
1327

@@ -39,7 +53,7 @@ Note: for test in Docker no changes in `/etc/hosts` needed.
3953
npm run test
4054
```
4155
42-
2. Run specific tests
56+
2. Run a specific test file
4357
4458
```bash
4559
npm run test test/anonymize_proxy.js

test/server.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1647,3 +1647,63 @@ useSslVariants.forEach((useSsl) => {
16471647
});
16481648
});
16491649
});
1650+
1651+
describe('Socket error handler regression test', () => {
1652+
let server;
1653+
let logs = [];
1654+
const originalLog = console.log;
1655+
1656+
before(() => {
1657+
console.log = (...args) => {
1658+
logs.push(args.join(' '));
1659+
originalLog.apply(console, args);
1660+
};
1661+
});
1662+
1663+
after(() => {
1664+
console.log = originalLog;
1665+
});
1666+
1667+
beforeEach(() => {
1668+
logs = [];
1669+
});
1670+
1671+
afterEach(async () => {
1672+
if (server) {
1673+
await server.close(true);
1674+
server = null;
1675+
}
1676+
});
1677+
1678+
// The bug was checking `this.listenerCount('error')` (Server) instead of `socket.listenerCount('error')`.
1679+
// By adding an error listener to the Server, we make server.listenerCount('error') === 1.
1680+
// With buggy code: condition becomes TRUE (1 === 1) and incorrectly logs.
1681+
// With fixed code: condition stays FALSE (socket has 2 listeners, 2 !== 1) and correctly doesn't log.
1682+
it('does not log when server has 1 error listener but socket has multiple', (done) => {
1683+
server = new Server({ port: 0, verbose: true });
1684+
1685+
server.on('error', () => {});
1686+
1687+
server.server.once('connection', (serverSocket) => {
1688+
setImmediate(() => {
1689+
expect(server.listenerCount('error')).to.equal(1);
1690+
expect(serverSocket.listenerCount('error')).to.equal(2);
1691+
1692+
serverSocket.emit('error', new Error('Regression test error'));
1693+
1694+
setTimeout(() => {
1695+
const hasLog = logs.some((log) => log.includes('Source socket emitted error') && log.includes('Regression test error'));
1696+
1697+
expect(hasLog).to.equal(false, 'Should check socket.listenerCount, not this.listenerCount (server)');
1698+
1699+
serverSocket.destroy();
1700+
done();
1701+
}, 50);
1702+
});
1703+
});
1704+
1705+
server.listen().then(() => {
1706+
net.connect(server.port, '127.0.0.1');
1707+
});
1708+
});
1709+
});

0 commit comments

Comments
 (0)