mirror of
https://github.com/oven-sh/bun
synced 2026-02-12 20:09:04 +00:00
[bun.js] Add stdout, stderr, stdin to Bun and support sendfile() + splice()
This commit is contained in:
@@ -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" },
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user