[bun.js] Add stdout, stderr, stdin to Bun and support sendfile() + splice()

This commit is contained in:
Jarred SUmner
2022-04-06 01:52:15 -07:00
parent 57cf035a73
commit 81eb47de0e
25 changed files with 552 additions and 141 deletions

View File

@@ -255,6 +255,75 @@ pub fn getOrigin(
return ZigString.init(VirtualMachine.vm.origin.origin).toValue(ctx.ptr()).asRef();
}
pub fn getStdin(
_: void,
ctx: js.JSContextRef,
_: js.JSValueRef,
_: js.JSStringRef,
_: js.ExceptionRef,
) js.JSValueRef {
var existing = ctx.ptr().getCachedObject(&ZigString.init("BunSTDIN"));
if (existing.isEmpty()) {
var rare_data = JSC.VirtualMachine.vm.rareData();
var store = rare_data.stdin();
var blob = bun.default_allocator.create(JSC.WebCore.Blob) catch unreachable;
blob.* = JSC.WebCore.Blob.initWithStore(store, ctx.ptr());
return ctx.ptr().putCachedObject(
&ZigString.init("BunSTDIN"),
JSC.JSValue.fromRef(JSC.WebCore.Blob.Class.make(ctx, blob)),
).asObjectRef();
}
return existing.asObjectRef();
}
pub fn getStderr(
_: void,
ctx: js.JSContextRef,
_: js.JSValueRef,
_: js.JSStringRef,
_: js.ExceptionRef,
) js.JSValueRef {
var existing = ctx.ptr().getCachedObject(&ZigString.init("BunSTDERR"));
if (existing.isEmpty()) {
var rare_data = JSC.VirtualMachine.vm.rareData();
var store = rare_data.stderr();
var blob = bun.default_allocator.create(JSC.WebCore.Blob) catch unreachable;
blob.* = JSC.WebCore.Blob.initWithStore(store, ctx.ptr());
return ctx.ptr().putCachedObject(
&ZigString.init("BunSTDERR"),
JSC.JSValue.fromRef(JSC.WebCore.Blob.Class.make(ctx, blob)),
).asObjectRef();
}
return existing.asObjectRef();
}
pub fn getStdout(
_: void,
ctx: js.JSContextRef,
_: js.JSValueRef,
_: js.JSStringRef,
_: js.ExceptionRef,
) js.JSValueRef {
var existing = ctx.ptr().getCachedObject(&ZigString.init("BunSTDOUT"));
if (existing.isEmpty()) {
var rare_data = JSC.VirtualMachine.vm.rareData();
var store = rare_data.stdout();
var blob = bun.default_allocator.create(JSC.WebCore.Blob) catch unreachable;
blob.* = JSC.WebCore.Blob.initWithStore(store, ctx.ptr());
return ctx.ptr().putCachedObject(
&ZigString.init("BunSTDOUT"),
JSC.JSValue.fromRef(JSC.WebCore.Blob.Class.make(ctx, blob)),
).asObjectRef();
}
return existing.asObjectRef();
}
pub fn enableANSIColors(
_: void,
ctx: js.JSContextRef,
@@ -1063,6 +1132,15 @@ pub const Class = NewClass(
.get = getOrigin,
.ts = d.ts{ .name = "origin", .@"return" = "string" },
},
.stdin = .{
.get = getStdin,
},
.stdout = .{
.get = getStdout,
},
.stderr = .{
.get = getStderr,
},
.routesDir = .{
.get = getRoutesDir,
.ts = d.ts{ .name = "routesDir", .@"return" = "string" },

View File

@@ -304,7 +304,7 @@ pub const HTMLRewriter = struct {
if (is_pending) {
input.doReadFileInternal(*BufferOutputSink, sink, onFinishedLoading, global);
} else if (sink.runOutputSink(input.sharedView(), false)) |error_value| {
} else if (sink.runOutputSink(input.sharedView(), false, false)) |error_value| {
return error_value;
}
@@ -337,15 +337,24 @@ pub const HTMLRewriter = struct {
return;
},
.result => |data| {
_ = sink.runOutputSink(data, true);
_ = sink.runOutputSink(data.buf, true, data.is_temporary);
},
}
}
pub fn runOutputSink(sink: *BufferOutputSink, bytes: []const u8, is_async: bool) ?JSValue {
pub fn runOutputSink(
sink: *BufferOutputSink,
bytes: []const u8,
is_async: bool,
free_bytes_on_end: bool,
) ?JSValue {
defer if (free_bytes_on_end)
bun.default_allocator.free(bun.constStrToU8(bytes));
sink.bytes.growBy(bytes.len) catch unreachable;
var global = sink.global;
var response = sink.response;
sink.rewriter.write(bytes) catch {
sink.deinit();
bun.default_allocator.destroy(sink);

View File

@@ -357,7 +357,9 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
sendfile: SendfileContext = undefined,
request_js_object: JSC.C.JSObjectRef = null,
request_body_buf: std.ArrayListUnmanaged(u8) = .{},
fallback_buf: std.ArrayListUnmanaged(u8) = .{},
/// Used either for temporary blob data or fallback
/// When the response body is a temporary value
response_buf_owned: std.ArrayListUnmanaged(u8) = .{},
pub const RequestContextStackAllocator = std.heap.StackFallbackAllocator(@sizeOf(RequestContext) * 2048 + 4096);
@@ -478,15 +480,19 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
return;
}
this.fallback_buf = std.ArrayListUnmanaged(u8){ .items = bb.items, .capacity = bb.capacity };
this.resp.onWritable(*RequestContext, onWritableFallback, this);
this.response_buf_owned = std.ArrayListUnmanaged(u8){ .items = bb.items, .capacity = bb.capacity };
this.renderResponseBuffer();
}
pub fn onWritableFallback(this: *RequestContext, write_offset: c_ulong, resp: *App.Response) callconv(.C) bool {
pub fn renderResponseBuffer(this: *RequestContext) void {
this.resp.onWritable(*RequestContext, onWritableResponseBuffer, this);
}
pub fn onWritableResponseBuffer(this: *RequestContext, write_offset: c_ulong, resp: *App.Response) callconv(.C) bool {
if (this.aborted) {
return false;
}
return this.sendWritableBytes(this.fallback_buf.items, write_offset, resp);
return this.sendWritableBytes(this.response_buf_owned.items, write_offset, resp);
}
pub fn create(this: *RequestContext, server: *ThisServer, req: *uws.Request, resp: *App.Response) void {
@@ -542,7 +548,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
this.response_headers = null;
}
this.fallback_buf.clearAndFree(bun.default_allocator);
this.response_buf_owned.clearAndFree(bun.default_allocator);
}
pub fn finalize(this: *RequestContext) void {
this.finalizeWithoutDeinit();
@@ -731,8 +737,15 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
return;
}
this.blob.resolveSize();
this.doRenderBlob();
const is_temporary = result.result.is_temporary;
if (!is_temporary) {
this.blob.resolveSize();
this.doRenderBlob();
} else {
this.blob.size = @truncate(Blob.SizeType, result.result.buf.len);
this.response_buf_owned = .{ .items = result.result.buf, .capacity = result.result.buf.len };
this.renderResponseBuffer();
}
}
pub fn doRenderWithBodyLocked(this: *anyopaque, value: *JSC.WebCore.Body.Value) void {