aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Ciro Spaciari <ciro.spaciari@gmail.com> 2023-02-15 19:20:40 -0300
committerGravatar GitHub <noreply@github.com> 2023-02-15 14:20:40 -0800
commit597053ea91a83ed0ce98bf1b8bb59fbf282c3619 (patch)
tree51141e81e587d8ce747fe81fb6064f5740d5bc40 /src
parent1c221d33b0def3810c262bd19a4bf8060389dae0 (diff)
downloadbun-597053ea91a83ed0ce98bf1b8bb59fbf282c3619.tar.gz
bun-597053ea91a83ed0ce98bf1b8bb59fbf282c3619.tar.zst
bun-597053ea91a83ed0ce98bf1b8bb59fbf282c3619.zip
feat(fetch) AbortSignal (#2019)
* add fetch abort signal * get aborted (still segfaults) * bidings.zig u0 error * still GC/memory error * fix start crash * fix AbortSignal fromJS * change fromJS to obj.as * addAbortSignalEventListenner * handle abort types, and add tests * fix tests * add custom reason test * merge 2 substring methods, use MAKE_STATIC_STRING_IMPL * fix create AbortError and TimeoutError, move globalThis and exception creation to main thread * fix tests and rebuild headers * no need to check with substring reason is already an exception * no need to check with substring reason is already an exception * fix dumb error inverting conditions for check reason * fix custom reason behavior
Diffstat (limited to 'src')
-rw-r--r--src/bun.js/bindings/ZigGlobalObject.cpp2
-rw-r--r--src/bun.js/bindings/bindings.cpp97
-rw-r--r--src/bun.js/bindings/bindings.zig79
-rw-r--r--src/bun.js/bindings/headers-cpp.h16
-rw-r--r--src/bun.js/bindings/headers.h17
-rw-r--r--src/bun.js/bindings/headers.zig9
-rw-r--r--src/bun.js/bindings/sizes.zig2
-rw-r--r--src/bun.js/bindings/webcore/AbortSignal.cpp6
-rw-r--r--src/bun.js/bindings/webcore/AbortSignal.h2
-rw-r--r--src/bun.js/event_loop.zig1
-rw-r--r--src/bun.js/javascript.zig2
-rw-r--r--src/bun.js/webcore/response.zig45
-rw-r--r--src/bundler.zig2
-rw-r--r--src/http_client_async.zig156
-rw-r--r--src/install/install.zig4
-rw-r--r--src/string_immutable.zig1
16 files changed, 383 insertions, 58 deletions
diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp
index 0f4fe92e2..8fd9f366a 100644
--- a/src/bun.js/bindings/ZigGlobalObject.cpp
+++ b/src/bun.js/bindings/ZigGlobalObject.cpp
@@ -1533,7 +1533,7 @@ JSC_DEFINE_HOST_FUNCTION(whenSignalAborted, (JSGlobalObject * globalObject, Call
Ref<AbortAlgorithm> abortAlgorithm = JSAbortAlgorithm::create(vm, callFrame->uncheckedArgument(1).getObject());
- bool result = AbortSignal::whenSignalAborted(abortSignal->wrapped(), WTFMove(abortAlgorithm));
+ bool result = WebCore::AbortSignal::whenSignalAborted(abortSignal->wrapped(), WTFMove(abortAlgorithm));
return JSValue::encode(result ? JSValue(JSC::JSValue::JSTrue) : JSValue(JSC::JSValue::JSFalse));
}
diff --git a/src/bun.js/bindings/bindings.cpp b/src/bun.js/bindings/bindings.cpp
index aa8a28601..4b614788d 100644
--- a/src/bun.js/bindings/bindings.cpp
+++ b/src/bun.js/bindings/bindings.cpp
@@ -84,6 +84,8 @@
#include "JavaScriptCore/PropertyNameArray.h"
#include "JavaScriptCore/HashMapImpl.h"
#include "JavaScriptCore/HashMapImplInlines.h"
+#include "webcore/JSAbortSignal.h"
+#include "JSAbortAlgorithm.h"
#include "DOMFormData.h"
#include "JSDOMFormData.h"
@@ -3732,6 +3734,101 @@ extern "C" void JSC__JSGlobalObject__queueMicrotaskJob(JSC__JSGlobalObject* arg0
JSC::JSValue::decode(JSValue4));
}
+extern "C" JSC__AbortSignal* JSC__AbortSignal__signal(JSC__AbortSignal* arg0, JSC__JSValue JSValue1) {
+ WebCore::AbortSignal* abortSignal = reinterpret_cast<WebCore::AbortSignal*>(arg0);
+ abortSignal->signalAbort(JSC::JSValue::decode(JSValue1));
+ return arg0;
+}
+
+extern "C" bool JSC__AbortSignal__aborted(JSC__AbortSignal* arg0) {
+ WebCore::AbortSignal* abortSignal = reinterpret_cast<WebCore::AbortSignal*>(arg0);
+ return abortSignal->aborted();
+}
+
+extern "C" JSC__JSValue JSC__AbortSignal__abortReason(JSC__AbortSignal* arg0) {
+ WebCore::AbortSignal* abortSignal = reinterpret_cast<WebCore::AbortSignal*>(arg0);
+ return JSC::JSValue::encode(abortSignal->reason().getValue());
+}
+
+
+extern "C" JSC__AbortSignal* JSC__AbortSignal__ref(JSC__AbortSignal* arg0) {
+ WebCore::AbortSignal* abortSignal = reinterpret_cast<WebCore::AbortSignal*>(arg0);
+ abortSignal->ref();
+ return arg0;
+}
+
+extern "C" JSC__AbortSignal* JSC__AbortSignal__unref(JSC__AbortSignal* arg0) {
+ WebCore::AbortSignal* abortSignal = reinterpret_cast<WebCore::AbortSignal*>(arg0);
+ abortSignal->deref();
+ return arg0;
+}
+
+extern "C" JSC__AbortSignal* JSC__AbortSignal__addListener(JSC__AbortSignal* arg0, void* ctx, void (*callback)(void* ctx, JSC__JSValue reason)) {
+ WebCore::AbortSignal* abortSignal = reinterpret_cast<WebCore::AbortSignal*>(arg0);
+
+ if(abortSignal->aborted()){
+ callback(ctx, JSC::JSValue::encode(abortSignal->reason().getValue()));
+ return arg0;
+ }
+
+ abortSignal->addNativeCallback(std::make_tuple(ctx, callback));
+
+ return arg0;
+}
+extern "C" JSC__AbortSignal* JSC__AbortSignal__fromJS(JSC__JSValue value)
+{
+ JSC::JSValue decodedValue = JSC::JSValue::decode(value);
+ if (decodedValue.isEmpty())
+ return nullptr;
+ WebCore::JSAbortSignal* object = JSC::jsDynamicCast<WebCore::JSAbortSignal*>(decodedValue);
+ if (!object)
+ return nullptr;
+
+ return reinterpret_cast<JSC__AbortSignal*>(&object->wrapped());
+}
+static auto ABORT_ERROR_NAME = MAKE_STATIC_STRING_IMPL("AbortError");
+extern "C" JSC__JSValue JSC__AbortSignal__createAbortError(const ZigString* message, const ZigString* arg1,
+ JSC__JSGlobalObject* globalObject)
+{
+ JSC::VM& vm = globalObject->vm();
+ ZigString code = *arg1;
+ JSC::JSObject* error = Zig::getErrorInstance(message, globalObject).asCell()->getObject();
+
+ error->putDirect(
+ vm, vm.propertyNames->name,
+ JSC::JSValue(JSC::jsOwnedString(vm, ABORT_ERROR_NAME)),
+ 0);
+
+ if (code.len > 0) {
+ auto clientData = WebCore::clientData(vm);
+ JSC::JSValue codeValue = Zig::toJSStringValue(code, globalObject);
+ error->putDirect(vm, clientData->builtinNames().codePublicName(), codeValue, 0);
+ }
+
+ return JSC::JSValue::encode(error);
+}
+
+static auto TIMEOUT_ERROR_NAME = MAKE_STATIC_STRING_IMPL("TimeoutError");
+extern "C" JSC__JSValue JSC__AbortSignal__createTimeoutError(const ZigString* message, const ZigString* arg1,
+ JSC__JSGlobalObject* globalObject)
+{
+ JSC::VM& vm = globalObject->vm();
+ ZigString code = *arg1;
+ JSC::JSObject* error = Zig::getErrorInstance(message, globalObject).asCell()->getObject();
+
+ error->putDirect(
+ vm, vm.propertyNames->name,
+ JSC::JSValue(JSC::jsOwnedString(vm, TIMEOUT_ERROR_NAME)),
+ 0);
+
+ if (code.len > 0) {
+ auto clientData = WebCore::clientData(vm);
+ JSC::JSValue codeValue = Zig::toJSStringValue(code, globalObject);
+ error->putDirect(vm, clientData->builtinNames().codePublicName(), codeValue, 0);
+ }
+
+ return JSC::JSValue::encode(error);
+}
#pragma mark - WebCore::DOMFormData
CPP_DECL void WebCore__DOMFormData__append(WebCore__DOMFormData* arg0, ZigString* arg1, ZigString* arg2)
diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig
index 4c1469564..6b5386a68 100644
--- a/src/bun.js/bindings/bindings.zig
+++ b/src/bun.js/bindings/bindings.zig
@@ -209,12 +209,19 @@ pub const ZigString = extern struct {
return ZigString__toJSONObject(&this, globalThis);
}
- pub fn substring(this: ZigString, offset: usize) ZigString {
+ pub fn substring(this: ZigString, offset: usize, maxlen: usize) ZigString {
+ var len: usize = undefined;
+ if(maxlen == 0){
+ len = this.len;
+ }else {
+ len = @max(this.len, maxlen);
+ }
+
if (this.is16Bit()) {
- return ZigString.from16Slice(this.utf16SliceAligned()[@min(this.len, offset)..]);
+ return ZigString.from16Slice(this.utf16SliceAligned()[@min(this.len, offset)..len]);
}
- var out = ZigString.init(this.slice()[@min(this.len, offset)..]);
+ var out = ZigString.init(this.slice()[@min(this.len, offset)..len]);
if (this.isUTF8()) {
out.markUTF8();
}
@@ -1662,6 +1669,72 @@ pub fn PromiseCallback(comptime Type: type, comptime CallbackFunction: fn (*Type
}.callback;
}
+pub const AbortSignal = extern opaque {
+ pub const shim = Shimmer("JSC", "AbortSignal", @This());
+ const cppFn = shim.cppFn;
+ pub const include = "WebCore/AbortSignal.h";
+ pub const name = "JSC::AbortSignal";
+ pub const namespace = "JSC";
+
+ pub fn addListener(
+ this: *AbortSignal,
+ ctx: ?*anyopaque,
+ callback: *const fn (?*anyopaque, JSValue) callconv(.C) void,
+ ) *AbortSignal {
+ return cppFn("addListener", .{ this, ctx, callback });
+ }
+ pub fn signal(
+ this: *AbortSignal,
+ reason: JSValue,
+ ) *AbortSignal {
+ return cppFn("signal", .{ this, reason });
+ }
+
+ pub fn aborted(this: *AbortSignal) bool {
+ return cppFn("aborted", .{this});
+ }
+
+ pub fn abortReason(this: *AbortSignal) JSValue {
+ return cppFn("abortReason", .{this});
+ }
+
+ pub fn ref(
+ this: *AbortSignal,
+ ) *AbortSignal {
+ return cppFn("ref", .{this});
+ }
+
+ pub fn unref(
+ this: *AbortSignal,
+ ) *AbortSignal {
+ return cppFn("unref", .{this});
+ }
+
+ pub fn fromJS(value: JSValue) ?*AbortSignal {
+ return cppFn("fromJS", .{value});
+ }
+
+ pub fn createAbortError(message: *const ZigString, code: *const ZigString, global: *JSGlobalObject) JSValue {
+ return cppFn("createAbortError", .{ message, code, global });
+ }
+
+ pub fn createTimeoutError(message: *const ZigString, code: *const ZigString, global: *JSGlobalObject) JSValue {
+ return cppFn("createTimeoutError", .{ message, code, global });
+ }
+
+ pub const Extern = [_][]const u8{
+ "createAbortError",
+ "createTimeoutError",
+ "ref",
+ "unref",
+ "signal",
+ "abortReason",
+ "aborted",
+ "addListener",
+ "fromJS",
+ };
+};
+
pub const JSPromise = extern struct {
pub const shim = Shimmer("JSC", "JSPromise", @This());
bytes: shim.Bytes,
diff --git a/src/bun.js/bindings/headers-cpp.h b/src/bun.js/bindings/headers-cpp.h
index 4dc7a2143..d0abc7db0 100644
--- a/src/bun.js/bindings/headers-cpp.h
+++ b/src/bun.js/bindings/headers-cpp.h
@@ -1,4 +1,4 @@
-//-- AUTOGENERATED FILE -- 1676266700
+//-- AUTOGENERATED FILE -- 1676470760
// clang-format off
#pragma once
@@ -56,6 +56,14 @@ extern "C" const size_t JSC__JSString_object_align_ = alignof(JSC::JSString);
extern "C" const size_t JSC__JSModuleLoader_object_size_ = sizeof(JSC::JSModuleLoader);
extern "C" const size_t JSC__JSModuleLoader_object_align_ = alignof(JSC::JSModuleLoader);
+#ifndef INCLUDED_WebCore_AbortSignal_h
+#define INCLUDED_WebCore_AbortSignal_h
+#include "WebCore/AbortSignal.h"
+#endif
+
+extern "C" const size_t JSC__AbortSignal_object_size_ = sizeof(JSC::AbortSignal);
+extern "C" const size_t JSC__AbortSignal_object_align_ = alignof(JSC::AbortSignal);
+
#ifndef INCLUDED_JavaScriptCore_JSPromise_h
#define INCLUDED_JavaScriptCore_JSPromise_h
#include "JavaScriptCore/JSPromise.h"
@@ -160,8 +168,8 @@ extern "C" const size_t Zig__ConsoleClient_object_align_ = alignof(Zig::ConsoleC
extern "C" const size_t Bun__Timer_object_size_ = sizeof(Bun__Timer);
extern "C" const size_t Bun__Timer_object_align_ = alignof(Bun__Timer);
-const size_t sizes[39] = {sizeof(JSC::JSObject), sizeof(WebCore::DOMURL), sizeof(WebCore::DOMFormData), sizeof(WebCore::FetchHeaders), sizeof(SystemError), sizeof(JSC::JSCell), sizeof(JSC::JSString), sizeof(JSC::JSModuleLoader), sizeof(JSC::JSPromise), sizeof(JSC::JSInternalPromise), sizeof(JSC::JSFunction), sizeof(JSC::JSGlobalObject), sizeof(JSC::JSValue), sizeof(JSC::Exception), sizeof(JSC::VM), sizeof(JSC::ThrowScope), sizeof(JSC::CatchScope), sizeof(FFI__ptr), sizeof(Reader__u8), sizeof(Reader__u16), sizeof(Reader__u32), sizeof(Reader__ptr), sizeof(Reader__i8), sizeof(Reader__i16), sizeof(Reader__i32), sizeof(Reader__f32), sizeof(Reader__f64), sizeof(Reader__i64), sizeof(Reader__u64), sizeof(Reader__intptr), sizeof(Crypto__getRandomValues), sizeof(Crypto__randomUUID), sizeof(Crypto__timingSafeEqual), sizeof(Zig::GlobalObject), sizeof(Bun__Path), sizeof(ArrayBufferSink), sizeof(HTTPSResponseSink), sizeof(HTTPResponseSink), sizeof(FileSink)};
+const size_t sizes[40] = {sizeof(JSC::JSObject), sizeof(WebCore::DOMURL), sizeof(WebCore::DOMFormData), sizeof(WebCore::FetchHeaders), sizeof(SystemError), sizeof(JSC::JSCell), sizeof(JSC::JSString), sizeof(JSC::JSModuleLoader), sizeof(JSC::AbortSignal), sizeof(JSC::JSPromise), sizeof(JSC::JSInternalPromise), sizeof(JSC::JSFunction), sizeof(JSC::JSGlobalObject), sizeof(JSC::JSValue), sizeof(JSC::Exception), sizeof(JSC::VM), sizeof(JSC::ThrowScope), sizeof(JSC::CatchScope), sizeof(FFI__ptr), sizeof(Reader__u8), sizeof(Reader__u16), sizeof(Reader__u32), sizeof(Reader__ptr), sizeof(Reader__i8), sizeof(Reader__i16), sizeof(Reader__i32), sizeof(Reader__f32), sizeof(Reader__f64), sizeof(Reader__i64), sizeof(Reader__u64), sizeof(Reader__intptr), sizeof(Crypto__getRandomValues), sizeof(Crypto__randomUUID), sizeof(Crypto__timingSafeEqual), sizeof(Zig::GlobalObject), sizeof(Bun__Path), sizeof(ArrayBufferSink), sizeof(HTTPSResponseSink), sizeof(HTTPResponseSink), sizeof(FileSink)};
-const char* names[39] = {"JSC__JSObject", "WebCore__DOMURL", "WebCore__DOMFormData", "WebCore__FetchHeaders", "SystemError", "JSC__JSCell", "JSC__JSString", "JSC__JSModuleLoader", "JSC__JSPromise", "JSC__JSInternalPromise", "JSC__JSFunction", "JSC__JSGlobalObject", "JSC__JSValue", "JSC__Exception", "JSC__VM", "JSC__ThrowScope", "JSC__CatchScope", "FFI__ptr", "Reader__u8", "Reader__u16", "Reader__u32", "Reader__ptr", "Reader__i8", "Reader__i16", "Reader__i32", "Reader__f32", "Reader__f64", "Reader__i64", "Reader__u64", "Reader__intptr", "Crypto__getRandomValues", "Crypto__randomUUID", "Crypto__timingSafeEqual", "Zig__GlobalObject", "Bun__Path", "ArrayBufferSink", "HTTPSResponseSink", "HTTPResponseSink", "FileSink"};
+const char* names[40] = {"JSC__JSObject", "WebCore__DOMURL", "WebCore__DOMFormData", "WebCore__FetchHeaders", "SystemError", "JSC__JSCell", "JSC__JSString", "JSC__JSModuleLoader", "JSC__AbortSignal", "JSC__JSPromise", "JSC__JSInternalPromise", "JSC__JSFunction", "JSC__JSGlobalObject", "JSC__JSValue", "JSC__Exception", "JSC__VM", "JSC__ThrowScope", "JSC__CatchScope", "FFI__ptr", "Reader__u8", "Reader__u16", "Reader__u32", "Reader__ptr", "Reader__i8", "Reader__i16", "Reader__i32", "Reader__f32", "Reader__f64", "Reader__i64", "Reader__u64", "Reader__intptr", "Crypto__getRandomValues", "Crypto__randomUUID", "Crypto__timingSafeEqual", "Zig__GlobalObject", "Bun__Path", "ArrayBufferSink", "HTTPSResponseSink", "HTTPResponseSink", "FileSink"};
-const size_t aligns[39] = {alignof(JSC::JSObject), alignof(WebCore::DOMURL), alignof(WebCore::DOMFormData), alignof(WebCore::FetchHeaders), alignof(SystemError), alignof(JSC::JSCell), alignof(JSC::JSString), alignof(JSC::JSModuleLoader), alignof(JSC::JSPromise), alignof(JSC::JSInternalPromise), alignof(JSC::JSFunction), alignof(JSC::JSGlobalObject), alignof(JSC::JSValue), alignof(JSC::Exception), alignof(JSC::VM), alignof(JSC::ThrowScope), alignof(JSC::CatchScope), alignof(FFI__ptr), alignof(Reader__u8), alignof(Reader__u16), alignof(Reader__u32), alignof(Reader__ptr), alignof(Reader__i8), alignof(Reader__i16), alignof(Reader__i32), alignof(Reader__f32), alignof(Reader__f64), alignof(Reader__i64), alignof(Reader__u64), alignof(Reader__intptr), alignof(Crypto__getRandomValues), alignof(Crypto__randomUUID), alignof(Crypto__timingSafeEqual), alignof(Zig::GlobalObject), alignof(Bun__Path), alignof(ArrayBufferSink), alignof(HTTPSResponseSink), alignof(HTTPResponseSink), alignof(FileSink)};
+const size_t aligns[40] = {alignof(JSC::JSObject), alignof(WebCore::DOMURL), alignof(WebCore::DOMFormData), alignof(WebCore::FetchHeaders), alignof(SystemError), alignof(JSC::JSCell), alignof(JSC::JSString), alignof(JSC::JSModuleLoader), alignof(JSC::AbortSignal), alignof(JSC::JSPromise), alignof(JSC::JSInternalPromise), alignof(JSC::JSFunction), alignof(JSC::JSGlobalObject), alignof(JSC::JSValue), alignof(JSC::Exception), alignof(JSC::VM), alignof(JSC::ThrowScope), alignof(JSC::CatchScope), alignof(FFI__ptr), alignof(Reader__u8), alignof(Reader__u16), alignof(Reader__u32), alignof(Reader__ptr), alignof(Reader__i8), alignof(Reader__i16), alignof(Reader__i32), alignof(Reader__f32), alignof(Reader__f64), alignof(Reader__i64), alignof(Reader__u64), alignof(Reader__intptr), alignof(Crypto__getRandomValues), alignof(Crypto__randomUUID), alignof(Crypto__timingSafeEqual), alignof(Zig::GlobalObject), alignof(Bun__Path), alignof(ArrayBufferSink), alignof(HTTPSResponseSink), alignof(HTTPResponseSink), alignof(FileSink)};
diff --git a/src/bun.js/bindings/headers.h b/src/bun.js/bindings/headers.h
index 159a7acbd..59450ecf1 100644
--- a/src/bun.js/bindings/headers.h
+++ b/src/bun.js/bindings/headers.h
@@ -1,5 +1,5 @@
// clang-format off
-//-- AUTOGENERATED FILE -- 1676266700
+//-- AUTOGENERATED FILE -- 1676470760
#pragma once
#include <stddef.h>
@@ -55,6 +55,7 @@ typedef void* JSClassRef;
typedef bJSC__JSObject JSC__JSObject; // JSC::JSObject
typedef WebSocketClient WebSocketClient;
typedef WebSocketHTTPSClient WebSocketHTTPSClient;
+ typedef struct JSC__AbortSignal JSC__AbortSignal; // JSC::AbortSignal
typedef JSClassRef JSClassRef;
typedef bJSC__VM JSC__VM; // JSC::VM
typedef Bun__ArrayBuffer Bun__ArrayBuffer;
@@ -85,6 +86,7 @@ typedef void* JSClassRef;
class JSGlobalObject;
class JSPromise;
class Exception;
+ class AbortSignal;
class JSString;
class JSInternalPromise;
class CatchScope;
@@ -116,6 +118,7 @@ typedef void* JSClassRef;
using JSC__JSGlobalObject = JSC::JSGlobalObject;
using JSC__JSPromise = JSC::JSPromise;
using JSC__Exception = JSC::Exception;
+ using JSC__AbortSignal = JSC::AbortSignal;
using JSC__JSString = JSC::JSString;
using JSC__JSInternalPromise = JSC::JSInternalPromise;
using JSC__CatchScope = JSC::CatchScope;
@@ -202,6 +205,18 @@ CPP_DECL void JSC__JSString__toZigString(JSC__JSString* arg0, JSC__JSGlobalObjec
CPP_DECL JSC__JSValue JSC__JSModuleLoader__evaluate(JSC__JSGlobalObject* arg0, const unsigned char* arg1, size_t arg2, const unsigned char* arg3, size_t arg4, const unsigned char* arg5, size_t arg6, JSC__JSValue JSValue7, JSC__JSValue* arg8);
CPP_DECL JSC__JSInternalPromise* JSC__JSModuleLoader__loadAndEvaluateModule(JSC__JSGlobalObject* arg0, const ZigString* arg1);
+#pragma mark - JSC::AbortSignal
+
+CPP_DECL bool JSC__AbortSignal__aborted(JSC__AbortSignal* arg0);
+CPP_DECL JSC__JSValue JSC__AbortSignal__abortReason(JSC__AbortSignal* arg0);
+CPP_DECL JSC__AbortSignal* JSC__AbortSignal__addListener(JSC__AbortSignal* arg0, void* arg1, void(* ArgFn2)(void* arg0, JSC__JSValue JSValue1)) __attribute__((nonnull (2)));
+CPP_DECL JSC__JSValue JSC__AbortSignal__createAbortError(const ZigString* arg0, const ZigString* arg1, JSC__JSGlobalObject* arg2);
+CPP_DECL JSC__JSValue JSC__AbortSignal__createTimeoutError(const ZigString* arg0, const ZigString* arg1, JSC__JSGlobalObject* arg2);
+CPP_DECL JSC__AbortSignal* JSC__AbortSignal__fromJS(JSC__JSValue JSValue0);
+CPP_DECL JSC__AbortSignal* JSC__AbortSignal__ref(JSC__AbortSignal* arg0);
+CPP_DECL JSC__AbortSignal* JSC__AbortSignal__signal(JSC__AbortSignal* arg0, JSC__JSValue JSValue1);
+CPP_DECL JSC__AbortSignal* JSC__AbortSignal__unref(JSC__AbortSignal* arg0);
+
#pragma mark - JSC::JSPromise
CPP_DECL JSC__JSValue JSC__JSPromise__asValue(JSC__JSPromise* arg0, JSC__JSGlobalObject* arg1);
diff --git a/src/bun.js/bindings/headers.zig b/src/bun.js/bindings/headers.zig
index 756a08bcc..9f2e1580d 100644
--- a/src/bun.js/bindings/headers.zig
+++ b/src/bun.js/bindings/headers.zig
@@ -135,6 +135,15 @@ pub extern fn JSC__JSString__toObject(arg0: [*c]bindings.JSString, arg1: *bindin
pub extern fn JSC__JSString__toZigString(arg0: [*c]bindings.JSString, arg1: *bindings.JSGlobalObject, arg2: [*c]ZigString) void;
pub extern fn JSC__JSModuleLoader__evaluate(arg0: *bindings.JSGlobalObject, arg1: [*c]const u8, arg2: usize, arg3: [*c]const u8, arg4: usize, arg5: [*c]const u8, arg6: usize, JSValue7: JSC__JSValue, arg8: [*c]bindings.JSValue) JSC__JSValue;
pub extern fn JSC__JSModuleLoader__loadAndEvaluateModule(arg0: *bindings.JSGlobalObject, arg1: [*c]const ZigString) [*c]bindings.JSInternalPromise;
+pub extern fn JSC__AbortSignal__aborted(arg0: ?*bindings.AbortSignal) bool;
+pub extern fn JSC__AbortSignal__abortReason(arg0: ?*bindings.AbortSignal) JSC__JSValue;
+pub extern fn JSC__AbortSignal__addListener(arg0: ?*bindings.AbortSignal, arg1: ?*anyopaque, ArgFn2: ?*const fn (?*anyopaque, JSC__JSValue) callconv(.C) void) ?*bindings.AbortSignal;
+pub extern fn JSC__AbortSignal__createAbortError(arg0: [*c]const ZigString, arg1: [*c]const ZigString, arg2: *bindings.JSGlobalObject) JSC__JSValue;
+pub extern fn JSC__AbortSignal__createTimeoutError(arg0: [*c]const ZigString, arg1: [*c]const ZigString, arg2: *bindings.JSGlobalObject) JSC__JSValue;
+pub extern fn JSC__AbortSignal__fromJS(JSValue0: JSC__JSValue) ?*bindings.AbortSignal;
+pub extern fn JSC__AbortSignal__ref(arg0: ?*bindings.AbortSignal) ?*bindings.AbortSignal;
+pub extern fn JSC__AbortSignal__signal(arg0: ?*bindings.AbortSignal, JSValue1: JSC__JSValue) ?*bindings.AbortSignal;
+pub extern fn JSC__AbortSignal__unref(arg0: ?*bindings.AbortSignal) ?*bindings.AbortSignal;
pub extern fn JSC__JSPromise__asValue(arg0: ?*bindings.JSPromise, arg1: *bindings.JSGlobalObject) JSC__JSValue;
pub extern fn JSC__JSPromise__create(arg0: *bindings.JSGlobalObject) ?*bindings.JSPromise;
pub extern fn JSC__JSPromise__isHandled(arg0: [*c]const JSC__JSPromise, arg1: *bindings.VM) bool;
diff --git a/src/bun.js/bindings/sizes.zig b/src/bun.js/bindings/sizes.zig
index 795159e49..b1b9c1679 100644
--- a/src/bun.js/bindings/sizes.zig
+++ b/src/bun.js/bindings/sizes.zig
@@ -78,4 +78,4 @@ pub const Bun_CallFrame__argumentCountIncludingThis = 4;
pub const Bun_CallFrame__thisArgument = 5;
pub const Bun_CallFrame__firstArgument = 6;
pub const Bun_CallFrame__size = 8;
-pub const Bun_CallFrame__align = 8;
+pub const Bun_CallFrame__align = 8; \ No newline at end of file
diff --git a/src/bun.js/bindings/webcore/AbortSignal.cpp b/src/bun.js/bindings/webcore/AbortSignal.cpp
index aa4143ebd..132ecefca 100644
--- a/src/bun.js/bindings/webcore/AbortSignal.cpp
+++ b/src/bun.js/bindings/webcore/AbortSignal.cpp
@@ -105,6 +105,12 @@ void AbortSignal::signalAbort(JSC::JSValue reason)
for (auto& algorithm : algorithms)
algorithm(reason);
+ auto callbacks = std::exchange(m_native_callbacks, {});
+ for (auto callback : callbacks) {
+ const auto [ ctx, func ] = callback;
+ func(ctx, JSC::JSValue::encode(reason));
+ }
+
// 5. Fire an event named abort at signal.
dispatchEvent(Event::create(eventNames().abortEvent, Event::CanBubble::No, Event::IsCancelable::No));
}
diff --git a/src/bun.js/bindings/webcore/AbortSignal.h b/src/bun.js/bindings/webcore/AbortSignal.h
index 05e64ca82..b0c59daae 100644
--- a/src/bun.js/bindings/webcore/AbortSignal.h
+++ b/src/bun.js/bindings/webcore/AbortSignal.h
@@ -65,6 +65,7 @@ public:
using Algorithm = Function<void(JSValue)>;
void addAlgorithm(Algorithm&& algorithm) { m_algorithms.append(WTFMove(algorithm)); }
+ void addNativeCallback(std::tuple<void*, void (*)(void*, JSC::EncodedJSValue)> callback) { m_native_callbacks.append(callback); }
bool isFollowingSignal() const { return !!m_followingSignal; }
@@ -86,6 +87,7 @@ private:
bool m_aborted { false };
Vector<Algorithm> m_algorithms;
+ Vector<std::tuple<void*, void (*)(void*, JSC::EncodedJSValue)>> m_native_callbacks;
WeakPtr<AbortSignal> m_followingSignal;
JSValueInWrappedObject m_reason;
bool m_hasActiveTimeoutTimer { false };
diff --git a/src/bun.js/event_loop.zig b/src/bun.js/event_loop.zig
index 8dbf5abfd..9c2627fda 100644
--- a/src/bun.js/event_loop.zig
+++ b/src/bun.js/event_loop.zig
@@ -173,6 +173,7 @@ pub const AnyTask = struct {
}
};
+
pub const CppTask = opaque {
extern fn Bun__performTask(globalObject: *JSGlobalObject, task: *CppTask) void;
pub fn run(this: *CppTask, global: *JSGlobalObject) void {
diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig
index b926c4ee9..a5ef4a44a 100644
--- a/src/bun.js/javascript.zig
+++ b/src/bun.js/javascript.zig
@@ -1150,7 +1150,7 @@ pub const VirtualMachine = struct {
const after_namespace = if (namespace.len == 0)
specifier
else
- specifier.substring(namespace.len + 1);
+ specifier.substring(namespace.len + 1, specifier.len);
if (plugin_runner.onResolveJSC(ZigString.init(namespace), after_namespace, source, .bun)) |resolved_path| {
res.* = resolved_path;
diff --git a/src/bun.js/webcore/response.zig b/src/bun.js/webcore/response.zig
index 2c3b1ee31..725a4e64c 100644
--- a/src/bun.js/webcore/response.zig
+++ b/src/bun.js/webcore/response.zig
@@ -688,6 +688,31 @@ pub const Fetch = struct {
}
pub fn onReject(this: *FetchTasklet) JSValue {
+ if (this.result.isTimeout()) {
+ //Timeout with reason
+ if (this.result.reason) |exception| {
+ if (!exception.isEmptyOrUndefinedOrNull()) {
+ return exception;
+ }
+ }
+ //Timeout without reason
+ const exception = JSC.AbortSignal.createTimeoutError(JSC.ZigString.static("The operation timed out"), &JSC.ZigString.Empty, this.global_this);
+ return exception;
+ }
+
+ if (this.result.isAbort()) {
+ //Abort can be TimeoutError (AbortSignal.timeout(ms)) or AbortError so we need to detect
+ if (this.result.reason) |exception| {
+ if (!exception.isEmptyOrUndefinedOrNull()) {
+ return exception;
+ }
+ }
+
+ //Abort without reason
+ const exception = JSC.AbortSignal.createAbortError(JSC.ZigString.static("The user aborted a request"), &JSC.ZigString.Empty, this.global_this);
+ return exception;
+ }
+
const fetch_error = JSC.SystemError{
.code = ZigString.init(@errorName(this.result.fail)),
.message = ZigString.init("fetch() failed"),
@@ -788,7 +813,7 @@ pub const Fetch = struct {
FetchTasklet.callback,
).init(
fetch_tasklet,
- ), proxy);
+ ), proxy, fetch_options.signal);
if (!fetch_options.follow_redirects) {
fetch_tasklet.http.?.client.remaining_redirect_count = 0;
@@ -800,7 +825,7 @@ pub const Fetch = struct {
return fetch_tasklet;
}
- const FetchOptions = struct { method: Method, headers: Headers, body: AnyBlob, timeout: usize, disable_timeout: bool, disable_keepalive: bool, url: ZigURL, verbose: bool = false, follow_redirects: bool = true, proxy: ?ZigURL = null, url_proxy_buffer: []const u8 = "" };
+ const FetchOptions = struct { method: Method, headers: Headers, body: AnyBlob, timeout: usize, disable_timeout: bool, disable_keepalive: bool, url: ZigURL, verbose: bool = false, follow_redirects: bool = true, proxy: ?ZigURL = null, url_proxy_buffer: []const u8 = "", signal: ?*JSC.AbortSignal = null, globalThis: ?*JSGlobalObject };
pub fn queue(
allocator: std.mem.Allocator,
@@ -862,6 +887,8 @@ pub const Fetch = struct {
var verbose = false;
var proxy: ?ZigURL = null;
var follow_redirects = true;
+ var signal: ?*JSC.AbortSignal = null;
+
var url_proxy_buffer: []const u8 = undefined;
if (first_arg.as(Request)) |request| {
@@ -929,6 +956,12 @@ pub const Fetch = struct {
if (options.get(globalThis, "verbose")) |verb| {
verbose = verb.toBoolean();
}
+ if (options.get(globalThis, "signal")) |signal_arg| {
+ if (signal_arg.as(JSC.AbortSignal)) |signal_| {
+ _ = signal_.ref();
+ signal = signal_;
+ }
+ }
if (options.get(globalThis, "proxy")) |proxy_arg| {
if (!proxy_arg.isUndefined()) {
if (proxy_arg.isNull()) {
@@ -1040,6 +1073,12 @@ pub const Fetch = struct {
if (options.get(globalThis, "verbose")) |verb| {
verbose = verb.toBoolean();
}
+ if (options.get(globalThis, "signal")) |signal_arg| {
+ if (signal_arg.as(JSC.AbortSignal)) |signal_| {
+ _ = signal_.ref();
+ signal = signal_;
+ }
+ }
if (options.get(globalThis, "proxy")) |proxy_arg| {
if (!proxy_arg.isUndefined()) {
var proxy_str = proxy_arg.toStringOrNull(globalThis) orelse return null;
@@ -1159,7 +1198,7 @@ pub const Fetch = struct {
globalThis,
.{ .method = method, .url = url, .headers = headers orelse Headers{
.allocator = bun.default_allocator,
- }, .body = body, .timeout = std.time.ns_per_hour, .disable_keepalive = disable_keepalive, .disable_timeout = disable_timeout, .follow_redirects = follow_redirects, .verbose = verbose, .proxy = proxy, .url_proxy_buffer = url_proxy_buffer },
+ }, .body = body, .timeout = std.time.ns_per_hour, .disable_keepalive = disable_keepalive, .disable_timeout = disable_timeout, .follow_redirects = follow_redirects, .verbose = verbose, .proxy = proxy, .url_proxy_buffer = url_proxy_buffer, .signal = signal, .globalThis = globalThis },
JSC.JSValue.fromRef(deferred_promise),
) catch unreachable;
return deferred_promise;
diff --git a/src/bundler.zig b/src/bundler.zig
index f540436b0..26a75ec43 100644
--- a/src/bundler.zig
+++ b/src/bundler.zig
@@ -180,7 +180,7 @@ pub const PluginRunner = struct {
JSC.ZigString.init("");
const on_resolve_plugin = global.runOnResolvePlugins(
namespace,
- JSC.ZigString.init(specifier).substring(if (namespace.len > 0) namespace.len + 1 else 0),
+ JSC.ZigString.init(specifier).substring(if (namespace.len > 0) namespace.len + 1 else 0, 0),
JSC.ZigString.init(importer),
target,
) orelse return null;
diff --git a/src/http_client_async.zig b/src/http_client_async.zig
index 853ab8f3d..b6dd0e828 100644
--- a/src/http_client_async.zig
+++ b/src/http_client_async.zig
@@ -1,5 +1,6 @@
const picohttp = @import("bun").picohttp;
const bun = @import("bun");
+const JSC = bun.JSC;
const string = bun.string;
const Output = bun.Output;
const Global = bun.Global;
@@ -658,6 +659,7 @@ pub fn onOpen(
ssl.configureHTTPClient(hostname);
}
}
+ client.addAbortSignalEventListenner(is_ssl, socket);
if (client.state.request_stage == .pending) {
client.onWritable(true, comptime is_ssl, socket);
}
@@ -691,7 +693,7 @@ pub fn onClose(
}
if (in_progress) {
- client.fail(error.ConnectionClosed);
+ client.fail(error.ConnectionClosed, null);
}
}
pub fn onTimeout(
@@ -702,8 +704,9 @@ pub fn onTimeout(
_ = socket;
log("Timeout {s}\n", .{client.url.href});
- if (client.state.stage != .done and client.state.stage != .fail)
- client.fail(error.Timeout);
+ if (client.state.stage != .done and client.state.stage != .fail) {
+ client.fail(error.Timeout, null);
+ }
}
pub fn onConnectError(
client: *HTTPClient,
@@ -714,7 +717,7 @@ pub fn onConnectError(
log("onConnectError {s}\n", .{client.url.href});
if (client.state.stage != .done and client.state.stage != .fail)
- client.fail(error.ConnectionRefused);
+ client.fail(error.ConnectionRefused, null);
}
pub fn onEnd(
client: *HTTPClient,
@@ -724,7 +727,7 @@ pub fn onEnd(
log("onEnd {s}\n", .{client.url.href});
if (client.state.stage != .done and client.state.stage != .fail)
- client.fail(error.ConnectionClosed);
+ client.fail(error.ConnectionClosed, null);
}
pub inline fn getAllocator() std.mem.Allocator {
@@ -989,23 +992,68 @@ http_proxy: ?URL = null,
proxy_authorization: ?[]u8 = null,
proxy_tunneling: bool = false,
proxy_tunnel: ?ProxyTunnel = null,
+signal: ?*JSC.AbortSignal = null,
+abort_handler: ?*anyopaque = null,
+abort_handler_deinit: ?*const fn (?*anyopaque) void = null,
+pub fn init(allocator: std.mem.Allocator, method: Method, url: URL, header_entries: Headers.Entries, header_buf: string, signal: ?*JSC.AbortSignal) HTTPClient {
+ return HTTPClient{ .allocator = allocator, .method = method, .url = url, .header_entries = header_entries, .header_buf = header_buf, .signal = signal, .abort_handler = null, .abort_handler_deinit = null };
+}
-pub fn init(
- allocator: std.mem.Allocator,
- method: Method,
- url: URL,
- header_entries: Headers.Entries,
- header_buf: string,
-) HTTPClient {
- return HTTPClient{
- .allocator = allocator,
- .method = method,
- .url = url,
- .header_entries = header_entries,
- .header_buf = header_buf,
+pub fn ClientSocketAbortHandler(comptime is_ssl: bool) type {
+ return struct {
+ client: *HTTPClient,
+ socket: NewHTTPContext(is_ssl).HTTPSocket,
+
+ pub fn init(client: *HTTPClient, socket: NewHTTPContext(is_ssl).HTTPSocket) !*@This() {
+ var ctx = try client.allocator.create(@This());
+ ctx.client = client;
+ ctx.socket = socket;
+ return ctx;
+ }
+
+ pub fn onAborted(this: ?*anyopaque, reason: JSC.JSValue) callconv(.C) void {
+ log("onAborted", .{});
+ if (this) |this_| {
+ const self = bun.cast(*@This(), this_);
+ self.client.closeAndAbort(reason, is_ssl, self.socket);
+ }
+ }
+
+ pub fn deinit(this: ?*anyopaque) void {
+ if (this) |this_| {
+ var self = bun.cast(*@This(), this_);
+ const allocator = self.client.allocator;
+ allocator.destroy(self);
+ }
+ }
};
}
+pub fn addAbortSignalEventListenner(this: *HTTPClient, comptime is_ssl: bool, socket: NewHTTPContext(is_ssl).HTTPSocket) void {
+ if (this.signal) |signal| {
+ const handler = ClientSocketAbortHandler(is_ssl).init(this, socket) catch unreachable;
+ this.abort_handler = bun.cast(*anyopaque, handler);
+ this.abort_handler_deinit = ClientSocketAbortHandler(is_ssl).deinit;
+ _ = signal.addListener(this.abort_handler.?, ClientSocketAbortHandler(is_ssl).onAborted);
+ log("addAbortSignalEventListenner added!", .{});
+ return;
+ }
+ log("addAbortSignalEventListenner (signal == null)", .{});
+}
+
+pub fn hasSignalAborted(this: *HTTPClient) ?JSC.JSValue {
+ if (this.signal) |signal| {
+ const aborted = signal.aborted();
+ log("hasSignalAborted {any}", .{aborted});
+ if (aborted) {
+ return signal.abortReason();
+ }
+ return null;
+ }
+ log("hasSignalAborted (signal == null)", .{});
+ return null;
+}
+
pub fn deinit(this: *HTTPClient) void {
if (this.redirect) |redirect| {
redirect.release();
@@ -1019,6 +1067,17 @@ pub fn deinit(this: *HTTPClient) void {
tunnel.deinit();
this.proxy_tunnel = null;
}
+
+ if (this.signal != null) {
+ var signal = this.signal.?;
+ _ = signal.unref();
+ this.signal = null;
+ }
+ if (this.abort_handler != null and this.abort_handler_deinit != null) {
+ this.abort_handler_deinit.?(this.abort_handler.?);
+ this.abort_handler = null;
+ this.abort_handler_deinit = null;
+ }
this.state.compressed_body.deinit();
this.state.response_message_buffer.deinit();
}
@@ -1178,20 +1237,9 @@ pub const AsyncHTTP = struct {
};
const AtomicState = std.atomic.Atomic(State);
- pub fn init(
- allocator: std.mem.Allocator,
- method: Method,
- url: URL,
- headers: Headers.Entries,
- headers_buf: string,
- response_buffer: *MutableString,
- request_body: []const u8,
- timeout: usize,
- callback: HTTPClientResult.Callback,
- http_proxy: ?URL,
- ) AsyncHTTP {
+ pub fn init(allocator: std.mem.Allocator, method: Method, url: URL, headers: Headers.Entries, headers_buf: string, response_buffer: *MutableString, request_body: []const u8, timeout: usize, callback: HTTPClientResult.Callback, http_proxy: ?URL, signal: ?*JSC.AbortSignal) AsyncHTTP {
var this = AsyncHTTP{ .allocator = allocator, .url = url, .method = method, .request_headers = headers, .request_header_buf = headers_buf, .request_body = request_body, .response_buffer = response_buffer, .completion_callback = callback, .http_proxy = http_proxy };
- this.client = HTTPClient.init(allocator, method, url, headers, headers_buf);
+ this.client = HTTPClient.init(allocator, method, url, headers, headers_buf, signal);
this.client.timeout = timeout;
this.client.http_proxy = this.http_proxy;
if (http_proxy) |proxy| {
@@ -1222,7 +1270,7 @@ pub const AsyncHTTP = struct {
}
pub fn initSync(allocator: std.mem.Allocator, method: Method, url: URL, headers: Headers.Entries, headers_buf: string, response_buffer: *MutableString, request_body: []const u8, timeout: usize, http_proxy: ?URL) AsyncHTTP {
- return @This().init(allocator, method, url, headers, headers_buf, response_buffer, request_body, timeout, undefined, http_proxy);
+ return @This().init(allocator, method, url, headers, headers_buf, response_buffer, request_body, timeout, undefined, http_proxy, null);
}
fn reset(this: *AsyncHTTP) !void {
@@ -1454,7 +1502,7 @@ pub fn doRedirect(this: *HTTPClient) void {
std.debug.assert(this.follow_redirects);
if (this.remaining_redirect_count == 0) {
- this.fail(error.TooManyRedirects);
+ this.fail(error.TooManyRedirects, null);
return;
}
this.state.reset();
@@ -1491,12 +1539,12 @@ pub fn start(this: *HTTPClient, body: []const u8, body_out_str: *MutableString)
fn start_(this: *HTTPClient, comptime is_ssl: bool) void {
var socket = http_thread.connect(this, is_ssl) catch |err| {
- this.fail(err);
+ this.fail(err, null);
return;
};
if (socket.isClosed() and (this.state.response_stage != .done and this.state.response_stage != .fail)) {
- this.fail(error.ConnectionClosed);
+ this.fail(error.ConnectionClosed, null);
std.debug.assert(this.state.fail != error.NoError);
}
}
@@ -1522,6 +1570,11 @@ fn printResponse(response: picohttp.Response) void {
}
pub fn onWritable(this: *HTTPClient, comptime is_first_call: bool, comptime is_ssl: bool, socket: NewHTTPContext(is_ssl).HTTPSocket) void {
+ if (this.hasSignalAborted()) |reason| {
+ this.closeAndAbort(reason, is_ssl, socket);
+ return;
+ }
+
switch (this.state.request_stage) {
.pending, .headers => {
var stack_fallback = std.heap.stackFallback(16384, default_allocator);
@@ -1766,8 +1819,8 @@ pub fn closeAndFail(this: *HTTPClient, err: anyerror, comptime is_ssl: bool, soc
**anyopaque,
NewHTTPContext(is_ssl).ActiveSocket.init(&dead_socket).ptr(),
);
- this.fail(err);
socket.close(0, null);
+ this.fail(err, null);
}
fn startProxySendHeaders(this: *HTTPClient, comptime is_ssl: bool, socket: NewHTTPContext(is_ssl).HTTPSocket) void {
@@ -1821,6 +1874,10 @@ 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 {
+ if (this.hasSignalAborted()) |reason| {
+ this.closeAndAbort(reason, is_ssl, socket);
+ return;
+ }
switch (this.state.response_stage) {
.pending, .headers, .proxy_decoded_headers => {
var to_read = incoming_data;
@@ -2054,14 +2111,23 @@ pub fn onData(this: *HTTPClient, comptime is_ssl: bool, incoming_data: []const u
}
}
-fn fail(this: *HTTPClient, err: anyerror) void {
+pub fn closeAndAbort(this: *HTTPClient, reason: JSC.JSValue, comptime is_ssl: bool, socket: NewHTTPContext(is_ssl).HTTPSocket) void {
+ socket.ext(**anyopaque).?.* = bun.cast(
+ **anyopaque,
+ NewHTTPContext(is_ssl).ActiveSocket.init(&dead_socket).ptr(),
+ );
+ socket.close(0, null);
+ this.fail(error.Aborted, reason);
+}
+
+fn fail(this: *HTTPClient, err: anyerror, reason: ?JSC.JSValue) void {
this.state.request_stage = .fail;
this.state.response_stage = .fail;
this.state.fail = err;
this.state.stage = .fail;
const callback = this.completion_callback;
- const result = this.toResult(this.cloned_metadata);
+ const result = this.toResult(this.cloned_metadata, reason);
this.state.reset();
this.proxy_tunneling = false;
@@ -2101,7 +2167,7 @@ pub fn done(this: *HTTPClient, comptime is_ssl: bool, ctx: *NewHTTPContext(is_ss
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 result = this.toResult(this.cloned_metadata, null);
const callback = this.completion_callback;
this.state.response_stage = .done;
@@ -2147,11 +2213,20 @@ pub const HTTPClientResult = struct {
fail: anyerror = error.NoError,
redirected: bool = false,
headers_buf: []picohttp.Header = &.{},
+ reason: ?JSC.JSValue = null,
pub fn isSuccess(this: *const HTTPClientResult) bool {
return this.fail == error.NoError;
}
+ pub fn isTimeout(this: *const HTTPClientResult) bool {
+ return this.fail == error.Timeout;
+ }
+
+ pub fn isAbort(this: *const HTTPClientResult) bool {
+ return this.fail == error.Aborted;
+ }
+
pub fn deinitMetadata(this: *HTTPClientResult) void {
if (this.metadata_buf.len > 0) bun.default_allocator.free(this.metadata_buf);
if (this.headers_buf.len > 0) bun.default_allocator.free(this.headers_buf);
@@ -2191,7 +2266,7 @@ pub const HTTPClientResult = struct {
};
};
-pub fn toResult(this: *HTTPClient, metadata: HTTPResponseMetadata) HTTPClientResult {
+pub fn toResult(this: *HTTPClient, metadata: HTTPResponseMetadata, reason: ?JSC.JSValue) HTTPClientResult {
return HTTPClientResult{
.body = this.state.body_out_str,
.response = metadata.response,
@@ -2199,6 +2274,7 @@ pub fn toResult(this: *HTTPClient, metadata: HTTPResponseMetadata) HTTPClientRes
.redirected = this.remaining_redirect_count != default_redirect_count,
.href = metadata.url,
.fail = this.state.fail,
+ .reason = reason,
.headers_buf = metadata.response.headers,
};
}
diff --git a/src/install/install.zig b/src/install/install.zig
index 7bc79b015..5b5346294 100644
--- a/src/install/install.zig
+++ b/src/install/install.zig
@@ -329,7 +329,7 @@ const NetworkTask = struct {
var url = URL.parse(this.url_buf);
var http_proxy: ?URL = env_loader.getHttpProxy(url);
- this.http = AsyncHTTP.init(allocator, .GET, url, header_builder.entries, header_builder.content.ptr.?[0..header_builder.content.len], &this.response_buffer, "", 0, this.getCompletionCallback(), http_proxy);
+ this.http = AsyncHTTP.init(allocator, .GET, url, header_builder.entries, header_builder.content.ptr.?[0..header_builder.content.len], &this.response_buffer, "", 0, this.getCompletionCallback(), http_proxy, null);
this.http.max_retry_count = this.package_manager.options.max_retry_count;
this.callback = .{
.package_manifest = .{
@@ -396,7 +396,7 @@ const NetworkTask = struct {
var url = URL.parse(this.url_buf);
var http_proxy: ?URL = env_loader.getHttpProxy(url);
- this.http = AsyncHTTP.init(allocator, .GET, url, header_builder.entries, header_buf, &this.response_buffer, "", 0, this.getCompletionCallback(), http_proxy);
+ this.http = AsyncHTTP.init(allocator, .GET, url, header_builder.entries, header_buf, &this.response_buffer, "", 0, this.getCompletionCallback(), http_proxy, null);
this.http.max_retry_count = this.package_manager.options.max_retry_count;
this.callback = .{ .extract = tarball };
}
diff --git a/src/string_immutable.zig b/src/string_immutable.zig
index 9d36d0c78..e012b6e5a 100644
--- a/src/string_immutable.zig
+++ b/src/string_immutable.zig
@@ -1133,7 +1133,6 @@ pub fn toUTF16Alloc(allocator: std.mem.Allocator, bytes: []const u8, comptime fa
else => return out,
}
} else null;
-
var output = output_ orelse fallback: {
var list = try std.ArrayList(u16).initCapacity(allocator, i + 2);
list.items.len = i;