From 3144d274584ae3b96cca4e609c66c56d534f1715 Mon Sep 17 00:00:00 2001 From: Sean Oxley <13091705+OxleyS@users.noreply.github.com> Date: Wed, 31 May 2023 21:27:40 +0900 Subject: [PATCH] fix(uws): discard any write to an aborted uWS response (#682) This bug only exists for polling transport connections running on top of uWS. If the remote client abruptly disconnects (thus aborting the request) while the server is waiting on an asynchronous operation such as compression, the server may attempt to write a response via the aborted response object. This causes an uncaught exception to be thrown. --- lib/userver.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/userver.ts b/lib/userver.ts index 951d3b96..654f037d 100644 --- a/lib/userver.ts +++ b/lib/userver.ts @@ -258,6 +258,7 @@ export class uServer extends BaseServer { class ResponseWrapper { private statusWritten: boolean = false; private headers = []; + private isAborted = false; constructor(readonly res: HttpResponse) {} @@ -291,6 +292,8 @@ class ResponseWrapper { public getHeader() {} public writeStatus(status: string) { + if (this.isAborted) return; + this.res.writeStatus(status); this.statusWritten = true; this.writeBufferedHeaders(); @@ -298,6 +301,8 @@ class ResponseWrapper { } public writeHeader(key: string, value: string) { + if (this.isAborted) return; + if (key === "Content-Length") { // the content length is automatically added by uWebSockets.js return; @@ -316,6 +321,8 @@ class ResponseWrapper { } public end(data) { + if (this.isAborted) return; + if (!this.statusWritten) { // status will be inferred as "200 OK" this.writeBufferedHeaders(); @@ -324,10 +331,18 @@ class ResponseWrapper { } public onData(fn) { + if (this.isAborted) return; + this.res.onData(fn); } public onAborted(fn) { - this.res.onAborted(fn); + if (this.isAborted) return; + + this.res.onAborted(() => { + // Any attempt to use the UWS response object after abort will throw! + this.isAborted = true; + fn(); + }); } }