Handle when unable to use sendfile() with Bun.file

This commit is contained in:
Jarred Sumner
2022-04-03 21:23:10 -07:00
parent abc15f4d30
commit b069ff253e
3 changed files with 61 additions and 29 deletions

View File

@@ -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| {

View File

@@ -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 {
if (this.aborted) {
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;
}
var response = this.response_ptr.?;
var body = &response.body;
switch (body.value) {
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;
}
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 "",
);
}
}

View File

@@ -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;