mirror of
https://github.com/oven-sh/bun
synced 2026-02-15 21:32:05 +00:00
handle bodies of 0 length better
This commit is contained in:
@@ -277,7 +277,6 @@ pub fn NewServer(comptime ssl_enabled: bool) type {
|
||||
const names = entries.items(.name);
|
||||
const values = entries.items(.value);
|
||||
|
||||
this.resp.writeHeaderInt("content-length", this.blob.size);
|
||||
this.resp.writeHeaders(names, values, headers.buf.items);
|
||||
}
|
||||
|
||||
@@ -366,6 +365,22 @@ pub fn NewServer(comptime ssl_enabled: bool) type {
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn onWritableBytes(this: *RequestContext, write_offset: c_ulong, resp: *App.Response) callconv(.C) bool {
|
||||
if (this.aborted)
|
||||
return false;
|
||||
|
||||
var bytes = this.blob.sharedView();
|
||||
|
||||
bytes = bytes[@minimum(bytes.len, @truncate(usize, write_offset))..];
|
||||
if (resp.tryEnd(bytes, this.blob.size)) {
|
||||
this.finalize();
|
||||
return true;
|
||||
} else {
|
||||
this.resp.onWritable(*RequestContext, onWritableBytes, this);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn onWritableSendfile(this: *RequestContext, _: c_ulong, _: *App.Response) callconv(.C) bool {
|
||||
return this.onSendfile();
|
||||
}
|
||||
@@ -389,18 +404,6 @@ pub fn NewServer(comptime ssl_enabled: bool) type {
|
||||
return;
|
||||
};
|
||||
this.blob.size = size_;
|
||||
const code = this.response_ptr.?.statusCode();
|
||||
if (size_ == 0 and code >= 200 and code < 300) {
|
||||
this.writeStatus(204);
|
||||
} else {
|
||||
this.writeStatus(code);
|
||||
}
|
||||
|
||||
if (this.response_ptr.?.body.init.headers) |headers_| {
|
||||
this.writeHeaders(headers_);
|
||||
} else {
|
||||
this.resp.writeHeaderInt("content-length", size_);
|
||||
}
|
||||
|
||||
this.sendfile = .{
|
||||
.fd = fd,
|
||||
@@ -408,6 +411,8 @@ pub fn NewServer(comptime ssl_enabled: bool) type {
|
||||
.socket_fd = this.resp.getNativeHandle(),
|
||||
};
|
||||
|
||||
this.resp.runCorked(*RequestContext, renderMetadata, this);
|
||||
|
||||
if (size_ == 0) {
|
||||
this.cleanupAfterSendfile();
|
||||
this.finalize();
|
||||
@@ -460,31 +465,47 @@ pub fn NewServer(comptime ssl_enabled: bool) type {
|
||||
}
|
||||
}
|
||||
|
||||
this.renderBytes(response);
|
||||
if (this.has_abort_handler)
|
||||
this.resp.runCorked(*RequestContext, renderMetadata, this)
|
||||
else
|
||||
this.renderMetadata();
|
||||
|
||||
this.renderBytes();
|
||||
}
|
||||
|
||||
pub fn renderBytes(this: *RequestContext, response: *JSC.WebCore.Response) void {
|
||||
const status = response.statusCode();
|
||||
pub fn renderMetadata(this: *RequestContext) void {
|
||||
var response: *JSC.WebCore.Response = this.response_ptr.?;
|
||||
var status = response.statusCode();
|
||||
const size = this.blob.size;
|
||||
status = if (status == 200 and size == 0)
|
||||
204
|
||||
else
|
||||
status;
|
||||
|
||||
this.writeStatus(status);
|
||||
|
||||
if (response.body.init.headers) |headers_| {
|
||||
this.writeHeaders(headers_);
|
||||
}
|
||||
}
|
||||
|
||||
if (status == 302 or status == 202 or this.blob.size == 0) {
|
||||
this.resp.endWithoutBody();
|
||||
this.finalize();
|
||||
pub fn renderBytes(this: *RequestContext) void {
|
||||
const bytes = this.blob.sharedView();
|
||||
|
||||
if (!this.resp.tryEnd(
|
||||
bytes,
|
||||
bytes.len,
|
||||
)) {
|
||||
this.resp.onWritable(*RequestContext, onWritableBytes, this);
|
||||
return;
|
||||
}
|
||||
|
||||
this.resp.end(this.blob.sharedView(), false);
|
||||
this.finalize();
|
||||
}
|
||||
|
||||
pub fn render(this: *RequestContext, response: *JSC.WebCore.Response) void {
|
||||
this.response_ptr = response;
|
||||
// this.resp.runCorked(*RequestContext, doRender, this);
|
||||
|
||||
this.doRender();
|
||||
}
|
||||
|
||||
@@ -495,7 +516,10 @@ pub fn NewServer(comptime ssl_enabled: bool) type {
|
||||
var bytes = this.request_body_buf.toOwnedSlice(bun.default_allocator);
|
||||
var old = req.body;
|
||||
req.body = .{
|
||||
.Blob = Blob.init(bytes, bun.default_allocator, this.server.globalThis),
|
||||
.Blob = if (bytes.len > 0)
|
||||
Blob.init(bytes, bun.default_allocator, this.server.globalThis)
|
||||
else
|
||||
Blob.initEmpty(this.server.globalThis),
|
||||
};
|
||||
old.resolve(&req.body, this.server.globalThis);
|
||||
VirtualMachine.vm.tick();
|
||||
|
||||
@@ -3356,8 +3356,12 @@ pub const Blob = struct {
|
||||
}
|
||||
|
||||
pub fn initWithAllASCII(bytes: []u8, allocator: std.mem.Allocator, globalThis: *JSGlobalObject, is_all_ascii: bool) Blob {
|
||||
var store = Blob.Store.init(bytes, allocator) catch unreachable;
|
||||
store.is_all_ascii = is_all_ascii;
|
||||
// avoid allocating a Blob.Store if the buffer is actually empty
|
||||
var store: ?*Blob.Store = null;
|
||||
if (bytes.len > 0) {
|
||||
store = Blob.Store.init(bytes, allocator) catch unreachable;
|
||||
store.?.is_all_ascii = is_all_ascii;
|
||||
}
|
||||
return Blob{
|
||||
.size = @truncate(SizeType, bytes.len),
|
||||
.store = store,
|
||||
@@ -3371,7 +3375,10 @@ pub const Blob = struct {
|
||||
pub fn init(bytes: []u8, allocator: std.mem.Allocator, globalThis: *JSGlobalObject) Blob {
|
||||
return Blob{
|
||||
.size = @truncate(SizeType, bytes.len),
|
||||
.store = Blob.Store.init(bytes, allocator) catch unreachable,
|
||||
.store = if (bytes.len > 0)
|
||||
Blob.Store.init(bytes, allocator) catch unreachable
|
||||
else
|
||||
null,
|
||||
.allocator = null,
|
||||
.content_type = "",
|
||||
.globalThis = globalThis,
|
||||
@@ -3793,7 +3800,7 @@ pub const Blob = struct {
|
||||
=> {
|
||||
var sliced = top_value.toSlice(global, bun.default_allocator);
|
||||
const is_all_ascii = !sliced.allocated;
|
||||
if (!sliced.allocated) {
|
||||
if (!sliced.allocated and sliced.len > 0) {
|
||||
sliced.ptr = @ptrCast([*]const u8, (try bun.default_allocator.dupe(u8, sliced.slice())).ptr);
|
||||
sliced.allocated = true;
|
||||
}
|
||||
@@ -4119,14 +4126,16 @@ pub const Body = struct {
|
||||
deinit: bool = false,
|
||||
action: Action = Action.none,
|
||||
|
||||
pub fn setPromise(value: *PendingValue, globalThis: *JSC.JSGlobalObject, action: Action) void {
|
||||
pub fn setPromise(value: *PendingValue, globalThis: *JSC.JSGlobalObject, action: Action) JSValue {
|
||||
value.action = action;
|
||||
var promise = JSC.JSPromise.create(globalThis);
|
||||
value.promise = promise.asValue(globalThis);
|
||||
const promise_value = promise.asValue(globalThis);
|
||||
value.promise = promise_value;
|
||||
if (value.onRequestData) |onRequestData| {
|
||||
value.onRequestData = null;
|
||||
onRequestData(value.task.?);
|
||||
}
|
||||
return promise_value;
|
||||
}
|
||||
|
||||
pub const Action = enum {
|
||||
@@ -4732,8 +4741,7 @@ fn BlobInterface(comptime Type: type) type {
|
||||
) js.JSValueRef {
|
||||
var value = this.getBodyValue();
|
||||
if (value.* == .Locked) {
|
||||
value.Locked.setPromise(ctx.ptr(), .getText);
|
||||
return value.Locked.promise.?.asObjectRef();
|
||||
return value.Locked.setPromise(ctx.ptr(), .getText).asObjectRef();
|
||||
}
|
||||
|
||||
var blob = this.body.use();
|
||||
@@ -4750,8 +4758,7 @@ fn BlobInterface(comptime Type: type) type {
|
||||
) js.JSValueRef {
|
||||
var value = this.getBodyValue();
|
||||
if (value.* == .Locked) {
|
||||
value.Locked.setPromise(ctx.ptr(), .getJSON);
|
||||
return value.Locked.promise.?.asObjectRef();
|
||||
return value.Locked.setPromise(ctx.ptr(), .getJSON).asObjectRef();
|
||||
}
|
||||
|
||||
var blob = this.body.use();
|
||||
@@ -4768,8 +4775,7 @@ fn BlobInterface(comptime Type: type) type {
|
||||
var value = this.getBodyValue();
|
||||
|
||||
if (value.* == .Locked) {
|
||||
value.Locked.setPromise(ctx.ptr(), .getArrayBuffer);
|
||||
return value.Locked.promise.?.asObjectRef();
|
||||
return value.Locked.setPromise(ctx.ptr(), .getArrayBuffer).asObjectRef();
|
||||
}
|
||||
|
||||
var blob = this.body.use();
|
||||
@@ -4786,8 +4792,7 @@ fn BlobInterface(comptime Type: type) type {
|
||||
) js.JSValueRef {
|
||||
var value = this.getBodyValue();
|
||||
if (value.* == .Locked) {
|
||||
value.Locked.setPromise(ctx.ptr(), .getBlob);
|
||||
return value.Locked.promise.?.asObjectRef();
|
||||
return value.Locked.setPromise(ctx.ptr(), .getBlob).asObjectRef();
|
||||
}
|
||||
|
||||
var blob = this.body.use();
|
||||
|
||||
Reference in New Issue
Block a user