partial fix for the sendfile() bug

This commit is contained in:
Jarred Sumner
2022-04-08 06:31:14 -07:00
parent 489299cdcc
commit 8cdb55d94f
2 changed files with 60 additions and 27 deletions

View File

@@ -769,29 +769,41 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
return this.onSendfile();
}
pub fn onPrepareSendfileWrap(this: *anyopaque, fd: i32, size: anyerror!Blob.SizeType, _: *JSGlobalObject) void {
onPrepareSendfile(bun.cast(*RequestContext, this), fd, size);
pub fn onPrepareSendfileWrap(this: *anyopaque, fd: i32, size: Blob.SizeType, err: ?JSC.SystemError, globalThis: *JSGlobalObject) void {
onPrepareSendfile(bun.cast(*RequestContext, this), fd, size, err, globalThis);
}
fn onPrepareSendfile(this: *RequestContext, fd: i32, size: anyerror!Blob.SizeType) void {
fn onPrepareSendfile(this: *RequestContext, fd: i32, size: Blob.SizeType, err: ?JSC.SystemError, globalThis: *JSGlobalObject) void {
this.setAbortHandler();
if (this.aborted) return;
const size_ = size catch {
this.req.setYield(true);
this.finalize();
if (err) |system_error| {
if (system_error.errno == @enumToInt(std.os.E.NOENT)) {
this.runErrorHandlerWithStatusCode(system_error.toErrorInstance(globalThis), 404);
} else {
this.runErrorHandlerWithStatusCode(system_error.toErrorInstance(globalThis), 500);
}
return;
};
this.blob.size = size_;
}
this.blob.size = size;
this.needs_content_length = true;
this.sendfile = .{
.fd = fd,
.remain = size_,
.socket_fd = this.resp.getNativeHandle(),
.remain = size,
.socket_fd = if (!this.aborted) this.resp.getNativeHandle() else -999,
};
if (this.aborted) {
_ = JSC.Node.Syscall.close(this.sendfile.fd);
this.finalize();
return;
}
this.resp.runCorked(*RequestContext, renderMetadata, this);
if (size_ == 0) {
if (size == 0) {
this.cleanupAfterSendfile();
this.finalize();
@@ -900,15 +912,34 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
this.doRenderWithBody(&response.body.value);
}
pub fn renderProductionError(this: *RequestContext) void {
this.resp.writeStatus("500 Internal Server Error");
this.resp.writeHeader("content-type", "text/plain");
this.resp.end("Something went wrong!", true);
pub fn renderProductionError(this: *RequestContext, status: u16) void {
switch (status) {
404 => {
this.resp.writeStatus("404 Not Found");
this.resp.endWithoutBody();
},
else => {
this.resp.writeStatus("500 Internal Server Error");
this.resp.writeHeader("content-type", "text/plain");
this.resp.end("Something went wrong!", true);
},
}
this.finalize();
}
pub fn runErrorHandler(this: *RequestContext, value: JSC.JSValue) void {
pub fn runErrorHandler(
this: *RequestContext,
value: JSC.JSValue,
) void {
runErrorHandlerWithStatusCode(this, value, 500);
}
pub fn runErrorHandlerWithStatusCode(
this: *RequestContext,
value: JSC.JSValue,
status: u16,
) void {
if (this.resp.hasResponded()) return;
var exception_list: std.ArrayList(Api.JsException) = std.ArrayList(Api.JsException).init(bun.default_allocator);
@@ -919,10 +950,8 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
const result = JSC.C.JSObjectCallAsFunctionReturnValue(this.server.globalThis.ref(), this.server.config.onError.asObjectRef(), null, 1, &args);
if (!result.isEmptyOrUndefinedOrNull()) {
JSC.C.JSValueProtect(this.server.globalThis.ref(), result.asObjectRef());
if (result.isError() or result.isAggregateError(this.server.globalThis)) {
this.runErrorHandler(result);
JSC.C.JSValueUnprotect(this.server.globalThis.ref(), result.asObjectRef());
return;
} else if (result.as(Response)) |response| {
this.render(response);
@@ -942,8 +971,9 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
.{ std.mem.span(@tagName(this.method)), this.url },
);
} else {
JSC.VirtualMachine.vm.defaultErrorHandler(value, &exception_list);
this.renderProductionError();
if (status != 404)
JSC.VirtualMachine.vm.defaultErrorHandler(value, &exception_list);
this.renderProductionError(status);
}
JSC.VirtualMachine.vm.log.reset();
return;

View File

@@ -1714,7 +1714,8 @@ pub const Blob = struct {
pub const OnCompleteCallback = fn (
ctx: *anyopaque,
fd: JSC.Node.FileDescriptor,
size: anyerror!SizeType,
size: SizeType,
system_error: ?SystemError,
global: *JSGlobalObject,
) void;
@@ -1759,15 +1760,16 @@ pub const Blob = struct {
var cb_ctx = this.onCompleteCtx;
const fd = this.opened_fd;
const _size = this.size;
const errno = this.errno;
this.store.deref();
const system_error_ = this.system_error;
var store = this.store;
bun.default_allocator.destroy(this);
if (errno) |err| {
cb(cb_ctx, fd, err, globalThis);
if (system_error_) |err| {
cb(cb_ctx, -1, 0, err, globalThis);
} else {
cb(cb_ctx, fd, _size, globalThis);
cb(cb_ctx, fd, _size, null, globalThis);
}
store.deref();
}
fn _runAsync(this: *OpenAndStatFile) void {
@@ -1785,6 +1787,7 @@ pub const Blob = struct {
.result => |result| result,
.err => |err| {
this.errno = AsyncIO.asError(err.errno);
this.system_error = err.toSystemError();
return;
},
};