aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2022-04-12 03:45:58 -0700
committerGravatar Jarred Sumner <jarred@jarredsumner.com> 2022-04-12 03:46:21 -0700
commit743ad44c0a012545989d68eb956a6c0befa277e2 (patch)
tree468fce02957975b9e1b1cd20913fc0f155f9bb13
parent9db701ab41cb1195f0ec506455840ea79be07aee (diff)
downloadbun-743ad44c0a012545989d68eb956a6c0befa277e2.tar.gz
bun-743ad44c0a012545989d68eb956a6c0befa277e2.tar.zst
bun-743ad44c0a012545989d68eb956a6c0befa277e2.zip
Make sendfile more reliable
-rw-r--r--Makefile4
-rw-r--r--src/deps/_libusockets.h2
-rw-r--r--src/deps/libuwsockets.cpp45
m---------src/deps/uws0
-rw-r--r--src/deps/uws.zig5
-rw-r--r--src/javascript/jsc/api/server.zig120
-rw-r--r--src/javascript/jsc/javascript.zig9
-rw-r--r--src/javascript/jsc/webcore/response.zig134
8 files changed, 122 insertions, 197 deletions
diff --git a/Makefile b/Makefile
index e2fd04d44..87bd852e2 100644
--- a/Makefile
+++ b/Makefile
@@ -302,7 +302,7 @@ ARCHIVE_FILES_WITHOUT_LIBCRYPTO = $(MIMALLOC_FILE_PATH) \
ARCHIVE_FILES = $(ARCHIVE_FILES_WITHOUT_LIBCRYPTO) -lcrypto
ifeq ($(OS_NAME), darwin)
- ARCHIVE_FILES += $(wildcard $(BUN_DEPS_DIR)/uws/uSockets/src/*.o) $(wildcard $(BUN_DEPS_DIR)/uws/uSockets/src/**/*.o) $(BUN_DEPS_OUT_DIR)/libuwsockets.o
+ ARCHIVE_FILES += $(wildcard $(BUN_DEPS_DIR)/uws/uSockets/src/**/*.bc) $(wildcard $(BUN_DEPS_DIR)/uws/uSockets/src/*.bc) $(BUN_DEPS_OUT_DIR)/libuwsockets.o
else
ARCHIVE_FILES += -lusockets $(BUN_DEPS_OUT_DIR)/libuwsockets.o
endif
@@ -485,7 +485,7 @@ usockets:
$(CXX) -fPIC $(CXXFLAGS) $(UWS_CXX_FLAGS) -emit-llvm -Isrc $(UWS_LDFLAGS) -g $(DEFAULT_LINKER_FLAGS) $(PLATFORM_LINKER_FLAGS) $(OPTIMIZATION_LEVEL) -g -c *.cpp;
cd $(BUN_DEPS_DIR)/uws/uSockets && \
- $(AR) rcvs $(BUN_DEPS_OUT_DIR)/libusockets.a src/*.o src/eventing/*.o src/crypto/*.o
+ $(AR) rcvs $(BUN_DEPS_OUT_DIR)/libusockets.a $(wildcard $(BUN_DEPS_DIR)/uws/uSockets/src/**/*.bc) $(wildcard $(BUN_DEPS_DIR)/uws/uSockets/src/*.bc)
uws: usockets
$(CXX) -emit-llvm -fPIC -I$(BUN_DEPS_DIR)/uws/uSockets/src $(CLANG_FLAGS) $(CFLAGS) $(UWS_CXX_FLAGS) $(UWS_LDFLAGS) $(PLATFORM_LINKER_FLAGS) -c -I$(BUN_DEPS_DIR) $(BUN_DEPS_OUT_DIR)/libusockets.a $(BUN_DEPS_DIR)/libuwsockets.cpp -o $(BUN_DEPS_OUT_DIR)/libuwsockets.o
diff --git a/src/deps/_libusockets.h b/src/deps/_libusockets.h
index f6b8e2158..08410de0b 100644
--- a/src/deps/_libusockets.h
+++ b/src/deps/_libusockets.h
@@ -302,6 +302,8 @@ void uws_res_set_write_offset(int ssl, uws_res_t *res, size_t off);
void us_socket_mark_needs_more_not_ssl(uws_res_t *res);
bool uws_res_try_end(int ssl, uws_res_t *res, const char *bytes, size_t len,
size_t total_len);
+
+void uws_res_prepare_for_sendfile(int ssl, uws_res_t *res);
#ifdef __cplusplus
}
#endif
diff --git a/src/deps/libuwsockets.cpp b/src/deps/libuwsockets.cpp
index 7eba32d44..f854cafdb 100644
--- a/src/deps/libuwsockets.cpp
+++ b/src/deps/libuwsockets.cpp
@@ -793,11 +793,17 @@ void uws_res_write_header_int(int ssl, uws_res_t *res, const char *key,
void uws_res_end_without_body(int ssl, uws_res_t *res) {
if (ssl) {
uWS::HttpResponse<true> *uwsRes = (uWS::HttpResponse<true> *)res;
- uwsRes->endWithoutBody(0);
+ uwsRes->getHttpResponseData()->state |=
+ uWS::HttpResponseData<true>::HTTP_END_CALLED;
+ uwsRes->markDone(uwsRes->getHttpResponseData());
+ us_socket_timeout(true, (us_socket_t *)uwsRes, uWS::HTTP_TIMEOUT_S);
} else {
uWS::HttpResponse<false> *uwsRes = (uWS::HttpResponse<false> *)res;
- uwsRes->endWithoutBody(0);
+ uwsRes->getHttpResponseData()->state |=
+ uWS::HttpResponseData<false>::HTTP_END_CALLED;
+ uwsRes->markDone(uwsRes->getHttpResponseData());
+ us_socket_timeout(false, (us_socket_t *)uwsRes, uWS::HTTP_TIMEOUT_S);
}
}
@@ -1002,15 +1008,13 @@ void uws_res_write_headers(int ssl, uws_res_t *res, const StringPointer *names,
}
void uws_res_uncork(int ssl, uws_res_t *res) {
- // if (ssl) {
- // uWS::HttpResponse<true> *uwsRes =
- // (uWS::HttpResponse<true> *)res;
- // uwsRes->uncork();
- // } else {
- // uWS::HttpResponse<false> *uwsRes =
- // (uWS::HttpResponse<false> *)res;
- // uwsRes->uncork();
- // }
+ if (ssl) {
+ uWS::HttpResponse<true> *uwsRes = (uWS::HttpResponse<true> *)res;
+ uwsRes->uncork();
+ } else {
+ uWS::HttpResponse<false> *uwsRes = (uWS::HttpResponse<false> *)res;
+ uwsRes->uncork();
+ }
}
void us_socket_mark_needs_more_not_ssl(uws_res_t *res) {
@@ -1035,12 +1039,31 @@ void uws_res_cork(int ssl, uws_res_t *res, void *ctx,
if (ssl) {
uWS::HttpResponse<true> *uwsRes = (uWS::HttpResponse<true> *)res;
uwsRes->cork([ctx, corker]() { corker(ctx); });
+
} else {
uWS::HttpResponse<false> *uwsRes = (uWS::HttpResponse<false> *)res;
uwsRes->cork([ctx, corker]() { corker(ctx); });
}
}
+void uws_res_prepare_for_sendfile(int ssl, uws_res_t *res) {
+ if (ssl) {
+ uWS::HttpResponse<true> *uwsRes = (uWS::HttpResponse<true> *)res;
+ auto pair = uwsRes->getSendBuffer(2);
+ char *ptr = pair.first;
+ ptr[0] = '\r';
+ ptr[1] = '\n';
+ uwsRes->uncork();
+ } else {
+ uWS::HttpResponse<false> *uwsRes = (uWS::HttpResponse<false> *)res;
+ auto pair = uwsRes->getSendBuffer(2);
+ char *ptr = pair.first;
+ ptr[0] = '\r';
+ ptr[1] = '\n';
+ uwsRes->uncork();
+ }
+}
+
bool uws_res_try_end(int ssl, uws_res_t *res, const char *bytes, size_t len,
size_t total_len) {
if (ssl) {
diff --git a/src/deps/uws b/src/deps/uws
-Subproject ec7fec7ae264000b86ac308b7844043acc9e309
+Subproject f0ea7574ab3c642bc1c0ee4991e771c1ee164f4
diff --git a/src/deps/uws.zig b/src/deps/uws.zig
index 6ec3e6855..101bac88e 100644
--- a/src/deps/uws.zig
+++ b/src/deps/uws.zig
@@ -443,6 +443,10 @@ pub fn NewApp(comptime ssl: bool) type {
return uws_res_try_end(ssl_flag, res.downcast(), data.ptr, data.len, total);
}
+ pub fn prepareForSendfile(res: *Response) void {
+ return uws_res_prepare_for_sendfile(ssl_flag, res.downcast());
+ }
+
pub fn uncork(_: *Response) void {
// uws_res_uncork(
// ssl_flag,
@@ -639,6 +643,7 @@ pub fn NewApp(comptime ssl: bool) type {
};
};
}
+extern fn uws_res_prepare_for_sendfile(ssl: c_int, res: *uws_res) void;
extern fn uws_res_get_native_handle(ssl: c_int, res: *uws_res) *us_socket_t;
extern fn uws_create_app(ssl: c_int, options: us_socket_context_options_t) *uws_app_t;
extern fn uws_app_destroy(ssl: c_int, app: *uws_app_t) void;
diff --git a/src/javascript/jsc/api/server.zig b/src/javascript/jsc/api/server.zig
index 2ebd30ee1..9f38045f0 100644
--- a/src/javascript/jsc/api/server.zig
+++ b/src/javascript/jsc/api/server.zig
@@ -89,7 +89,9 @@ const SendfileContext = struct {
offset: Blob.SizeType = 0,
has_listener: bool = false,
has_set_on_writable: bool = false,
+ auto_close: bool = false,
};
+const DateTime = @import("datetime");
const linux = std.os.linux;
pub const ServerConfig = struct {
@@ -769,7 +771,8 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
this.resp.setWriteOffset(this.sendfile.offset);
this.resp.endWithoutBody();
// use node syscall so that we don't segfault on BADF
- _ = JSC.Node.Syscall.close(this.sendfile.fd);
+ if (this.sendfile.auto_close)
+ _ = JSC.Node.Syscall.close(this.sendfile.fd);
this.sendfile = undefined;
this.finalize();
}
@@ -802,7 +805,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
this.sendfile.remain -= @intCast(Blob.SizeType, this.sendfile.offset - start);
if (errcode != .SUCCESS or this.aborted or this.sendfile.remain == 0 or val == 0) {
- if (errcode != .SUCCESS) {
+ if (errcode != .AGAIN and errcode != .SUCCESS and errcode != .PIPE) {
Output.prettyErrorln("Error: {s}", .{@tagName(errcode)});
Output.flush();
}
@@ -826,7 +829,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
this.sendfile.offset += wrote;
this.sendfile.remain -= wrote;
if (errcode != .AGAIN or this.aborted or this.sendfile.remain == 0 or sbytes == 0) {
- if (errcode != .AGAIN and errcode != .SUCCESS) {
+ if (errcode != .AGAIN and errcode != .SUCCESS and errcode != .PIPE) {
Output.prettyErrorln("Error: {s}", .{@tagName(errcode)});
Output.flush();
}
@@ -840,6 +843,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
this.resp.onWritable(*RequestContext, onWritableSendfile, this);
}
+ this.setAbortHandler();
this.resp.markNeedsMore();
return true;
@@ -870,64 +874,99 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
return this.onSendfile();
}
- 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);
- }
+ // We tried open() in another thread for this
+ // it was not faster due to the mountain of syscalls
+ pub fn renderSendFile(this: *RequestContext, blob: JSC.WebCore.Blob) void {
+ this.blob = blob;
+ const file = &this.blob.store.?.data.file;
+ var file_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
+ const auto_close = file.pathlike != .fd;
+ const fd = if (!auto_close)
+ file.pathlike.fd
+ else switch (JSC.Node.Syscall.open(file.pathlike.path.sliceZ(&file_buf), std.os.O.RDONLY | std.os.O.NONBLOCK | std.os.O.CLOEXEC, 0)) {
+ .result => |_fd| _fd,
+ .err => |err| return this.runErrorHandler(err.withPath(file.pathlike.path.slice()).toSystemError().toErrorInstance(
+ this.server.globalThis,
+ )),
+ };
- fn onPrepareSendfile(this: *RequestContext, fd: i32, size: Blob.SizeType, err: ?JSC.SystemError, globalThis: *JSGlobalObject) void {
- if (err) |system_error| {
- if (this.aborted) {
- this.finalize();
+ // stat only blocks if the target is a file descriptor
+ const stat: std.os.Stat = switch (JSC.Node.Syscall.fstat(fd)) {
+ .result => |result| result,
+ .err => |err| {
+ this.runErrorHandler(err.withPath(file.pathlike.path.slice()).toSystemError().toErrorInstance(
+ this.server.globalThis,
+ ));
+ if (auto_close) {
+ _ = JSC.Node.Syscall.close(fd);
+ }
return;
- }
+ },
+ };
- if (system_error.errno == @enumToInt(std.os.E.NOENT)) {
- this.runErrorHandlerWithStatusCode(system_error.toErrorInstance(globalThis), 404);
- } else {
- this.runErrorHandlerWithStatusCode(system_error.toErrorInstance(globalThis), 500);
+ if (Environment.isMac) {
+ if (!std.os.S.ISREG(stat.mode)) {
+ if (auto_close) {
+ _ = JSC.Node.Syscall.close(fd);
+ }
+
+ var err = JSC.Node.Syscall.Error{
+ .errno = @intCast(JSC.Node.Syscall.Error.Int, @enumToInt(std.os.E.INVAL)),
+ .path = file.pathlike.path.slice(),
+ .syscall = .sendfile,
+ };
+ var sys = err.toSystemError();
+ sys.message = ZigString.init("MacOS does not support sending non-regular files");
+ this.runErrorHandler(sys.toErrorInstance(
+ this.server.globalThis,
+ ));
+ return;
}
+ }
- return;
+ if (Environment.isLinux) {
+ if (!(std.os.S.ISREG(stat.mode) or std.os.S.ISFIFO(stat.mode))) {
+ if (auto_close) {
+ _ = JSC.Node.Syscall.close(fd);
+ }
+
+ var err = JSC.Node.Syscall.Error{
+ .errno = @intCast(JSC.Node.Syscall.Error.Int, @enumToInt(std.os.E.INVAL)),
+ .path = file.pathlike.path.slice(),
+ .syscall = .sendfile,
+ };
+ var sys = err.toSystemError();
+ sys.message = ZigString.init("File must be regular or FIFO");
+ this.runErrorHandler(sys.toErrorInstance(
+ this.server.globalThis,
+ ));
+ return;
+ }
}
- this.blob.size = size;
+ this.blob.size = @intCast(Blob.SizeType, stat.size);
this.needs_content_length = true;
this.sendfile = .{
.fd = fd,
- .remain = size,
+ .remain = this.blob.size,
+ .auto_close = auto_close,
.socket_fd = if (!this.aborted) this.resp.getNativeHandle() else -999,
};
- if (this.aborted) {
- _ = JSC.Node.Syscall.close(fd);
- this.finalize();
- return;
- }
-
- this.resp.runCorked(*RequestContext, renderMetadata, this);
+ this.resp.runCorked(*RequestContext, renderMetadataAndNewline, this);
- if (size == 0) {
+ if (this.blob.size == 0) {
this.cleanupAndFinalizeAfterSendfile();
return;
}
- this.setAbortHandler();
-
- // TODO: fix this to be MSGHDR
- _ = std.os.write(this.sendfile.socket_fd, "\r\n") catch 0;
-
_ = this.onSendfile();
}
- pub fn renderSendFile(this: *RequestContext, blob: JSC.WebCore.Blob) void {
- JSC.WebCore.Blob.doOpenAndStatFile(
- &this.blob,
- *RequestContext,
- this,
- onPrepareSendfileWrap,
- blob.globalThis,
- );
+ pub fn renderMetadataAndNewline(this: *RequestContext) void {
+ this.renderMetadata();
+ this.resp.prepareForSendfile();
}
pub fn doSendfile(this: *RequestContext, blob: Blob) void {
@@ -939,12 +978,12 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
if (this.has_sendfile_ctx) return;
this.has_sendfile_ctx = true;
- this.setAbortHandler();
if (comptime can_sendfile) {
return this.renderSendFile(blob);
}
+ this.setAbortHandler();
this.blob.doReadFileInternal(*RequestContext, this, onReadFile, this.server.globalThis);
}
@@ -996,7 +1035,6 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
if (this.blob.needsToReadFile()) {
this.req.setYield(false);
- this.setAbortHandler();
if (!this.has_sendfile_ctx)
this.doSendfile(this.blob);
return;
diff --git a/src/javascript/jsc/javascript.zig b/src/javascript/jsc/javascript.zig
index 890a74554..7ed624d8c 100644
--- a/src/javascript/jsc/javascript.zig
+++ b/src/javascript/jsc/javascript.zig
@@ -301,7 +301,6 @@ const AsyncTransformTask = @import("./api/transpiler.zig").TransformTask.AsyncTr
const BunTimerTimeoutTask = Bun.Timer.Timeout.TimeoutTask;
const ReadFileTask = WebCore.Blob.Store.ReadFile.ReadFileTask;
const WriteFileTask = WebCore.Blob.Store.WriteFile.WriteFileTask;
-const OpenAndStatFileTask = WebCore.Blob.Store.OpenAndStatFile.OpenAndStatFileTask;
// const PromiseTask = JSInternalPromise.Completion.PromiseTask;
pub const Task = TaggedPointerUnion(.{
FetchTasklet,
@@ -309,7 +308,6 @@ pub const Task = TaggedPointerUnion(.{
AsyncTransformTask,
BunTimerTimeoutTask,
ReadFileTask,
- OpenAndStatFileTask,
CopyFilePromiseTask,
WriteFileTask,
AnyTask,
@@ -594,13 +592,6 @@ pub const VirtualMachine = struct {
finished += 1;
vm_.active_tasks -|= 1;
},
- @field(Task.Tag, @typeName(OpenAndStatFileTask)) => {
- var transform_task: *OpenAndStatFileTask = task.get(OpenAndStatFileTask).?;
- transform_task.*.runFromJS();
- transform_task.deinit();
- finished += 1;
- vm_.active_tasks -|= 1;
- },
@field(Task.Tag, @typeName(WriteFileTask)) => {
var transform_task: *WriteFileTask = task.get(WriteFileTask).?;
transform_task.*.runFromJS();
diff --git a/src/javascript/jsc/webcore/response.zig b/src/javascript/jsc/webcore/response.zig
index b92d0882f..1d4703bc1 100644
--- a/src/javascript/jsc/webcore/response.zig
+++ b/src/javascript/jsc/webcore/response.zig
@@ -1683,129 +1683,6 @@ pub const Blob = struct {
};
}
- pub const OpenAndStatFile = struct {
- const OpenFrameType = if (Environment.isMac)
- void
- else
- @Frame(OpenAndStatFile.getFdLinux);
-
- open_frame: OpenFrameType = undefined,
- errno: ?anyerror = null,
- system_error: ?JSC.SystemError = null,
- open_completion: HTTPClient.NetworkThread.Completion = undefined,
- opened_fd: JSC.Node.FileDescriptor = null_fd,
- size: SizeType = 0,
-
- store: *Store = undefined,
- file_store: FileStore,
-
- onCompleteCtx: *anyopaque = undefined,
- onCompleteCallback: OnCompleteCallback = undefined,
-
- task: HTTPClient.NetworkThread.Task = undefined,
-
- pub const OnCompleteCallback = fn (
- ctx: *anyopaque,
- fd: JSC.Node.FileDescriptor,
- size: SizeType,
- system_error: ?SystemError,
- global: *JSGlobalObject,
- ) void;
-
- pub usingnamespace FileOpenerMixin(OpenAndStatFile);
- pub usingnamespace FileCloserMixin(OpenAndStatFile);
-
- pub fn createWithCtx(
- allocator: std.mem.Allocator,
- store: *Store,
- ctx: *anyopaque,
- onCompleteCallback: OnCompleteCallback,
- ) !*OpenAndStatFile {
- var read_file = try allocator.create(OpenAndStatFile);
- read_file.* = OpenAndStatFile{
- .file_store = store.data.file,
-
- .store = store,
- .onCompleteCtx = ctx,
- .onCompleteCallback = onCompleteCallback,
- };
- store.ref();
- return read_file;
- }
-
- pub const OpenAndStatFileTask = JSC.IOTask(@This());
-
- pub fn run(this: *OpenAndStatFile, task: *OpenAndStatFileTask) void {
- var frame = HTTPClient.getAllocator().create(@Frame(runAsync)) catch unreachable;
- _ = @asyncCall(std.mem.asBytes(frame), undefined, runAsync, .{ this, task });
- }
-
- fn runAsync(this: *OpenAndStatFile, task: *OpenAndStatFileTask) void {
- this._runAsync();
- task.onFinish();
- suspend {
- HTTPClient.getAllocator().destroy(@frame());
- }
- }
-
- pub fn then(this: *OpenAndStatFile, globalThis: *JSC.JSGlobalObject) void {
- var cb = this.onCompleteCallback;
- var cb_ctx = this.onCompleteCtx;
- const fd = this.opened_fd;
- const _size = this.size;
- const system_error_ = this.system_error;
- var store = this.store;
-
- if (system_error_) |err| {
- cb(cb_ctx, -1, 0, err, globalThis);
- } else {
- cb(cb_ctx, fd, _size, null, globalThis);
- }
- store.deref();
- bun.default_allocator.destroy(this);
- }
-
- fn _runAsync(this: *OpenAndStatFile) void {
- this.opened_fd = null_fd;
- if (this.file_store.pathlike == .fd) {
- this.opened_fd = this.file_store.pathlike.fd;
- }
- const fd = if (this.opened_fd == null_fd)
- this.getFd() catch return
- else
- this.opened_fd;
-
- this.doWithFd(fd);
- }
-
- pub fn doWithFd(this: *OpenAndStatFile, fd: JSC.Node.FileDescriptor) void {
- const stat: std.os.Stat = switch (JSC.Node.Syscall.fstat(fd)) {
- .result => |result| result,
- .err => |err| {
- this.errno = AsyncIO.asError(err.errno);
- this.system_error = err.toSystemError();
- return;
- },
- };
-
- if (Environment.isMac) {
- if (!std.os.S.ISREG(stat.mode)) {
- this.errno = error.ENOTSUP;
- return;
- }
- }
-
- if (Environment.isLinux) {
- if (!(std.os.S.ISREG(stat.mode) or std.os.S.ISFIFO(stat.mode))) {
- this.errno = error.ENOTSUP;
- return;
- }
- }
-
- this.size = @truncate(SizeType, @intCast(u64, @maximum(@intCast(i64, stat.size), 0)));
- }
- };
-
pub const ReadFile = struct {
const OpenFrameType = if (Environment.isMac)
void
@@ -3308,17 +3185,6 @@ pub const Blob = struct {
read_file_task.schedule();
}
- pub fn doOpenAndStatFile(this: *Blob, comptime Handler: type, ctx: Handler, comptime Function: anytype, global: *JSGlobalObject) void {
- var file_read = Store.OpenAndStatFile.createWithCtx(
- bun.default_allocator,
- this.store.?,
- ctx,
- Function,
- ) catch unreachable;
- var read_file_task = Store.OpenAndStatFile.OpenAndStatFileTask.createOnJSThread(bun.default_allocator, global, file_read) catch unreachable;
- read_file_task.schedule();
- }
-
pub fn doReadFile(this: *Blob, comptime Function: anytype, comptime lifetime: Lifetime, global: *JSGlobalObject) JSValue {
const Handler = NewReadFileHandler(Function, lifetime);
var promise = JSPromise.create(global);