handle bodies of 0 length better

This commit is contained in:
Jarred Sumner
2022-03-23 22:53:22 -07:00
parent 6d230fc93e
commit f105a2fea7
6 changed files with 86 additions and 42 deletions

View File

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

View File

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