aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2022-06-29 07:10:30 -0700
committerGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2022-06-29 07:10:30 -0700
commit2fa51493c512df66d1b9e76e38530aedfbf07ecf (patch)
tree2a6dcf98dee27e9c319ad8f6dcfb7ace8bf1545c
parent4d3698e842f101a06168f96fb1f4b221e9414d14 (diff)
downloadbun-2fa51493c512df66d1b9e76e38530aedfbf07ecf.tar.gz
bun-2fa51493c512df66d1b9e76e38530aedfbf07ecf.tar.zst
bun-2fa51493c512df66d1b9e76e38530aedfbf07ecf.zip
[http server] Fix a segfault when aborting
-rw-r--r--src/bun.js/api/server.zig125
1 files changed, 67 insertions, 58 deletions
diff --git a/src/bun.js/api/server.zig b/src/bun.js/api/server.zig
index e93d325ac..070f07281 100644
--- a/src/bun.js/api/server.zig
+++ b/src/bun.js/api/server.zig
@@ -1255,6 +1255,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
@ptrCast(**anyopaque, &signal.ptr),
},
);
+ assignment_result.ensureStillAlive();
// assert that it was updated
std.debug.assert(!signal.isDead());
@@ -1292,74 +1293,80 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
return;
}
- // it returns a Promise when it goes through ReadableStreamDefaultReader
- if (assignment_result.asPromise()) |promise| {
- Output.debug("response_stream returned a promise", .{});
- switch (promise.status(this.server.globalThis.vm())) {
- .Pending => {
- // TODO: should this timeout?
- this.resp.onAborted(*ResponseStream, ResponseStream.onAborted, &response_stream.sink);
- const AwaitPromise = struct {
- pub fn onResolve(req: *RequestContext, _: *JSGlobalObject, _: []const JSC.JSValue) void {
- Output.debug("response_stream promise resolved", .{});
- if (!req.resp.hasResponded()) {
- req.renderMissing();
- return;
+ if (!assignment_result.isEmptyOrUndefinedOrNull()) {
+ assignment_result.ensureStillAlive();
+ // it returns a Promise when it goes through ReadableStreamDefaultReader
+ if (assignment_result.asPromise()) |promise| {
+ Output.debug("response_stream returned a promise", .{});
+ switch (promise.status(this.server.globalThis.vm())) {
+ .Pending => {
+ // TODO: should this timeout?
+ this.resp.onAborted(*ResponseStream, ResponseStream.onAborted, &response_stream.sink);
+ const AwaitPromise = struct {
+ pub fn onResolve(req: *RequestContext, _: *JSGlobalObject, _: []const JSC.JSValue) void {
+ Output.debug("response_stream promise resolved", .{});
+ if (!req.resp.hasResponded()) {
+ req.renderMissing();
+ return;
+ }
+ req.finalize();
}
- req.finalize();
- }
- pub fn onReject(req: *RequestContext, globalThis: *JSGlobalObject, args: []const JSC.JSValue) void {
- Output.debug("response_stream promise rejected", .{});
- if (args.len > 0) {
- req.handleReject(args[0]);
- return;
+ pub fn onReject(req: *RequestContext, globalThis: *JSGlobalObject, args: []const JSC.JSValue) void {
+ Output.debug("response_stream promise rejected", .{});
+ if (args.len > 0) {
+ req.handleReject(args[0]);
+ return;
+ }
+
+ const fallback = JSC.SystemError{
+ .code = ZigString.init(@as(string, @tagName(JSC.Node.ErrorCode.ERR_UNHANDLED_ERROR))),
+ .message = ZigString.init("Unhandled error in ReadableStream"),
+ };
+ req.handleReject(fallback.toErrorInstance(globalThis));
}
+ };
+ assignment_result.then(
+ this.server.globalThis,
+ RequestContext,
+ this,
+ AwaitPromise.onResolve,
+ AwaitPromise.onReject,
+ );
+ // the response_stream should be GC'd
+ return;
+ },
+ .Fulfilled => {
+ this.aborted = this.aborted or response_stream.sink.aborted;
+ response_stream.detach();
- const fallback = JSC.SystemError{
- .code = ZigString.init(@as(string, @tagName(JSC.Node.ErrorCode.ERR_UNHANDLED_ERROR))),
- .message = ZigString.init("Unhandled error in ReadableStream"),
- };
- req.handleReject(fallback.toErrorInstance(globalThis));
+ this.allocator.destroy(response_stream);
+
+ _ = promise.result(this.server.globalThis.vm());
+ if (!this.resp.hasResponded()) {
+ this.renderMissing();
+ return;
}
- };
- assignment_result.then(
- this.server.globalThis,
- RequestContext,
- this,
- AwaitPromise.onResolve,
- AwaitPromise.onReject,
- );
- // the response_stream should be GC'd
- return;
- },
- .Fulfilled => {
- this.aborted = this.aborted or response_stream.sink.aborted;
- response_stream.detach();
-
- this.allocator.destroy(response_stream);
-
- _ = promise.result(this.server.globalThis.vm());
- if (!this.resp.hasResponded()) {
- this.renderMissing();
+ this.finalize();
return;
- }
- this.finalize();
- return;
- },
- .Rejected => {
- this.aborted = this.aborted or response_stream.sink.aborted;
- response_stream.detach();
- this.allocator.destroy(response_stream);
-
- this.handleReject(promise.result(this.server.globalThis.vm()));
- return;
- },
+ },
+ .Rejected => {
+ this.aborted = this.aborted or response_stream.sink.aborted;
+ response_stream.detach();
+ this.allocator.destroy(response_stream);
+
+ this.handleReject(promise.result(this.server.globalThis.vm()));
+ return;
+ },
+ }
}
- return;
}
if (this.aborted) {
+ response_stream.detach();
+ stream.cancel(this.server.globalThis);
+ response_stream.sink.done = true;
this.finalizeForAbort();
+ response_stream.sink.finalize();
return;
}
@@ -1560,6 +1567,8 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
bytes.len,
)) {
this.resp.onWritable(*RequestContext, onWritableBytes, this);
+ // given a blob, we might not have set an abort handler yet
+ this.setAbortHandler();
return;
}