aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js/api/server.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/bun.js/api/server.zig')
-rw-r--r--src/bun.js/api/server.zig272
1 files changed, 144 insertions, 128 deletions
diff --git a/src/bun.js/api/server.zig b/src/bun.js/api/server.zig
index 39e9a8046..b79e6c7ab 100644
--- a/src/bun.js/api/server.zig
+++ b/src/bun.js/api/server.zig
@@ -549,38 +549,29 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
// TODO: support builtin compression
const can_sendfile = !ssl_enabled;
- pub const thenables = shim.thenables(.{
- PromiseHandler,
- });
-
- pub const lazy_static_functions = thenables;
- pub const Export = lazy_static_functions;
-
- const PromiseHandler = JSC.Thenable(RequestContext, onResolve, onReject);
-
pub fn setAbortHandler(this: *RequestContext) void {
if (this.has_abort_handler) return;
this.has_abort_handler = true;
this.resp.onAborted(*RequestContext, RequestContext.onAbort, this);
}
- pub fn onResolve(
- ctx: *RequestContext,
- _: *JSC.JSGlobalObject,
- arguments: []const JSC.JSValue,
- ) void {
+ pub fn onResolve(_: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSValue {
+ const arguments = callframe.arguments(2);
+ var ctx = arguments.ptr[1].asPromisePtr(@This());
+ const result = arguments.ptr[0];
ctx.pending_promises_for_abort -|= 1;
if (ctx.aborted) {
ctx.finalizeForAbort();
- return;
+ return JSValue.jsUndefined();
}
- if (arguments.len == 0) {
+ if (result.isEmptyOrUndefinedOrNull()) {
ctx.renderMissing();
- return;
+ return JSValue.jsUndefined();
}
- handleResolve(ctx, arguments[0]);
+ handleResolve(ctx, result);
+ return JSValue.jsUndefined();
}
fn handleResolve(ctx: *RequestContext, value: JSC.JSValue) void {
@@ -606,18 +597,19 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
if (this.pending_promises_for_abort == 0) this.finalize();
}
- pub fn onReject(
- ctx: *RequestContext,
- _: *JSC.JSGlobalObject,
- arguments: []const JSC.JSValue,
- ) void {
+ pub fn onReject(_: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSValue {
+ const arguments = callframe.arguments(2);
+ var ctx = arguments.ptr[1].asPromisePtr(@This());
+ const err = arguments.ptr[0];
+
ctx.pending_promises_for_abort -|= 1;
if (ctx.aborted) {
ctx.finalizeForAbort();
- return;
+ return JSValue.jsUndefined();
}
- handleReject(ctx, if (arguments.len > 0) arguments[0] else JSC.JSValue.jsUndefined());
+ handleReject(ctx, if (!err.isEmptyOrUndefinedOrNull()) err else JSC.JSValue.jsUndefined());
+ return JSValue.jsUndefined();
}
fn handleReject(ctx: *RequestContext, value: JSC.JSValue) void {
@@ -1247,101 +1239,6 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
assignment_result.ensureStillAlive();
// it returns a Promise when it goes through ReadableStreamDefaultReader
if (assignment_result.asPromise()) |promise| {
- const AwaitPromise = struct {
- pub fn onResolve(req: *RequestContext, _: *JSGlobalObject, _: []const JSC.JSValue) void {
- streamLog("onResolve", .{});
- var wrote_anything = false;
-
- if (req.sink) |wrapper| {
- wrapper.sink.pending_flush = null;
- wrapper.sink.done = true;
- req.aborted = req.aborted or wrapper.sink.aborted;
- wrote_anything = wrapper.sink.wrote > 0;
- wrapper.sink.finalize();
- wrapper.detach();
- req.sink = null;
- wrapper.sink.destroy();
- }
-
- if (req.response_ptr) |resp| {
- if (resp.body.value == .Locked) {
- resp.body.value.Locked.readable.?.done();
- resp.body.value = .{ .Used = {} };
- }
- }
-
- if (req.aborted) {
- req.finalizeForAbort();
- return;
- }
-
- const responded = req.resp.hasResponded();
-
- if (!responded and !wrote_anything) {
- req.resp.clearAborted();
- req.renderMissing();
- return;
- } else if (!responded and wrote_anything and !req.aborted) {
- req.resp.clearAborted();
- req.resp.endStream(false);
- }
-
- req.finalize();
- }
- pub fn onReject(req: *RequestContext, globalThis: *JSGlobalObject, args: []const JSC.JSValue) void {
- var wrote_anything = req.has_written_status;
-
- if (req.sink) |wrapper| {
- wrapper.sink.pending_flush = null;
- wrapper.sink.done = true;
- wrote_anything = wrote_anything or wrapper.sink.wrote > 0;
- req.aborted = req.aborted or wrapper.sink.aborted;
- wrapper.sink.finalize();
- wrapper.detach();
- req.sink = null;
- wrapper.sink.destroy();
- }
-
- if (req.response_ptr) |resp| {
- if (resp.body.value == .Locked) {
- resp.body.value.Locked.readable.?.done();
- resp.body.value = .{ .Used = {} };
- }
- }
-
- streamLog("onReject({s})", .{wrote_anything});
-
- if (req.aborted) {
- req.finalizeForAbort();
- return;
- }
-
- if (args.len > 0 and !wrote_anything) {
- req.response_jsvalue.unprotect();
- req.response_jsvalue = JSValue.zero;
- req.handleReject(args[0]);
- return;
- } else if (wrote_anything) {
- req.resp.endStream(true);
- if (comptime debug_mode) {
- if (args.len > 0) {
- var exception_list: std.ArrayList(Api.JsException) = std.ArrayList(Api.JsException).init(req.allocator);
- defer exception_list.deinit();
- req.server.vm.runErrorHandler(args[0], &exception_list);
- }
- }
- req.finalize();
- 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));
- }
- };
-
streamLog("returned a promise", .{});
switch (promise.status(this.server.globalThis.vm())) {
.Pending => {
@@ -1355,19 +1252,18 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
};
assignment_result.then(
this.server.globalThis,
- RequestContext,
this,
- AwaitPromise.onResolve,
- AwaitPromise.onReject,
+ onResolveStream,
+ onRejectStream,
);
// the response_stream should be GC'd
},
.Fulfilled => {
- AwaitPromise.onResolve(this, this.server.globalThis, &.{promise.result(this.server.globalThis.vm())});
+ this.handleResolveStream();
},
.Rejected => {
- AwaitPromise.onReject(this, this.server.globalThis, &.{promise.result(this.server.globalThis.vm())});
+ this.handleRejectStream(this.server.globalThis, promise.result(this.server.globalThis.vm()));
},
}
return;
@@ -1401,6 +1297,113 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
const streamLog = Output.scoped(.ReadableStream, false);
+ pub fn handleResolveStream(req: *RequestContext) void {
+ streamLog("onResolve", .{});
+ var wrote_anything = false;
+ if (req.sink) |wrapper| {
+ wrapper.sink.pending_flush = null;
+ wrapper.sink.done = true;
+ req.aborted = req.aborted or wrapper.sink.aborted;
+ wrote_anything = wrapper.sink.wrote > 0;
+ wrapper.sink.finalize();
+ wrapper.detach();
+ req.sink = null;
+ wrapper.sink.destroy();
+ }
+
+ if (req.response_ptr) |resp| {
+ if (resp.body.value == .Locked) {
+ resp.body.value.Locked.readable.?.done();
+ resp.body.value = .{ .Used = {} };
+ }
+ }
+
+ if (req.aborted) {
+ req.finalizeForAbort();
+ return;
+ }
+
+ const responded = req.resp.hasResponded();
+
+ if (!responded and !wrote_anything) {
+ req.resp.clearAborted();
+ req.renderMissing();
+ return;
+ } else if (!responded and wrote_anything and !req.aborted) {
+ req.resp.clearAborted();
+ req.resp.endStream(false);
+ }
+
+ req.finalize();
+ }
+
+ pub fn onResolveStream(_: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSValue {
+ var args = callframe.arguments(2);
+ var req: *@This() = args.ptr[args.len - 1].asPromisePtr(@This());
+ req.handleResolveStream();
+ return JSValue.jsUndefined();
+ }
+ pub fn onRejectStream(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSValue {
+ const args = callframe.arguments(2);
+ var req = args.ptr[args.len - 1].asPromisePtr(@This());
+ var err = args.ptr[0];
+ req.handleRejectStream(globalThis, err);
+ return JSValue.jsUndefined();
+ }
+
+ pub fn handleRejectStream(req: *@This(), globalThis: *JSC.JSGlobalObject, err: JSValue) void {
+ var wrote_anything = req.has_written_status;
+
+ if (req.sink) |wrapper| {
+ wrapper.sink.pending_flush = null;
+ wrapper.sink.done = true;
+ wrote_anything = wrote_anything or wrapper.sink.wrote > 0;
+ req.aborted = req.aborted or wrapper.sink.aborted;
+ wrapper.sink.finalize();
+ wrapper.detach();
+ req.sink = null;
+ wrapper.sink.destroy();
+ }
+
+ if (req.response_ptr) |resp| {
+ if (resp.body.value == .Locked) {
+ resp.body.value.Locked.readable.?.done();
+ resp.body.value = .{ .Used = {} };
+ }
+ }
+
+ streamLog("onReject({s})", .{wrote_anything});
+
+ if (req.aborted) {
+ req.finalizeForAbort();
+ return;
+ }
+
+ if (!err.isEmptyOrUndefinedOrNull() and !wrote_anything) {
+ req.response_jsvalue.unprotect();
+ req.response_jsvalue = JSValue.zero;
+ req.handleReject(err);
+ return;
+ } else if (wrote_anything) {
+ req.resp.endStream(true);
+ if (comptime debug_mode) {
+ if (!err.isEmptyOrUndefinedOrNull()) {
+ var exception_list: std.ArrayList(Api.JsException) = std.ArrayList(Api.JsException).init(req.allocator);
+ defer exception_list.deinit();
+ req.server.vm.runErrorHandler(err, &exception_list);
+ }
+ }
+ req.finalize();
+ 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));
+ }
+
pub fn doRenderWithBody(this: *RequestContext, value: *JSC.WebCore.Body.Value) void {
switch (value.*) {
.Error => {
@@ -1799,14 +1802,27 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
onPull(bun.cast(*RequestContext, this));
}
+ pub const Export = shim.exportFunctions(.{
+ .onResolve = onResolve,
+ .onReject = onReject,
+ .onResolveStream = onResolveStream,
+ .onRejectStream = onRejectStream,
+ });
+
comptime {
if (!JSC.is_bindgen) {
- @export(PromiseHandler.resolve, .{
+ @export(onResolve, .{
.name = Export[0].symbol_name,
});
- @export(PromiseHandler.reject, .{
+ @export(onReject, .{
.name = Export[1].symbol_name,
});
+ @export(onResolveStream, .{
+ .name = Export[2].symbol_name,
+ });
+ @export(onRejectStream, .{
+ .name = Export[3].symbol_name,
+ });
}
}
};
@@ -2235,7 +2251,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
request_object.headers = JSC.FetchHeaders.createFromUWS(this.globalThis, req);
}
- RequestContext.PromiseHandler.then(ctx, response_value, this.globalThis);
+ response_value.then(this.globalThis, ctx, RequestContext.onResolve, RequestContext.onReject);
return;
}