Skip to content

Commit 66bb189

Browse files
authored
connection: Do not throw on socket data if stream parser is null (#1100)
1 parent b4a8764 commit 66bb189

File tree

5 files changed

+106
-68
lines changed

5 files changed

+106
-68
lines changed

package-lock.json

Lines changed: 82 additions & 18 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
"husky": "^9.1.7",
2828
"jest": "^30.2.0",
2929
"jest-extended": "^7.0.0",
30-
"jsdom": "^27.2.0",
30+
"jsdom": "^27.3.0",
3131
"lerna": "^9.0.3",
3232
"lint-staged": "^16.2.7",
3333
"prettier": "^3.7.4",

packages/connection/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ class Connection extends EventEmitter {
4646
}
4747

4848
_onData(data) {
49+
// In some case it is possible for the socket to still have buffered data (therefor emit data events)
50+
// even after _detachParser has been called.
51+
// This is intentional so we just drop the data in that case; for example stream restart or stream error.
52+
if (!this.parser) return;
4953
const str = data.toString("utf8");
5054
this.parser.write(str);
5155
}

packages/connection/test/onData.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,13 @@ test("#_onData", () => {
1212

1313
conn._onData(foo);
1414
});
15+
16+
test("#_onData does not throw after _detachParser has been called", () => {
17+
expect.assertions(1);
18+
const foo = "<foo>";
19+
const conn = new Connection();
20+
conn._detachParser();
21+
expect(() => {
22+
conn._onData(foo);
23+
}).not.toThrow();
24+
});

test/stream-management.test.js

Lines changed: 9 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,20 @@ const domain = "localhost";
1111

1212
let xmpp;
1313

14-
afterEach(async () => {
14+
beforeAll(async () => {
15+
await server.enableModules(["smacks"]);
16+
});
17+
18+
beforeEach(async () => {
19+
await server.restart();
20+
});
21+
22+
afterAll(async () => {
1523
await xmpp?.stop();
1624
await server.reset();
1725
});
1826

1927
test("client ack stanzas", async () => {
20-
await server.enableModules(["smacks"]);
21-
await server.restart();
22-
2328
xmpp = client({ credentials, service: domain });
2429
debug(xmpp);
2530

@@ -36,9 +41,6 @@ test("client ack stanzas", async () => {
3641
});
3742

3843
test("client fail stanzas", async () => {
39-
await server.enableModules(["smacks"]);
40-
await server.restart();
41-
4244
xmpp = client({ credentials, service: domain });
4345
debug(xmpp);
4446

@@ -60,9 +62,6 @@ test("client fail stanzas", async () => {
6062
});
6163

6264
test("client retry stanzas", async () => {
63-
await server.enableModules(["smacks"]);
64-
await server.restart();
65-
6665
xmpp = client({ credentials, service: domain });
6766
debug(xmpp);
6867

@@ -86,9 +85,6 @@ test("client retry stanzas", async () => {
8685
});
8786

8887
test("client reconnects when server fails to ack stanza", async () => {
89-
await server.enableModules(["smacks"]);
90-
await server.restart();
91-
9288
xmpp = client({ credentials, service: domain });
9389
xmpp.streamManagement.timeout = 10;
9490
xmpp.streamManagement.requestAckInterval = 5;
@@ -110,39 +106,3 @@ test("client reconnects when server fails to ack stanza", async () => {
110106
await promise_resumed;
111107
expect().pass();
112108
});
113-
114-
test("pings do not prevent timeout", async () => {
115-
await server.enableModules(["smacks"]);
116-
await server.restart();
117-
118-
xmpp = client({ credentials, service: domain });
119-
xmpp.streamManagement.timeout = 10;
120-
xmpp.streamManagement.requestAckInterval = 5;
121-
122-
// Make sure an ack request is sent right away after a stanza
123-
xmpp.streamManagement.debounceAckRequest = 1;
124-
debug(xmpp);
125-
126-
let promise_disconnect = new Promise((resolve) => {
127-
xmpp.disconnect = () => {
128-
resolve();
129-
return Promise.resolve(null);
130-
};
131-
});
132-
await xmpp.start();
133-
134-
// Send just any stanza to trigger the act request send
135-
xmpp.send(
136-
<iq to={domain} id="ping" type="get">
137-
<ping xmlns="urn:xmppp:ping" />
138-
</iq>,
139-
);
140-
141-
// Pretend we don't receive the ack by removing event listeners
142-
// on the socket, so that the timeout can fire
143-
xmpp._detachSocket();
144-
145-
// Timeout fires, and disconnect happens
146-
await promise_disconnect;
147-
expect().pass();
148-
});

0 commit comments

Comments
 (0)