aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2023-03-19 14:08:20 -0700
committerGravatar GitHub <noreply@github.com> 2023-03-19 14:08:20 -0700
commit5a23d176208bb38483b65b9420b18c8597fabfef (patch)
treef163dc03fdc75b7827ee7f51e17355a9cc82329f /src
parent8f02ef829474cbd5453ffcb6485d40f93424ad26 (diff)
downloadbun-5a23d176208bb38483b65b9420b18c8597fabfef.tar.gz
bun-5a23d176208bb38483b65b9420b18c8597fabfef.tar.zst
bun-5a23d176208bb38483b65b9420b18c8597fabfef.zip
Several bug fixes (#2427)
* Fix test * Fix segfault when unexpected type is passed in `expect().toThrow` * Fix issues with request constructor * Don't bother cloning headers when its empty * woops * more tests * fix incorrect test * Make the fetch error messages better * Update response.zig * Fix test that failed on macOS * Fix test * Remove extra hash table lookups * Support running dummy registry directly cc @alexlamsl * Update test * Update test * fixup * Workaround crash in test runner * Fixup test * Fixup test * Update os.test.js --------- Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
Diffstat (limited to 'src')
-rw-r--r--src/bun.js/bindings/bindings.cpp27
-rw-r--r--src/bun.js/bindings/bindings.zig81
-rw-r--r--src/bun.js/bindings/headers-cpp.h2
-rw-r--r--src/bun.js/bindings/headers.h4
-rw-r--r--src/bun.js/bindings/headers.zig2
-rw-r--r--src/bun.js/builtins/BunBuiltinNames.h2
-rw-r--r--src/bun.js/test/jest.zig178
-rw-r--r--src/bun.js/webcore/body.zig14
-rw-r--r--src/bun.js/webcore/request.zig300
-rw-r--r--src/bun.js/webcore/response.zig20
-rw-r--r--src/env_loader.zig2
-rw-r--r--src/install/extract_tarball.zig2
-rw-r--r--src/install/install.zig48
13 files changed, 462 insertions, 220 deletions
diff --git a/src/bun.js/bindings/bindings.cpp b/src/bun.js/bindings/bindings.cpp
index 774c14d0c..a5af29128 100644
--- a/src/bun.js/bindings/bindings.cpp
+++ b/src/bun.js/bindings/bindings.cpp
@@ -700,6 +700,11 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2,
extern "C" {
+bool WebCore__FetchHeaders__isEmpty(WebCore__FetchHeaders* arg0)
+{
+ return arg0->size() == 0;
+}
+
void WebCore__FetchHeaders__toUWSResponse(WebCore__FetchHeaders* arg0, bool is_ssl, void* arg2)
{
if (is_ssl) {
@@ -3566,11 +3571,14 @@ enum class BuiltinNamesMap : uint8_t {
url,
body,
data,
+ toString,
+ redirect,
};
static JSC::Identifier builtinNameMap(JSC::JSGlobalObject* globalObject, unsigned char name)
{
- auto clientData = WebCore::clientData(globalObject->vm());
+ auto& vm = globalObject->vm();
+ auto clientData = WebCore::clientData(vm);
switch (static_cast<BuiltinNamesMap>(name)) {
case BuiltinNamesMap::method: {
return clientData->builtinNames().methodPublicName();
@@ -3590,7 +3598,24 @@ static JSC::Identifier builtinNameMap(JSC::JSGlobalObject* globalObject, unsigne
case BuiltinNamesMap::data: {
return clientData->builtinNames().dataPublicName();
}
+ case BuiltinNamesMap::toString: {
+ return vm.propertyNames->toString;
+ }
+ case BuiltinNamesMap::redirect: {
+ return clientData->builtinNames().redirectPublicName();
}
+ }
+}
+
+JSC__JSValue JSC__JSValue__fastGetDirect_(JSC__JSValue JSValue0, JSC__JSGlobalObject* globalObject, unsigned char arg2)
+{
+ JSC::JSValue value = JSC::JSValue::decode(JSValue0);
+ if (!value.isCell()) {
+ return JSValue::encode({});
+ }
+
+ return JSValue::encode(
+ value.getObject()->getDirect(globalObject->vm(), PropertyName(builtinNameMap(globalObject, arg2))));
}
JSC__JSValue JSC__JSValue__fastGet_(JSC__JSValue JSValue0, JSC__JSGlobalObject* globalObject, unsigned char arg2)
diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig
index 51f9c9fde..1bd045218 100644
--- a/src/bun.js/bindings/bindings.zig
+++ b/src/bun.js/bindings/bindings.zig
@@ -1041,6 +1041,12 @@ pub const FetchHeaders = opaque {
});
}
+ pub fn isEmpty(this: *FetchHeaders) bool {
+ return shim.cppFn("isEmpty", .{
+ this,
+ });
+ }
+
pub fn createFromUWS(
global: *JSGlobalObject,
uws_request: *anyopaque,
@@ -1422,6 +1428,7 @@ pub const FetchHeaders = opaque {
"remove",
"toJS",
"toUWSResponse",
+ "isEmpty",
};
};
@@ -3604,6 +3611,10 @@ pub const JSValue = enum(JSValueReprInt) {
return FFI.EncodedJSValue{ .asJSValue = this };
}
+ pub fn fromCell(ptr: *anyopaque) JSValue {
+ return (FFI.EncodedJSValue{ .asPtr = ptr }).asJSValue;
+ }
+
pub fn isInt32(this: JSValue) bool {
return FFI.JSVALUE_IS_INT32(.{ .asJSValue = this });
}
@@ -3773,6 +3784,13 @@ pub const JSValue = enum(JSValueReprInt) {
return str;
}
+ /// Convert a JSValue to a string, potentially calling `toString` on the
+ /// JSValue in JavaScript.
+ ///
+ /// This function can throw an exception in the `JSC::VM`. **If
+ /// the exception is not handled correctly, Bun will segfault**
+ ///
+ /// To handle exceptions, use `JSValue.toSliceOrNull`.
pub inline fn toSlice(this: JSValue, global: *JSGlobalObject, allocator: std.mem.Allocator) ZigString.Slice {
return getZigString(this, global).toSlice(allocator);
}
@@ -3786,11 +3804,39 @@ pub const JSValue = enum(JSValueReprInt) {
return cppFn("jsonStringify", .{ this, globalThis, indent, out });
}
- // On exception, this returns null, to make exception checks faster.
+ /// On exception, this returns null, to make exception checks clearer.
pub fn toStringOrNull(this: JSValue, globalThis: *JSGlobalObject) ?*JSString {
return cppFn("toStringOrNull", .{ this, globalThis });
}
+ /// Call `toString()` on the JSValue and clone the result.
+ /// On exception, this returns null.
+ pub fn toSliceOrNull(this: JSValue, globalThis: *JSGlobalObject) ?ZigString.Slice {
+ var str = this.toStringOrNull(globalThis) orelse return null;
+ return str.toSlice(globalThis, globalThis.allocator());
+ }
+
+ /// Call `toString()` on the JSValue and clone the result.
+ /// On exception or out of memory, this returns null.
+ ///
+ /// Remember that `Symbol` throws an exception when you call `toString()`.
+ pub fn toSliceClone(this: JSValue, globalThis: *JSGlobalObject) ?ZigString.Slice {
+ return this.toSliceCloneWithAllocator(globalThis, globalThis.allocator());
+ }
+
+ /// On exception or out of memory, this returns null, to make exception checks clearer.
+ pub fn toSliceCloneWithAllocator(
+ this: JSValue,
+ globalThis: *JSGlobalObject,
+ allocator: std.mem.Allocator,
+ ) ?ZigString.Slice {
+ var str = this.toStringOrNull(globalThis) orelse return null;
+ return str.toSlice(globalThis, allocator).cloneIfNeeded(allocator) catch {
+ globalThis.throwOutOfMemory();
+ return null;
+ };
+ }
+
pub fn toObject(this: JSValue, globalThis: *JSGlobalObject) *JSObject {
return cppFn("toObject", .{ this, globalThis });
}
@@ -3807,7 +3853,16 @@ pub const JSValue = enum(JSValueReprInt) {
return cppFn("eqlCell", .{ this, other });
}
- pub const BuiltinName = enum(u8) { method, headers, status, url, body, data };
+ pub const BuiltinName = enum(u8) {
+ method,
+ headers,
+ status,
+ url,
+ body,
+ data,
+ toString,
+ redirect,
+ };
// intended to be more lightweight than ZigString
pub fn fastGet(this: JSValue, global: *JSGlobalObject, builtin_name: BuiltinName) ?JSValue {
@@ -3819,11 +3874,24 @@ pub const JSValue = enum(JSValueReprInt) {
return result;
}
+ pub fn fastGetDirect(this: JSValue, global: *JSGlobalObject, builtin_name: BuiltinName) ?JSValue {
+ const result = fastGetDirect_(this, global, @enumToInt(builtin_name));
+ if (result == .zero) {
+ return null;
+ }
+
+ return result;
+ }
+
pub fn fastGet_(this: JSValue, global: *JSGlobalObject, builtin_name: u8) JSValue {
return cppFn("fastGet_", .{ this, global, builtin_name });
}
- // intended to be more lightweight than ZigString
+ pub fn fastGetDirect_(this: JSValue, global: *JSGlobalObject, builtin_name: u8) JSValue {
+ return cppFn("fastGetDirect_", .{ this, global, builtin_name });
+ }
+
+ /// Do not use this directly! Use `get` instead.
pub fn getIfPropertyExistsImpl(this: JSValue, global: *JSGlobalObject, ptr: [*]const u8, len: u32) JSValue {
return cppFn("getIfPropertyExistsImpl", .{ this, global, ptr, len });
}
@@ -3865,6 +3933,12 @@ pub const JSValue = enum(JSValueReprInt) {
return if (@enumToInt(value) != 0) value else return null;
}
+ pub fn implementsToString(this: JSValue, global: *JSGlobalObject) bool {
+ std.debug.assert(this.isCell());
+ const function = this.fastGet(global, BuiltinName.toString) orelse return false;
+ return function.isCell() and function.isCallable(global.vm());
+ }
+
pub fn getTruthy(this: JSValue, global: *JSGlobalObject, property: []const u8) ?JSValue {
if (get(this, global, property)) |prop| {
if (prop.isEmptyOrUndefinedOrNull()) return null;
@@ -4131,6 +4205,7 @@ pub const JSValue = enum(JSValueReprInt) {
"eqlCell",
"eqlValue",
"fastGet_",
+ "fastGetDirect_",
"forEach",
"forEachProperty",
"forEachPropertyOrdered",
diff --git a/src/bun.js/bindings/headers-cpp.h b/src/bun.js/bindings/headers-cpp.h
index 49391bb42..dafdaed17 100644
--- a/src/bun.js/bindings/headers-cpp.h
+++ b/src/bun.js/bindings/headers-cpp.h
@@ -1,4 +1,4 @@
-//-- AUTOGENERATED FILE -- 1679048516
+//-- AUTOGENERATED FILE -- 1679200292
// clang-format off
#pragma once
diff --git a/src/bun.js/bindings/headers.h b/src/bun.js/bindings/headers.h
index baefaf0b9..8c9b5c1d0 100644
--- a/src/bun.js/bindings/headers.h
+++ b/src/bun.js/bindings/headers.h
@@ -1,5 +1,5 @@
// clang-format off
-//-- AUTOGENERATED FILE -- 1679083592
+//-- AUTOGENERATED FILE -- 1679200292
#pragma once
#include <stddef.h>
@@ -183,6 +183,7 @@ CPP_DECL bool WebCore__FetchHeaders__fastHas_(WebCore__FetchHeaders* arg0, unsig
CPP_DECL void WebCore__FetchHeaders__fastRemove_(WebCore__FetchHeaders* arg0, unsigned char arg1);
CPP_DECL void WebCore__FetchHeaders__get_(WebCore__FetchHeaders* arg0, const ZigString* arg1, ZigString* arg2, JSC__JSGlobalObject* arg3);
CPP_DECL bool WebCore__FetchHeaders__has(WebCore__FetchHeaders* arg0, const ZigString* arg1, JSC__JSGlobalObject* arg2);
+CPP_DECL bool WebCore__FetchHeaders__isEmpty(WebCore__FetchHeaders* arg0);
CPP_DECL void WebCore__FetchHeaders__put_(WebCore__FetchHeaders* arg0, const ZigString* arg1, const ZigString* arg2, JSC__JSGlobalObject* arg3);
CPP_DECL void WebCore__FetchHeaders__remove(WebCore__FetchHeaders* arg0, const ZigString* arg1, JSC__JSGlobalObject* arg2);
CPP_DECL JSC__JSValue WebCore__FetchHeaders__toJS(WebCore__FetchHeaders* arg0, JSC__JSGlobalObject* arg1);
@@ -300,6 +301,7 @@ CPP_DECL bool JSC__JSValue__deepEquals(JSC__JSValue JSValue0, JSC__JSValue JSVal
CPP_DECL bool JSC__JSValue__eqlCell(JSC__JSValue JSValue0, JSC__JSCell* arg1);
CPP_DECL bool JSC__JSValue__eqlValue(JSC__JSValue JSValue0, JSC__JSValue JSValue1);
CPP_DECL JSC__JSValue JSC__JSValue__fastGet_(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, unsigned char arg2);
+CPP_DECL JSC__JSValue JSC__JSValue__fastGetDirect_(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, unsigned char arg2);
CPP_DECL void JSC__JSValue__forEach(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, void* arg2, void(* ArgFn3)(JSC__VM* arg0, JSC__JSGlobalObject* arg1, void* arg2, JSC__JSValue JSValue3)) __attribute__((nonnull (3)));
CPP_DECL void JSC__JSValue__forEachProperty(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, void* arg2, void(* ArgFn3)(JSC__JSGlobalObject* arg0, void* arg1, ZigString* arg2, JSC__JSValue JSValue3, bool arg4)) __attribute__((nonnull (3)));
CPP_DECL void JSC__JSValue__forEachPropertyOrdered(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, void* arg2, void(* ArgFn3)(JSC__JSGlobalObject* arg0, void* arg1, ZigString* arg2, JSC__JSValue JSValue3, bool arg4)) __attribute__((nonnull (3)));
diff --git a/src/bun.js/bindings/headers.zig b/src/bun.js/bindings/headers.zig
index a6a3b52fa..5779655fa 100644
--- a/src/bun.js/bindings/headers.zig
+++ b/src/bun.js/bindings/headers.zig
@@ -123,6 +123,7 @@ pub extern fn WebCore__FetchHeaders__fastHas_(arg0: ?*bindings.FetchHeaders, arg
pub extern fn WebCore__FetchHeaders__fastRemove_(arg0: ?*bindings.FetchHeaders, arg1: u8) void;
pub extern fn WebCore__FetchHeaders__get_(arg0: ?*bindings.FetchHeaders, arg1: [*c]const ZigString, arg2: [*c]ZigString, arg3: *bindings.JSGlobalObject) void;
pub extern fn WebCore__FetchHeaders__has(arg0: ?*bindings.FetchHeaders, arg1: [*c]const ZigString, arg2: *bindings.JSGlobalObject) bool;
+pub extern fn WebCore__FetchHeaders__isEmpty(arg0: ?*bindings.FetchHeaders) bool;
pub extern fn WebCore__FetchHeaders__put_(arg0: ?*bindings.FetchHeaders, arg1: [*c]const ZigString, arg2: [*c]const ZigString, arg3: *bindings.JSGlobalObject) void;
pub extern fn WebCore__FetchHeaders__remove(arg0: ?*bindings.FetchHeaders, arg1: [*c]const ZigString, arg2: *bindings.JSGlobalObject) void;
pub extern fn WebCore__FetchHeaders__toJS(arg0: ?*bindings.FetchHeaders, arg1: *bindings.JSGlobalObject) JSC__JSValue;
@@ -213,6 +214,7 @@ pub extern fn JSC__JSValue__deepEquals(JSValue0: JSC__JSValue, JSValue1: JSC__JS
pub extern fn JSC__JSValue__eqlCell(JSValue0: JSC__JSValue, arg1: [*c]bindings.JSCell) bool;
pub extern fn JSC__JSValue__eqlValue(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue) bool;
pub extern fn JSC__JSValue__fastGet_(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: u8) JSC__JSValue;
+pub extern fn JSC__JSValue__fastGetDirect_(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: u8) JSC__JSValue;
pub extern fn JSC__JSValue__forEach(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: ?*anyopaque, ArgFn3: ?*const fn (*bindings.VM, *bindings.JSGlobalObject, ?*anyopaque, JSC__JSValue) callconv(.C) void) void;
pub extern fn JSC__JSValue__forEachProperty(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: ?*anyopaque, ArgFn3: ?*const fn (*bindings.JSGlobalObject, ?*anyopaque, [*c]ZigString, JSC__JSValue, bool) callconv(.C) void) void;
pub extern fn JSC__JSValue__forEachPropertyOrdered(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject, arg2: ?*anyopaque, ArgFn3: ?*const fn (*bindings.JSGlobalObject, ?*anyopaque, [*c]ZigString, JSC__JSValue, bool) callconv(.C) void) void;
diff --git a/src/bun.js/builtins/BunBuiltinNames.h b/src/bun.js/builtins/BunBuiltinNames.h
index b9a9dfe13..ebc2c2c05 100644
--- a/src/bun.js/builtins/BunBuiltinNames.h
+++ b/src/bun.js/builtins/BunBuiltinNames.h
@@ -129,7 +129,6 @@ using namespace JSC;
macro(isAbsolute) \
macro(isDisturbed) \
macro(isPaused) \
- macro(isSecureContext) \
macro(isWindows) \
macro(join) \
macro(kind) \
@@ -183,6 +182,7 @@ using namespace JSC;
macro(reader) \
macro(readyPromise) \
macro(readyPromiseCapability) \
+ macro(redirect) \
macro(relative) \
macro(releaseLock) \
macro(removeEventListener) \
diff --git a/src/bun.js/test/jest.zig b/src/bun.js/test/jest.zig
index 883a3a48d..85bdb459e 100644
--- a/src/bun.js/test/jest.zig
+++ b/src/bun.js/test/jest.zig
@@ -2163,18 +2163,11 @@ pub const Expect = struct {
if (expected_value.isEmpty()) {
const signature_no_args = comptime getSignature("toThrow", "", true);
- if (result.isError()) {
- const name = result.getIfPropertyExistsImpl(globalObject, "name", 4);
- const message = result.getIfPropertyExistsImpl(globalObject, "message", 7);
+ if (result.toError()) |err| {
+ const name = err.get(globalObject, "name") orelse JSValue.undefined;
+ const message = err.get(globalObject, "message") orelse JSValue.undefined;
const fmt = signature_no_args ++ "\n\nError name: <red>{any}<r>\nError message: <red>{any}<r>\n";
- if (Output.enable_ansi_colors) {
- globalObject.throw(Output.prettyFmt(fmt, true), .{
- name.toFmt(globalObject, &formatter),
- message.toFmt(globalObject, &formatter),
- });
- return .zero;
- }
- globalObject.throw(Output.prettyFmt(fmt, false), .{
+ globalObject.throwPretty(fmt, .{
name.toFmt(globalObject, &formatter),
message.toFmt(globalObject, &formatter),
});
@@ -2183,41 +2176,25 @@ pub const Expect = struct {
// non error thrown
const fmt = signature_no_args ++ "\n\nThrown value: <red>{any}<r>\n";
- if (Output.enable_ansi_colors) {
- globalObject.throw(Output.prettyFmt(fmt, true), .{result.toFmt(globalObject, &formatter)});
- return .zero;
- }
- globalObject.throw(Output.prettyFmt(fmt, false), .{result.toFmt(globalObject, &formatter)});
+ globalObject.throwPretty(fmt, .{result.toFmt(globalObject, &formatter)});
return .zero;
}
if (expected_value.isString()) {
const received_message = result.getIfPropertyExistsImpl(globalObject, "message", 7);
+ // TODO: remove this allocation
// partial match
{
- var expected_string = ZigString.Empty;
- var received_string = ZigString.Empty;
- expected_value.toZigString(&expected_string, globalObject);
- received_message.toZigString(&received_string, globalObject);
- const expected_slice = expected_string.toSlice(default_allocator);
- const received_slice = received_string.toSlice(default_allocator);
- defer {
- expected_slice.deinit();
- received_slice.deinit();
- }
+ const expected_slice = expected_value.toSliceOrNull(globalObject) orelse return .zero;
+ defer expected_slice.deinit();
+ const received_slice = received_message.toSliceOrNull(globalObject) orelse return .zero;
+ defer received_slice.deinit();
if (!strings.contains(received_slice.slice(), expected_slice.slice())) return thisValue;
}
const fmt = signature ++ "\n\nExpected substring: not <green>{any}<r>\nReceived message: <red>{any}<r>\n";
- if (Output.enable_ansi_colors) {
- globalObject.throw(Output.prettyFmt(fmt, true), .{
- expected_value.toFmt(globalObject, &formatter),
- received_message.toFmt(globalObject, &formatter),
- });
- return .zero;
- }
- globalObject.throw(Output.prettyFmt(fmt, false), .{
+ globalObject.throwPretty(fmt, .{
expected_value.toFmt(globalObject, &formatter),
received_message.toFmt(globalObject, &formatter),
});
@@ -2227,20 +2204,14 @@ pub const Expect = struct {
if (expected_value.isRegExp()) {
const received_message = result.getIfPropertyExistsImpl(globalObject, "message", 7);
+ // TODO: REMOVE THIS GETTER! Expose a binding to call .test on the RegExp object directly.
if (expected_value.get(globalObject, "test")) |test_fn| {
const matches = test_fn.callWithThis(globalObject, expected_value, &.{received_message});
if (!matches.toBooleanSlow(globalObject)) return thisValue;
}
const fmt = signature ++ "\n\nExpected pattern: not <green>{any}<r>\nReceived message: <red>{any}<r>\n";
- if (Output.enable_ansi_colors) {
- globalObject.throw(Output.prettyFmt(fmt, true), .{
- expected_value.toFmt(globalObject, &formatter),
- received_message.toFmt(globalObject, &formatter),
- });
- return .zero;
- }
- globalObject.throw(Output.prettyFmt(fmt, false), .{
+ globalObject.throwPretty(fmt, .{
expected_value.toFmt(globalObject, &formatter),
received_message.toFmt(globalObject, &formatter),
});
@@ -2253,11 +2224,7 @@ pub const Expect = struct {
if (!expected_message.isSameValue(received_message, globalObject)) return thisValue;
const fmt = signature ++ "\n\nExpected message: not <green>{any}<r>\n";
- if (Output.enable_ansi_colors) {
- globalObject.throw(Output.prettyFmt(fmt, true), .{expected_message.toFmt(globalObject, &formatter)});
- return .zero;
- }
- globalObject.throw(Output.prettyFmt(fmt, false), .{expected_message.toFmt(globalObject, &formatter)});
+ globalObject.throwPretty(fmt, .{expected_message.toFmt(globalObject, &formatter)});
return .zero;
}
@@ -2279,22 +2246,26 @@ pub const Expect = struct {
if (did_throw) {
if (expected_value.isEmpty()) return thisValue;
- const result: JSValue = result_.?;
- const _received_message = result.get(globalObject, "message");
+ const result: JSValue = if (result_.?.toError()) |r|
+ r
+ else
+ result_.?;
+
+ const _received_message: ?JSValue = if (result.isObject())
+ result.get(globalObject, "message")
+ else if (result.toStringOrNull(globalObject)) |js_str|
+ JSC.JSValue.fromCell(js_str)
+ else
+ null;
if (expected_value.isString()) {
if (_received_message) |received_message| {
+ // TODO: remove this allocation
// partial match
- var expected_string = ZigString.Empty;
- var received_string = ZigString.Empty;
- expected_value.toZigString(&expected_string, globalObject);
- received_message.toZigString(&received_string, globalObject);
- const expected_slice = expected_string.toSlice(default_allocator);
- const received_slice = received_string.toSlice(default_allocator);
- defer {
- expected_slice.deinit();
- received_slice.deinit();
- }
+ const expected_slice = expected_value.toSliceOrNull(globalObject) orelse return .zero;
+ defer expected_slice.deinit();
+ const received_slice = received_message.toSlice(globalObject, globalObject.allocator());
+ defer received_slice.deinit();
if (strings.contains(received_slice.slice(), expected_slice.slice())) return thisValue;
}
@@ -2305,29 +2276,21 @@ pub const Expect = struct {
const expected_value_fmt = expected_value.toFmt(globalObject, &formatter);
const received_message_fmt = received_message.toFmt(globalObject, &formatter);
const fmt = signature ++ "\n\n" ++ "Expected substring: <green>{any}<r>\nReceived message: <red>{any}<r>\n";
- if (Output.enable_ansi_colors) {
- globalObject.throw(Output.prettyFmt(fmt, true), .{ expected_value_fmt, received_message_fmt });
- return .zero;
- }
-
- globalObject.throw(Output.prettyFmt(fmt, false), .{ expected_value_fmt, received_message_fmt });
+ globalObject.throwPretty(fmt, .{ expected_value_fmt, received_message_fmt });
return .zero;
}
const expected_fmt = expected_value.toFmt(globalObject, &formatter);
const received_fmt = result.toFmt(globalObject, &formatter);
const fmt = signature ++ "\n\n" ++ "Expected substring: <green>{any}<r>\nReceived value: <red>{any}<r>";
- if (Output.enable_ansi_colors) {
- globalObject.throw(Output.prettyFmt(fmt, true), .{ expected_fmt, received_fmt });
- return .zero;
- }
+ globalObject.throwPretty(fmt, .{ expected_fmt, received_fmt });
- globalObject.throw(Output.prettyFmt(fmt, false), .{ expected_fmt, received_fmt });
return .zero;
}
if (expected_value.isRegExp()) {
if (_received_message) |received_message| {
+ // TODO: REMOVE THIS GETTER! Expose a binding to call .test on the RegExp object directly.
if (expected_value.get(globalObject, "test")) |test_fn| {
const matches = test_fn.callWithThis(globalObject, expected_value, &.{received_message});
if (matches.toBooleanSlow(globalObject)) return thisValue;
@@ -2341,27 +2304,21 @@ pub const Expect = struct {
const expected_value_fmt = expected_value.toFmt(globalObject, &formatter);
const received_message_fmt = received_message.toFmt(globalObject, &formatter);
const fmt = signature ++ "\n\n" ++ "Expected pattern: <green>{any}<r>\nReceived message: <red>{any}<r>\n";
- if (Output.enable_ansi_colors) {
- globalObject.throw(Output.prettyFmt(fmt, true), .{ expected_value_fmt, received_message_fmt });
- return .zero;
- }
+ globalObject.throwPretty(fmt, .{ expected_value_fmt, received_message_fmt });
- globalObject.throw(Output.prettyFmt(fmt, false), .{ expected_value_fmt, received_message_fmt });
return .zero;
}
const expected_fmt = expected_value.toFmt(globalObject, &formatter);
const received_fmt = result.toFmt(globalObject, &formatter);
const fmt = signature ++ "\n\n" ++ "Expected pattern: <green>{any}<r>\nReceived value: <red>{any}<r>";
- if (Output.enable_ansi_colors) {
- globalObject.throw(Output.prettyFmt(fmt, true), .{ expected_fmt, received_fmt });
- return .zero;
- }
-
- globalObject.throw(Output.prettyFmt(fmt, false), .{ expected_fmt, received_fmt });
+ globalObject.throwPretty(fmt, .{ expected_fmt, received_fmt });
return .zero;
}
+ // If it's not an object, we are going to crash here.
+ std.debug.assert(expected_value.isObject());
+
if (expected_value.get(globalObject, "message")) |expected_message| {
if (_received_message) |received_message| {
if (received_message.isSameValue(expected_message, globalObject)) return thisValue;
@@ -2374,24 +2331,14 @@ pub const Expect = struct {
const expected_fmt = expected_message.toFmt(globalObject, &formatter);
const received_fmt = received_message.toFmt(globalObject, &formatter);
const fmt = signature ++ "\n\nExpected message: <green>{any}<r>\nReceived message: <red>{any}<r>\n";
- if (Output.enable_ansi_colors) {
- globalObject.throw(Output.prettyFmt(fmt, true), .{ expected_fmt, received_fmt });
- return .zero;
- }
-
- globalObject.throw(Output.prettyFmt(fmt, false), .{ expected_fmt, received_fmt });
+ globalObject.throwPretty(fmt, .{ expected_fmt, received_fmt });
return .zero;
}
const expected_fmt = expected_message.toFmt(globalObject, &formatter);
const received_fmt = result.toFmt(globalObject, &formatter);
const fmt = signature ++ "\n\nExpected message: <green>{any}<r>\nReceived value: <red>{any}<r>\n";
- if (Output.enable_ansi_colors) {
- globalObject.throw(Output.prettyFmt(fmt, true), .{ expected_fmt, received_fmt });
- return .zero;
- }
-
- globalObject.throw(Output.prettyFmt(fmt, false), .{ expected_fmt, received_fmt });
+ globalObject.throwPretty(fmt, .{ expected_fmt, received_fmt });
return .zero;
}
@@ -2408,16 +2355,8 @@ pub const Expect = struct {
if (_received_message) |received_message| {
const message_fmt = fmt ++ "Received message: <red>{any}<r>\n";
const received_message_fmt = received_message.toFmt(globalObject, &formatter);
- if (Output.enable_ansi_colors) {
- globalObject.throw(Output.prettyFmt(message_fmt, true), .{
- expected_class,
- received_class,
- received_message_fmt,
- });
- return .zero;
- }
- globalObject.throw(Output.prettyFmt(message_fmt, false), .{
+ globalObject.throwPretty(message_fmt, .{
expected_class,
received_class,
received_message_fmt,
@@ -2427,16 +2366,8 @@ pub const Expect = struct {
const received_fmt = result.toFmt(globalObject, &formatter);
const value_fmt = fmt ++ "Received value: <red>{any}<r>\n";
- if (Output.enable_ansi_colors) {
- globalObject.throw(Output.prettyFmt(value_fmt, true), .{
- expected_class,
- received_class,
- received_fmt,
- });
- return .zero;
- }
- globalObject.throw(Output.prettyFmt(value_fmt, false), .{
+ globalObject.throwPretty(value_fmt, .{
expected_class,
received_class,
received_fmt,
@@ -2824,7 +2755,7 @@ pub const Expect = struct {
}
unreachable;
};
-
+
if (not) pass = !pass;
if (pass) return thisValue;
@@ -3503,7 +3434,7 @@ pub const DescribeScope = struct {
.test_id = i,
.describe = this,
.globalThis = ctx,
- .source = source,
+ .source_file_path = source.path.text,
.value = JSC.Strong.create(this_object, ctx),
};
runner.ref.ref(ctx.bunVM());
@@ -3608,7 +3539,7 @@ pub const TestRunnerTask = struct {
test_id: TestRunner.Test.ID,
describe: *DescribeScope,
globalThis: *JSC.JSGlobalObject,
- source: logger.Source,
+ source_file_path: string = "",
value: JSC.Strong = .{},
needs_before_each: bool = true,
ref: JSC.Ref = JSC.Ref.init(),
@@ -3677,7 +3608,7 @@ pub const TestRunnerTask = struct {
const beforeEach = this.describe.runCallback(globalThis, .beforeEach);
if (!beforeEach.isEmpty()) {
- Jest.runner.?.reportFailure(test_id, this.source.path.text, label, 0, this.describe);
+ Jest.runner.?.reportFailure(test_id, this.source_file_path, label, 0, this.describe);
globalThis.bunVM().runErrorHandler(beforeEach, null);
return false;
}
@@ -3754,9 +3685,9 @@ pub const TestRunnerTask = struct {
fn processTestResult(this: *TestRunnerTask, globalThis: *JSC.JSGlobalObject, result: Result, test_: TestScope, test_id: u32, describe: *DescribeScope) void {
switch (result) {
- .pass => |count| Jest.runner.?.reportPass(test_id, this.source.path.text, test_.label, count, describe),
- .fail => |count| Jest.runner.?.reportFailure(test_id, this.source.path.text, test_.label, count, describe),
- .skip => Jest.runner.?.reportSkip(test_id, this.source.path.text, test_.label, describe),
+ .pass => |count| Jest.runner.?.reportPass(test_id, this.source_file_path, test_.label, count, describe),
+ .fail => |count| Jest.runner.?.reportFailure(test_id, this.source_file_path, test_.label, count, describe),
+ .skip => Jest.runner.?.reportSkip(test_id, this.source_file_path, test_.label, describe),
.pending => @panic("Unexpected pending test"),
}
describe.onTestComplete(globalThis, test_id, result == .skip);
@@ -3773,7 +3704,16 @@ pub const TestRunnerTask = struct {
this.value.deinit();
this.ref.unref(vm);
- default_allocator.destroy(this);
+
+ // there is a double free here involving async before/after callbacks
+ //
+ // Fortunately:
+ //
+ // - TestRunnerTask doesn't use much memory.
+ // - we don't have watch mode yet.
+ //
+ // TODO: fix this bug
+ // default_allocator.destroy(this);
}
};
diff --git a/src/bun.js/webcore/body.zig b/src/bun.js/webcore/body.zig
index 85a52bc3f..37a70343d 100644
--- a/src/bun.js/webcore/body.zig
+++ b/src/bun.js/webcore/body.zig
@@ -149,7 +149,9 @@ pub const Body = struct {
// we can skip calling JS getters
if (response_init.as(Request)) |req| {
if (req.headers) |headers| {
- result.headers = headers.cloneThis(ctx);
+ if (!headers.isEmpty()) {
+ result.headers = headers.cloneThis(ctx);
+ }
}
result.method = req.method;
@@ -163,7 +165,9 @@ pub const Body = struct {
if (response_init.fastGet(ctx, .headers)) |headers| {
if (headers.as(FetchHeaders)) |orig| {
- result.headers = orig.cloneThis(ctx);
+ if (!orig.isEmpty()) {
+ result.headers = orig.cloneThis(ctx);
+ }
} else {
result.headers = FetchHeaders.createFromJS(ctx.ptr(), headers);
}
@@ -185,7 +189,7 @@ pub const Body = struct {
}
} else if (status_value.isNumber()) {
const number = status_value.to(i32);
- if (100 <= number and number < 600)
+ if (100 <= number and number < 999)
result.status_code = @truncate(u16, @intCast(u32, number));
}
}
@@ -849,12 +853,12 @@ pub const Body = struct {
if (tag == .InternalBlob) {
this.InternalBlob.clearAndFree();
- this.* = Value{ .Null = {} }; //Value.empty;
+ this.* = Value{ .Null = {} };
}
if (tag == .Blob) {
this.Blob.deinit();
- this.* = Value{ .Null = {} }; //Value.empty;
+ this.* = Value{ .Null = {} };
}
if (tag == .Error) {
diff --git a/src/bun.js/webcore/request.zig b/src/bun.js/webcore/request.zig
index ede8cab5d..fe8fd9c9c 100644
--- a/src/bun.js/webcore/request.zig
+++ b/src/bun.js/webcore/request.zig
@@ -379,100 +379,242 @@ pub const Request = struct {
}
}
+ const Fields = enum {
+ method,
+ headers,
+ body,
+ // referrer,
+ // referrerPolicy,
+ // mode,
+ // credentials,
+ // redirect,
+ // integrity,
+ // keepalive,
+ signal,
+ // proxy,
+ // timeout,
+ url,
+ };
+
pub fn constructInto(
globalThis: *JSC.JSGlobalObject,
arguments: []const JSC.JSValue,
) ?Request {
- var request = Request{};
-
- switch (arguments.len) {
- 0 => {},
- 1 => {
- const urlOrObject = arguments[0];
- const url_or_object_type = urlOrObject.jsType();
- if (url_or_object_type.isStringLike()) {
- request.url = (arguments[0].toSlice(globalThis, bun.default_allocator).cloneIfNeeded(bun.default_allocator) catch {
- return null;
- }).slice();
- request.url_was_allocated = request.url.len > 0;
- request.body = .{
- .Null = {},
- };
- } else {
- if (Body.Init.init(getAllocator(globalThis), globalThis, arguments[0]) catch null) |req_init| {
- request.headers = req_init.headers;
- request.method = req_init.method;
+ var req = Request{};
+
+ if (arguments.len == 0) {
+ globalThis.throw("Failed to construct 'Request': 1 argument required, but only 0 present.", .{});
+ return null;
+ } else if (arguments[0].isEmptyOrUndefinedOrNull() or !arguments[0].isCell()) {
+ globalThis.throw("Failed to construct 'Request': expected non-empty string or object, got undefined", .{});
+ return null;
+ }
+
+ const url_or_object = arguments[0];
+ const url_or_object_type = url_or_object.jsType();
+ var fields = std.EnumSet(Fields).initEmpty();
+
+ const is_first_argument_a_url =
+ // fastest path:
+ url_or_object_type.isStringLike() or
+ // slower path:
+ url_or_object.as(JSC.DOMURL) != null;
+
+ if (is_first_argument_a_url) {
+ const slice = arguments[0].toSliceOrNull(globalThis) orelse {
+ req.finalizeWithoutDeinit();
+ return null;
+ };
+ req.url = (slice.cloneIfNeeded(globalThis.allocator()) catch {
+ req.finalizeWithoutDeinit();
+ return null;
+ }).slice();
+ req.url_was_allocated = req.url.len > 0;
+ if (req.url.len > 0)
+ fields.insert(.url);
+ } else if (!url_or_object_type.isObject()) {
+ globalThis.throw("Failed to construct 'Request': expected non-empty string or object", .{});
+ return null;
+ }
+
+ const values_to_try_ = [_]JSValue{
+ if (arguments.len > 1 and arguments[1].isObject())
+ arguments[1]
+ else if (is_first_argument_a_url)
+ JSValue.undefined
+ else
+ url_or_object,
+ if (is_first_argument_a_url) JSValue.undefined else url_or_object,
+ };
+ const values_to_try = values_to_try_[0 .. @as(usize, @boolToInt(!is_first_argument_a_url)) +
+ @as(usize, @boolToInt(arguments.len > 1 and arguments[1].isObject()))];
+
+ for (values_to_try) |value| {
+ const value_type = value.jsType();
+
+ if (value_type == .DOMWrapper) {
+ if (value.as(Request)) |request| {
+ if (values_to_try.len == 1) {
+ request.cloneInto(&req, globalThis.allocator(), globalThis);
+ if (req.url_was_allocated) {
+ req.url = req.url;
+ req.url_was_allocated = true;
+ }
+ return req;
}
- if (urlOrObject.fastGet(globalThis, .body)) |body_| {
- if (Body.Value.fromJS(globalThis, body_)) |body| {
- request.body = body;
- } else {
- request.finalizeWithoutDeinit();
- return null;
+ if (!fields.contains(.method)) {
+ req.method = request.method;
+ fields.insert(.method);
+ }
+
+ if (!fields.contains(.headers)) {
+ if (request.cloneHeaders(globalThis)) |headers| {
+ req.headers = headers;
+ fields.insert(.headers);
}
- } else {
- request.body = .{
- .Null = {},
- };
}
- if (urlOrObject.fastGet(globalThis, .url)) |url| {
- request.url = (url.toSlice(globalThis, bun.default_allocator).cloneIfNeeded(bun.default_allocator) catch {
- return null;
- }).slice();
- request.url_was_allocated = request.url.len > 0;
+ if (!fields.contains(.body)) {
+ switch (request.body) {
+ .Null, .Empty, .Used => {},
+ else => {
+ req.body = request.body.clone(globalThis);
+ fields.insert(.body);
+ },
+ }
}
}
- },
- else => {
- if (arguments[1].get(globalThis, "signal")) |signal_| {
- if (AbortSignal.fromJS(signal_)) |signal| {
- //Keep it alive
- signal_.ensureStillAlive();
- request.signal = signal.ref();
- } else {
- globalThis.throw("Failed to construct 'Request': member signal is not of type AbortSignal.", .{});
- request.finalizeWithoutDeinit();
- return null;
+ if (value.as(JSC.WebCore.Response)) |response| {
+ if (!fields.contains(.method)) {
+ req.method = response.body.init.method;
+ fields.insert(.method);
+ }
+
+ if (!fields.contains(.headers)) {
+ if (response.body.init.headers) |headers| {
+ req.headers = headers.cloneThis(globalThis);
+ fields.insert(.headers);
+ }
}
- }
- if (Body.Init.init(getAllocator(globalThis), globalThis, arguments[1]) catch null) |req_init| {
- request.headers = req_init.headers;
- request.method = req_init.method;
+ if (!fields.contains(.url)) {
+ if (response.url.len > 0) {
+ req.url = globalThis.allocator().dupe(u8, response.url) catch unreachable;
+ req.url_was_allocated = true;
+ fields.insert(.url);
+ }
+ }
+
+ if (!fields.contains(.body)) {
+ switch (response.body.value) {
+ .Null, .Empty, .Used => {},
+ else => {
+ req.body = response.body.value.clone(globalThis);
+ fields.insert(.body);
+ },
+ }
+ }
}
+ }
- if (arguments[1].fastGet(globalThis, .body)) |body_| {
+ if (!fields.contains(.body)) {
+ if (value.fastGet(globalThis, .body)) |body_| {
+ fields.insert(.body);
if (Body.Value.fromJS(globalThis, body_)) |body| {
- request.body = body;
+ req.body = body;
} else {
- request.finalizeWithoutDeinit();
+ req.finalizeWithoutDeinit();
return null;
}
- } else {
- request.body = .{
- .Null = {},
+ }
+ }
+
+ if (!fields.contains(.url)) {
+ if (value.fastGet(globalThis, .url)) |url| {
+ req.url = (url.toSlice(globalThis, bun.default_allocator).cloneIfNeeded(bun.default_allocator) catch {
+ return null;
+ }).slice();
+ req.url_was_allocated = req.url.len > 0;
+ if (req.url.len > 0)
+ fields.insert(.url);
+
+ // first value
+ } else if (@enumToInt(value) == @enumToInt(values_to_try[values_to_try.len - 1]) and !is_first_argument_a_url and
+ value.implementsToString(globalThis))
+ {
+ const slice = value.toSliceOrNull(globalThis) orelse {
+ req.finalizeWithoutDeinit();
+ return null;
};
+ req.url = (slice.cloneIfNeeded(globalThis.allocator()) catch {
+ req.finalizeWithoutDeinit();
+ return null;
+ }).slice();
+ req.url_was_allocated = req.url.len > 0;
+ if (req.url.len > 0)
+ fields.insert(.url);
}
+ }
- request.url = (arguments[0].toSlice(globalThis, bun.default_allocator).cloneIfNeeded(bun.default_allocator) catch {
- return null;
- }).slice();
- request.url_was_allocated = request.url.len > 0;
- },
+ if (!fields.contains(.signal)) {
+ if (value.get(globalThis, "signal")) |signal_| {
+ fields.insert(.signal);
+
+ if (AbortSignal.fromJS(signal_)) |signal| {
+ //Keep it alive
+ signal_.ensureStillAlive();
+ req.signal = signal.ref();
+ } else {
+ globalThis.throw("Failed to construct 'Request': signal is not of type AbortSignal.", .{});
+ req.finalizeWithoutDeinit();
+ return null;
+ }
+ }
+ }
+
+ if (!fields.contains(.method) or !fields.contains(.headers)) {
+ if (Body.Init.init(globalThis.allocator(), globalThis, value) catch null) |init| {
+ if (!fields.contains(.method)) {
+ req.method = init.method;
+ fields.insert(.method);
+ }
+
+ if (init.headers) |headers| {
+ if (!fields.contains(.headers)) {
+ req.headers = headers;
+ fields.insert(.headers);
+ } else {
+ headers.deref();
+ }
+ }
+ }
+ }
}
- if (request.body == .Blob and
- request.headers != null and
- request.body.Blob.content_type.len > 0 and
- !request.headers.?.fastHas(.ContentType))
+ if (req.url.len == 0) {
+ globalThis.throw("Failed to construct 'Request': url is required.", .{});
+ req.finalizeWithoutDeinit();
+ return null;
+ }
+
+ const parsed_url = ZigURL.parse(req.url);
+ if (parsed_url.hostname.len == 0) {
+ globalThis.throw("Failed to construct 'Request': Invalid URL (missing a hostname)", .{});
+ req.finalizeWithoutDeinit();
+ return null;
+ }
+
+ if (req.body == .Blob and
+ req.headers != null and
+ req.body.Blob.content_type.len > 0 and
+ !req.headers.?.fastHas(.ContentType))
{
- request.headers.?.put("content-type", request.body.Blob.content_type, globalThis);
+ req.headers.?.put("content-type", req.body.Blob.content_type, globalThis);
}
- return request;
+ return req;
}
pub fn constructor(
@@ -531,6 +673,24 @@ pub const Request = struct {
return this.headers.?.toJS(globalThis);
}
+ pub fn cloneHeaders(this: *Request, globalThis: *JSGlobalObject) ?*FetchHeaders {
+ if (this.headers == null) {
+ if (this.uws_request) |uws_req| {
+ this.headers = FetchHeaders.createFromUWS(globalThis, uws_req);
+ }
+ }
+
+ if (this.headers) |head| {
+ if (head.isEmpty()) {
+ return null;
+ }
+
+ return head.cloneThis(globalThis);
+ }
+
+ return null;
+ }
+
pub fn cloneInto(
this: *Request,
req: *Request,
@@ -546,15 +706,9 @@ pub const Request = struct {
return;
},
.method = this.method,
+ .headers = this.cloneHeaders(globalThis),
};
- if (this.headers) |head| {
- req.headers = head.cloneThis(globalThis);
- } else if (this.uws_request) |uws_req| {
- req.headers = FetchHeaders.createFromUWS(globalThis, uws_req);
- this.headers = req.headers.?.cloneThis(globalThis).?;
- }
-
if (this.signal) |signal| {
req.signal = signal.ref();
}
diff --git a/src/bun.js/webcore/response.zig b/src/bun.js/webcore/response.zig
index 9dfee821a..a19ee9ca4 100644
--- a/src/bun.js/webcore/response.zig
+++ b/src/bun.js/webcore/response.zig
@@ -490,7 +490,14 @@ pub const Response = struct {
globalThis: *JSC.JSGlobalObject,
callframe: *JSC.CallFrame,
) callconv(.C) ?*Response {
- const args_list = callframe.arguments(2);
+ const args_list = brk: {
+ var args = callframe.arguments(2);
+ if (args.len > 1 and args.ptr[1].isEmptyOrUndefinedOrNull()) {
+ args.len = 1;
+ }
+ break :brk args;
+ };
+
const arguments = args_list.ptr[0..args_list.len];
const body: Body = @as(?Body, brk: {
switch (arguments.len) {
@@ -501,11 +508,12 @@ pub const Response = struct {
break :brk Body.extract(globalThis, arguments[0]);
},
else => {
- if (arguments[1].isUndefinedOrNull()) break :brk Body.extract(globalThis, arguments[0]);
if (arguments[1].isObject()) {
break :brk Body.extractWithInit(globalThis, arguments[0], arguments[1]);
}
+ std.debug.assert(!arguments[1].isEmptyOrUndefinedOrNull());
+
const err = globalThis.createTypeErrorInstance("Expected options to be one of: null, undefined, or object", .{});
globalThis.throwValue(err);
break :brk null;
@@ -731,7 +739,13 @@ pub const Fetch = struct {
const fetch_error = JSC.SystemError{
.code = ZigString.init(@errorName(this.result.fail)),
- .message = ZigString.init("fetch() failed"),
+ .message = switch (this.result.fail) {
+ error.ConnectionClosed => ZigString.init("The socket connection was closed unexpectedly. For more information, pass `verbose: true` in the second argument to fetch()"),
+ error.FailedToOpenSocket => ZigString.init("Was there a typo in the url or port?"),
+ error.TooManyRedirects => ZigString.init("The response redirected too many times. For more information, pass `verbose: true` in the second argument to fetch()"),
+ error.ConnectionRefused => ZigString.init("Unable to connect. Is the computer able to access the url?"),
+ else => ZigString.init("fetch() failed. For more information, pass `verbose: true` in the second argument to fetch()"),
+ },
.path = ZigString.init(this.http.?.url.href),
};
diff --git a/src/env_loader.zig b/src/env_loader.zig
index 41fb25fe5..38c0744a3 100644
--- a/src/env_loader.zig
+++ b/src/env_loader.zig
@@ -451,7 +451,7 @@ pub const Loader = struct {
}
}
- //NO_PROXY filter
+ // NO_PROXY filter
if (http_proxy != null) {
if (this.map.get("no_proxy") orelse this.map.get("NO_PROXY")) |no_proxy_text| {
if (no_proxy_text.len == 0) return http_proxy;
diff --git a/src/install/extract_tarball.zig b/src/install/extract_tarball.zig
index 0df11ffcd..bec5f5eff 100644
--- a/src/install/extract_tarball.zig
+++ b/src/install/extract_tarball.zig
@@ -110,7 +110,7 @@ pub fn buildURLWithPrinter(
var name = full_name;
if (name[0] == '@') {
- if (std.mem.indexOfScalar(u8, name, '/')) |i| {
+ if (strings.indexOfChar(name, '/')) |i| {
name = name[i + 1 ..];
}
}
diff --git a/src/install/install.zig b/src/install/install.zig
index 0c280ccaa..0927c9335 100644
--- a/src/install/install.zig
+++ b/src/install/install.zig
@@ -323,11 +323,21 @@ const NetworkTask = struct {
this.response_buffer = try MutableString.init(allocator, 0);
this.allocator = allocator;
- const env = this.package_manager.env;
- var url = URL.parse(this.url_buf);
- var http_proxy: ?URL = env.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, null);
+ const url = URL.parse(this.url_buf);
+ 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(),
+ this.package_manager.httpProxy(url),
+ null,
+ );
this.http.max_retry_count = this.package_manager.options.max_retry_count;
this.callback = .{
.package_manifest = .{
@@ -389,12 +399,21 @@ const NetworkTask = struct {
header_buf = header_builder.content.ptr.?[0..header_builder.content.len];
}
- const env = this.package_manager.env;
-
- var url = URL.parse(this.url_buf);
- var http_proxy: ?URL = env.getHttpProxy(url);
+ const url = URL.parse(this.url_buf);
- this.http = AsyncHTTP.init(allocator, .GET, url, header_builder.entries, header_buf, &this.response_buffer, "", 0, this.getCompletionCallback(), http_proxy, null);
+ this.http = AsyncHTTP.init(
+ allocator,
+ .GET,
+ url,
+ header_builder.entries,
+ header_buf,
+ &this.response_buffer,
+ "",
+ 0,
+ this.getCompletionCallback(),
+ this.package_manager.httpProxy(url),
+ null,
+ );
this.http.max_retry_count = this.package_manager.options.max_retry_count;
this.callback = .{ .extract = tarball };
}
@@ -1590,6 +1609,10 @@ pub const PackageManager = struct {
80,
);
+ pub fn httpProxy(this: *PackageManager, url: URL) ?URL {
+ return this.env.getHttpProxy(url);
+ }
+
pub const WakeHandler = struct {
// handler: fn (ctx: *anyopaque, pm: *PackageManager) void = undefined,
// onDependencyError: fn (ctx: *anyopaque, Dependency, PackageID, anyerror) void = undefined,
@@ -6561,11 +6584,14 @@ pub const PackageManager = struct {
const cwd = std.fs.cwd();
while (iterator.nextNodeModulesFolder()) |node_modules| {
- try cwd.makePath(bun.span(node_modules.relative_path));
// We deliberately do not close this folder.
// If the package hasn't been downloaded, we will need to install it later
// We use this file descriptor to know where to put it.
- installer.node_modules_folder = try cwd.openIterableDir(node_modules.relative_path, .{});
+ installer.node_modules_folder = cwd.openIterableDir(node_modules.relative_path, .{}) catch brk: {
+ // Avoid extra mkdir() syscall
+ try cwd.makePath(bun.span(node_modules.relative_path));
+ break :brk try cwd.openIterableDir(node_modules.relative_path, .{});
+ };
var remaining = node_modules.dependencies;