Skip to content

Commit dcfa52b

Browse files
rsikdarbenlesh
authored andcommitted
fix(WebSocketSubject): fix subject failing to close socket (#4446)
Fix WebSocketSubject failing to close the underlying socket connection when it is unsubscribed before the socket is in the open state. Currently, when unsubscribe is called on the subject or when a subscription is unsubscribed there are checks on whether the socket is open (readyState = 1) before it closes the connection. If unsubscribe is called before the connection is open, it will not close the socket but will reset the state of the subject (_socket set to null), and it becomes impossible to close the socket.
1 parent e691379 commit dcfa52b

File tree

2 files changed

+36
-5
lines changed

2 files changed

+36
-5
lines changed

spec/observables/dom/webSocket-spec.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,34 @@ describe('webSocket', () => {
143143
(<any>socket.close).restore();
144144
});
145145

146+
it('should close the socket when unsubscribed before socket open', () => {
147+
const subject = webSocket<string>('ws://mysocket');
148+
subject.subscribe();
149+
subject.unsubscribe();
150+
const socket = MockWebSocket.lastSocket;
151+
sinon.spy(socket, 'close');
152+
socket.open();
153+
154+
expect(socket.close).have.been.called;
155+
expect(socket.readyState).to.equal(3); // closed
156+
157+
(<any>socket.close).restore();
158+
});
159+
160+
it('should close the socket when subscription is cancelled before socket open', () => {
161+
const subject = webSocket<string>('ws://mysocket');
162+
const subscription = subject.subscribe();
163+
subscription.unsubscribe();
164+
const socket = MockWebSocket.lastSocket;
165+
sinon.spy(socket, 'close');
166+
socket.open();
167+
168+
expect(socket.close).have.been.called;
169+
expect(socket.readyState).to.equal(3); // closed
170+
171+
(<any>socket.close).restore();
172+
});
173+
146174
it('should close the socket with a code and a reason when errored', () => {
147175
const subject = webSocket<string>('ws://mysocket');
148176
subject.subscribe();

src/internal/observable/dom/WebSocketSubject.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,12 @@ export class WebSocketSubject<T> extends AnonymousSubject<T> {
184184
});
185185

186186
socket.onopen = (e: Event) => {
187+
const { _socket } = this;
188+
if (!_socket) {
189+
socket.close();
190+
this._resetState();
191+
return;
192+
}
187193
const { openObserver } = this._config;
188194
if (openObserver) {
189195
openObserver.next(e);
@@ -280,14 +286,11 @@ export class WebSocketSubject<T> extends AnonymousSubject<T> {
280286
}
281287

282288
unsubscribe() {
283-
const { source, _socket } = this;
289+
const { _socket } = this;
284290
if (_socket && _socket.readyState === 1) {
285291
_socket.close();
286-
this._resetState();
287292
}
293+
this._resetState();
288294
super.unsubscribe();
289-
if (!source) {
290-
this.destination = new ReplaySubject();
291-
}
292295
}
293296
}

0 commit comments

Comments
 (0)