From 9027484ae1a9eaf9769d79828db48de66450a3fc Mon Sep 17 00:00:00 2001 From: Ciro Spaciari Date: Tue, 22 Aug 2023 00:30:34 -0300 Subject: [PATCH] fetch(stream) add stream support for compressed and uncompressed data (#4127) * streams non compressed data in 64kb chunks (at least) * fmt * wip remove pause * fix default streaming and buffering * fix atomic lags * fix size * make chunked encoding work again (WIP streaming chunked) * WIP: chunked encoding streaming * fix end of streamings * working streaming + compression * add fixes + tests * fmt + fix proxy * fix oopsies * codegen after merge * fmt + fixes * more fixes * more fixes and logs * avoid double free * check empty before pop * check empty on pop * fix copy to real when complete * remove unnecessary logs * better has_schedule_callback swap, body locked size helper, remove isEmpty from unbounded_queue pop * fix response ref, fix body_size * add deflate support, fix error throw, add more tests * codegen after merge * remove logs, add connection close test * fix macOS build * fix redirect error option * make body_size more clear * support new Reponse(response) * toString DOMWrapper objects properly instead of supporting response in Response constructor * ignore headers with no name, add more tests * oops * handle transform with fetch * add gz image stream test * remove duplicate test * fix missing chunk on macOS under pressure * oops include all OS * some fixes * compare buffers instead of sizes * refactor err.err and protect it --- misctools/fetch.zig | 2 +- src/bun.js/api/bun/subprocess.zig | 6 +- src/bun.js/bindings/bindings.cpp | 2 +- src/bun.js/event_loop.zig | 3 +- src/bun.js/webcore/blob.zig | 20 + src/bun.js/webcore/body.zig | 18 +- src/bun.js/webcore/response.zig | 262 +++++- src/bun.js/webcore/streams.zig | 89 +- src/cli/create_command.zig | 56 +- src/cli/upgrade_command.zig | 28 +- src/deps/uws.zig | 16 + src/http/zlib.zig | 1 - src/http_client_async.zig | 373 ++++++-- src/zlib.zig | 8 +- test/js/web/fetch/fetch-gzip.test.ts | 4 +- test/js/web/fetch/fetch.stream.test.ts | 1129 ++++++++++++++++++++++++ test/js/web/fetch/fetch.test.ts | 17 +- test/js/web/fetch/fixture.png | Bin 0 -> 82022 bytes test/js/web/fetch/fixture.png.gz | Bin 0 -> 78116 bytes 19 files changed, 1877 insertions(+), 157 deletions(-) create mode 100644 test/js/web/fetch/fetch.stream.test.ts create mode 100644 test/js/web/fetch/fixture.png create mode 100644 test/js/web/fetch/fixture.png.gz diff --git a/misctools/fetch.zig b/misctools/fetch.zig index e450ab5d34..bb9e09a2a8 100644 --- a/misctools/fetch.zig +++ b/misctools/fetch.zig @@ -187,7 +187,7 @@ pub fn main() anyerror!void { var ctx = try default_allocator.create(HTTP.HTTPChannelContext); ctx.* = .{ .channel = channel, - .http = try HTTP.AsyncHTTP.init(default_allocator, args.method, args.url, args.headers, args.headers_buf, response_body_string, args.body, 0, HTTP.FetchRedirect.follow), + .http = try HTTP.AsyncHTTP.init(default_allocator, args.method, args.url, args.headers, args.headers_buf, response_body_string, args.body, 0, HTTP.FetchRedirect.follow,), }; ctx.http.callback = HTTP.HTTPChannelContext.callback; var batch = HTTPThread.Batch{}; diff --git a/src/bun.js/api/bun/subprocess.zig b/src/bun.js/api/bun/subprocess.zig index 4fb02b8afb..b8bf6939ce 100644 --- a/src/bun.js/api/bun/subprocess.zig +++ b/src/bun.js/api/bun/subprocess.zig @@ -616,7 +616,11 @@ pub const Subprocess = struct { return; }, .err => |err| { - this.status = .{ .err = err }; + if (err == .Error) { + this.status = .{ .err = err.Error }; + } else { + this.status = .{ .err = JSC.Node.Syscall.Error.fromCode(.CANCELED, .read) }; + } this.fifo.close(); return; diff --git a/src/bun.js/bindings/bindings.cpp b/src/bun.js/bindings/bindings.cpp index 37594288d7..badfd34376 100644 --- a/src/bun.js/bindings/bindings.cpp +++ b/src/bun.js/bindings/bindings.cpp @@ -1181,7 +1181,7 @@ WebCore::FetchHeaders* WebCore__FetchHeaders__createFromPicoHeaders_(const void* for (size_t j = 0; j < end; j++) { PicoHTTPHeader header = pico_headers.ptr[j]; - if (header.value.len == 0) + if (header.value.len == 0 || header.name.len == 0) continue; StringView nameView = StringView(reinterpret_cast(header.name.ptr), header.name.len); diff --git a/src/bun.js/event_loop.zig b/src/bun.js/event_loop.zig index 92613d0f07..92874b6a4a 100644 --- a/src/bun.js/event_loop.zig +++ b/src/bun.js/event_loop.zig @@ -545,8 +545,7 @@ pub const EventLoop = struct { }, .FetchTasklet => { var fetch_task: *Fetch.FetchTasklet = task.get(Fetch.FetchTasklet).?; - fetch_task.onDone(); - fetch_task.deinit(); + fetch_task.onProgressUpdate(); }, @field(Task.Tag, @typeName(AsyncTransformTask)) => { var transform_task: *AsyncTransformTask = task.get(AsyncTransformTask).?; diff --git a/src/bun.js/webcore/blob.zig b/src/bun.js/webcore/blob.zig index df2e17ce45..c794ab59b1 100644 --- a/src/bun.js/webcore/blob.zig +++ b/src/bun.js/webcore/blob.zig @@ -3794,6 +3794,10 @@ pub const Blob = struct { } else { return build.blob.dupe(); } + } else if (current.toSliceClone(global)) |sliced| { + if (sliced.allocator.get()) |allocator| { + return Blob.initWithAllASCII(bun.constStrToU8(sliced.slice()), allocator, global, false); + } } }, @@ -3886,6 +3890,14 @@ pub const Blob = struct { could_have_non_ascii = could_have_non_ascii or !(blob.is_all_ascii orelse false); joiner.append(blob.sharedView(), 0, null); continue; + } else if (current.toSliceClone(global)) |sliced| { + const allocator = sliced.allocator.get(); + could_have_non_ascii = could_have_non_ascii or allocator != null; + joiner.append( + sliced.slice(), + 0, + allocator, + ); } }, else => {}, @@ -3900,6 +3912,14 @@ pub const Blob = struct { if (current.as(Blob)) |blob| { could_have_non_ascii = could_have_non_ascii or !(blob.is_all_ascii orelse false); joiner.append(blob.sharedView(), 0, null); + } else if (current.toSliceClone(global)) |sliced| { + const allocator = sliced.allocator.get(); + could_have_non_ascii = could_have_non_ascii or allocator != null; + joiner.append( + sliced.slice(), + 0, + allocator, + ); } }, diff --git a/src/bun.js/webcore/body.zig b/src/bun.js/webcore/body.zig index b59125bc6e..fa0ec9b247 100644 --- a/src/bun.js/webcore/body.zig +++ b/src/bun.js/webcore/body.zig @@ -210,10 +210,24 @@ pub const Body = struct { /// used in HTTP server to ignore request bodies unless asked for it onStartBuffering: ?*const fn (ctx: *anyopaque) void = null, onStartStreaming: ?*const fn (ctx: *anyopaque) JSC.WebCore.DrainResult = null, + size_hint: Blob.SizeType = 0, deinit: bool = false, action: Action = Action{ .none = {} }, + /// For Http Client requests + /// when Content-Length is provided this represents the whole size of the request + /// If chunked encoded this will represent the total received size (ignoring the chunk headers) + /// If the size is unknown will be 0 + fn sizeHint(this: *const PendingValue) Blob.SizeType { + if (this.readable) |readable| { + if (readable.ptr == .Bytes) { + return readable.ptr.Bytes.size_hint; + } + } + return this.size_hint; + } + pub fn toAnyBlob(this: *PendingValue) ?AnyBlob { if (this.promise != null) return null; @@ -375,6 +389,7 @@ pub const Body = struct { .Blob => this.Blob.size, .InternalBlob => @as(Blob.SizeType, @truncate(this.InternalBlob.sliceConst().len)), .WTFStringImpl => @as(Blob.SizeType, @truncate(this.WTFStringImpl.utf8ByteLength())), + .Locked => this.Locked.sizeHint(), // .InlineBlob => @truncate(Blob.SizeType, this.InlineBlob.sliceConst().len), else => 0, }; @@ -382,9 +397,9 @@ pub const Body = struct { pub fn fastSize(this: *const Value) Blob.SizeType { return switch (this.*) { - .Blob => this.Blob.size, .InternalBlob => @as(Blob.SizeType, @truncate(this.InternalBlob.sliceConst().len)), .WTFStringImpl => @as(Blob.SizeType, @truncate(this.WTFStringImpl.byteSlice().len)), + .Locked => this.Locked.sizeHint(), // .InlineBlob => @truncate(Blob.SizeType, this.InlineBlob.sliceConst().len), else => 0, }; @@ -394,6 +409,7 @@ pub const Body = struct { return switch (this.*) { .InternalBlob => this.InternalBlob.sliceConst().len, .WTFStringImpl => this.WTFStringImpl.byteSlice().len, + .Locked => this.Locked.sizeHint(), // .InlineBlob => this.InlineBlob.sliceConst().len, else => 0, }; diff --git a/src/bun.js/webcore/response.zig b/src/bun.js/webcore/response.zig index 4b15efc0e2..01ecfad36f 100644 --- a/src/bun.js/webcore/response.zig +++ b/src/bun.js/webcore/response.zig @@ -44,6 +44,7 @@ const JSPrinter = bun.js_printer; const picohttp = @import("root").bun.picohttp; const StringJoiner = @import("../../string_joiner.zig"); const uws = @import("root").bun.uws; +const Mutex = @import("../../lock.zig").Lock; const InlineBlob = JSC.WebCore.InlineBlob; const AnyBlob = JSC.WebCore.AnyBlob; @@ -123,6 +124,7 @@ pub const Response = struct { pub fn writeFormat(this: *Response, comptime Formatter: type, formatter: *Formatter, writer: anytype, comptime enable_ansi_colors: bool) !void { const Writer = @TypeOf(writer); try writer.print("Response ({}) {{\n", .{bun.fmt.size(this.body.len())}); + { formatter.indent += 1; defer formatter.indent -|= 1; @@ -618,11 +620,21 @@ pub const Fetch = struct { javascript_vm: *VirtualMachine = undefined, global_this: *JSGlobalObject = undefined, request_body: HTTPRequestBody = undefined, + /// buffer being used by AsyncHTTP response_buffer: MutableString = undefined, + /// buffer used to stream response to JS + scheduled_response_buffer: MutableString = undefined, + /// response strong ref + response: JSC.Strong = .{}, request_headers: Headers = Headers{ .allocator = undefined }, promise: JSC.JSPromise.Strong, concurrent_task: JSC.ConcurrentTask = .{}, poll_ref: JSC.PollRef = .{}, + /// For Http Client requests + /// when Content-Length is provided this represents the whole size of the request + /// If chunked encoded this will represent the total received size (ignoring the chunk headers) + /// If is not chunked encoded and Content-Length is not provided this will be unknown + body_size: HTTPClient.HTTPClientResult.BodySize = .unknown, /// This is url + proxy memory buffer and is owned by FetchTasklet /// We always clone url and proxy (if informed) @@ -630,11 +642,14 @@ pub const Fetch = struct { signal: ?*JSC.WebCore.AbortSignal = null, aborted: std.atomic.Atomic(bool) = std.atomic.Atomic(bool).init(false), + has_schedule_callback: std.atomic.Atomic(bool) = std.atomic.Atomic(bool).init(false), // must be stored because AbortSignal stores reason weakly abort_reason: JSValue = JSValue.zero, // Custom Hostname hostname: ?[]u8 = null, + is_waiting_body: bool = false, + mutex: Mutex, tracker: JSC.AsyncTaskTracker, @@ -691,6 +706,8 @@ pub const Fetch = struct { this.result.deinitMetadata(); this.response_buffer.deinit(); + this.response.deinit(); + this.scheduled_response_buffer.deinit(); this.request_body.detach(); if (this.abort_reason != .zero) @@ -707,9 +724,122 @@ pub const Fetch = struct { this.javascript_vm.allocator.destroy(this); } - pub fn onDone(this: *FetchTasklet) void { - JSC.markBinding(@src()); + pub fn onBodyReceived(this: *FetchTasklet) void { + const success = this.result.isSuccess(); + const globalThis = this.global_this; + defer { + if (!success or !this.result.has_more) { + var vm = globalThis.bunVM(); + this.poll_ref.unref(vm); + this.clearData(); + this.deinit(); + } + } + if (!success) { + const err = this.onReject(); + err.ensureStillAlive(); + if (this.response.get()) |response_js| { + if (response_js.as(Response)) |response| { + const body = response.body; + if (body.value == .Locked) { + if (body.value.Locked.readable) |readable| { + readable.ptr.Bytes.onData( + .{ + .err = .{ .JSValue = err }, + }, + bun.default_allocator, + ); + return; + } + } + + response.body.value.toErrorInstance(err, globalThis); + return; + } + } + + globalThis.throwValue(err); + return; + } + + if (this.response.get()) |response_js| { + if (response_js.as(Response)) |response| { + const body = response.body; + if (body.value == .Locked) { + if (body.value.Locked.readable) |readable| { + if (readable.ptr == .Bytes) { + readable.ptr.Bytes.size_hint = this.getSizeHint(); + + var scheduled_response_buffer = this.scheduled_response_buffer.list; + + const chunk = scheduled_response_buffer.items; + + if (this.result.has_more) { + readable.ptr.Bytes.onData( + .{ + .temporary = bun.ByteList.initConst(chunk), + }, + bun.default_allocator, + ); + + // clean for reuse later + this.scheduled_response_buffer.reset(); + } else { + readable.ptr.Bytes.onData( + .{ + .temporary_and_done = bun.ByteList.initConst(chunk), + }, + bun.default_allocator, + ); + } + + return; + } + } else { + response.body.value.Locked.size_hint = this.getSizeHint(); + } + // we will reach here when not streaming + if (!this.result.has_more) { + var scheduled_response_buffer = this.scheduled_response_buffer.list; + + // done resolve body + var old = body.value; + var body_value = Body.Value{ + .InternalBlob = .{ + .bytes = scheduled_response_buffer.toManaged(bun.default_allocator), + }, + }; + response.body.value = body_value; + + this.scheduled_response_buffer = .{ + .allocator = bun.default_allocator, + .list = .{ + .items = &.{}, + .capacity = 0, + }, + }; + + if (old == .Locked) { + old.resolve(&response.body.value, this.global_this); + } + } + } + } + } + } + + pub fn onProgressUpdate(this: *FetchTasklet) void { + JSC.markBinding(@src()); + this.mutex.lock(); + defer { + this.has_schedule_callback.store(false, .Monotonic); + this.mutex.unlock(); + } + + if (this.is_waiting_body) { + return this.onBodyReceived(); + } const globalThis = this.global_this; var ref = this.promise; @@ -718,13 +848,22 @@ pub const Fetch = struct { var poll_ref = this.poll_ref; var vm = globalThis.bunVM(); - defer poll_ref.unref(vm); if (promise_value.isEmptyOrUndefinedOrNull()) { + poll_ref.unref(vm); this.clearData(); + this.deinit(); return; } + defer { + if (!this.is_waiting_body) { + poll_ref.unref(vm); + this.clearData(); + this.deinit(); + } + } + const promise = promise_value.asAnyPromise().?; const tracker = this.tracker; tracker.willDispatch(globalThis); @@ -735,7 +874,6 @@ pub const Fetch = struct { false => this.onReject(), }; result.ensureStillAlive(); - this.clearData(); promise_value.ensureStillAlive(); @@ -784,9 +922,73 @@ pub const Fetch = struct { return fetch_error.toErrorInstance(this.global_this); } + pub fn onStartStreamingRequestBodyCallback(ctx: *anyopaque) JSC.WebCore.DrainResult { + const this = bun.cast(*FetchTasklet, ctx); + if (this.http) |http| { + http.enableBodyStreaming(); + } + if (this.aborted.load(.Acquire)) { + return JSC.WebCore.DrainResult{ + .aborted = {}, + }; + } + + this.mutex.lock(); + defer this.mutex.unlock(); + const size_hint = this.getSizeHint(); + + var scheduled_response_buffer = this.scheduled_response_buffer.list; + // This means we have received part of the body but not the whole thing + if (scheduled_response_buffer.items.len > 0) { + this.scheduled_response_buffer = .{ + .allocator = default_allocator, + .list = .{ + .items = &.{}, + .capacity = 0, + }, + }; + + return .{ + .owned = .{ + .list = scheduled_response_buffer.toManaged(bun.default_allocator), + .size_hint = size_hint, + }, + }; + } + + return .{ + .estimated_size = size_hint, + }; + } + + fn getSizeHint(this: *FetchTasklet) Blob.SizeType { + return switch (this.body_size) { + .content_length => @truncate(this.body_size.content_length), + .total_received => @truncate(this.body_size.total_received), + else => 0, + }; + } + fn toBodyValue(this: *FetchTasklet) Body.Value { - var response_buffer = this.response_buffer.list; - this.response_buffer = .{ + if (this.is_waiting_body) { + const response = Body.Value{ + .Locked = .{ + .size_hint = this.getSizeHint(), + .task = this, + .global = this.global_this, + .onStartStreaming = FetchTasklet.onStartStreamingRequestBodyCallback, + }, + }; + return response; + } + + var scheduled_response_buffer = this.scheduled_response_buffer.list; + const response = Body.Value{ + .InternalBlob = .{ + .bytes = scheduled_response_buffer.toManaged(bun.default_allocator), + }, + }; + this.scheduled_response_buffer = .{ .allocator = default_allocator, .list = .{ .items = &.{}, @@ -794,23 +996,12 @@ pub const Fetch = struct { }, }; - // if (response_buffer.items.len < InlineBlob.available_bytes) { - // const inline_blob = InlineBlob.init(response_buffer.items); - // defer response_buffer.deinit(bun.default_allocator); - // return .{ .InlineBlob = inline_blob }; - // } - - const response = Body.Value{ - .InternalBlob = .{ - .bytes = response_buffer.toManaged(bun.default_allocator), - }, - }; - return response; } fn toResponse(this: *FetchTasklet, allocator: std.mem.Allocator) Response { const http_response = this.result.response; + this.is_waiting_body = this.result.has_more; return Response{ .allocator = allocator, .url = bun.String.createAtomIfPossible(this.result.href), @@ -830,7 +1021,10 @@ pub const Fetch = struct { const allocator = bun.default_allocator; var response = allocator.create(Response) catch unreachable; response.* = this.toResponse(allocator); - return Response.makeMaybePooled(@as(js.JSContextRef, @ptrCast(this.global_this)), response); + const response_js = Response.makeMaybePooled(@as(js.JSContextRef, this.global_this), response); + response_js.ensureStillAlive(); + this.response = JSC.Strong.create(response_js, this.global_this); + return response_js; } pub fn get( @@ -843,6 +1037,14 @@ pub const Fetch = struct { var fetch_tasklet = try jsc_vm.allocator.create(FetchTasklet); fetch_tasklet.* = .{ + .mutex = Mutex.init(), + .scheduled_response_buffer = .{ + .allocator = bun.default_allocator, + .list = .{ + .items = &.{}, + .capacity = 0, + }, + }, .response_buffer = MutableString{ .allocator = bun.default_allocator, .list = .{ @@ -905,6 +1107,8 @@ pub const Fetch = struct { fetch_tasklet.http.?.client.disable_timeout = fetch_options.disable_timeout; fetch_tasklet.http.?.client.verbose = fetch_options.verbose; fetch_tasklet.http.?.client.disable_keepalive = fetch_options.disable_keepalive; + // we wanna to return after headers are received + fetch_tasklet.http.?.signalHeaderProgress(); if (fetch_tasklet.request_body == .Sendfile) { std.debug.assert(fetch_options.url.isHTTP()); @@ -973,8 +1177,26 @@ pub const Fetch = struct { } pub fn callback(task: *FetchTasklet, result: HTTPClient.HTTPClientResult) void { - task.response_buffer = result.body.?.*; + task.mutex.lock(); + defer task.mutex.unlock(); task.result = result; + task.body_size = result.body_size; + + const success = result.isSuccess(); + task.response_buffer = result.body.?.*; + + if (success) { + _ = task.scheduled_response_buffer.write(task.response_buffer.list.items) catch @panic("OOM"); + } + + // reset for reuse + task.response_buffer.reset(); + + if (task.has_schedule_callback.compareAndSwap(false, true, .Acquire, .Monotonic)) |has_schedule_callback| { + if (has_schedule_callback) { + return; + } + } task.javascript_vm.eventLoop().enqueueTaskConcurrent(task.concurrent_task.from(task, .manual_deinit)); } }; diff --git a/src/bun.js/webcore/streams.zig b/src/bun.js/webcore/streams.zig index be6942392e..955d10ffb2 100644 --- a/src/bun.js/webcore/streams.zig +++ b/src/bun.js/webcore/streams.zig @@ -525,9 +525,16 @@ pub const StreamResult = union(Tag) { into_array: IntoArray, into_array_and_done: IntoArray, pending: *Pending, - err: Syscall.Error, + + err: union(Err) { Error: Syscall.Error, JSValue: JSC.JSValue }, + done: void, + pub const Err = enum { + Error, + JSValue, + }; + pub const Tag = enum { owned, owned_and_done, @@ -757,7 +764,14 @@ pub const StreamResult = union(Tag) { promise.asValue(globalThis).unprotect(); switch (result) { .err => |err| { - promise.reject(globalThis, err.toJSC(globalThis)); + if (err == .Error) { + promise.reject(globalThis, err.Error.toJSC(globalThis)); + } else { + const js_err = err.JSValue; + js_err.ensureStillAlive(); + js_err.unprotect(); + promise.reject(globalThis, js_err); + } }, .done => { promise.resolve(globalThis, JSValue.jsBoolean(false)); @@ -803,7 +817,13 @@ pub const StreamResult = union(Tag) { }, .err => |err| { - return JSC.JSPromise.rejectedPromise(globalThis, JSValue.c(err.toJS(globalThis))).asValue(globalThis); + if (err == .Error) { + return JSC.JSPromise.rejectedPromise(globalThis, JSValue.c(err.Error.toJS(globalThis))).asValue(globalThis); + } + const js_err = err.JSValue; + js_err.ensureStillAlive(); + js_err.unprotect(); + return JSC.JSPromise.rejectedPromise(globalThis, js_err).asValue(globalThis); }, // false == controller.close() @@ -2380,6 +2400,9 @@ pub fn HTTPServerWritable(comptime ssl: bool) type { return true; } else { this.has_backpressure = !this.res.write(buf); + if (this.has_backpressure) { + this.res.onWritable(*@This(), onWritable, this); + } return true; } @@ -2986,7 +3009,14 @@ pub fn ReadableStreamSource( pub fn processResult(globalThis: *JSGlobalObject, flags: JSValue, result: StreamResult) JSC.JSValue { switch (result) { .err => |err| { - globalThis.vm().throwError(globalThis, err.toJSC(globalThis)); + if (err == .Error) { + globalThis.vm().throwError(globalThis, err.Error.toJSC(globalThis)); + } else { + const js_err = err.JSValue; + js_err.ensureStillAlive(); + js_err.unprotect(); + globalThis.vm().throwError(globalThis, js_err); + } return JSValue.jsUndefined(); }, .temporary_and_done, .owned_and_done, .into_array_and_done => { @@ -3301,12 +3331,29 @@ pub const ByteStream = struct { if (is_really_done) { this.done = true; - this.pending.result = .{ - .into_array_and_done = .{ - .value = this.value(), - .len = @as(Blob.SizeType, @truncate(to_copy.len)), - }, - }; + + if (to_copy.len == 0) { + if (stream == .err) { + if (stream.err == .Error) { + this.pending.result = .{ .err = .{ .Error = stream.err.Error } }; + } + const js_err = stream.err.JSValue; + js_err.ensureStillAlive(); + js_err.protect(); + this.pending.result = .{ .err = .{ .JSValue = js_err } }; + } else { + this.pending.result = .{ + .done = {}, + }; + } + } else { + this.pending.result = .{ + .into_array_and_done = .{ + .value = this.value(), + .len = @as(Blob.SizeType, @truncate(to_copy.len)), + }, + }; + } } else { this.pending.result = .{ .into_array = .{ @@ -3488,7 +3535,7 @@ pub const ReadResult = union(enum) { pub fn toStreamWithIsDone(this: ReadResult, pending: *StreamResult.Pending, buf: []u8, view: JSValue, close_on_empty: bool, is_done: bool) StreamResult { return switch (this) { .pending => .{ .pending = pending }, - .err => .{ .err = this.err }, + .err => .{ .err = .{ .Error = this.err } }, .done => .{ .done = {} }, .read => |slice| brk: { const owned = slice.ptr != buf.ptr; @@ -4064,17 +4111,21 @@ pub const File = struct { this.concurrent.read = @as(Blob.SizeType, @truncate(result catch |err| { if (@hasField(HTTPClient.NetworkThread.Completion, "result")) { this.pending.result = .{ - .err = Syscall.Error{ - .errno = @as(Syscall.Error.Int, @intCast(-completion.result)), - .syscall = .read, + .err = .{ + .Error = Syscall.Error{ + .errno = @as(Syscall.Error.Int, @intCast(-completion.result)), + .syscall = .read, + }, }, }; } else { this.pending.result = .{ - .err = Syscall.Error{ - // this is too hacky - .errno = @as(Syscall.Error.Int, @truncate(@as(u16, @intCast(@max(1, @intFromError(err)))))), - .syscall = .read, + .err = .{ + .Error = Syscall.Error{ + // this is too hacky + .errno = @as(Syscall.Error.Int, @truncate(@as(u16, @intCast(@max(1, @intFromError(err)))))), + .syscall = .read, + }, }, }; } @@ -4101,7 +4152,7 @@ pub const File = struct { else => {}, } - this.pending.result = .{ .err = err }; + this.pending.result = .{ .err = .{ .Error = err } }; scheduleMainThreadTask(this); return; }, diff --git a/src/cli/create_command.zig b/src/cli/create_command.zig index 544329a983..284de1fd5d 100644 --- a/src/cli/create_command.zig +++ b/src/cli/create_command.zig @@ -1852,7 +1852,19 @@ pub const Example = struct { // ensure very stable memory address var async_http: *HTTP.AsyncHTTP = ctx.allocator.create(HTTP.AsyncHTTP) catch unreachable; - async_http.* = HTTP.AsyncHTTP.initSync(ctx.allocator, .GET, api_url, header_entries, headers_buf, mutable, "", 60 * std.time.ns_per_min, http_proxy, null, HTTP.FetchRedirect.follow); + async_http.* = HTTP.AsyncHTTP.initSync( + ctx.allocator, + .GET, + api_url, + header_entries, + headers_buf, + mutable, + "", + 60 * std.time.ns_per_min, + http_proxy, + null, + HTTP.FetchRedirect.follow, + ); async_http.client.progress_node = progress; const response = try async_http.sendSync(true); @@ -1916,7 +1928,19 @@ pub const Example = struct { // ensure very stable memory address var async_http: *HTTP.AsyncHTTP = ctx.allocator.create(HTTP.AsyncHTTP) catch unreachable; - async_http.* = HTTP.AsyncHTTP.initSync(ctx.allocator, .GET, url, .{}, "", mutable, "", 60 * std.time.ns_per_min, http_proxy, null, HTTP.FetchRedirect.follow); + async_http.* = HTTP.AsyncHTTP.initSync( + ctx.allocator, + .GET, + url, + .{}, + "", + mutable, + "", + 60 * std.time.ns_per_min, + http_proxy, + null, + HTTP.FetchRedirect.follow, + ); async_http.client.progress_node = progress; var response = try async_http.sendSync(true); @@ -1992,7 +2016,19 @@ pub const Example = struct { http_proxy = env_loader.getHttpProxy(parsed_tarball_url); - async_http.* = HTTP.AsyncHTTP.initSync(ctx.allocator, .GET, parsed_tarball_url, .{}, "", mutable, "", 60 * std.time.ns_per_min, http_proxy, null, HTTP.FetchRedirect.follow); + async_http.* = HTTP.AsyncHTTP.initSync( + ctx.allocator, + .GET, + parsed_tarball_url, + .{}, + "", + mutable, + "", + 60 * std.time.ns_per_min, + http_proxy, + null, + HTTP.FetchRedirect.follow, + ); async_http.client.progress_node = progress; refresher.maybeRefresh(); @@ -2022,7 +2058,19 @@ pub const Example = struct { var mutable = try ctx.allocator.create(MutableString); mutable.* = try MutableString.init(ctx.allocator, 2048); - async_http.* = HTTP.AsyncHTTP.initSync(ctx.allocator, .GET, url, .{}, "", mutable, "", 60 * std.time.ns_per_min, http_proxy, null, HTTP.FetchRedirect.follow); + async_http.* = HTTP.AsyncHTTP.initSync( + ctx.allocator, + .GET, + url, + .{}, + "", + mutable, + "", + 60 * std.time.ns_per_min, + http_proxy, + null, + HTTP.FetchRedirect.follow, + ); if (Output.enable_ansi_colors) { async_http.client.progress_node = progress_node; diff --git a/src/cli/upgrade_command.zig b/src/cli/upgrade_command.zig index 3fadfe5c2c..79a7777f32 100644 --- a/src/cli/upgrade_command.zig +++ b/src/cli/upgrade_command.zig @@ -223,7 +223,19 @@ pub const UpgradeCommand = struct { // ensure very stable memory address var async_http: *HTTP.AsyncHTTP = allocator.create(HTTP.AsyncHTTP) catch unreachable; - async_http.* = HTTP.AsyncHTTP.initSync(allocator, .GET, api_url, header_entries, headers_buf, &metadata_body, "", 60 * std.time.ns_per_min, http_proxy, null, HTTP.FetchRedirect.follow); + async_http.* = HTTP.AsyncHTTP.initSync( + allocator, + .GET, + api_url, + header_entries, + headers_buf, + &metadata_body, + "", + 60 * std.time.ns_per_min, + http_proxy, + null, + HTTP.FetchRedirect.follow, + ); if (!silent) async_http.client.progress_node = progress; const response = try async_http.sendSync(true); @@ -454,7 +466,19 @@ pub const UpgradeCommand = struct { var zip_file_buffer = try ctx.allocator.create(MutableString); zip_file_buffer.* = try MutableString.init(ctx.allocator, @max(version.size, 1024)); - async_http.* = HTTP.AsyncHTTP.initSync(ctx.allocator, .GET, zip_url, .{}, "", zip_file_buffer, "", timeout, http_proxy, null, HTTP.FetchRedirect.follow); + async_http.* = HTTP.AsyncHTTP.initSync( + ctx.allocator, + .GET, + zip_url, + .{}, + "", + zip_file_buffer, + "", + timeout, + http_proxy, + null, + HTTP.FetchRedirect.follow, + ); async_http.client.timeout = timeout; async_http.client.progress_node = progress; const response = try async_http.sendSync(true); diff --git a/src/deps/uws.zig b/src/deps/uws.zig index 5714eb09f8..2610b07204 100644 --- a/src/deps/uws.zig +++ b/src/deps/uws.zig @@ -200,6 +200,7 @@ pub fn NewSocketHandler(comptime is_ssl: bool) type { this.socket, ).?; } + pub fn flush(this: ThisSocket) void { return us_socket_flush( comptime ssl_int, @@ -687,6 +688,13 @@ pub const SocketContext = opaque { us_socket_context_free(@as(i32, 0), this); } + fn getLoop(this: *SocketContext, ssl: bool) ?*Loop { + if (ssl) { + return us_socket_context_loop(@as(i32, 1), this); + } + return us_socket_context_loop(@as(i32, 0), this); + } + /// closes and deinit the SocketContexts pub fn deinit(this: *SocketContext, ssl: bool) void { this.close(ssl); @@ -1000,6 +1008,14 @@ pub const Poll = opaque { us_poll_stop(self, loop); } + pub fn change(self: *Poll, loop: *Loop, events: i32) void { + us_poll_change(self, loop, events); + } + + pub fn getEvents(self: *Poll) i32 { + return us_poll_events(self); + } + pub fn data(self: *Poll, comptime Data: type) *Data { return us_poll_ext(self).?; } diff --git a/src/http/zlib.zig b/src/http/zlib.zig index e827dc1b3d..8144930c23 100644 --- a/src/http/zlib.zig +++ b/src/http/zlib.zig @@ -11,7 +11,6 @@ fn initMutableString(allocator: std.mem.Allocator) anyerror!MutableString { } const BufferPool = bun.ObjectPool(MutableString, initMutableString, false, 4); - pub fn get(allocator: std.mem.Allocator) *MutableString { return &BufferPool.get(allocator).data; } diff --git a/src/http_client_async.zig b/src/http_client_async.zig index 4998cec857..725e960d68 100644 --- a/src/http_client_async.zig +++ b/src/http_client_async.zig @@ -30,6 +30,7 @@ const ObjectPool = @import("./pool.zig").ObjectPool; const SOCK = os.SOCK; const Arena = @import("./mimalloc_arena.zig").Arena; const ZlibPool = @import("./http/zlib.zig"); + const URLBufferPool = ObjectPool([4096]u8, null, false, 10); const uws = bun.uws; pub const MimeType = @import("./http/mime_type.zig"); @@ -723,6 +724,11 @@ pub const HTTPThread = struct { this.loop.wakeup(); } + pub fn wakeup(this: *@This()) void { + if (this.has_awoken.load(.Monotonic)) + this.loop.wakeup(); + } + pub fn schedule(this: *@This(), batch: Batch) void { if (batch.len == 0) return; @@ -808,11 +814,12 @@ pub fn onClose( // if the peer closed after a full chunk, treat this // as if the transfer had complete, browsers appear to ignore // a missing 0\r\n chunk - if (in_progress and client.state.transfer_encoding == .chunked) { + if (in_progress and client.state.isChunkedEncoding()) { if (picohttp.phr_decode_chunked_is_in_data(&client.state.chunked_decoder) == 0) { var buf = client.state.getBodyBuffer(); if (buf.list.items.len > 0) { - client.done(comptime is_ssl, if (is_ssl) &http_thread.https_context else &http_thread.http_context, socket); + client.state.received_last_chunk = true; + client.progressUpdate(comptime is_ssl, if (is_ssl) &http_thread.https_context else &http_thread.http_context, socket); return; } } @@ -988,14 +995,17 @@ pub const InternalState = struct { response_message_buffer: MutableString = undefined, pending_response: picohttp.Response = undefined, allow_keepalive: bool = true, + received_last_chunk: bool = false, transfer_encoding: Encoding = Encoding.identity, encoding: Encoding = Encoding.identity, content_encoding_i: u8 = std.math.maxInt(u8), chunked_decoder: picohttp.phr_chunked_decoder = .{}, + zlib_reader: ?*Zlib.ZlibReaderArrayList = null, stage: Stage = Stage.pending, body_out_str: ?*MutableString = null, compressed_body: MutableString = undefined, - body_size: usize = 0, + content_length: ?usize = null, + total_body_received: usize = 0, request_body: []const u8 = "", original_request_body: HTTPRequestBody = .{ .bytes = "" }, request_sent_len: usize = 0, @@ -1015,12 +1025,20 @@ pub const InternalState = struct { }; } + pub fn isChunkedEncoding(this: *InternalState) bool { + return this.transfer_encoding == Encoding.chunked; + } + pub fn reset(this: *InternalState) void { this.compressed_body.deinit(); this.response_message_buffer.deinit(); var body_msg = this.body_out_str; if (body_msg) |body| body.reset(); + if (this.zlib_reader) |reader| { + this.zlib_reader = null; + reader.deinit(); + } this.* = .{ .body_out_str = body_msg, @@ -1042,27 +1060,78 @@ pub const InternalState = struct { } } - fn decompress(this: *InternalState, buffer: MutableString, body_out_str: *MutableString) !void { - defer this.compressed_body.deinit(); + fn isDone(this: *InternalState) bool { + if (this.isChunkedEncoding()) { + return this.received_last_chunk; + } + if (this.content_length) |content_length| { + return this.total_body_received >= content_length; + } + + // TODO: in future to handle Content-Type: text/event-stream we should be done only when Close/End/Timeout connection + return true; + } + + fn decompressConst(this: *InternalState, buffer: []const u8, body_out_str: *MutableString) !void { + defer this.compressed_body.reset(); var gzip_timer: std.time.Timer = undefined; if (extremely_verbose) gzip_timer = std.time.Timer.start() catch @panic("Timer failure"); - body_out_str.list.expandToCapacity(); + var reader: *Zlib.ZlibReaderArrayList = undefined; + if (this.zlib_reader) |current_reader| { + reader = current_reader; + reader.zlib.next_in = buffer.ptr; + reader.zlib.avail_in = @as(u32, @truncate(buffer.len)); - ZlibPool.decompress(buffer.list.items, body_out_str, default_allocator) catch |err| { - Output.prettyErrorln("Zlib error: {s}", .{bun.asByteSlice(@errorName(err))}); - Output.flush(); - return err; + reader.list = body_out_str.list; + const initial = body_out_str.list.items.len; + body_out_str.list.expandToCapacity(); + if (body_out_str.list.capacity == initial) { + try body_out_str.list.ensureUnusedCapacity(body_out_str.allocator, 4096); + body_out_str.list.expandToCapacity(); + } + reader.zlib.next_out = &body_out_str.list.items[initial]; + reader.zlib.avail_out = @as(u32, @truncate(body_out_str.list.capacity - initial)); + // we reset the total out so we can track how much we decompressed this time + reader.zlib.total_out = initial; + } else { + reader = try Zlib.ZlibReaderArrayList.initWithOptionsAndListAllocator( + buffer, + &body_out_str.list, + body_out_str.allocator, + default_allocator, + .{ + // TODO: add br support today we support gzip and deflate only + // zlib.MAX_WBITS = 15 + // to (de-)compress deflate format, use wbits = -zlib.MAX_WBITS + // to (de-)compress zlib format, use wbits = zlib.MAX_WBITS + // to (de-)compress gzip format, use wbits = zlib.MAX_WBITS | 16 + .windowBits = if (this.encoding == Encoding.gzip) Zlib.MAX_WBITS | 16 else -Zlib.MAX_WBITS, + }, + ); + this.zlib_reader = reader; + } + + reader.readAll() catch |err| { + if (this.isDone() or error.ShortRead != err) { + Output.prettyErrorln("Zlib error: {s}", .{bun.asByteSlice(@errorName(err))}); + Output.flush(); + return err; + } }; if (extremely_verbose) this.gzip_elapsed = gzip_timer.read(); } - pub fn processBodyBuffer(this: *InternalState, buffer: MutableString) !void { + fn decompress(this: *InternalState, buffer: MutableString, body_out_str: *MutableString) !void { + try this.decompressConst(buffer.list.items, body_out_str); + } + + pub fn processBodyBuffer(this: *InternalState, buffer: MutableString) !usize { var body_out_str = this.body_out_str.?; switch (this.encoding) { @@ -1080,10 +1149,10 @@ pub const InternalState = struct { }, } - this.postProcessBody(body_out_str); + return this.postProcessBody(); } - pub fn postProcessBody(this: *InternalState, body_out_str: *MutableString) void { + pub fn postProcessBody(this: *InternalState) usize { var response = &this.pending_response; // if it compressed with this header, it is no longer if (this.content_encoding_i < response.headers.len) { @@ -1093,7 +1162,7 @@ pub const InternalState = struct { this.content_encoding_i = std.math.maxInt(@TypeOf(this.content_encoding_i)); } - this.body_size = @as(usize, @truncate(body_out_str.list.items.len)); + return this.body_out_str.?.list.items.len; } }; @@ -1119,7 +1188,7 @@ disable_keepalive: bool = false, state: InternalState = .{}, -completion_callback: HTTPClientResult.Callback = undefined, +result_callback: HTTPClientResult.Callback = undefined, /// Some HTTP servers (such as npm) report Last-Modified times but ignore If-Modified-Since. /// This is a workaround for that. @@ -1135,7 +1204,20 @@ proxy_tunnel: ?ProxyTunnel = null, aborted: ?*std.atomic.Atomic(bool) = null, async_http_id: u32 = 0, hostname: ?[]u8 = null, -pub fn init(allocator: std.mem.Allocator, method: Method, url: URL, header_entries: Headers.Entries, header_buf: string, signal: ?*std.atomic.Atomic(bool), hostname: ?[]u8) HTTPClient { +signal_header_progress: *std.atomic.Atomic(bool), +enable_body_stream: *std.atomic.Atomic(bool), + +pub fn init( + allocator: std.mem.Allocator, + method: Method, + url: URL, + header_entries: Headers.Entries, + header_buf: string, + signal: ?*std.atomic.Atomic(bool), + hostname: ?[]u8, + signal_header_progress: *std.atomic.Atomic(bool), + enable_body_stream: *std.atomic.Atomic(bool), +) HTTPClient { return HTTPClient{ .allocator = allocator, .method = method, @@ -1144,6 +1226,8 @@ pub fn init(allocator: std.mem.Allocator, method: Method, url: URL, header_entri .header_buf = header_buf, .aborted = signal, .hostname = hostname, + .signal_header_progress = signal_header_progress, + .enable_body_stream = enable_body_stream, }; } @@ -1160,9 +1244,6 @@ pub fn deinit(this: *HTTPClient) void { tunnel.deinit(); this.proxy_tunnel = null; } - - this.state.compressed_body.deinit(); - this.state.response_message_buffer.deinit(); } const Stage = enum(u8) { @@ -1286,7 +1367,7 @@ pub const AsyncHTTP = struct { next: ?*AsyncHTTP = null, task: ThreadPool.Task = ThreadPool.Task{ .callback = &startAsyncHTTP }, - completion_callback: HTTPClientResult.Callback = undefined, + result_callback: HTTPClientResult.Callback = undefined, /// Timeout in nanoseconds timeout: usize = 0, @@ -1303,6 +1384,9 @@ pub const AsyncHTTP = struct { elapsed: u64 = 0, gzip_elapsed: u64 = 0, + signal_header_progress: std.atomic.Atomic(bool), + enable_body_stream: std.atomic.Atomic(bool), + pub var active_requests_count = std.atomic.Atomic(usize).init(0); pub var max_simultaneous_requests = std.atomic.Atomic(usize).init(256); @@ -1332,6 +1416,16 @@ pub const AsyncHTTP = struct { } } + pub fn signalHeaderProgress(this: *AsyncHTTP) void { + @fence(.Release); + this.client.signal_header_progress.store(true, .Release); + } + + pub fn enableBodyStreaming(this: *AsyncHTTP) void { + @fence(.Release); + this.client.enable_body_stream.store(true, .Release); + } + pub fn clearData(this: *AsyncHTTP) void { this.response_headers.deinit(this.allocator); this.response_headers = .{}; @@ -1371,12 +1465,14 @@ pub const AsyncHTTP = struct { .request_header_buf = headers_buf, .request_body = .{ .bytes = request_body }, .response_buffer = response_buffer, - .completion_callback = callback, + .result_callback = callback, .http_proxy = http_proxy, .async_http_id = if (signal != null) async_http_id.fetchAdd(1, .Monotonic) else 0, + .signal_header_progress = std.atomic.Atomic(bool).init(false), + .enable_body_stream = std.atomic.Atomic(bool).init(false), }; - this.client = HTTPClient.init(allocator, method, url, headers, headers_buf, signal, hostname); + this.client = HTTPClient.init(allocator, method, url, headers, headers_buf, signal, hostname, &this.signal_header_progress, &this.enable_body_stream); this.client.async_http_id = this.async_http_id; this.client.timeout = timeout; this.client.http_proxy = this.http_proxy; @@ -1537,7 +1633,7 @@ pub const AsyncHTTP = struct { var ctx = try bun.default_allocator.create(SingleHTTPChannel); ctx.* = SingleHTTPChannel.init(); - this.completion_callback = HTTPClientResult.Callback.New( + this.result_callback = HTTPClientResult.Callback.New( *SingleHTTPChannel, sendSyncCallback, ).init(ctx); @@ -1557,12 +1653,10 @@ pub const AsyncHTTP = struct { unreachable; } - pub fn onAsyncHTTPComplete(this: *AsyncHTTP, result: HTTPClientResult) void { + pub fn onAsyncHTTPCallback(this: *AsyncHTTP, result: HTTPClientResult) void { std.debug.assert(this.real != null); - const active_requests = AsyncHTTP.active_requests_count.fetchSub(1, .Monotonic); - std.debug.assert(active_requests > 0); - var completion = this.completion_callback; + var callback = this.result_callback; this.elapsed = http_thread.timer.read() -| this.elapsed; this.redirected = this.client.remaining_redirect_count != default_redirect_count; if (!result.isSuccess()) { @@ -1574,19 +1668,27 @@ pub const AsyncHTTP = struct { this.response = result.response; this.state.store(.success, .Monotonic); } - this.client.deinit(); - this.real.?.* = this.*; - this.real.?.response_buffer = this.response_buffer; + if (result.has_more) { + callback.function(callback.ctx, result); + } else { + this.client.deinit(); - log("onAsyncHTTPComplete: {any}", .{bun.fmt.fmtDuration(this.elapsed)}); + this.real.?.* = this.*; + this.real.?.response_buffer = this.response_buffer; - default_allocator.destroy(this); + log("onAsyncHTTPCallback: {any}", .{bun.fmt.fmtDuration(this.elapsed)}); - completion.function(completion.ctx, result); + default_allocator.destroy(this); - if (active_requests >= AsyncHTTP.max_simultaneous_requests.load(.Monotonic)) { - http_thread.drainEvents(); + const active_requests = AsyncHTTP.active_requests_count.fetchSub(1, .Monotonic); + std.debug.assert(active_requests > 0); + + callback.function(callback.ctx, result); + + if (active_requests >= AsyncHTTP.max_simultaneous_requests.load(.Monotonic)) { + http_thread.drainEvents(); + } } } @@ -1599,7 +1701,7 @@ pub const AsyncHTTP = struct { _ = active_requests_count.fetchAdd(1, .Monotonic); this.err = null; this.state.store(.sending, .Monotonic); - this.client.completion_callback = HTTPClientResult.Callback.New(*AsyncHTTP, onAsyncHTTPComplete).init( + this.client.result_callback = HTTPClientResult.Callback.New(*AsyncHTTP, onAsyncHTTPCallback).init( this, ); @@ -2153,6 +2255,7 @@ fn startProxyHandshake(this: *HTTPClient, comptime is_ssl: bool, socket: NewHTTP } pub fn onData(this: *HTTPClient, comptime is_ssl: bool, incoming_data: []const u8, ctx: *NewHTTPContext(is_ssl), socket: NewHTTPContext(is_ssl).HTTPSocket) void { + log("onData {}", .{incoming_data.len}); if (this.hasSignalAborted()) { this.closeAndAbort(is_ssl, socket); return; @@ -2241,7 +2344,11 @@ pub fn onData(this: *HTTPClient, comptime is_ssl: bool, incoming_data: []const u this.cloneMetadata(); if (!can_continue) { - this.done(is_ssl, ctx, socket); + // if is chuncked but no body is expected we mark the last chunk + this.state.received_last_chunk = true; + // if is not we ignore the content_length + this.state.content_length = 0; + this.progressUpdate(is_ssl, ctx, socket); return; } @@ -2251,35 +2358,45 @@ pub fn onData(this: *HTTPClient, comptime is_ssl: bool, incoming_data: []const u } if (body_buf.len == 0) { + // no body data yet, but we can report the headers + if (this.signal_header_progress.load(.Acquire)) { + this.progressUpdate(is_ssl, ctx, socket); + } return; } if (this.state.response_stage == .body) { { - const is_done = this.handleResponseBody(body_buf, true) catch |err| { + const report_progress = this.handleResponseBody(body_buf, true) catch |err| { this.closeAndFail(err, is_ssl, socket); return; }; - if (is_done) { - this.done(is_ssl, ctx, socket); + if (report_progress) { + this.progressUpdate(is_ssl, ctx, socket); return; } } } else if (this.state.response_stage == .body_chunk) { this.setTimeout(socket, 500); { - const is_done = this.handleResponseBodyChunkedEncoding(body_buf) catch |err| { + const report_progress = this.handleResponseBodyChunkedEncoding(body_buf) catch |err| { this.closeAndFail(err, is_ssl, socket); return; }; - if (is_done) { - this.done(is_ssl, ctx, socket); + if (report_progress) { + this.progressUpdate(is_ssl, ctx, socket); return; } } } + + // if not reported we report partially now + if (this.signal_header_progress.load(.Acquire)) { + this.progressUpdate(is_ssl, ctx, socket); + return; + } }, .body => { @@ -2295,23 +2412,23 @@ pub fn onData(this: *HTTPClient, comptime is_ssl: bool, incoming_data: []const u defer data.deinit(); const decoded_data = data.slice(); if (decoded_data.len == 0) return; - const is_done = this.handleResponseBody(decoded_data, false) catch |err| { + const report_progress = this.handleResponseBody(decoded_data, false) catch |err| { this.closeAndFail(err, is_ssl, socket); return; }; - if (is_done) { - this.done(is_ssl, ctx, socket); + if (report_progress) { + this.progressUpdate(is_ssl, ctx, socket); return; } } else { - const is_done = this.handleResponseBody(incoming_data, false) catch |err| { + const report_progress = this.handleResponseBody(incoming_data, false) catch |err| { this.closeAndFail(err, is_ssl, socket); return; }; - if (is_done) { - this.done(is_ssl, ctx, socket); + if (report_progress) { + this.progressUpdate(is_ssl, ctx, socket); return; } } @@ -2331,23 +2448,23 @@ pub fn onData(this: *HTTPClient, comptime is_ssl: bool, incoming_data: []const u const decoded_data = data.slice(); if (decoded_data.len == 0) return; - const is_done = this.handleResponseBodyChunkedEncoding(decoded_data) catch |err| { + const report_progress = this.handleResponseBodyChunkedEncoding(decoded_data) catch |err| { this.closeAndFail(err, is_ssl, socket); return; }; - if (is_done) { - this.done(is_ssl, ctx, socket); + if (report_progress) { + this.progressUpdate(is_ssl, ctx, socket); return; } } else { - const is_done = this.handleResponseBodyChunkedEncoding(incoming_data) catch |err| { + const report_progress = this.handleResponseBodyChunkedEncoding(incoming_data) catch |err| { this.closeAndFail(err, is_ssl, socket); return; }; - if (is_done) { - this.done(is_ssl, ctx, socket); + if (report_progress) { + this.progressUpdate(is_ssl, ctx, socket); return; } } @@ -2403,7 +2520,7 @@ fn fail(this: *HTTPClient, err: anyerror) void { this.state.fail = err; this.state.stage = .fail; - const callback = this.completion_callback; + const callback = this.result_callback; const result = this.toResult(this.cloned_metadata); this.state.reset(); this.proxy_tunneling = false; @@ -2440,39 +2557,50 @@ pub fn setTimeout(this: *HTTPClient, socket: anytype, amount: c_uint) void { socket.timeout(amount); } -pub fn done(this: *HTTPClient, comptime is_ssl: bool, ctx: *NewHTTPContext(is_ssl), socket: NewHTTPContext(is_ssl).HTTPSocket) void { +pub fn progressUpdate(this: *HTTPClient, comptime is_ssl: bool, ctx: *NewHTTPContext(is_ssl), socket: NewHTTPContext(is_ssl).HTTPSocket) void { if (this.state.stage != .done and this.state.stage != .fail) { - if (this.aborted != null) { + const is_done = this.state.isDone(); + + if (this.aborted != null and is_done) { _ = socket_async_http_abort_tracker.swapRemove(this.async_http_id); } - log("done", .{}); + log("progressUpdate {}", .{is_done}); var out_str = this.state.body_out_str.?; var body = out_str.*; this.cloned_metadata.response = this.state.pending_response; const result = this.toResult(this.cloned_metadata); - const callback = this.completion_callback; + const callback = this.result_callback; - socket.ext(**anyopaque).?.* = bun.cast(**anyopaque, NewHTTPContext(is_ssl).ActiveSocket.init(&dead_socket).ptr()); + if (is_done) { + socket.ext(**anyopaque).?.* = bun.cast(**anyopaque, NewHTTPContext(is_ssl).ActiveSocket.init(&dead_socket).ptr()); - if (this.state.allow_keepalive and !this.disable_keepalive and !socket.isClosed() and FeatureFlags.enable_keepalive) { - ctx.releaseSocket( - socket, - this.connected_url.hostname, - this.connected_url.getPortAuto(), - ); - } else if (!socket.isClosed()) { - socket.close(0, null); + if (this.state.allow_keepalive and !this.disable_keepalive and !socket.isClosed() and FeatureFlags.enable_keepalive) { + ctx.releaseSocket( + socket, + this.connected_url.hostname, + this.connected_url.getPortAuto(), + ); + } else if (!socket.isClosed()) { + socket.close(0, null); + } + this.state.reset(); + this.state.response_stage = .done; + this.state.request_stage = .done; + this.state.stage = .done; + this.proxy_tunneling = false; + if (comptime print_every > 0) { + print_every_i += 1; + if (print_every_i % print_every == 0) { + Output.prettyln("Heap stats for HTTP thread\n", .{}); + Output.flush(); + default_arena.dumpThreadStats(); + print_every_i = 0; + } + } } - - this.state.reset(); result.body.?.* = body; - std.debug.assert(this.state.stage != .done); - this.state.response_stage = .done; - this.state.request_stage = .done; - this.state.stage = .done; - this.proxy_tunneling = false; if (comptime print_every > 0) { print_every_i += 1; if (print_every_i % print_every == 0) { @@ -2494,6 +2622,19 @@ pub const HTTPClientResult = struct { fail: anyerror = error.NoError, redirected: bool = false, headers_buf: []picohttp.Header = &.{}, + has_more: bool = false, + + /// For Http Client requests + /// when Content-Length is provided this represents the whole size of the request + /// If chunked encoded this will represent the total received size (ignoring the chunk headers) + /// If is not chunked encoded and Content-Length is not provided this will be unknown + body_size: BodySize = .unknown, + + pub const BodySize = union(enum) { + total_received: usize, + content_length: usize, + unknown: void, + }; pub fn isSuccess(this: *const HTTPClientResult) bool { return this.fail == error.NoError; @@ -2547,6 +2688,12 @@ pub const HTTPClientResult = struct { }; pub fn toResult(this: *HTTPClient, metadata: HTTPResponseMetadata) HTTPClientResult { + const body_size: HTTPClientResult.BodySize = if (this.state.isChunkedEncoding()) + .{ .total_received = this.state.total_body_received } + else if (this.state.content_length) |content_length| + .{ .content_length = content_length } + else + .{ .unknown = {} }; return HTTPClientResult{ .body = this.state.body_out_str, .response = metadata.response, @@ -2555,6 +2702,8 @@ pub fn toResult(this: *HTTPClient, metadata: HTTPResponseMetadata) HTTPClientRes .href = metadata.url, .fail = this.state.fail, .headers_buf = metadata.response.headers, + .has_more = this.state.fail == error.NoError and !this.state.isDone(), + .body_size = body_size, }; } @@ -2566,10 +2715,10 @@ const preallocate_max = 1024 * 1024 * 256; pub fn handleResponseBody(this: *HTTPClient, incoming_data: []const u8, is_only_buffer: bool) !bool { std.debug.assert(this.state.transfer_encoding == .identity); - + const content_length = this.state.content_length orelse 0; // is it exactly as much as we need? - if (is_only_buffer and incoming_data.len >= this.state.body_size) { - try handleResponseBodyFromSinglePacket(this, incoming_data[0..this.state.body_size]); + if (is_only_buffer and incoming_data.len >= content_length) { + try handleResponseBodyFromSinglePacket(this, incoming_data[0..content_length]); return true; } else { return handleResponseBodyFromMultiplePackets(this, incoming_data); @@ -2577,6 +2726,10 @@ pub fn handleResponseBody(this: *HTTPClient, incoming_data: []const u8, is_only_ } fn handleResponseBodyFromSinglePacket(this: *HTTPClient, incoming_data: []const u8) !void { + if (!this.state.isChunkedEncoding()) { + this.state.total_body_received += incoming_data.len; + } + if (this.state.encoding.isCompressed()) { var body_buffer = this.state.body_out_str.?; if (body_buffer.list.capacity == 0) { @@ -2584,7 +2737,7 @@ fn handleResponseBodyFromSinglePacket(this: *HTTPClient, incoming_data: []const try body_buffer.growBy(@max(@as(usize, @intFromFloat(min)), 32)); } - try ZlibPool.decompress(incoming_data, body_buffer, default_allocator); + try this.state.decompressConst(incoming_data, body_buffer); } else { try this.state.getBodyBuffer().appendSliceExact(incoming_data); } @@ -2605,42 +2758,44 @@ fn handleResponseBodyFromSinglePacket(this: *HTTPClient, incoming_data: []const progress.context.maybeRefresh(); } - this.state.postProcessBody(this.state.getBodyBuffer()); + _ = this.state.postProcessBody(); } fn handleResponseBodyFromMultiplePackets(this: *HTTPClient, incoming_data: []const u8) !bool { var buffer = this.state.getBodyBuffer(); + const content_length = this.state.content_length orelse 0; if (buffer.list.items.len == 0 and - this.state.body_size > 0 and this.state.body_size < preallocate_max) + content_length > 0 and incoming_data.len < preallocate_max) { - // since we don't do streaming yet, we might as well just allocate the whole thing - // when we know the expected size - buffer.list.ensureTotalCapacityPrecise(buffer.allocator, this.state.body_size) catch {}; + buffer.list.ensureTotalCapacityPrecise(buffer.allocator, incoming_data.len) catch {}; } - const remaining_content_length = this.state.body_size -| buffer.list.items.len; + const remaining_content_length = content_length -| this.state.total_body_received; var remainder = incoming_data[0..@min(incoming_data.len, remaining_content_length)]; _ = try buffer.write(remainder); + this.state.total_body_received += remainder.len; + if (this.progress_node) |progress| { progress.activate(); - progress.setCompletedItems(buffer.list.items.len); + progress.setCompletedItems(this.state.total_body_received); progress.context.maybeRefresh(); } - if (buffer.list.items.len == this.state.body_size) { - try this.state.processBodyBuffer(buffer.*); + // done or streaming + const is_done = this.state.total_body_received >= content_length; + if (is_done or this.enable_body_stream.load(.Acquire)) { + const processed = try this.state.processBodyBuffer(buffer.*); if (this.progress_node) |progress| { progress.activate(); - progress.setCompletedItems(buffer.list.items.len); + progress.setCompletedItems(this.state.total_body_received); progress.context.maybeRefresh(); } - return true; + return is_done or processed > 0; } - return false; } @@ -2676,6 +2831,8 @@ fn handleResponseBodyChunkedEncodingFromMultiplePackets( &bytes_decoded, ); buffer.list.items.len -|= incoming_data.len - bytes_decoded; + this.state.total_body_received += bytes_decoded; + buffer_.* = buffer; switch (pret) { @@ -2690,12 +2847,18 @@ fn handleResponseBodyChunkedEncodingFromMultiplePackets( progress.setCompletedItems(buffer.list.items.len); progress.context.maybeRefresh(); } + // streaming chunks + if (this.enable_body_stream.load(.Acquire)) { + const processed = try this.state.processBodyBuffer(buffer); + return processed > 0; + } return false; }, // Done else => { - try this.state.processBodyBuffer( + this.state.received_last_chunk = true; + _ = try this.state.processBodyBuffer( buffer, ); @@ -2746,6 +2909,7 @@ fn handleResponseBodyChunkedEncodingFromSinglePacket( &bytes_decoded, ); buffer.len -|= incoming_data.len - bytes_decoded; + this.state.total_body_received += bytes_decoded; switch (pret) { // Invalid HTTP response body @@ -2759,12 +2923,21 @@ fn handleResponseBodyChunkedEncodingFromSinglePacket( progress.setCompletedItems(buffer.len); progress.context.maybeRefresh(); } - try this.state.getBodyBuffer().appendSliceExact(buffer); + const body_buffer = this.state.getBodyBuffer(); + try body_buffer.appendSliceExact(buffer); + + // streaming chunks + if (this.enable_body_stream.load(.Acquire)) { + const processed = try this.state.processBodyBuffer(body_buffer.*); + return processed > 0; + } return false; }, // Done else => { + this.state.received_last_chunk = true; + try this.handleResponseBodyFromSinglePacket(buffer); std.debug.assert(this.state.body_out_str.?.list.items.ptr != buffer.ptr); if (this.progress_node) |progress| { @@ -2790,8 +2963,13 @@ pub fn handleResponseMetadata( for (response.headers, 0..) |header, header_i| { switch (hashHeaderName(header.name)) { hashHeaderConst("Content-Length") => { - const content_length = std.fmt.parseInt(@TypeOf(this.state.body_size), header.value, 10) catch 0; - this.state.body_size = content_length; + const content_length = std.fmt.parseInt(usize, header.value, 10) catch 0; + if (this.method.hasBody()) { + this.state.content_length = content_length; + } else { + // ignore body size for HEAD requests + this.state.content_length = content_length; + } }, hashHeaderConst("Content-Encoding") => { if (strings.eqlComptime(header.value, "gzip")) { @@ -2968,6 +3146,7 @@ pub fn handleResponseMetadata( // if is no redirect or if is redirect == "manual" just proceed this.state.response_stage = if (this.state.transfer_encoding == .chunked) .body_chunk else .body; + const content_length = this.state.content_length orelse 0; // if no body is expected we should stop processing - return this.method.hasBody() and (this.state.body_size > 0 or this.state.transfer_encoding == .chunked); + return this.method.hasBody() and (content_length > 0 or this.state.transfer_encoding == .chunked); } diff --git a/src/zlib.zig b/src/zlib.zig index d79965a2ad..b578f0ede6 100644 --- a/src/zlib.zig +++ b/src/zlib.zig @@ -3,6 +3,8 @@ const std = @import("std"); const bun = @import("root").bun; +pub const MAX_WBITS = 15; + test "Zlib Read" { const expected_text = @embedFile("./zlib.test.txt"); const input = bun.asByteSlice(@embedFile("./zlib.test.gz")); @@ -525,7 +527,11 @@ pub const ZlibReaderArrayList = struct { pub fn readAll(this: *ZlibReader) ZlibError!void { defer { - this.list.shrinkRetainingCapacity(this.zlib.total_out); + if (this.list.items.len > this.zlib.total_out) { + this.list.shrinkRetainingCapacity(this.zlib.total_out); + } else if (this.zlib.total_out < this.list.capacity) { + this.list.items.len = this.zlib.total_out; + } this.list_ptr.* = this.list; } diff --git a/test/js/web/fetch/fetch-gzip.test.ts b/test/js/web/fetch/fetch-gzip.test.ts index 32888947bb..0569eaad84 100644 --- a/test/js/web/fetch/fetch-gzip.test.ts +++ b/test/js/web/fetch/fetch-gzip.test.ts @@ -86,7 +86,7 @@ it("fetch() with a protocol-relative redirect that returns a buffered gzip respo server.stop(); }); -it("fetch() with a gzip response works (one chunk, streamed, with a delay", async () => { +it("fetch() with a gzip response works (one chunk, streamed, with a delay)", async () => { var server = Bun.serve({ port: 0, @@ -121,7 +121,7 @@ it("fetch() with a gzip response works (one chunk, streamed, with a delay", asyn server.stop(); }); -it("fetch() with a gzip response works (multiple chunks, TCP server", async done => { +it("fetch() with a gzip response works (multiple chunks, TCP server)", async done => { const compressed = await Bun.file(import.meta.dir + "/fixture.html.gz").arrayBuffer(); var socketToClose!: Socket; const server = Bun.listen({ diff --git a/test/js/web/fetch/fetch.stream.test.ts b/test/js/web/fetch/fetch.stream.test.ts new file mode 100644 index 0000000000..efef6a161e --- /dev/null +++ b/test/js/web/fetch/fetch.stream.test.ts @@ -0,0 +1,1129 @@ +import { Socket, Server, TCPSocketListener } from "bun"; +import { readFileSync } from "fs"; +import { join } from "path"; +import { describe, expect, it } from "bun:test"; +import { gcTick } from "harness"; + +const fixtures = { + "fixture": readFileSync(join(import.meta.dir, "fixture.html")), + "fixture.png": readFileSync(join(import.meta.dir, "fixture.png")), + "fixture.png.gz": readFileSync(join(import.meta.dir, "fixture.png.gz")), +}; + +const invalid = Buffer.from([0xc0]); + +const bigText = Buffer.from("a".repeat(1 * 1024 * 1024)); +const smallText = Buffer.from("Hello".repeat(16)); +const empty = Buffer.alloc(0); + +describe("fetch() with streaming", () => { + it("stream still works after response get out of scope", async () => { + let server: Server | null = null; + try { + const content = "Hello, world!\n".repeat(5); + server = Bun.serve({ + port: 0, + fetch(req) { + return new Response( + new ReadableStream({ + type: "direct", + async pull(controller) { + const data = Buffer.from(content, "utf8"); + const size = data.byteLength / 5; + controller.write(data.slice(0, size)); + await controller.flush(); + await Bun.sleep(100); + controller.write(data.slice(size, size * 2)); + await controller.flush(); + await Bun.sleep(100); + controller.write(data.slice(size * 2, size * 3)); + await controller.flush(); + await Bun.sleep(100); + controller.write(data.slice(size * 3, size * 5)); + await controller.flush(); + + controller.close(); + }, + }), + { status: 200, headers: { "Content-Type": "text/plain" } }, + ); + }, + }); + + async function getReader() { + return (await fetch(`http://${server.hostname}:${server.port}`, {})).body?.getReader(); + } + gcTick(false); + const reader = await getReader(); + gcTick(false); + let buffer = Buffer.alloc(0); + let parts = 0; + while (true) { + gcTick(false); + + const { done, value } = (await reader?.read()) as ReadableStreamDefaultReadResult; + if (value) { + buffer = Buffer.concat([buffer, value]); + } + parts++; + if (done) { + break; + } + } + + gcTick(false); + expect(buffer.toString("utf8")).toBe(content); + expect(parts).toBeGreaterThan(1); + } finally { + server?.stop(); + } + }); + + it("response inspected size should reflect stream state", async () => { + let server: Server | null = null; + try { + const content = "Bun!\n".repeat(4); + server = Bun.serve({ + port: 0, + fetch(req) { + return new Response( + new ReadableStream({ + type: "direct", + async pull(controller) { + const data = Buffer.from(content, "utf8"); + const size = data.byteLength / 5; + controller.write(data.slice(0, size)); + await controller.flush(); + await Bun.sleep(100); + controller.write(data.slice(size, size * 2)); + await controller.flush(); + await Bun.sleep(100); + controller.write(data.slice(size * 2, size * 3)); + await controller.flush(); + await Bun.sleep(100); + controller.write(data.slice(size * 3, size * 4)); + await controller.flush(); + + controller.close(); + }, + }), + { status: 200, headers: { "Content-Type": "text/plain" } }, + ); + }, + }); + + function inspectBytes(response: Response) { + const match = /Response \(([0-9]+ )bytes\)/g.exec( + Bun.inspect(response, { + depth: 0, + }), + ); + if (!match) return 0; + return parseInt(match[1]?.trim(), 10); + } + + const res = await fetch(`http://${server.hostname}:${server.port}`, {}); + gcTick(false); + const reader = res.body?.getReader(); + gcTick(false); + let size = 0; + while (true) { + gcTick(false); + + const { done, value } = (await reader?.read()) as ReadableStreamDefaultReadResult; + if (value) { + size += value.length; + } + expect(inspectBytes(res)).toBe(size); + if (done) { + break; + } + } + + gcTick(false); + } finally { + server?.stop(); + } + }); + + it("can handle multiple simultaneos requests", async () => { + let server: Server | null = null; + try { + const content = "Hello, world!\n".repeat(5); + server = Bun.serve({ + port: 0, + fetch(req) { + return new Response( + new ReadableStream({ + type: "direct", + async pull(controller) { + const data = Buffer.from(content, "utf8"); + const size = data.byteLength / 5; + controller.write(data.slice(0, size)); + await controller.flush(); + await Bun.sleep(100); + controller.write(data.slice(size, size * 2)); + await controller.flush(); + await Bun.sleep(100); + controller.write(data.slice(size * 2, size * 3)); + await controller.flush(); + await Bun.sleep(100); + controller.write(data.slice(size * 3, size * 5)); + await controller.flush(); + + controller.close(); + }, + }), + { + status: 200, + headers: { + "Content-Type": "text/plain", + }, + }, + ); + }, + }); + + const server_url = `http://${server.hostname}:${server.port}`; + async function doRequest() { + await Bun.sleep(10); + const res = await fetch(server_url); + const reader = res.body?.getReader(); + let buffer = Buffer.alloc(0); + let parts = 0; + while (true) { + const { done, value } = (await reader?.read()) as ReadableStreamDefaultReadResult; + if (value) { + buffer = Buffer.concat([buffer, value]); + parts++; + } + if (done) { + break; + } + } + + gcTick(false); + expect(buffer.toString("utf8")).toBe(content); + expect(parts).toBeGreaterThan(1); + } + + await Promise.all([doRequest(), doRequest(), doRequest(), doRequest(), doRequest(), doRequest()]); + } finally { + server?.stop(); + } + }); + + it(`can handle transforms`, async () => { + let server: Server | null = null; + try { + const content = "Hello, world!\n".repeat(5); + server = Bun.serve({ + port: 0, + fetch(req) { + return new Response( + new ReadableStream({ + type: "direct", + async pull(controller) { + const data = Buffer.from(content, "utf8"); + const size = data.byteLength / 5; + controller.write(data.slice(0, size)); + await controller.flush(); + await Bun.sleep(100); + controller.write(data.slice(size, size * 2)); + await controller.flush(); + await Bun.sleep(100); + controller.write(data.slice(size * 2, size * 3)); + await controller.flush(); + await Bun.sleep(100); + controller.write(data.slice(size * 3, size * 5)); + await controller.flush(); + + controller.close(); + }, + }), + { + status: 200, + headers: { + "Content-Type": "text/plain", + }, + }, + ); + }, + }); + + const server_url = `http://${server.hostname}:${server.port}`; + const res = await fetch(server_url); + + const transform = new TransformStream({ + transform(chunk, controller) { + controller.enqueue(Buffer.from(chunk).toString("utf8").toUpperCase()); + }, + }); + + const reader = res.body?.pipeThrough(transform).getReader(); + + let result = ""; + while (true) { + const { done, value } = (await reader?.read()) as ReadableStreamDefaultReadResult; + if (value) { + result += value; + } + if (done) { + break; + } + } + + gcTick(false); + expect(result).toBe(content.toUpperCase()); + } finally { + server?.stop(); + } + }); + + it(`can handle gz images`, async () => { + let server: Server | null = null; + try { + server = Bun.serve({ + port: 0, + fetch(req) { + const data = fixtures["fixture.png.gz"]; + return new Response(data, { + status: 200, + headers: { + "Content-Type": "text/plain", + "Content-Encoding": "gzip", + }, + }); + }, + }); + + const server_url = `http://${server.hostname}:${server.port}`; + const res = await fetch(server_url); + + const reader = res.body?.getReader(); + + let buffer = Buffer.alloc(0); + while (true) { + const { done, value } = (await reader?.read()) as ReadableStreamDefaultReadResult; + if (value) { + buffer = Buffer.concat([buffer, value]); + } + if (done) { + break; + } + } + + gcTick(false); + expect(buffer).toEqual(fixtures["fixture.png"]); + } finally { + server?.stop(); + } + }); + + it(`can proxy fetch with Bun.serve`, async () => { + let server: Server | null = null; + let server_original: Server | null = null; + try { + const content = "a".repeat(64 * 1024); + + server_original = Bun.serve({ + port: 0, + fetch(req) { + return new Response( + new ReadableStream({ + type: "direct", + async pull(controller) { + const data = Buffer.from(content, "utf8"); + const size = data.byteLength / 5; + controller.write(data.slice(0, size)); + await controller.flush(); + await Bun.sleep(100); + controller.write(data.slice(size, size * 2)); + await controller.flush(); + await Bun.sleep(100); + controller.write(data.slice(size * 2, size * 3)); + await controller.flush(); + await Bun.sleep(100); + controller.write(data.slice(size * 3, size * 5)); + await controller.flush(); + + controller.close(); + }, + }), + { + status: 200, + headers: { + "Content-Type": "text/plain", + }, + }, + ); + }, + }); + + server = Bun.serve({ + port: 0, + async fetch(req) { + const response = await fetch(`http://${server_original.hostname}:${server_original.port}`, {}); + await Bun.sleep(10); + return new Response(response.body, { + status: 200, + headers: { + "Content-Type": "text/plain", + }, + }); + }, + }); + + let res = await fetch(`http://${server.hostname}:${server.port}`, {}); + gcTick(false); + const reader = res.body?.getReader(); + + let buffer = Buffer.alloc(0); + let parts = 0; + while (true) { + gcTick(false); + + const { done, value } = (await reader?.read()) as ReadableStreamDefaultReadResult; + if (value) { + buffer = Buffer.concat([buffer, value]); + parts++; + } + if (done) { + break; + } + } + + gcTick(false); + expect(buffer.toString("utf8")).toBe(content); + expect(parts).toBeGreaterThanOrEqual(1); + } finally { + server?.stop(); + server_original?.stop(); + } + }); + const matrix = [ + { name: "small", data: fixtures["fixture"] }, + { name: "small text", data: smallText }, + { name: "big text", data: bigText }, + { name: "img", data: fixtures["fixture.png"] }, + { name: "empty", data: empty }, + ]; + for (let i = 0; i < matrix.length; i++) { + const fixture = matrix[i]; + for (let j = 0; j < matrix.length; j++) { + const fixtureb = matrix[j]; + const test = fixture.name == "empty" && fixtureb.name == "empty" ? it.todo : it; + test(`can handle fixture ${fixture.name} x ${fixtureb.name}`, async () => { + let server: Server | null = null; + try { + //@ts-ignore + const data = fixture.data; + //@ts-ignore + const data_b = fixtureb.data; + const content = Buffer.concat([data, data_b]); + server = Bun.serve({ + port: 0, + fetch(req) { + return new Response( + new ReadableStream({ + type: "direct", + async pull(controller) { + controller.write(data); + await controller.flush(); + await Bun.sleep(100); + controller.write(data_b); + await controller.flush(); + controller.close(); + }, + }), + { + status: 200, + headers: { + "Content-Type": "text/plain", + }, + }, + ); + }, + }); + + const server_url = `http://${server.hostname}:${server.port}`; + const res = await fetch(server_url); + const reader = res.body?.getReader(); + let buffer = Buffer.alloc(0); + while (true) { + const { done, value } = (await reader?.read()) as ReadableStreamDefaultReadResult; + if (value) { + buffer = Buffer.concat([buffer, value]); + } + if (done) { + break; + } + } + gcTick(false); + expect(buffer).toEqual(content); + } finally { + server?.stop(); + } + }); + } + } + + type CompressionType = "no" | "gzip" | "deflate" | "br"; + type TestType = { headers: Record; compression: CompressionType; skip?: boolean }; + const types: Array = [ + { headers: {}, compression: "no" }, + { headers: { "Content-Encoding": "gzip" }, compression: "gzip" }, + { headers: { "Content-Encoding": "deflate" }, compression: "deflate" }, + // { headers: { "Content-Encoding": "br" }, compression: "br", skip: true }, // not implemented yet + ]; + + function compress(compression: CompressionType, data: Uint8Array) { + switch (compression) { + case "gzip": + return Bun.gzipSync(data); + case "deflate": + return Bun.deflateSync(data); + default: + return data; + } + } + + for (const { headers, compression, skip } of types) { + const test = skip ? it.skip : it; + + test(`with invalid utf8 with ${compression} compression`, async () => { + let server: Server | null = null; + try { + const content = Buffer.concat([invalid, Buffer.from("Hello, world!\n".repeat(5), "utf8"), invalid]); + server = Bun.serve({ + port: 0, + fetch(req) { + return new Response( + new ReadableStream({ + type: "direct", + async pull(controller) { + const data = compress(compression, content); + const size = data.byteLength / 4; + controller.write(data.slice(0, size)); + await controller.flush(); + await Bun.sleep(100); + controller.write(data.slice(size, size * 2)); + await controller.flush(); + await Bun.sleep(100); + controller.write(data.slice(size * 2, size * 3)); + await controller.flush(); + await Bun.sleep(100); + controller.write(data.slice(size * 3, size * 4)); + await controller.flush(); + + controller.close(); + }, + }), + { + status: 200, + headers: { + "Content-Type": "text/plain", + ...headers, + }, + }, + ); + }, + }); + + let res = await fetch(`http://${server.hostname}:${server.port}`, {}); + gcTick(false); + const reader = res.body?.getReader(); + + let buffer = Buffer.alloc(0); + while (true) { + gcTick(false); + + const { done, value } = (await reader?.read()) as ReadableStreamDefaultReadResult; + if (value) { + buffer = Buffer.concat([buffer, value]); + } + if (done) { + break; + } + } + + gcTick(false); + expect(buffer).toEqual(content); + } finally { + server?.stop(); + } + }); + + test(`chunked response works (single chunk) with ${compression} compression`, async () => { + let server: Server | null = null; + try { + const content = "Hello, world!\n".repeat(5); + server = Bun.serve({ + port: 0, + fetch(req) { + return new Response( + new ReadableStream({ + type: "direct", + async pull(controller) { + const data = compress(compression, Buffer.from(content, "utf8")); + controller.write(data); + await controller.flush(); + controller.close(); + }, + }), + { + status: 200, + headers: { + "Content-Type": "text/plain", + ...headers, + }, + }, + ); + }, + }); + let res = await fetch(`http://${server.hostname}:${server.port}`, {}); + gcTick(false); + const result = await res.text(); + gcTick(false); + expect(result).toBe(content); + + res = await fetch(`http://${server.hostname}:${server.port}`, {}); + gcTick(false); + const reader = res.body?.getReader(); + + let buffer = Buffer.alloc(0); + let parts = 0; + while (true) { + gcTick(false); + + const { done, value } = (await reader?.read()) as ReadableStreamDefaultReadResult; + if (value) { + buffer = Buffer.concat([buffer, value]); + parts++; + } + if (done) { + break; + } + } + + gcTick(false); + expect(buffer.toString("utf8")).toBe(content); + expect(parts).toBe(1); + } finally { + server?.stop(); + } + }); + + test(`chunked response works (multiple chunks) with ${compression} compression`, async () => { + let server: Server | null = null; + try { + const content = "Hello, world!\n".repeat(5); + server = Bun.serve({ + port: 0, + fetch(req) { + return new Response( + new ReadableStream({ + type: "direct", + async pull(controller) { + const data = compress(compression, Buffer.from(content, "utf8")); + const size = data.byteLength / 5; + controller.write(data.slice(0, size)); + await controller.flush(); + await Bun.sleep(100); + controller.write(data.slice(size, size * 2)); + await controller.flush(); + await Bun.sleep(100); + controller.write(data.slice(size * 2, size * 3)); + await controller.flush(); + await Bun.sleep(100); + controller.write(data.slice(size * 3, size * 5)); + await controller.flush(); + + controller.close(); + }, + }), + { + status: 200, + headers: { + "Content-Type": "text/plain", + ...headers, + }, + }, + ); + }, + }); + let res = await fetch(`http://${server.hostname}:${server.port}`, {}); + gcTick(false); + const result = await res.text(); + gcTick(false); + expect(result).toBe(content); + + res = await fetch(`http://${server.hostname}:${server.port}`, {}); + gcTick(false); + const reader = res.body?.getReader(); + + let buffer = Buffer.alloc(0); + let parts = 0; + while (true) { + gcTick(false); + + const { done, value } = (await reader?.read()) as ReadableStreamDefaultReadResult; + if (value) { + buffer = Buffer.concat([buffer, value]); + } + parts++; + if (done) { + break; + } + } + + gcTick(false); + expect(buffer.toString("utf8")).toBe(content); + expect(parts).toBeGreaterThan(1); + } finally { + server?.stop(); + } + }); + + test(`Content-Length response works (single part) with ${compression} compression`, async () => { + let server: Server | null = null; + try { + const content = "a".repeat(1024); + + server = Bun.serve({ + port: 0, + fetch(req) { + return new Response(compress(compression, Buffer.from(content)), { + status: 200, + headers: { + "Content-Type": "text/plain", + ...headers, + }, + }); + }, + }); + let res = await fetch(`http://${server.hostname}:${server.port}`, {}); + gcTick(false); + const result = await res.text(); + gcTick(false); + expect(result).toBe(content); + + res = await fetch(`http://${server.hostname}:${server.port}`, {}); + gcTick(false); + const reader = res.body?.getReader(); + + let buffer = Buffer.alloc(0); + let parts = 0; + while (true) { + gcTick(false); + + const { done, value } = (await reader?.read()) as ReadableStreamDefaultReadResult; + if (value) { + buffer = Buffer.concat([buffer, value]); + parts++; + } + if (done) { + break; + } + } + + gcTick(false); + expect(buffer.toString("utf8")).toBe(content); + expect(parts).toBe(1); + } finally { + server?.stop(); + } + }); + + test(`Content-Length response works (multiple parts) with ${compression} compression`, async () => { + let server: Server | null = null; + try { + const content = "a".repeat(64 * 1024); + + server = Bun.serve({ + port: 0, + fetch(req) { + return new Response(compress(compression, Buffer.from(content)), { + status: 200, + headers: { + "Content-Type": "text/plain", + ...headers, + }, + }); + }, + }); + let res = await fetch(`http://${server.hostname}:${server.port}`, {}); + gcTick(false); + const result = await res.text(); + gcTick(false); + expect(result).toBe(content); + + res = await fetch(`http://${server.hostname}:${server.port}`, {}); + gcTick(false); + const reader = res.body?.getReader(); + + let buffer = Buffer.alloc(0); + let parts = 0; + while (true) { + gcTick(false); + + const { done, value } = (await reader?.read()) as ReadableStreamDefaultReadResult; + if (value) { + buffer = Buffer.concat([buffer, value]); + parts++; + } + if (done) { + break; + } + } + + gcTick(false); + expect(buffer.toString("utf8")).toBe(content); + expect(parts).toBeGreaterThan(1); + } finally { + server?.stop(); + } + }); + + test(`Extra data should be ignored on streaming (multiple chunks, TCP server) with ${compression} compression`, async () => { + let server: TCPSocketListener | null = null; + + try { + const parts = 5; + const content = "Hello".repeat(parts); + + server = Bun.listen({ + port: 0, + hostname: "0.0.0.0", + socket: { + async open(socket) { + var corked: any[] = []; + var cork = true; + async function write(chunk: any) { + await new Promise((resolve, reject) => { + if (cork) { + corked.push(chunk); + } + + if (!cork && corked.length) { + socket.write(corked.join("")); + corked.length = 0; + socket.flush(); + } + + if (!cork) { + socket.write(chunk); + socket.flush(); + } + + resolve(); + }); + } + const compressed = compress(compression, Buffer.from(content, "utf8")); + await write("HTTP/1.1 200 OK\r\n"); + await write("Content-Type: text/plain\r\n"); + for (const [key, value] of Object.entries(headers)) { + await write(key + ": " + value + "\r\n"); + } + await write("Content-Length: " + compressed.byteLength + "\r\n"); + await write("\r\n"); + const size = compressed.byteLength / 5; + for (var i = 0; i < 5; i++) { + cork = false; + await write(compressed.slice(size * i, size * (i + 1))); + } + await write("Extra Data!"); + await write("Extra Data!"); + socket.flush(); + }, + drain(socket) {}, + }, + }); + + const res = await fetch(`http://${server.hostname}:${server.port}`, {}); + gcTick(false); + const reader = res.body?.getReader(); + + let buffer = Buffer.alloc(0); + while (true) { + gcTick(false); + + const { done, value } = (await reader?.read()) as ReadableStreamDefaultReadResult; + if (value) { + buffer = Buffer.concat([buffer, value]); + } + if (done) { + break; + } + } + + gcTick(false); + expect(buffer.toString("utf8")).toBe(content); + } finally { + server?.stop(true); + } + }); + + test(`Missing data should timeout on streaming (multiple chunks, TCP server) with ${compression} compression`, async () => { + let server: TCPSocketListener | null = null; + + try { + const parts = 5; + const content = "Hello".repeat(parts); + + server = Bun.listen({ + port: 0, + hostname: "0.0.0.0", + socket: { + async open(socket) { + var corked: any[] = []; + var cork = true; + async function write(chunk: any) { + await new Promise((resolve, reject) => { + if (cork) { + corked.push(chunk); + } + + if (!cork && corked.length) { + socket.write(corked.join("")); + corked.length = 0; + socket.flush(); + } + + if (!cork) { + socket.write(chunk); + socket.flush(); + } + + resolve(); + }); + } + const compressed = compress(compression, Buffer.from(content, "utf8")); + await write("HTTP/1.1 200 OK\r\n"); + await write("Content-Type: text/plain\r\n"); + for (const [key, value] of Object.entries(headers)) { + await write(key + ": " + value + "\r\n"); + } + // 10 extra missing bytes that we will never sent + await write("Content-Length: " + compressed.byteLength + 10 + "\r\n"); + await write("\r\n"); + const size = compressed.byteLength / 5; + for (var i = 0; i < 5; i++) { + cork = false; + await write(compressed.slice(size * i, size * (i + 1))); + } + socket.flush(); + }, + drain(socket) {}, + }, + }); + + const res = await fetch(`http://${server.hostname}:${server.port}`, { + signal: AbortSignal.timeout(1000), + }); + gcTick(false); + try { + const reader = res.body?.getReader(); + + let buffer = Buffer.alloc(0); + while (true) { + gcTick(false); + + const { done, value } = (await reader?.read()) as ReadableStreamDefaultReadResult; + if (value) { + buffer = Buffer.concat([buffer, value]); + } + if (done) { + break; + } + } + + gcTick(false); + expect(buffer.toString("utf8")).toBe("unreachable"); + } catch (err) { + expect((err as Error).name).toBe("TimeoutError"); + } + } finally { + server?.stop(true); + } + }); + + if (compression !== "no") { + test(`can handle corrupted ${compression} compression`, async () => { + let server: TCPSocketListener | null = null; + + try { + const parts = 5; + const content = "Hello".repeat(parts); + server = Bun.listen({ + port: 0, + hostname: "0.0.0.0", + socket: { + async open(socket) { + var corked: any[] = []; + var cork = true; + async function write(chunk: any) { + await new Promise((resolve, reject) => { + if (cork) { + corked.push(chunk); + } + + if (!cork && corked.length) { + socket.write(corked.join("")); + corked.length = 0; + socket.flush(); + } + + if (!cork) { + socket.write(chunk); + socket.flush(); + } + + resolve(); + }); + } + const compressed = compress(compression, Buffer.from(content, "utf8")); + await write("HTTP/1.1 200 OK\r\n"); + await write("Content-Type: text/plain\r\n"); + for (const [key, value] of Object.entries(headers)) { + await write(key + ": " + value + "\r\n"); + } + // 10 extra missing bytes that we will never sent in this case we will wait to close + await write("Content-Length: " + compressed.byteLength + "\r\n"); + await write("\r\n"); + const size = compressed.byteLength / 5; + compressed[0] = 0; // corrupt data + cork = false; + for (var i = 0; i < 5; i++) { + await write(compressed.slice(size * i, size * (i + 1))); + } + socket.flush(); + }, + drain(socket) {}, + }, + }); + + const res = await fetch(`http://${server.hostname}:${server.port}`, {}); + gcTick(false); + + try { + const reader = res.body?.getReader(); + + let buffer = Buffer.alloc(0); + + while (true) { + gcTick(false); + const read_promise = reader?.read(); + const { done, value } = (await read_promise) as ReadableStreamDefaultReadResult; + + if (value) { + buffer = Buffer.concat([buffer, value]); + } + + if (done) { + break; + } + } + + gcTick(false); + expect(buffer.toString("utf8")).toBe("unreachable"); + } catch (err) { + expect((err as Error).name).toBe("ZlibError"); + } + } finally { + server?.stop(true); + } + }); + } + + test(`can handle socket close with ${compression} compression`, async () => { + let server: TCPSocketListener | null = null; + + try { + const parts = 5; + const content = "Hello".repeat(parts); + const { promise, resolve: resolveSocket } = Promise.withResolvers(); + server = Bun.listen({ + port: 0, + hostname: "0.0.0.0", + socket: { + async open(socket) { + var corked: any[] = []; + var cork = true; + async function write(chunk: any) { + await new Promise((resolve, reject) => { + if (cork) { + corked.push(chunk); + } + + if (!cork && corked.length) { + socket.write(corked.join("")); + corked.length = 0; + socket.flush(); + } + + if (!cork) { + socket.write(chunk); + socket.flush(); + } + + resolve(); + }); + } + const compressed = compress(compression, Buffer.from(content, "utf8")); + await write("HTTP/1.1 200 OK\r\n"); + await write("Content-Type: text/plain\r\n"); + for (const [key, value] of Object.entries(headers)) { + await write(key + ": " + value + "\r\n"); + } + // 10 extra missing bytes that we will never sent in this case we will wait to close + await write("Content-Length: " + compressed.byteLength + 10 + "\r\n"); + await write("\r\n"); + const size = compressed.byteLength / 5; + for (var i = 0; i < 5; i++) { + cork = false; + await write(compressed.slice(size * i, size * (i + 1))); + } + socket.flush(); + resolveSocket(socket); + }, + drain(socket) {}, + }, + }); + + const res = await fetch(`http://${server.hostname}:${server.port}`, {}); + gcTick(false); + + let socket: Socket | null = await promise; + try { + const reader = res.body?.getReader(); + + let buffer = Buffer.alloc(0); + + while (true) { + gcTick(false); + const read_promise = reader?.read(); + socket?.end(); + socket = null; + const { done, value } = (await read_promise) as ReadableStreamDefaultReadResult; + + if (value) { + buffer = Buffer.concat([buffer, value]); + } + + if (done) { + break; + } + } + + gcTick(false); + expect(buffer.toString("utf8")).toBe("unreachable"); + } catch (err) { + expect((err as Error).name).toBe("ConnectionClosed"); + } + } finally { + server?.stop(true); + } + }); + } +}); diff --git a/test/js/web/fetch/fetch.test.ts b/test/js/web/fetch/fetch.test.ts index a381cb3203..59847dde98 100644 --- a/test/js/web/fetch/fetch.test.ts +++ b/test/js/web/fetch/fetch.test.ts @@ -4,7 +4,7 @@ import { chmodSync, mkdtempSync, readFileSync, realpathSync, rmSync, writeFileSy import { mkfifo } from "mkfifo"; import { tmpdir } from "os"; import { join } from "path"; -import { gc, withoutAggressiveGC } from "harness"; +import { gc, withoutAggressiveGC, gcTick } from "harness"; const tmp_dir = mkdtempSync(join(realpathSync(tmpdir()), "fetch.test")); @@ -1334,11 +1334,18 @@ it("fetch() file:// works", async () => { expect(await (await fetch(new URL("fetch.test.ts", import.meta.url))).text()).toEqual( await Bun.file(Bun.fileURLToPath(new URL("fetch.test.ts", import.meta.url))).text(), ); - expect(await (await fetch(new URL("file with space in the name.txt", import.meta.url))).text()).toEqual( - await Bun.file(Bun.fileURLToPath(new URL("file with space in the name.txt", import.meta.url))).text(), - ); + gc(true); + var fileResponse = await fetch(new URL("file with space in the name.txt", import.meta.url)); + gc(true); + var fileResponseText = await fileResponse.text(); + gc(true); + var bunFile = Bun.file(Bun.fileURLToPath(new URL("file with space in the name.txt", import.meta.url))); + gc(true); + var bunFileText = await bunFile.text(); + gc(true); + expect(fileResponseText).toEqual(bunFileText); + gc(true); }); - it("cloned response headers are independent before accessing", () => { const response = new Response("hello", { headers: { diff --git a/test/js/web/fetch/fixture.png b/test/js/web/fetch/fixture.png new file mode 100644 index 0000000000000000000000000000000000000000..b34dbd29d785e1ea7206c4c979d393ffe7c1481b GIT binary patch literal 82022 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⪼ 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 literal 0 HcmV?d00001 diff --git a/test/js/web/fetch/fixture.png.gz b/test/js/web/fetch/fixture.png.gz new file mode 100644 index 0000000000000000000000000000000000000000..8c007181150fdd062a2a530511310fe68aa0a2d1 GIT binary patch literal 78116 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