Skip to content

Commit 8f46a4f

Browse files
authored
Fix bug where sse response hangs if handler threw an error. (#1668)
* Fix bug where sse response hangs if handler threw an error. * Add formatter. * Better typing.
1 parent 731befe commit 8f46a4f

File tree

2 files changed

+33
-15
lines changed

2 files changed

+33
-15
lines changed

spec/helper.ts

+31-14
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,11 @@ export function runHandler(
4747
// MockResponse mocks an express.Response.
4848
// This class lives here so it can reference resolve and reject.
4949
class MockResponse {
50-
private sentBody = "";
50+
private sentBody: string | undefined;
5151
private statusCode = 0;
5252
private headers: { [name: string]: string } = {};
5353
private callback: () => void;
54+
private writeCalled = false;
5455

5556
constructor() {
5657
request.on("close", () => this.end());
@@ -71,29 +72,45 @@ export function runHandler(
7172
}
7273

7374
public send(sendBody: any) {
74-
const toSend = typeof sendBody === "object" ? JSON.stringify(sendBody) : sendBody;
75-
const body = this.sentBody ? this.sentBody + ((toSend as string) || "") : toSend;
76-
77-
resolve({
78-
status: this.statusCode,
79-
headers: this.headers,
80-
body,
81-
});
82-
if (this.callback) {
83-
this.callback();
75+
if (this.writeCalled) {
76+
throw Error("Cannot set headers after they are sent to the client");
8477
}
78+
79+
const toSend = typeof sendBody === "object" ? JSON.stringify(sendBody) : sendBody;
80+
const body =
81+
typeof this.sentBody === "undefined"
82+
? toSend
83+
: this.sentBody + String(toSend || "");
84+
this.end(body);
8585
}
8686

8787
public write(writeBody: any, cb?: () => void) {
88-
this.sentBody += typeof writeBody === "object" ? JSON.stringify(writeBody) : writeBody;
88+
this.writeCalled = true;
89+
90+
if (typeof this.sentBody === "undefined") {
91+
this.sentBody = writeBody;
92+
} else {
93+
this.sentBody += typeof writeBody === "object" ? JSON.stringify(writeBody) : writeBody;
94+
}
8995
if (cb) {
9096
setImmediate(cb);
9197
}
9298
return true;
9399
}
94100

95-
public end() {
96-
this.send(undefined);
101+
public end(body?: unknown) {
102+
if (body) {
103+
this.write(body);
104+
}
105+
resolve({
106+
status: this.statusCode,
107+
headers: this.headers,
108+
body: this.sentBody,
109+
});
110+
111+
if (this.callback) {
112+
this.callback();
113+
}
97114
}
98115

99116
public on(event: string, callback: () => void) {

src/common/providers/https.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -933,7 +933,8 @@ function wrapOnCallHandler<Req = any, Res = any, Stream = unknown>(
933933
const { status } = httpErr.httpErrorCode;
934934
const body = { error: httpErr.toJSON() };
935935
if (version === "gcfv2" && req.header("accept") === "text/event-stream") {
936-
res.send(encodeSSE(body));
936+
res.write(encodeSSE(body));
937+
res.end();
937938
} else {
938939
res.status(status).send(body);
939940
}

0 commit comments

Comments
 (0)