aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2022-04-03 21:23:10 -0700
committerGravatar Jarred Sumner <jarred@jarredsumner.com> 2022-04-03 21:23:10 -0700
commitb069ff253e6fda72103646924fa052d4d051d5aa (patch)
tree7f1fa711a6bb6664e73006aa6688e7e63024fe80
parentabc15f4d304e74fbc400b069e40b187614674934 (diff)
downloadbun-b069ff253e6fda72103646924fa052d4d051d5aa.tar.gz
bun-b069ff253e6fda72103646924fa052d4d051d5aa.tar.zst
bun-b069ff253e6fda72103646924fa052d4d051d5aa.zip
Handle when unable to use sendfile() with `Bun.file`
-rw-r--r--src/javascript/jsc/api/html_rewriter.zig6
-rw-r--r--src/javascript/jsc/api/server.zig70
-rw-r--r--src/javascript/jsc/webcore/response.zig12
3 files changed, 60 insertions, 28 deletions
diff --git a/src/javascript/jsc/api/html_rewriter.zig b/src/javascript/jsc/api/html_rewriter.zig
index ac6190f7e..7d8ef2abf 100644
--- a/src/javascript/jsc/api/html_rewriter.zig
+++ b/src/javascript/jsc/api/html_rewriter.zig
@@ -303,7 +303,7 @@ pub const HTMLRewriter = struct {
defer if (!is_pending) input.detach();
if (is_pending) {
- input.doReadFileInternal(*BufferOutputSink, sink, onFinishedLoadingWrap, global);
+ input.doReadFileInternal(*BufferOutputSink, sink, onFinishedLoading, global);
} else if (sink.runOutputSink(input.sharedView(), false)) |error_value| {
return error_value;
}
@@ -315,10 +315,6 @@ pub const HTMLRewriter = struct {
);
}
- pub fn onFinishedLoadingWrap(sink: *anyopaque, bytes: JSC.WebCore.Blob.Store.ReadFile.ResultType) void {
- onFinishedLoading(bun.cast(*BufferOutputSink, sink), bytes);
- }
-
pub fn onFinishedLoading(sink: *BufferOutputSink, bytes: JSC.WebCore.Blob.Store.ReadFile.ResultType) void {
switch (bytes) {
.err => |err| {
diff --git a/src/javascript/jsc/api/server.zig b/src/javascript/jsc/api/server.zig
index 271f25cf3..4a57c927f 100644
--- a/src/javascript/jsc/api/server.zig
+++ b/src/javascript/jsc/api/server.zig
@@ -354,6 +354,9 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
pub const RequestContextStackAllocator = std.heap.StackFallbackAllocator(@sizeOf(RequestContext) * 2048 + 4096);
+ // TODO: support builtin compression
+ const can_sendfile = !ssl_enabled;
+
pub threadlocal var pool: *RequestContextStackAllocator = undefined;
pub fn setAbortHandler(this: *RequestContext) void {
@@ -476,7 +479,6 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
if (this.aborted) {
return false;
}
-
return this.sendWritableBytes(this.fallback_buf.items, write_offset, resp);
}
@@ -657,12 +659,6 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
return this.onSendfile();
}
- pub fn onWritablePrepareSendfile(this: *RequestContext, _: c_ulong, _: *App.Response) callconv(.C) bool {
- this.renderSendFile(this.blob);
-
- return true;
- }
-
pub fn onPrepareSendfileWrap(this: *anyopaque, fd: i32, size: anyerror!Blob.SizeType, _: *JSGlobalObject) void {
onPrepareSendfile(bun.cast(*RequestContext, this), fd, size);
}
@@ -699,10 +695,6 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
}
pub fn renderSendFile(this: *RequestContext, blob: JSC.WebCore.Blob) void {
- if (this.has_sendfile_ctx) return;
- this.has_sendfile_ctx = true;
- this.setAbortHandler();
-
JSC.WebCore.Blob.doOpenAndStatFile(
&this.blob,
*RequestContext,
@@ -712,27 +704,53 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
);
}
- pub fn doRender(this: *RequestContext) void {
+ pub fn doSendfile(this: *RequestContext, blob: Blob) void {
+ if (this.has_sendfile_ctx) return;
+ this.has_sendfile_ctx = true;
+ this.setAbortHandler();
+
+ if (comptime can_sendfile) {
+ return this.renderSendFile(blob);
+ }
+
+ this.blob.doReadFileInternal(*RequestContext, this, onReadFile, this.server.globalThis);
+ }
+
+ pub fn onReadFile(this: *RequestContext, result: Blob.Store.ReadFile.ResultType) void {
+ if (result == .err) {
+ this.runErrorHandler(result.err.toErrorInstance(this.server.globalThis));
+ return;
+ }
+
+ this.blob.resolveSize();
+ this.doRenderBlob();
+ }
+
+ pub fn doRenderWithBodyLocked(this: *anyopaque, value: *JSC.WebCore.Body.Value) void {
+ doRenderWithBody(bun.cast(*RequestContext, this), value);
+ }
+
+ pub fn doRenderWithBody(this: *RequestContext, value: *JSC.WebCore.Body.Value) void {
if (this.aborted) {
+ this.finalize();
return;
}
- var response = this.response_ptr.?;
- var body = &response.body;
- switch (body.value) {
+ switch (value.*) {
.Error => {
- const err = body.value.Error;
- _ = response.body.use();
+ const err = value.Error;
+ _ = value.use();
this.runErrorHandler(err);
return;
},
.Blob => {
- this.blob = response.body.use();
+ this.blob = value.use();
if (this.blob.needsToReadFile()) {
this.req.setYield(false);
this.setAbortHandler();
- if (!this.has_sendfile_ctx) this.renderSendFile(this.blob);
+ if (!this.has_sendfile_ctx)
+ this.doSendfile(this.blob);
return;
}
},
@@ -742,6 +760,10 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
else => {},
}
+ this.doRenderBlob();
+ }
+
+ pub fn doRenderBlob(this: *RequestContext) void {
if (this.has_abort_handler)
this.resp.runCorked(*RequestContext, renderMetadata, this)
else
@@ -750,6 +772,14 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
this.renderBytes();
}
+ pub fn doRender(this: *RequestContext) void {
+ if (this.aborted) {
+ return;
+ }
+ var response = this.response_ptr.?;
+ 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");
@@ -851,7 +881,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
this.resp.writeHeader(
"content-disposition",
- std.fmt.bufPrint(&filename_buf, "filename=\"{s}\"", .{basename}) catch "",
+ std.fmt.bufPrint(&filename_buf, "filename=\"{s}\"", .{basename[0..@minimum(basename.len, 1024 - 32)]}) catch "",
);
}
}
diff --git a/src/javascript/jsc/webcore/response.zig b/src/javascript/jsc/webcore/response.zig
index af0f244dc..b20d1319c 100644
--- a/src/javascript/jsc/webcore/response.zig
+++ b/src/javascript/jsc/webcore/response.zig
@@ -1802,8 +1802,14 @@ pub const Blob = struct {
bun.default_allocator.destroy(this);
- cb(cb_ctx, .{ .result = bytes });
- store.deref();
+ // Attempt to free it as soon as possible
+ if (store.ref_count > 1) {
+ store.deref();
+ cb(cb_ctx, .{ .result = bytes });
+ } else {
+ cb(cb_ctx, .{ .result = bytes });
+ store.deref();
+ }
}
pub fn run(this: *ReadFile, task: *ReadFileTask) void {
var frame = HTTPClient.getAllocator().create(@Frame(runAsync)) catch unreachable;
@@ -3007,7 +3013,7 @@ pub const Blob = struct {
bun.default_allocator,
this.store.?,
ctx,
- Function,
+ NewInternalReadFileHandler(Handler, Function).run,
this.offset,
this.size,
) catch unreachable;