Skip to content

Commit

Permalink
fix(uws): discard any write to an aborted uWS response (#682)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
OxleyS authored May 31, 2023
1 parent 7bd7775 commit 3144d27
Showing 1 changed file with 16 additions and 1 deletion.
17 changes: 16 additions & 1 deletion lib/userver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ export class uServer extends BaseServer {
class ResponseWrapper {
private statusWritten: boolean = false;
private headers = [];
private isAborted = false;

constructor(readonly res: HttpResponse) {}

Expand Down Expand Up @@ -291,13 +292,17 @@ class ResponseWrapper {
public getHeader() {}

public writeStatus(status: string) {
if (this.isAborted) return;

this.res.writeStatus(status);
this.statusWritten = true;
this.writeBufferedHeaders();
return this;
}

public writeHeader(key: string, value: string) {
if (this.isAborted) return;

if (key === "Content-Length") {
// the content length is automatically added by uWebSockets.js
return;
Expand All @@ -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();
Expand All @@ -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();
});
}
}

0 comments on commit 3144d27

Please sign in to comment.