aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js/api
diff options
context:
space:
mode:
Diffstat (limited to 'src/bun.js/api')
-rw-r--r--src/bun.js/api/JSBundler.zig47
-rw-r--r--src/bun.js/api/JSTranspiler.zig10
-rw-r--r--src/bun.js/api/bun.zig205
-rw-r--r--src/bun.js/api/bun/dns_resolver.zig22
-rw-r--r--src/bun.js/api/bun/socket.zig601
-rw-r--r--src/bun.js/api/bun/subprocess.zig6
-rw-r--r--src/bun.js/api/ffi.zig36
-rw-r--r--src/bun.js/api/html_rewriter.zig169
-rw-r--r--src/bun.js/api/server.zig443
-rw-r--r--src/bun.js/api/sockets.classes.ts12
10 files changed, 1032 insertions, 519 deletions
diff --git a/src/bun.js/api/JSBundler.zig b/src/bun.js/api/JSBundler.zig
index 8e85f1190..44ceaee9d 100644
--- a/src/bun.js/api/JSBundler.zig
+++ b/src/bun.js/api/JSBundler.zig
@@ -26,7 +26,7 @@ const strings = bun.strings;
const NewClass = Base.NewClass;
const To = Base.To;
const Request = WebCore.Request;
-
+const String = bun.String;
const FetchEvent = WebCore.FetchEvent;
const MacroMap = @import("../../resolver/package_json.zig").MacroMap;
const TSConfigJSON = @import("../../resolver/tsconfig_json.zig").TSConfigJSON;
@@ -844,7 +844,7 @@ pub const JSBundler = struct {
this.value = .{
.success = .{
- .loader = @intToEnum(options.Loader, @intCast(u8, loader_as_int.to(i32))),
+ .loader = @enumFromInt(options.Loader, @intCast(u8, loader_as_int.to(i32))),
.source_code = source_code,
},
};
@@ -871,16 +871,16 @@ pub const JSBundler = struct {
extern fn JSBundlerPlugin__anyMatches(
*Plugin,
- namespaceString: *const ZigString,
- path: *const ZigString,
+ namespaceString: *const String,
+ path: *const String,
bool,
) bool;
extern fn JSBundlerPlugin__matchOnLoad(
*JSC.JSGlobalObject,
*Plugin,
- namespaceString: *const ZigString,
- path: *const ZigString,
+ namespaceString: *const String,
+ path: *const String,
context: *anyopaque,
u8,
) void;
@@ -888,9 +888,9 @@ pub const JSBundler = struct {
extern fn JSBundlerPlugin__matchOnResolve(
*JSC.JSGlobalObject,
*Plugin,
- namespaceString: *const ZigString,
- path: *const ZigString,
- importer: *const ZigString,
+ namespaceString: *const String,
+ path: *const String,
+ importer: *const String,
context: *anyopaque,
u8,
) void;
@@ -905,10 +905,10 @@ pub const JSBundler = struct {
defer tracer.end();
const namespace_string = if (path.isFile())
- ZigString.Empty
+ bun.String.empty
else
- ZigString.fromUTF8(path.namespace);
- const path_string = ZigString.fromUTF8(path.text);
+ bun.String.create(path.namespace);
+ const path_string = bun.String.create(path.text);
return JSBundlerPlugin__anyMatches(this, &namespace_string, &path_string, is_onLoad);
}
@@ -924,11 +924,13 @@ pub const JSBundler = struct {
const tracer = bun.tracy.traceNamed(@src(), "JSBundler.matchOnLoad");
defer tracer.end();
const namespace_string = if (namespace.len == 0)
- ZigString.init("file")
+ bun.String.static("file")
else
- ZigString.fromUTF8(namespace);
- const path_string = ZigString.fromUTF8(path);
- JSBundlerPlugin__matchOnLoad(globalThis, this, &namespace_string, &path_string, context, @enumToInt(default_loader));
+ bun.String.create(namespace);
+ const path_string = bun.String.create(path);
+ defer namespace_string.deref();
+ defer path_string.deref();
+ JSBundlerPlugin__matchOnLoad(globalThis, this, &namespace_string, &path_string, context, @intFromEnum(default_loader));
}
pub fn matchOnResolve(
@@ -944,12 +946,15 @@ pub const JSBundler = struct {
const tracer = bun.tracy.traceNamed(@src(), "JSBundler.matchOnResolve");
defer tracer.end();
const namespace_string = if (strings.eqlComptime(namespace, "file"))
- ZigString.Empty
+ bun.String.empty
else
- ZigString.fromUTF8(namespace);
- const path_string = ZigString.fromUTF8(path);
- const importer_string = ZigString.fromUTF8(importer);
- JSBundlerPlugin__matchOnResolve(globalThis, this, &namespace_string, &path_string, &importer_string, context, @enumToInt(import_record_kind));
+ bun.String.create(namespace);
+ const path_string = bun.String.create(path);
+ const importer_string = bun.String.create(importer);
+ defer namespace_string.deref();
+ defer path_string.deref();
+ defer importer_string.deref();
+ JSBundlerPlugin__matchOnResolve(globalThis, this, &namespace_string, &path_string, &importer_string, context, @intFromEnum(import_record_kind));
}
pub fn addPlugin(
diff --git a/src/bun.js/api/JSTranspiler.zig b/src/bun.js/api/JSTranspiler.zig
index a1e1cfa36..308738abf 100644
--- a/src/bun.js/api/JSTranspiler.zig
+++ b/src/bun.js/api/JSTranspiler.zig
@@ -85,7 +85,7 @@ const TranspilerOptions = struct {
// This is going to be hard to not leak
pub const TransformTask = struct {
input_code: ZigString = ZigString.init(""),
- protected_input_value: JSC.JSValue = @intToEnum(JSC.JSValue, 0),
+ protected_input_value: JSC.JSValue = @enumFromInt(JSC.JSValue, 0),
output_code: ZigString = ZigString.init(""),
bundler: Bundler.Bundler = undefined,
log: logger.Log,
@@ -220,8 +220,8 @@ pub const TransformTask = struct {
finish(this.output_code, this.global, promise);
- if (@enumToInt(this.protected_input_value) != 0) {
- this.protected_input_value = @intToEnum(JSC.JSValue, 0);
+ if (@intFromEnum(this.protected_input_value) != 0) {
+ this.protected_input_value = @enumFromInt(JSC.JSValue, 0);
}
this.deinit();
}
@@ -611,7 +611,7 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std
while (length_iter.next()) |value| {
if (value.isString()) {
const length = @truncate(u32, value.getLength(globalThis));
- string_count += @as(u32, @boolToInt(length > 0));
+ string_count += @as(u32, @intFromBool(length > 0));
total_name_buf_len += length;
}
}
@@ -877,7 +877,7 @@ fn getParseResult(this: *Transpiler, allocator: std.mem.Allocator, code: []const
for (res.ast.import_records.slice()) |*import| {
if (import.kind.isCommonJS()) {
import.do_commonjs_transform_in_printer = true;
- import.module_id = @truncate(u32, std.hash.Wyhash.hash(0, import.path.pretty));
+ import.module_id = @truncate(u32, bun.hash(import.path.pretty));
}
}
}
diff --git a/src/bun.js/api/bun.zig b/src/bun.js/api/bun.zig
index 5580e8840..fbf567446 100644
--- a/src/bun.js/api/bun.zig
+++ b/src/bun.js/api/bun.zig
@@ -303,7 +303,7 @@ pub fn registerMacro(
return js.JSValueMakeUndefined(ctx);
}
// TODO: make this faster
- const id = @truncate(i32, @floatToInt(i64, js.JSValueToNumber(ctx, arguments[0], exception)));
+ const id = @truncate(i32, @intFromFloat(i64, js.JSValueToNumber(ctx, arguments[0], exception)));
if (id == -1 or id == 0) {
JSError(getAllocator(ctx), "Internal error registering macros: invalid id", .{}, ctx, exception);
return js.JSValueMakeUndefined(ctx);
@@ -523,7 +523,7 @@ pub fn getFilePath(ctx: js.JSContextRef, arguments: []const js.JSValueRef, buf:
temp_strings_list[temp_strings_list_len] = out_slice;
// The dots are kind of unnecessary. They'll be normalized.
- if (out.len == 0 or @ptrToInt(out.ptr) == 0 or std.mem.eql(u8, out_slice, ".") or std.mem.eql(u8, out_slice, "..") or std.mem.eql(u8, out_slice, "../")) {
+ if (out.len == 0 or @intFromPtr(out.ptr) == 0 or std.mem.eql(u8, out_slice, ".") or std.mem.eql(u8, out_slice, "..") or std.mem.eql(u8, out_slice, "../")) {
JSError(getAllocator(ctx), "Expected a file path as a string or an array of strings to be part of a file path.", .{}, ctx, exception);
return null;
}
@@ -600,7 +600,7 @@ pub fn readFileAsStringCallback(
return js.JSValueMakeUndefined(ctx);
};
- if (stat.kind != .File) {
+ if (stat.kind != .file) {
JSError(getAllocator(ctx), "Can't read a {s} as a string (\"{s}\")", .{ @tagName(stat.kind), path }, ctx, exception);
return js.JSValueMakeUndefined(ctx);
}
@@ -641,7 +641,7 @@ pub fn readFileAsBytesCallback(
return js.JSValueMakeUndefined(ctx);
};
- if (stat.kind != .File) {
+ if (stat.kind != .file) {
JSError(allocator, "Can't read a {s} as a string (\"{s}\")", .{ @tagName(stat.kind), path }, ctx, exception);
return js.JSValueMakeUndefined(ctx);
}
@@ -896,6 +896,9 @@ pub fn createNodeFS(
) js.JSValueRef {
var module = ctx.allocator().create(JSC.Node.NodeJSFS) catch unreachable;
module.* = .{};
+ var vm = ctx.bunVM();
+ if (vm.standalone_module_graph != null)
+ module.node_fs.vm = vm;
return module.toJS(ctx).asObjectRef();
}
@@ -1612,7 +1615,7 @@ pub const Crypto = struct {
fn createCryptoError(globalThis: *JSC.JSGlobalObject, err_code: u32) JSValue {
var outbuf: [128 + 1 + "BoringSSL error: ".len]u8 = undefined;
- @memset(&outbuf, 0, outbuf.len);
+ @memset(&outbuf, 0);
outbuf[0.."BoringSSL error: ".len].* = "BoringSSL error: ".*;
var message_buf = outbuf["BoringSSL error: ".len..];
@@ -3171,9 +3174,9 @@ pub fn mmapFile(
return JSC.C.JSObjectMakeTypedArrayWithBytesNoCopy(ctx, JSC.C.JSTypedArrayType.kJSTypedArrayTypeUint8Array, @ptrCast(?*anyopaque, map.ptr), map.len, struct {
pub fn x(ptr: ?*anyopaque, size: ?*anyopaque) callconv(.C) void {
- _ = JSC.Node.Syscall.munmap(@ptrCast([*]align(std.mem.page_size) u8, @alignCast(std.mem.page_size, ptr))[0..@ptrToInt(size)]);
+ _ = JSC.Node.Syscall.munmap(@ptrCast([*]align(std.mem.page_size) u8, @alignCast(std.mem.page_size, ptr))[0..@intFromPtr(size)]);
}
- }.x, @intToPtr(?*anyopaque, map.len), exception);
+ }.x, @ptrFromInt(?*anyopaque, map.len), exception);
}
pub fn getTranspilerConstructor(
@@ -3401,7 +3404,7 @@ pub const Unsafe = struct {
globalThis: *JSC.JSGlobalObject,
value_: ?JSValue,
) JSValue {
- const ret = JSValue.jsNumber(@as(i32, @enumToInt(globalThis.bunVM().aggressive_garbage_collection)));
+ const ret = JSValue.jsNumber(@as(i32, @intFromEnum(globalThis.bunVM().aggressive_garbage_collection)));
if (value_) |value| {
switch (value.coerce(i32, globalThis)) {
@@ -3712,21 +3715,32 @@ pub const Timer = struct {
const kind = this.kind;
var map: *TimeoutMap = vm.timer.maps.get(kind);
- // This doesn't deinit the timer
- // Timers are deinit'd separately
- // We do need to handle when the timer is cancelled after the job has been enqueued
- if (kind != .setInterval) {
- if (map.fetchSwapRemove(this.id) == null) {
- // if the timeout was cancelled, don't run the callback
- this.deinit();
- return;
- }
- } else {
- if (!map.contains(this.id)) {
- // if the interval was cancelled, don't run the callback
- this.deinit();
- return;
+ const should_cancel_job = brk: {
+ // This doesn't deinit the timer
+ // Timers are deinit'd separately
+ // We do need to handle when the timer is cancelled after the job has been enqueued
+ if (kind != .setInterval) {
+ if (map.get(this.id)) |tombstone_or_timer| {
+ break :brk tombstone_or_timer != null;
+ } else {
+ // clearTimeout has been called
+ break :brk true;
+ }
+ } else {
+ if (map.get(this.id)) |tombstone_or_timer| {
+ // .refresh() was called after CallbackJob enqueued
+ break :brk tombstone_or_timer == null;
+ }
}
+
+ break :brk false;
+ };
+
+ if (should_cancel_job) {
+ this.deinit();
+ return;
+ } else if (kind != .setInterval) {
+ _ = map.swapRemove(this.id);
}
var args_buf: [8]JSC.JSValue = undefined;
@@ -3791,6 +3805,8 @@ pub const Timer = struct {
result.then(globalThis, this, CallbackJob__onResolve, CallbackJob__onReject);
},
}
+ } else {
+ this.deinit();
}
}
};
@@ -3820,10 +3836,29 @@ pub const Timer = struct {
return timer_js;
}
- pub fn doRef(this: *TimerObject, _: *JSC.JSGlobalObject, _: *JSC.CallFrame) callconv(.C) JSValue {
+ pub fn doRef(this: *TimerObject, globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSValue {
+ const this_value = callframe.this();
+ this_value.ensureStillAlive();
if (this.ref_count > 0)
this.ref_count +|= 1;
- return JSValue.jsUndefined();
+
+ var vm = globalObject.bunVM();
+ switch (this.kind) {
+ .setTimeout, .setImmediate, .setInterval => {
+ if (vm.timer.maps.get(this.kind).getPtr(this.id)) |val_| {
+ if (val_.*) |*val| {
+ val.poll_ref.ref(vm);
+
+ if (val.did_unref_timer) {
+ val.did_unref_timer = false;
+ vm.uws_event_loop.?.num_polls += 1;
+ }
+ }
+ }
+ },
+ }
+
+ return this_value;
}
pub fn doRefresh(this: *TimerObject, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSValue {
@@ -3912,27 +3947,34 @@ pub const Timer = struct {
id,
Timeout.run,
this.interval,
- @as(i32, @boolToInt(this.kind == .setInterval)) * this.interval,
+ @as(i32, @intFromBool(this.kind == .setInterval)) * this.interval,
);
return this_value;
}
return JSValue.jsUndefined();
}
- pub fn doUnref(this: *TimerObject, globalObject: *JSC.JSGlobalObject, _: *JSC.CallFrame) callconv(.C) JSValue {
+ pub fn doUnref(this: *TimerObject, globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSValue {
+ const this_value = callframe.this();
+ this_value.ensureStillAlive();
this.ref_count -|= 1;
- if (this.ref_count == 0) {
- switch (this.kind) {
- .setTimeout, .setImmediate => {
- _ = clearTimeout(globalObject, JSValue.jsNumber(this.id));
- },
- .setInterval => {
- _ = clearInterval(globalObject, JSValue.jsNumber(this.id));
- },
- }
+ var vm = globalObject.bunVM();
+ switch (this.kind) {
+ .setTimeout, .setImmediate, .setInterval => {
+ if (vm.timer.maps.get(this.kind).getPtr(this.id)) |val_| {
+ if (val_.*) |*val| {
+ val.poll_ref.unref(vm);
+
+ if (!val.did_unref_timer) {
+ val.did_unref_timer = true;
+ vm.uws_event_loop.?.num_polls -= 1;
+ }
+ }
+ }
+ },
}
- return JSValue.jsUndefined();
+ return this_value;
}
pub fn hasRef(this: *TimerObject, globalObject: *JSC.JSGlobalObject, _: *JSC.CallFrame) callconv(.C) JSValue {
return JSValue.jsBoolean(this.ref_count > 0 and globalObject.bunVM().timer.maps.get(this.kind).contains(this.id));
@@ -3954,6 +3996,7 @@ pub const Timer = struct {
callback: JSC.Strong = .{},
globalThis: *JSC.JSGlobalObject,
timer: *uws.Timer,
+ did_unref_timer: bool = false,
poll_ref: JSC.PollRef = JSC.PollRef.init(),
arguments: JSC.Strong = .{},
@@ -4055,8 +4098,14 @@ pub const Timer = struct {
var vm = this.globalThis.bunVM();
- this.poll_ref.unrefOnNextTick(vm);
+ this.poll_ref.unref(vm);
+
this.timer.deinit();
+ if (this.did_unref_timer) {
+ // balance double-unrefing
+ vm.uws_event_loop.?.num_polls += 1;
+ }
+
this.callback.deinit();
this.arguments.deinit();
}
@@ -4130,7 +4179,7 @@ pub const Timer = struct {
},
Timeout.run,
interval,
- @as(i32, @boolToInt(kind == .setInterval)) * interval,
+ @as(i32, @intFromBool(kind == .setInterval)) * interval,
);
}
@@ -4318,7 +4367,7 @@ pub const FFI = struct {
arguments: []const JSValue,
) JSValue {
const addr = arguments[0].asPtrAddress() + if (arguments.len > 1) @intCast(usize, arguments[1].to(i32)) else @as(usize, 0);
- const value = @intToPtr(*align(1) u8, addr).*;
+ const value = @ptrFromInt(*align(1) u8, addr).*;
return JSValue.jsNumber(value);
}
pub fn @"u16"(
@@ -4327,7 +4376,7 @@ pub const FFI = struct {
arguments: []const JSValue,
) JSValue {
const addr = arguments[0].asPtrAddress() + if (arguments.len > 1) @intCast(usize, arguments[1].to(i32)) else @as(usize, 0);
- const value = @intToPtr(*align(1) u16, addr).*;
+ const value = @ptrFromInt(*align(1) u16, addr).*;
return JSValue.jsNumber(value);
}
pub fn @"u32"(
@@ -4336,7 +4385,7 @@ pub const FFI = struct {
arguments: []const JSValue,
) JSValue {
const addr = arguments[0].asPtrAddress() + if (arguments.len > 1) @intCast(usize, arguments[1].to(i32)) else @as(usize, 0);
- const value = @intToPtr(*align(1) u32, addr).*;
+ const value = @ptrFromInt(*align(1) u32, addr).*;
return JSValue.jsNumber(value);
}
pub fn ptr(
@@ -4345,7 +4394,7 @@ pub const FFI = struct {
arguments: []const JSValue,
) JSValue {
const addr = arguments[0].asPtrAddress() + if (arguments.len > 1) @intCast(usize, arguments[1].to(i32)) else @as(usize, 0);
- const value = @intToPtr(*align(1) u64, addr).*;
+ const value = @ptrFromInt(*align(1) u64, addr).*;
return JSValue.jsNumber(value);
}
pub fn @"i8"(
@@ -4354,7 +4403,7 @@ pub const FFI = struct {
arguments: []const JSValue,
) JSValue {
const addr = arguments[0].asPtrAddress() + if (arguments.len > 1) @intCast(usize, arguments[1].to(i32)) else @as(usize, 0);
- const value = @intToPtr(*align(1) i8, addr).*;
+ const value = @ptrFromInt(*align(1) i8, addr).*;
return JSValue.jsNumber(value);
}
pub fn @"i16"(
@@ -4363,7 +4412,7 @@ pub const FFI = struct {
arguments: []const JSValue,
) JSValue {
const addr = arguments[0].asPtrAddress() + if (arguments.len > 1) @intCast(usize, arguments[1].to(i32)) else @as(usize, 0);
- const value = @intToPtr(*align(1) i16, addr).*;
+ const value = @ptrFromInt(*align(1) i16, addr).*;
return JSValue.jsNumber(value);
}
pub fn @"i32"(
@@ -4372,7 +4421,7 @@ pub const FFI = struct {
arguments: []const JSValue,
) JSValue {
const addr = arguments[0].asPtrAddress() + if (arguments.len > 1) @intCast(usize, arguments[1].to(i32)) else @as(usize, 0);
- const value = @intToPtr(*align(1) i32, addr).*;
+ const value = @ptrFromInt(*align(1) i32, addr).*;
return JSValue.jsNumber(value);
}
pub fn intptr(
@@ -4381,7 +4430,7 @@ pub const FFI = struct {
arguments: []const JSValue,
) JSValue {
const addr = arguments[0].asPtrAddress() + if (arguments.len > 1) @intCast(usize, arguments[1].to(i32)) else @as(usize, 0);
- const value = @intToPtr(*align(1) i64, addr).*;
+ const value = @ptrFromInt(*align(1) i64, addr).*;
return JSValue.jsNumber(value);
}
@@ -4391,7 +4440,7 @@ pub const FFI = struct {
arguments: []const JSValue,
) JSValue {
const addr = arguments[0].asPtrAddress() + if (arguments.len > 1) @intCast(usize, arguments[1].to(i32)) else @as(usize, 0);
- const value = @intToPtr(*align(1) f32, addr).*;
+ const value = @ptrFromInt(*align(1) f32, addr).*;
return JSValue.jsNumber(value);
}
@@ -4401,7 +4450,7 @@ pub const FFI = struct {
arguments: []const JSValue,
) JSValue {
const addr = arguments[0].asPtrAddress() + if (arguments.len > 1) @intCast(usize, arguments[1].to(i32)) else @as(usize, 0);
- const value = @intToPtr(*align(1) f64, addr).*;
+ const value = @ptrFromInt(*align(1) f64, addr).*;
return JSValue.jsNumber(value);
}
@@ -4411,7 +4460,7 @@ pub const FFI = struct {
arguments: []const JSValue,
) JSValue {
const addr = arguments[0].asPtrAddress() + if (arguments.len > 1) @intCast(usize, arguments[1].to(i32)) else @as(usize, 0);
- const value = @intToPtr(*align(1) i64, addr).*;
+ const value = @ptrFromInt(*align(1) i64, addr).*;
return JSValue.fromInt64NoTruncate(global, value);
}
@@ -4421,7 +4470,7 @@ pub const FFI = struct {
arguments: []const JSValue,
) JSValue {
const addr = arguments[0].asPtrAddress() + if (arguments.len > 1) @intCast(usize, arguments[1].to(i32)) else @as(usize, 0);
- const value = @intToPtr(*align(1) u64, addr).*;
+ const value = @ptrFromInt(*align(1) u64, addr).*;
return JSValue.fromUInt64NoTruncate(global, value);
}
@@ -4432,7 +4481,7 @@ pub const FFI = struct {
offset: i32,
) callconv(.C) JSValue {
const addr = @intCast(usize, raw_addr) + @intCast(usize, offset);
- const value = @intToPtr(*align(1) u8, addr).*;
+ const value = @ptrFromInt(*align(1) u8, addr).*;
return JSValue.jsNumber(value);
}
pub fn u16WithoutTypeChecks(
@@ -4442,7 +4491,7 @@ pub const FFI = struct {
offset: i32,
) callconv(.C) JSValue {
const addr = @intCast(usize, raw_addr) + @intCast(usize, offset);
- const value = @intToPtr(*align(1) u16, addr).*;
+ const value = @ptrFromInt(*align(1) u16, addr).*;
return JSValue.jsNumber(value);
}
pub fn u32WithoutTypeChecks(
@@ -4452,7 +4501,7 @@ pub const FFI = struct {
offset: i32,
) callconv(.C) JSValue {
const addr = @intCast(usize, raw_addr) + @intCast(usize, offset);
- const value = @intToPtr(*align(1) u32, addr).*;
+ const value = @ptrFromInt(*align(1) u32, addr).*;
return JSValue.jsNumber(value);
}
pub fn ptrWithoutTypeChecks(
@@ -4462,7 +4511,7 @@ pub const FFI = struct {
offset: i32,
) callconv(.C) JSValue {
const addr = @intCast(usize, raw_addr) + @intCast(usize, offset);
- const value = @intToPtr(*align(1) u64, addr).*;
+ const value = @ptrFromInt(*align(1) u64, addr).*;
return JSValue.jsNumber(value);
}
pub fn i8WithoutTypeChecks(
@@ -4472,7 +4521,7 @@ pub const FFI = struct {
offset: i32,
) callconv(.C) JSValue {
const addr = @intCast(usize, raw_addr) + @intCast(usize, offset);
- const value = @intToPtr(*align(1) i8, addr).*;
+ const value = @ptrFromInt(*align(1) i8, addr).*;
return JSValue.jsNumber(value);
}
pub fn i16WithoutTypeChecks(
@@ -4482,7 +4531,7 @@ pub const FFI = struct {
offset: i32,
) callconv(.C) JSValue {
const addr = @intCast(usize, raw_addr) + @intCast(usize, offset);
- const value = @intToPtr(*align(1) i16, addr).*;
+ const value = @ptrFromInt(*align(1) i16, addr).*;
return JSValue.jsNumber(value);
}
pub fn i32WithoutTypeChecks(
@@ -4492,7 +4541,7 @@ pub const FFI = struct {
offset: i32,
) callconv(.C) JSValue {
const addr = @intCast(usize, raw_addr) + @intCast(usize, offset);
- const value = @intToPtr(*align(1) i32, addr).*;
+ const value = @ptrFromInt(*align(1) i32, addr).*;
return JSValue.jsNumber(value);
}
pub fn intptrWithoutTypeChecks(
@@ -4502,7 +4551,7 @@ pub const FFI = struct {
offset: i32,
) callconv(.C) JSValue {
const addr = @intCast(usize, raw_addr) + @intCast(usize, offset);
- const value = @intToPtr(*align(1) i64, addr).*;
+ const value = @ptrFromInt(*align(1) i64, addr).*;
return JSValue.jsNumber(value);
}
@@ -4513,7 +4562,7 @@ pub const FFI = struct {
offset: i32,
) callconv(.C) JSValue {
const addr = @intCast(usize, raw_addr) + @intCast(usize, offset);
- const value = @intToPtr(*align(1) f32, addr).*;
+ const value = @ptrFromInt(*align(1) f32, addr).*;
return JSValue.jsNumber(value);
}
@@ -4524,7 +4573,7 @@ pub const FFI = struct {
offset: i32,
) callconv(.C) JSValue {
const addr = @intCast(usize, raw_addr) + @intCast(usize, offset);
- const value = @intToPtr(*align(1) f64, addr).*;
+ const value = @ptrFromInt(*align(1) f64, addr).*;
return JSValue.jsNumber(value);
}
@@ -4535,7 +4584,7 @@ pub const FFI = struct {
offset: i32,
) callconv(.C) JSValue {
const addr = @intCast(usize, raw_addr) + @intCast(usize, offset);
- const value = @intToPtr(*align(1) u64, addr).*;
+ const value = @ptrFromInt(*align(1) u64, addr).*;
return JSValue.fromUInt64NoTruncate(global, value);
}
@@ -4546,7 +4595,7 @@ pub const FFI = struct {
offset: i32,
) callconv(.C) JSValue {
const addr = @intCast(usize, raw_addr) + @intCast(usize, offset);
- const value = @intToPtr(*align(1) i64, addr).*;
+ const value = @ptrFromInt(*align(1) i64, addr).*;
return JSValue.fromInt64NoTruncate(global, value);
}
@@ -4590,7 +4639,7 @@ pub const FFI = struct {
_: *anyopaque,
array: *JSC.JSUint8Array,
) callconv(.C) JSValue {
- return JSValue.fromPtrAddress(@ptrToInt(array.ptr()));
+ return JSValue.fromPtrAddress(@intFromPtr(array.ptr()));
}
fn ptr_(
@@ -4610,9 +4659,9 @@ pub const FFI = struct {
return JSC.toInvalidArguments("ArrayBufferView must have a length > 0. A pointer to empty memory doesn't work", .{}, globalThis);
}
- var addr: usize = @ptrToInt(array_buffer.ptr);
+ var addr: usize = @intFromPtr(array_buffer.ptr);
// const Sizes = @import("../bindings/sizes.zig");
- // std.debug.assert(addr == @ptrToInt(value.asEncoded().ptr) + Sizes.Bun_FFI_PointerOffsetToTypedArrayVector);
+ // std.debug.assert(addr == @intFromPtr(value.asEncoded().ptr) + Sizes.Bun_FFI_PointerOffsetToTypedArrayVector);
if (byteOffset) |off| {
if (!off.isEmptyOrUndefinedOrNull()) {
@@ -4628,7 +4677,7 @@ pub const FFI = struct {
addr += @intCast(usize, bytei64);
}
- if (addr > @ptrToInt(array_buffer.ptr) + @as(usize, array_buffer.byte_len)) {
+ if (addr > @intFromPtr(array_buffer.ptr) + @as(usize, array_buffer.byte_len)) {
return JSC.toInvalidArguments("byteOffset out of bounds", .{}, globalThis);
}
}
@@ -4720,11 +4769,11 @@ pub const FFI = struct {
}
const length = @intCast(usize, length_i);
- return .{ .slice = @intToPtr([*]u8, addr)[0..length] };
+ return .{ .slice = @ptrFromInt([*]u8, addr)[0..length] };
}
}
- return .{ .slice = bun.span(@intToPtr([*:0]u8, addr)) };
+ return .{ .slice = bun.span(@ptrFromInt([*:0]u8, addr)) };
}
fn getCPtr(value: JSValue) ?usize {
@@ -4759,11 +4808,11 @@ pub const FFI = struct {
var ctx: ?*anyopaque = null;
if (finalizationCallback) |callback_value| {
if (getCPtr(callback_value)) |callback_ptr| {
- callback = @intToPtr(JSC.C.JSTypedArrayBytesDeallocator, callback_ptr);
+ callback = @ptrFromInt(JSC.C.JSTypedArrayBytesDeallocator, callback_ptr);
if (finalizationCtxOrPtr) |ctx_value| {
if (getCPtr(ctx_value)) |ctx_ptr| {
- ctx = @intToPtr(*anyopaque, ctx_ptr);
+ ctx = @ptrFromInt(*anyopaque, ctx_ptr);
} else if (!ctx_value.isUndefinedOrNull()) {
return JSC.toInvalidArguments("Expected user data to be a C pointer (number or BigInt)", .{}, globalThis);
}
@@ -4773,7 +4822,7 @@ pub const FFI = struct {
}
} else if (finalizationCtxOrPtr) |callback_value| {
if (getCPtr(callback_value)) |callback_ptr| {
- callback = @intToPtr(JSC.C.JSTypedArrayBytesDeallocator, callback_ptr);
+ callback = @ptrFromInt(JSC.C.JSTypedArrayBytesDeallocator, callback_ptr);
} else if (!callback_value.isEmptyOrUndefinedOrNull()) {
return JSC.toInvalidArguments("Expected callback to be a C pointer (number or BigInt)", .{}, globalThis);
}
@@ -4801,11 +4850,11 @@ pub const FFI = struct {
var ctx: ?*anyopaque = null;
if (finalizationCallback) |callback_value| {
if (getCPtr(callback_value)) |callback_ptr| {
- callback = @intToPtr(JSC.C.JSTypedArrayBytesDeallocator, callback_ptr);
+ callback = @ptrFromInt(JSC.C.JSTypedArrayBytesDeallocator, callback_ptr);
if (finalizationCtxOrPtr) |ctx_value| {
if (getCPtr(ctx_value)) |ctx_ptr| {
- ctx = @intToPtr(*anyopaque, ctx_ptr);
+ ctx = @ptrFromInt(*anyopaque, ctx_ptr);
} else if (!ctx_value.isEmptyOrUndefinedOrNull()) {
return JSC.toInvalidArguments("Expected user data to be a C pointer (number or BigInt)", .{}, globalThis);
}
@@ -4815,7 +4864,7 @@ pub const FFI = struct {
}
} else if (finalizationCtxOrPtr) |callback_value| {
if (getCPtr(callback_value)) |callback_ptr| {
- callback = @intToPtr(JSC.C.JSTypedArrayBytesDeallocator, callback_ptr);
+ callback = @ptrFromInt(JSC.C.JSTypedArrayBytesDeallocator, callback_ptr);
} else if (!callback_value.isEmptyOrUndefinedOrNull()) {
return JSC.toInvalidArguments("Expected callback to be a C pointer (number or BigInt)", .{}, globalThis);
}
@@ -4935,11 +4984,11 @@ pub const EnvironmentVariables = struct {
pub fn getEnvNames(globalObject: *JSC.JSGlobalObject, names: []ZigString) usize {
var vm = globalObject.bunVM();
const keys = vm.bundler.env.map.map.keys();
- const max = @min(names.len, keys.len);
- for (keys[0..max], 0..) |key, i| {
- names[i] = ZigString.initUTF8(key);
+ const len = @min(names.len, keys.len);
+ for (keys[0..len], names[0..len]) |key, *name| {
+ name.* = ZigString.initUTF8(key);
}
- return keys.len;
+ return len;
}
pub fn getEnvValue(globalObject: *JSC.JSGlobalObject, name: ZigString) ?ZigString {
var vm = globalObject.bunVM();
diff --git a/src/bun.js/api/bun/dns_resolver.zig b/src/bun.js/api/bun/dns_resolver.zig
index aec295056..d0d4f5b7b 100644
--- a/src/bun.js/api/bun/dns_resolver.zig
+++ b/src/bun.js/api/bun/dns_resolver.zig
@@ -123,7 +123,7 @@ const LibInfo = struct {
this.vm.uws_event_loop.?,
.machport,
true,
- @ptrToInt(request.backend.libinfo.machport),
+ @intFromPtr(request.backend.libinfo.machport),
) == .result,
);
@@ -230,7 +230,7 @@ fn addrInfoCount(addrinfo: *std.c.addrinfo) u32 {
var count: u32 = 1;
var current: ?*std.c.addrinfo = addrinfo.next;
while (current != null) : (current = current.?.next) {
- count += @boolToInt(current.?.addr != null);
+ count += @intFromBool(current.?.addr != null);
}
return count;
}
@@ -285,7 +285,7 @@ pub const GetAddrInfo = struct {
pub fn toCAres(this: GetAddrInfo) bun.c_ares.AddrInfo_hints {
var hints: bun.c_ares.AddrInfo_hints = undefined;
- @memset(std.mem.asBytes(&hints), 0, @sizeOf(bun.c_ares.AddrInfo_hints));
+ @memset(std.mem.asBytes(&hints)[0..@sizeOf(bun.c_ares.AddrInfo_hints)], 0);
hints.ai_family = this.options.family.toLibC();
hints.ai_socktype = this.options.socktype.toLibC();
@@ -320,7 +320,7 @@ pub const GetAddrInfo = struct {
}
var hints: std.c.addrinfo = undefined;
- @memset(std.mem.asBytes(&hints), 0, @sizeOf(std.c.addrinfo));
+ @memset(std.mem.asBytes(&hints)[0..@sizeOf(std.c.addrinfo)], 0);
hints.family = this.family.toLibC();
hints.socktype = this.socktype.toLibC();
@@ -793,7 +793,7 @@ pub const GetAddrInfoRequest = struct {
addr_info: ?*std.c.addrinfo,
arg: ?*anyopaque,
) callconv(.C) void {
- const this = @intToPtr(*GetAddrInfoRequest, @ptrToInt(arg));
+ const this = @ptrFromInt(*GetAddrInfoRequest, @intFromPtr(arg));
log("getAddrInfoAsyncCallback: status={d}", .{status});
if (this.backend == .libinfo) {
@@ -846,8 +846,8 @@ pub const GetAddrInfoRequest = struct {
err,
debug_timer,
});
- if (@enumToInt(err) != 0 or addrinfo == null) {
- this.* = .{ .err = @enumToInt(err) };
+ if (@intFromEnum(err) != 0 or addrinfo == null) {
+ this.* = .{ .err = @intFromEnum(err) };
return;
}
@@ -1925,8 +1925,8 @@ pub const DNSResolver = struct {
.err => |err| {
const system_error = JSC.SystemError{
.errno = -1,
- .code = JSC.ZigString.init(err.code()),
- .message = JSC.ZigString.init(err.label()),
+ .code = bun.String.static(err.code()),
+ .message = bun.String.static(err.label()),
};
globalThis.throwValue(system_error.toErrorInstance(globalThis));
@@ -1972,8 +1972,8 @@ pub const DNSResolver = struct {
.err => |err| {
const system_error = JSC.SystemError{
.errno = -1,
- .code = JSC.ZigString.init(err.code()),
- .message = JSC.ZigString.init(err.label()),
+ .code = bun.String.static(err.code()),
+ .message = bun.String.static(err.label()),
};
globalThis.throwValue(system_error.toErrorInstance(globalThis));
diff --git a/src/bun.js/api/bun/socket.zig b/src/bun.js/api/bun/socket.zig
index 48bfe4218..1d85c705c 100644
--- a/src/bun.js/api/bun/socket.zig
+++ b/src/bun.js/api/bun/socket.zig
@@ -69,6 +69,11 @@ fn normalizeHost(input: anytype) @TypeOf(input) {
const BinaryType = JSC.BinaryType;
+const WrappedType = enum {
+ none,
+ tls,
+ tcp,
+};
const Handlers = struct {
onOpen: JSC.JSValue = .zero,
onClose: JSC.JSValue = .zero,
@@ -97,8 +102,8 @@ const Handlers = struct {
handlers: *Handlers,
socket_context: *uws.SocketContext,
- pub fn exit(this: *Scope, ssl: bool) void {
- this.handlers.markInactive(ssl, this.socket_context);
+ pub fn exit(this: *Scope, ssl: bool, wrapped: WrappedType) void {
+ this.handlers.markInactive(ssl, this.socket_context, wrapped);
}
};
@@ -123,19 +128,24 @@ const Handlers = struct {
return true;
}
- pub fn markInactive(this: *Handlers, ssl: bool, ctx: *uws.SocketContext) void {
+ pub fn markInactive(this: *Handlers, ssl: bool, ctx: *uws.SocketContext, wrapped: WrappedType) void {
Listener.log("markInactive", .{});
this.active_connections -= 1;
- if (this.active_connections == 0 and this.is_server) {
- var listen_socket: *Listener = @fieldParentPtr(Listener, "handlers", this);
- // allow it to be GC'd once the last connection is closed and it's not listening anymore
- if (listen_socket.listener == null) {
- listen_socket.strong_self.clear();
+ if (this.active_connections == 0) {
+ if (this.is_server) {
+ var listen_socket: *Listener = @fieldParentPtr(Listener, "handlers", this);
+ // allow it to be GC'd once the last connection is closed and it's not listening anymore
+ if (listen_socket.listener == null) {
+ listen_socket.strong_self.clear();
+ }
+ } else {
+ this.unprotect();
+ // will deinit when is not wrapped or when is the TCP wrapped connection
+ if (wrapped != .tls) {
+ ctx.deinit(ssl);
+ }
+ bun.default_allocator.destroy(this);
}
- } else if (this.active_connections == 0 and !this.is_server) {
- this.unprotect();
- ctx.deinit(ssl);
- bun.default_allocator.destroy(this);
}
}
@@ -364,6 +374,7 @@ pub const Listener = struct {
connection: UnixOrHost,
socket_context: ?*uws.SocketContext = null,
ssl: bool = false,
+ protos: ?[]const u8 = null,
strong_data: JSC.Strong = .{},
strong_self: JSC.Strong = .{},
@@ -395,13 +406,26 @@ pub const Listener = struct {
port: u16,
},
+ pub fn clone(this: UnixOrHost) UnixOrHost {
+ switch (this) {
+ .unix => |u| {
+ return .{
+ .unix = (bun.default_allocator.dupe(u8, u) catch unreachable),
+ };
+ },
+ .host => |h| {
+ return .{ .host = .{ .host = (bun.default_allocator.dupe(u8, h.host) catch unreachable), .port = this.host.port } };
+ },
+ }
+ }
+
pub fn deinit(this: UnixOrHost) void {
switch (this) {
.unix => |u| {
- bun.default_allocator.destroy(@intToPtr([*]u8, @ptrToInt(u.ptr)));
+ bun.default_allocator.destroy(@ptrFromInt([*]u8, @intFromPtr(u.ptr)));
},
.host => |h| {
- bun.default_allocator.destroy(@intToPtr([*]u8, @ptrToInt(h.host.ptr)));
+ bun.default_allocator.destroy(@ptrFromInt([*]u8, @intFromPtr(h.host.ptr)));
},
}
}
@@ -455,10 +479,12 @@ pub const Listener = struct {
var socket_config = SocketConfig.fromJS(opts, globalObject, exception) orelse {
return .zero;
};
+
var hostname_or_unix = socket_config.hostname_or_unix;
var port = socket_config.port;
var ssl = socket_config.ssl;
var handlers = socket_config.handlers;
+ var protos: ?[]const u8 = null;
const exclusive = socket_config.exclusive;
handlers.is_server = true;
@@ -472,7 +498,7 @@ pub const Listener = struct {
globalObject.bunVM().eventLoop().ensureWaker();
var socket_context = uws.us_create_bun_socket_context(
- @boolToInt(ssl_enabled),
+ @intFromBool(ssl_enabled),
uws.Loop.get().?,
@sizeOf(usize),
ctx_opts,
@@ -483,7 +509,7 @@ pub const Listener = struct {
hostname_or_unix.deinit();
}
- const errno = @enumToInt(std.c.getErrno(-1));
+ const errno = @intFromEnum(std.c.getErrno(-1));
if (errno != 0) {
err.put(globalObject, ZigString.static("errno"), JSValue.jsNumber(errno));
if (bun.C.SystemErrno.init(errno)) |str| {
@@ -496,6 +522,10 @@ pub const Listener = struct {
};
if (ssl_enabled) {
+ if (ssl.?.protos) |p| {
+ protos = p[0..ssl.?.protos_len];
+ }
+
uws.NewSocketHandler(true).configure(
socket_context,
true,
@@ -544,7 +574,7 @@ pub const Listener = struct {
defer bun.default_allocator.free(host);
const socket = uws.us_socket_context_listen(
- @boolToInt(ssl_enabled),
+ @intFromBool(ssl_enabled),
socket_context,
normalizeHost(@as([:0]const u8, host)),
c.port,
@@ -560,13 +590,13 @@ pub const Listener = struct {
.unix => |u| {
var host = bun.default_allocator.dupeZ(u8, u) catch unreachable;
defer bun.default_allocator.free(host);
- break :brk uws.us_socket_context_listen_unix(@boolToInt(ssl_enabled), socket_context, host, socket_flags, 8);
+ break :brk uws.us_socket_context_listen_unix(@intFromBool(ssl_enabled), socket_context, host, socket_flags, 8);
},
}
} orelse {
defer {
hostname_or_unix.deinit();
- uws.us_socket_context_free(@boolToInt(ssl_enabled), socket_context);
+ uws.us_socket_context_free(@intFromBool(ssl_enabled), socket_context);
}
const err = globalObject.createErrorInstance(
@@ -575,7 +605,7 @@ pub const Listener = struct {
bun.span(hostname_or_unix.slice()),
},
);
- const errno = @enumToInt(std.c.getErrno(-1));
+ const errno = @intFromEnum(std.c.getErrno(-1));
if (errno != 0) {
err.put(globalObject, ZigString.static("errno"), JSValue.jsNumber(errno));
if (bun.C.SystemErrno.init(errno)) |str| {
@@ -593,6 +623,7 @@ pub const Listener = struct {
.ssl = ssl_enabled,
.socket_context = socket_context,
.listener = listen_socket,
+ .protos = if (protos) |p| (bun.default_allocator.dupe(u8, p) catch unreachable) else null,
};
socket.handlers.protect();
@@ -649,6 +680,8 @@ pub const Listener = struct {
.handlers = &listener.handlers,
.this_value = .zero,
.socket = socket,
+ .protos = listener.protos,
+ .owned_protos = false,
};
if (listener.strong_data.get()) |default_data| {
const globalObject = listener.handlers.globalObject;
@@ -715,6 +748,10 @@ pub const Listener = struct {
this.handlers.unprotect();
this.connection.deinit();
+ if (this.protos) |protos| {
+ this.protos = null;
+ bun.default_allocator.destroy(protos);
+ }
bun.default_allocator.destroy(this);
}
@@ -775,13 +812,17 @@ pub const Listener = struct {
const socket_config = SocketConfig.fromJS(opts, globalObject, exception) orelse {
return .zero;
};
+
var hostname_or_unix = socket_config.hostname_or_unix;
var port = socket_config.port;
var ssl = socket_config.ssl;
var handlers = socket_config.handlers;
var default_data = socket_config.default_data;
+ var protos: ?[]const u8 = null;
+ var server_name: ?[]const u8 = null;
const ssl_enabled = ssl != null;
+ defer if (ssl != null) ssl.?.deinit();
handlers.protect();
@@ -789,7 +830,7 @@ pub const Listener = struct {
globalObject.bunVM().eventLoop().ensureWaker();
- var socket_context = uws.us_create_bun_socket_context(@boolToInt(ssl_enabled), uws.Loop.get().?, @sizeOf(usize), ctx_opts).?;
+ var socket_context = uws.us_create_bun_socket_context(@intFromBool(ssl_enabled), uws.Loop.get().?, @sizeOf(usize), ctx_opts).?;
var connection: Listener.UnixOrHost = if (port) |port_| .{
.host = .{ .host = (hostname_or_unix.cloneIfNeeded(bun.default_allocator) catch unreachable).slice(), .port = port_ },
} else .{
@@ -797,6 +838,12 @@ pub const Listener = struct {
};
if (ssl_enabled) {
+ if (ssl.?.protos) |p| {
+ protos = p[0..ssl.?.protos_len];
+ }
+ if (ssl.?.server_name) |s| {
+ server_name = bun.default_allocator.dupe(u8, s[0..bun.len(s)]) catch unreachable;
+ }
uws.NewSocketHandler(true).configure(
socket_context,
true,
@@ -848,6 +895,8 @@ pub const Listener = struct {
.this_value = .zero,
.socket = undefined,
.connection = connection,
+ .protos = if (protos) |p| (bun.default_allocator.dupe(u8, p) catch unreachable) else null,
+ .server_name = server_name,
};
TLSSocket.dataSetCached(tls.getThisValue(globalObject), globalObject, default_data);
@@ -871,6 +920,8 @@ pub const Listener = struct {
.this_value = .zero,
.socket = undefined,
.connection = null,
+ .protos = null,
+ .server_name = null,
};
TCPSocket.dataSetCached(tcp.getThisValue(globalObject), globalObject, default_data);
@@ -898,11 +949,41 @@ fn JSSocketType(comptime ssl: bool) type {
}
}
+fn selectALPNCallback(
+ _: ?*BoringSSL.SSL,
+ out: [*c][*c]const u8,
+ outlen: [*c]u8,
+ in: [*c]const u8,
+ inlen: c_uint,
+ arg: ?*anyopaque,
+) callconv(.C) c_int {
+ const this = bun.cast(*TLSSocket, arg);
+ if (this.protos) |protos| {
+ if (protos.len == 0) {
+ return BoringSSL.SSL_TLSEXT_ERR_NOACK;
+ }
+
+ const status = BoringSSL.SSL_select_next_proto(bun.cast([*c][*c]u8, out), outlen, protos.ptr, @intCast(c_uint, protos.len), in, inlen);
+
+ // Previous versions of Node.js returned SSL_TLSEXT_ERR_NOACK if no protocol
+ // match was found. This would neither cause a fatal alert nor would it result
+ // in a useful ALPN response as part of the Server Hello message.
+ // We now return SSL_TLSEXT_ERR_ALERT_FATAL in that case as per Section 3.2
+ // of RFC 7301, which causes a fatal no_application_protocol alert.
+ const expected = if (comptime BoringSSL.OPENSSL_NPN_NEGOTIATED == 1) BoringSSL.SSL_TLSEXT_ERR_OK else BoringSSL.SSL_TLSEXT_ERR_ALERT_FATAL;
+
+ return if (status == expected) 1 else 0;
+ } else {
+ return BoringSSL.SSL_TLSEXT_ERR_NOACK;
+ }
+}
+
fn NewSocket(comptime ssl: bool) type {
return struct {
pub const Socket = uws.NewSocketHandler(ssl);
socket: Socket,
detached: bool = false,
+ wrapped: WrappedType = .none,
handlers: *Handlers,
this_value: JSC.JSValue = .zero,
poll_ref: JSC.PollRef = JSC.PollRef.init(),
@@ -910,6 +991,9 @@ fn NewSocket(comptime ssl: bool) type {
last_4: [4]u8 = .{ 0, 0, 0, 0 },
authorized: bool = false,
connection: ?Listener.UnixOrHost = null,
+ protos: ?[]const u8,
+ owned_protos: bool = true,
+ server_name: ?[]const u8 = null,
// TODO: switch to something that uses `visitAggregate` and have the
// `Listener` keep a list of all the sockets JSValue in there
@@ -1022,8 +1106,8 @@ fn NewSocket(comptime ssl: bool) type {
var globalObject = handlers.globalObject;
const err = JSC.SystemError{
.errno = errno,
- .message = ZigString.init("Failed to connect"),
- .syscall = ZigString.init("connect"),
+ .message = bun.String.static("Failed to connect"),
+ .syscall = bun.String.static("connect"),
};
if (callback == .zero) {
@@ -1079,7 +1163,7 @@ fn NewSocket(comptime ssl: bool) type {
var vm = this.handlers.vm;
this.reffer.unref(vm);
- this.handlers.markInactive(ssl, this.socket.context());
+ this.handlers.markInactive(ssl, this.socket.context(), this.wrapped);
this.poll_ref.unref(vm);
this.has_pending_activity.store(false, .Release);
}
@@ -1091,25 +1175,42 @@ fn NewSocket(comptime ssl: bool) type {
// Add SNI support for TLS (mongodb and others requires this)
if (comptime ssl) {
- if (this.connection) |connection| {
- if (connection == .host) {
- const host = normalizeHost(connection.host.host);
+ var ssl_ptr: *BoringSSL.SSL = @ptrCast(*BoringSSL.SSL, socket.getNativeHandle());
+ if (!ssl_ptr.isInitFinished()) {
+ if (this.server_name) |server_name| {
+ const host = normalizeHost(server_name);
if (host.len > 0) {
- var ssl_ptr: *BoringSSL.SSL = @ptrCast(*BoringSSL.SSL, socket.getNativeHandle());
- if (!ssl_ptr.isInitFinished()) {
+ var host__ = default_allocator.dupeZ(u8, host) catch unreachable;
+ defer default_allocator.free(host__);
+ ssl_ptr.setHostname(host__);
+ }
+ } else if (this.connection) |connection| {
+ if (connection == .host) {
+ const host = normalizeHost(connection.host.host);
+ if (host.len > 0) {
var host__ = default_allocator.dupeZ(u8, host) catch unreachable;
defer default_allocator.free(host__);
ssl_ptr.setHostname(host__);
}
}
}
+ if (this.protos) |protos| {
+ if (this.handlers.is_server) {
+ BoringSSL.SSL_CTX_set_alpn_select_cb(BoringSSL.SSL_get_SSL_CTX(ssl_ptr), selectALPNCallback, bun.cast(*anyopaque, this));
+ } else {
+ _ = BoringSSL.SSL_set_alpn_protos(ssl_ptr, protos.ptr, @intCast(c_uint, protos.len));
+ }
+ }
}
}
this.poll_ref.ref(this.handlers.vm);
this.detached = false;
this.socket = socket;
- socket.ext(**anyopaque).?.* = bun.cast(**anyopaque, this);
+
+ if (this.wrapped == .none) {
+ socket.ext(**anyopaque).?.* = bun.cast(**anyopaque, this);
+ }
const handlers = this.handlers;
const callback = handlers.onOpen;
@@ -1161,6 +1262,8 @@ fn NewSocket(comptime ssl: bool) type {
pub fn onEnd(this: *This, socket: Socket) void {
JSC.markBinding(@src());
log("onEnd", .{});
+ if (this.detached) return;
+
this.detached = true;
defer this.markInactive();
@@ -1174,7 +1277,7 @@ fn NewSocket(comptime ssl: bool) type {
// the handlers must be kept alive for the duration of the function call
// that way if we need to call the error handler, we can
var scope = handlers.enter(socket.context());
- defer scope.exit(ssl);
+ defer scope.exit(ssl, this.wrapped);
const globalObject = handlers.globalObject;
const this_value = this.getThisValue(globalObject);
@@ -1211,7 +1314,7 @@ fn NewSocket(comptime ssl: bool) type {
// the handlers must be kept alive for the duration of the function call
// that way if we need to call the error handler, we can
var scope = handlers.enter(socket.context());
- defer scope.exit(ssl);
+ defer scope.exit(ssl, this.wrapped);
const globalObject = handlers.globalObject;
const this_value = this.getThisValue(globalObject);
@@ -1232,8 +1335,8 @@ fn NewSocket(comptime ssl: bool) type {
const reason = if (ssl_error.reason == null) "" else ssl_error.reason[0..bun.len(ssl_error.reason)];
const fallback = JSC.SystemError{
- .code = ZigString.init(code),
- .message = ZigString.init(reason),
+ .code = bun.String.create(code),
+ .message = bun.String.create(reason),
};
authorization_error = fallback.toErrorInstance(globalObject);
@@ -1255,7 +1358,6 @@ fn NewSocket(comptime ssl: bool) type {
log("onClose", .{});
this.detached = true;
defer this.markInactive();
-
const handlers = this.handlers;
this.poll_ref.unref(handlers.vm);
@@ -1265,7 +1367,7 @@ fn NewSocket(comptime ssl: bool) type {
// the handlers must be kept alive for the duration of the function call
// that way if we need to call the error handler, we can
var scope = handlers.enter(socket.context());
- defer scope.exit(ssl);
+ defer scope.exit(ssl, this.wrapped);
var globalObject = handlers.globalObject;
const this_value = this.getThisValue(globalObject);
@@ -1295,7 +1397,7 @@ fn NewSocket(comptime ssl: bool) type {
// the handlers must be kept alive for the duration of the function call
// that way if we need to call the error handler, we can
var scope = handlers.enter(socket.context());
- defer scope.exit(ssl);
+ defer scope.exit(ssl, this.wrapped);
// const encoding = handlers.encoding;
const result = callback.callWithThis(globalObject, this_value, &[_]JSValue{
@@ -1409,8 +1511,8 @@ fn NewSocket(comptime ssl: bool) type {
const reason = if (ssl_error.reason == null) "" else ssl_error.reason[0..bun.len(ssl_error.reason)];
const fallback = JSC.SystemError{
- .code = ZigString.init(code),
- .message = ZigString.init(reason),
+ .code = bun.String.create(code),
+ .message = bun.String.create(reason),
};
return fallback.toErrorInstance(globalObject);
@@ -1476,10 +1578,20 @@ fn NewSocket(comptime ssl: bool) type {
}
fn writeMaybeCorked(this: *This, buffer: []const u8, is_end: bool) i32 {
- if (this.socket.isShutdown() or this.socket.isClosed()) {
+ if (this.detached or this.socket.isShutdown() or this.socket.isClosed()) {
return -1;
}
// we don't cork yet but we might later
+
+ if (comptime ssl) {
+ // TLS wrapped but in TCP mode
+ if (this.wrapped == .tcp) {
+ const res = this.socket.rawWrite(buffer, is_end);
+ log("write({d}, {any}) = {d}", .{ buffer.len, is_end, res });
+ return res;
+ }
+ }
+
const res = this.socket.write(buffer, is_end);
log("write({d}, {any}) = {d}", .{ buffer.len, is_end, res });
return res;
@@ -1487,7 +1599,6 @@ fn NewSocket(comptime ssl: bool) type {
fn writeOrEnd(this: *This, globalObject: *JSC.JSGlobalObject, args: []const JSC.JSValue, is_end: bool) WriteResult {
if (args.len == 0) return .{ .success = .{} };
-
if (args.ptr[0].asArrayBuffer(globalObject)) |array_buffer| {
var slice = array_buffer.slice();
@@ -1681,9 +1792,6 @@ fn NewSocket(comptime ssl: bool) type {
if (result.wrote == result.total) {
this.socket.flush();
this.detached = true;
- if (!this.socket.isClosed()) {
- this.socket.close(0, null);
- }
this.markInactive();
}
break :brk JSValue.jsNumber(result.wrote);
@@ -1706,17 +1814,32 @@ fn NewSocket(comptime ssl: bool) type {
pub fn finalize(this: *This) callconv(.C) void {
log("finalize()", .{});
- if (this.detached) return;
- this.detached = true;
- if (!this.socket.isClosed()) {
- this.socket.close(0, null);
+ if (!this.detached) {
+ this.detached = true;
+ if (!this.socket.isClosed()) {
+ this.socket.close(0, null);
+ }
+ this.markInactive();
}
+
+ this.poll_ref.unref(JSC.VirtualMachine.get());
+ // need to deinit event without being attached
+ if (this.owned_protos) {
+ if (this.protos) |protos| {
+ this.protos = null;
+ default_allocator.free(protos);
+ }
+ }
+
+ if (this.server_name) |server_name| {
+ this.server_name = null;
+ default_allocator.free(server_name);
+ }
+
if (this.connection) |connection| {
- connection.deinit();
this.connection = null;
+ connection.deinit();
}
- this.markInactive();
- this.poll_ref.unref(JSC.VirtualMachine.get());
}
pub fn reload(this: *This, globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSValue {
@@ -1756,8 +1879,384 @@ fn NewSocket(comptime ssl: bool) type {
return JSValue.jsUndefined();
}
+
+ pub fn getALPNProtocol(
+ this: *This,
+ globalObject: *JSC.JSGlobalObject,
+ ) callconv(.C) JSValue {
+ if (comptime ssl == false) {
+ return JSValue.jsBoolean(false);
+ }
+
+ if (this.detached) {
+ return JSValue.jsBoolean(false);
+ }
+
+ var alpn_proto: [*c]const u8 = null;
+ var alpn_proto_len: u32 = 0;
+
+ var ssl_ptr: *BoringSSL.SSL = @ptrCast(*BoringSSL.SSL, this.socket.getNativeHandle());
+ BoringSSL.SSL_get0_alpn_selected(ssl_ptr, &alpn_proto, &alpn_proto_len);
+ if (alpn_proto == null or alpn_proto_len == 0) {
+ return JSValue.jsBoolean(false);
+ }
+
+ const slice = alpn_proto[0..alpn_proto_len];
+ if (strings.eql(slice, "h2")) {
+ return ZigString.static("h2").toValue(globalObject);
+ }
+ if (strings.eql(slice, "http/1.1")) {
+ return ZigString.static("http/1.1").toValue(globalObject);
+ }
+ return ZigString.fromUTF8(slice).toValueGC(globalObject);
+ }
+
+ pub fn setServername(
+ this: *This,
+ globalObject: *JSC.JSGlobalObject,
+ callframe: *JSC.CallFrame,
+ ) callconv(.C) JSValue {
+ if (comptime ssl == false) {
+ return JSValue.jsUndefined();
+ }
+
+ if (this.handlers.is_server) {
+ globalObject.throw("Cannot issue SNI from a TLS server-side socket", .{});
+ return .zero;
+ }
+
+ const args = callframe.arguments(1);
+ if (args.len < 1) {
+ globalObject.throw("Expected 1 argument", .{});
+ return .zero;
+ }
+
+ const server_name = args.ptr[0];
+ if (!server_name.isString()) {
+ globalObject.throw("Expected \"serverName\" to be a string", .{});
+ return .zero;
+ }
+
+ const slice = server_name.getZigString(globalObject).toOwnedSlice(bun.default_allocator) catch unreachable;
+ if (this.server_name) |old| {
+ this.server_name = slice;
+ default_allocator.free(old);
+ } else {
+ this.server_name = slice;
+ }
+
+ if (this.detached) {
+ // will be attached onOpen
+ return JSValue.jsUndefined();
+ }
+
+ const host = normalizeHost(@as([]const u8, slice));
+ if (host.len > 0) {
+ var ssl_ptr: *BoringSSL.SSL = @ptrCast(*BoringSSL.SSL, this.socket.getNativeHandle());
+ if (ssl_ptr.isInitFinished()) {
+ // match node.js exceptions
+ globalObject.throw("Already started.", .{});
+ return .zero;
+ }
+ var host__ = default_allocator.dupeZ(u8, host) catch unreachable;
+ defer default_allocator.free(host__);
+ ssl_ptr.setHostname(host__);
+ }
+
+ return JSValue.jsUndefined();
+ }
+
+ // this invalidates the current socket returning 2 new sockets
+ // one for non-TLS and another for TLS
+ // handlers for non-TLS are preserved
+ pub fn upgradeTLS(
+ this: *This,
+ globalObject: *JSC.JSGlobalObject,
+ callframe: *JSC.CallFrame,
+ ) callconv(.C) JSValue {
+ JSC.markBinding(@src());
+ if (comptime ssl) {
+ return JSValue.jsUndefined();
+ }
+
+ if (this.detached) {
+ return JSValue.jsUndefined();
+ }
+
+ const args = callframe.arguments(1);
+
+ if (args.len < 1) {
+ globalObject.throw("Expected 1 arguments", .{});
+ return .zero;
+ }
+
+ var exception: JSC.C.JSValueRef = null;
+
+ const opts = args.ptr[0];
+ if (opts.isEmptyOrUndefinedOrNull() or opts.isBoolean() or !opts.isObject()) {
+ globalObject.throw("Expected options object", .{});
+ return .zero;
+ }
+
+ var socket_obj = opts.get(globalObject, "socket") orelse {
+ globalObject.throw("Expected \"socket\" option", .{});
+ return .zero;
+ };
+
+ var handlers = Handlers.fromJS(globalObject, socket_obj, &exception) orelse {
+ globalObject.throwValue(exception.?.value());
+ return .zero;
+ };
+
+ var ssl_opts: ?JSC.API.ServerConfig.SSLConfig = null;
+
+ if (opts.getTruthy(globalObject, "tls")) |tls| {
+ if (tls.isBoolean()) {
+ if (tls.toBoolean()) {
+ ssl_opts = JSC.API.ServerConfig.SSLConfig.zero;
+ }
+ } else {
+ if (JSC.API.ServerConfig.SSLConfig.inJS(globalObject, tls, &exception)) |ssl_config| {
+ ssl_opts = ssl_config;
+ } else if (exception != null) {
+ return .zero;
+ }
+ }
+ }
+
+ if (ssl_opts == null) {
+ globalObject.throw("Expected \"tls\" option", .{});
+ return .zero;
+ }
+
+ var default_data = JSValue.zero;
+ if (opts.getTruthy(globalObject, "data")) |default_data_value| {
+ default_data = default_data_value;
+ default_data.ensureStillAlive();
+ }
+
+ var socket_config = ssl_opts.?;
+ defer socket_config.deinit();
+ const options = socket_config.asUSockets();
+
+ const protos = socket_config.protos;
+ const protos_len = socket_config.protos_len;
+
+ const ext_size = @sizeOf(WrappedSocket);
+
+ const is_server = this.handlers.is_server;
+ var tls = handlers.vm.allocator.create(TLSSocket) catch @panic("OOM");
+ var handlers_ptr = handlers.vm.allocator.create(Handlers) catch @panic("OOM");
+ handlers_ptr.* = handlers;
+ handlers_ptr.is_server = is_server;
+ handlers_ptr.protect();
+
+ tls.* = .{
+ .handlers = handlers_ptr,
+ .this_value = .zero,
+ .socket = undefined,
+ .connection = if (this.connection) |c| c.clone() else null,
+ .wrapped = .tls,
+ .protos = if (protos) |p| (bun.default_allocator.dupe(u8, p[0..protos_len]) catch unreachable) else null,
+ .server_name = if (socket_config.server_name) |server_name| (bun.default_allocator.dupe(u8, server_name[0..bun.len(server_name)]) catch unreachable) else null,
+ };
+
+ var tls_js_value = tls.getThisValue(globalObject);
+ TLSSocket.dataSetCached(tls_js_value, globalObject, default_data);
+
+ const TCPHandler = NewWrappedHandler(false);
+
+ // reconfigure context to use the new wrapper handlers
+ Socket.unsafeConfigure(this.socket.context(), true, true, WrappedSocket, TCPHandler);
+ const old_context = this.socket.context();
+ const TLSHandler = NewWrappedHandler(true);
+ const new_socket = this.socket.wrapTLS(
+ options,
+ ext_size,
+ true,
+ WrappedSocket,
+ TLSHandler,
+ ) orelse {
+ handlers_ptr.unprotect();
+ handlers.vm.allocator.destroy(handlers_ptr);
+ bun.default_allocator.destroy(tls);
+ return JSValue.jsUndefined();
+ };
+
+ tls.socket = new_socket;
+
+ var raw = handlers.vm.allocator.create(TLSSocket) catch @panic("OOM");
+ var raw_handlers_ptr = handlers.vm.allocator.create(Handlers) catch @panic("OOM");
+ raw_handlers_ptr.* = .{
+ .vm = globalObject.bunVM(),
+ .globalObject = globalObject,
+ .onOpen = this.handlers.onOpen,
+ .onClose = this.handlers.onClose,
+ .onData = this.handlers.onData,
+ .onWritable = this.handlers.onWritable,
+ .onTimeout = this.handlers.onTimeout,
+ .onConnectError = this.handlers.onConnectError,
+ .onEnd = this.handlers.onEnd,
+ .onError = this.handlers.onError,
+ .onHandshake = this.handlers.onHandshake,
+ .binary_type = this.handlers.binary_type,
+ .is_server = is_server,
+ };
+ this.handlers.onOpen = .zero;
+ this.handlers.onClose = .zero;
+ this.handlers.onData = .zero;
+ this.handlers.onWritable = .zero;
+ this.handlers.onTimeout = .zero;
+ this.handlers.onConnectError = .zero;
+ this.handlers.onEnd = .zero;
+ this.handlers.onError = .zero;
+ this.handlers.onHandshake = .zero;
+ raw.* = .{
+ .handlers = raw_handlers_ptr,
+ .this_value = .zero,
+ .socket = new_socket,
+ .connection = if (this.connection) |c| c.clone() else null,
+ .wrapped = .tcp,
+ .protos = null,
+ };
+
+ var raw_js_value = raw.getThisValue(globalObject);
+ if (JSSocketType(ssl).dataGetCached(this.getThisValue(globalObject))) |raw_default_data| {
+ raw_default_data.ensureStillAlive();
+ TLSSocket.dataSetCached(raw_js_value, globalObject, raw_default_data);
+ }
+ // marks both as active
+ raw.markActive();
+ // this will keep tls alive until socket.open() is called to start TLS certificate and the handshake process
+ // open is not immediately called because we need to set bunSocketInternal
+ tls.markActive();
+
+ // mark both instances on socket data
+ new_socket.ext(WrappedSocket).?.* = .{ .tcp = raw, .tls = tls };
+
+ // start TLS handshake after we set ext
+ new_socket.startTLS(!this.handlers.is_server);
+
+ //detach and invalidate the old instance
+ this.detached = true;
+ if (this.reffer.has) {
+ var vm = this.handlers.vm;
+ this.reffer.unref(vm);
+ old_context.deinit(ssl);
+ bun.default_allocator.destroy(this.handlers);
+ this.poll_ref.unref(vm);
+ this.has_pending_activity.store(false, .Release);
+ }
+
+ const array = JSC.JSValue.createEmptyArray(globalObject, 2);
+ array.putIndex(globalObject, 0, raw_js_value);
+ array.putIndex(globalObject, 1, tls_js_value);
+ return array;
+ }
};
}
pub const TCPSocket = NewSocket(false);
pub const TLSSocket = NewSocket(true);
+
+pub const WrappedSocket = extern struct {
+ // both shares the same socket but one behaves as TLS and the other as TCP
+ tls: *TLSSocket,
+ tcp: *TLSSocket,
+};
+
+pub fn NewWrappedHandler(comptime tls: bool) type {
+ const Socket = uws.NewSocketHandler(true);
+ return struct {
+ pub fn onOpen(
+ this: WrappedSocket,
+ socket: Socket,
+ ) void {
+ // only TLS will call onOpen
+ if (comptime tls) {
+ TLSSocket.onOpen(this.tls, socket);
+ }
+ }
+
+ pub fn onEnd(
+ this: WrappedSocket,
+ socket: Socket,
+ ) void {
+ if (comptime tls) {
+ TLSSocket.onEnd(this.tls, socket);
+ } else {
+ TLSSocket.onEnd(this.tcp, socket);
+ }
+ }
+
+ pub fn onHandshake(
+ this: WrappedSocket,
+ socket: Socket,
+ success: i32,
+ ssl_error: uws.us_bun_verify_error_t,
+ ) void {
+ // only TLS will call onHandshake
+ if (comptime tls) {
+ TLSSocket.onHandshake(this.tls, socket, success, ssl_error);
+ }
+ }
+
+ pub fn onClose(
+ this: WrappedSocket,
+ socket: Socket,
+ err: c_int,
+ data: ?*anyopaque,
+ ) void {
+ if (comptime tls) {
+ TLSSocket.onClose(this.tls, socket, err, data);
+ } else {
+ TLSSocket.onClose(this.tcp, socket, err, data);
+ }
+ }
+
+ pub fn onData(
+ this: WrappedSocket,
+ socket: Socket,
+ data: []const u8,
+ ) void {
+ if (comptime tls) {
+ TLSSocket.onData(this.tls, socket, data);
+ } else {
+ TLSSocket.onData(this.tcp, socket, data);
+ }
+ }
+
+ pub fn onWritable(
+ this: WrappedSocket,
+ socket: Socket,
+ ) void {
+ if (comptime tls) {
+ TLSSocket.onWritable(this.tls, socket);
+ } else {
+ TLSSocket.onWritable(this.tcp, socket);
+ }
+ }
+ pub fn onTimeout(
+ this: WrappedSocket,
+ socket: Socket,
+ ) void {
+ if (comptime tls) {
+ TLSSocket.onTimeout(this.tls, socket);
+ } else {
+ TLSSocket.onTimeout(this.tcp, socket);
+ }
+ }
+
+ pub fn onConnectError(
+ this: WrappedSocket,
+ socket: Socket,
+ errno: c_int,
+ ) void {
+ if (comptime tls) {
+ TLSSocket.onConnectError(this.tls, socket, errno);
+ } else {
+ TLSSocket.onConnectError(this.tcp, socket, errno);
+ }
+ }
+ };
+}
diff --git a/src/bun.js/api/bun/subprocess.zig b/src/bun.js/api/bun/subprocess.zig
index 832afac78..ba813c463 100644
--- a/src/bun.js/api/bun/subprocess.zig
+++ b/src/bun.js/api/bun/subprocess.zig
@@ -1011,7 +1011,7 @@ pub const Subprocess = struct {
if (signal.name()) |name|
return JSC.ZigString.init(name).toValueGC(global)
else
- return JSC.JSValue.jsNumber(@enumToInt(signal));
+ return JSC.JSValue.jsNumber(@intFromEnum(signal));
}
return JSC.JSValue.jsNull();
@@ -1535,9 +1535,9 @@ pub const Subprocess = struct {
}
if (std.os.W.IFSIGNALED(result.status)) {
- this.signal_code = @intToEnum(SignalCode, @truncate(u8, std.os.W.TERMSIG(result.status)));
+ this.signal_code = @enumFromInt(SignalCode, @truncate(u8, std.os.W.TERMSIG(result.status)));
} else if (std.os.W.IFSTOPPED(result.status)) {
- this.signal_code = @intToEnum(SignalCode, @truncate(u8, std.os.W.STOPSIG(result.status)));
+ this.signal_code = @enumFromInt(SignalCode, @truncate(u8, std.os.W.STOPSIG(result.status)));
}
if (!this.hasExited()) {
diff --git a/src/bun.js/api/ffi.zig b/src/bun.js/api/ffi.zig
index fe2b50955..ba31b67ed 100644
--- a/src/bun.js/api/ffi.zig
+++ b/src/bun.js/api/ffi.zig
@@ -137,8 +137,8 @@ pub const FFI = struct {
globalThis,
ZigString.static("ptr"),
ZigString.static("ctx"),
- JSC.JSValue.fromPtrAddress(@ptrToInt(function_.step.compiled.ptr)),
- JSC.JSValue.fromPtrAddress(@ptrToInt(function_)),
+ JSC.JSValue.fromPtrAddress(@intFromPtr(function_.step.compiled.ptr)),
+ JSC.JSValue.fromPtrAddress(@intFromPtr(function_)),
);
},
}
@@ -311,9 +311,9 @@ pub const FFI = struct {
break :brk std.DynLib.open(backup_name) catch {
// Then, if that fails, report an error.
const system_error = JSC.SystemError{
- .code = ZigString.init(@tagName(JSC.Node.ErrorCode.ERR_DLOPEN_FAILED)),
- .message = ZigString.init("Failed to open library. This is usually caused by a missing library or an invalid library path."),
- .syscall = ZigString.init("dlopen"),
+ .code = bun.String.create(@tagName(JSC.Node.ErrorCode.ERR_DLOPEN_FAILED)),
+ .message = bun.String.create("Failed to open library. This is usually caused by a missing library or an invalid library path."),
+ .syscall = bun.String.create("dlopen"),
};
return system_error.toErrorInstance(global);
};
@@ -523,7 +523,7 @@ pub const FFI = struct {
const int = val.to(i32);
switch (int) {
0...ABIType.max => {
- abi_types.appendAssumeCapacity(@intToEnum(ABIType, int));
+ abi_types.appendAssumeCapacity(@enumFromInt(ABIType, int));
continue;
},
else => {
@@ -560,7 +560,7 @@ pub const FFI = struct {
const int = ret_value.toInt32();
switch (int) {
0...ABIType.max => {
- return_type = @intToEnum(ABIType, int);
+ return_type = @enumFromInt(ABIType, int);
break :brk;
},
else => {
@@ -594,11 +594,11 @@ pub const FFI = struct {
if (ptr.isNumber()) {
const num = ptr.asPtrAddress();
if (num > 0)
- function.symbol_from_dynamic_library = @intToPtr(*anyopaque, num);
+ function.symbol_from_dynamic_library = @ptrFromInt(*anyopaque, num);
} else {
const num = ptr.toUInt64NoTruncate();
if (num > 0) {
- function.symbol_from_dynamic_library = @intToPtr(*anyopaque, num);
+ function.symbol_from_dynamic_library = @ptrFromInt(*anyopaque, num);
}
}
}
@@ -866,7 +866,7 @@ pub const FFI = struct {
c: u8,
byte_count: usize,
) callconv(.C) void {
- @memset(dest, c, byte_count);
+ @memset(dest[0..byte_count], c);
}
noinline fn memcpy(
@@ -874,7 +874,7 @@ pub const FFI = struct {
noalias source: [*]const u8,
byte_count: usize,
) callconv(.C) void {
- @memcpy(dest, source, byte_count);
+ @memcpy(dest[0..byte_count], source[0..byte_count]);
}
pub fn define(state: *TCC.TCCState) void {
@@ -1205,7 +1205,7 @@ pub const FFI = struct {
writer: anytype,
) !void {
{
- const ptr = @ptrToInt(globalObject);
+ const ptr = @intFromPtr(globalObject);
const fmt = bun.fmt.hexIntUpper(ptr);
try writer.print("#define JS_GLOBAL_OBJECT (void*)0x{any}ULL\n", .{fmt});
}
@@ -1290,7 +1290,7 @@ pub const FFI = struct {
var inner_buf: []u8 = &.{};
{
- const ptr = @ptrToInt(context_ptr);
+ const ptr = @intFromPtr(context_ptr);
const fmt = bun.fmt.hexIntUpper(ptr);
if (this.arg_types.items.len > 0) {
@@ -1355,7 +1355,7 @@ pub const FFI = struct {
function = 17,
- pub const max = @enumToInt(ABIType.function);
+ pub const max = @intFromEnum(ABIType.function);
/// Types that we can directly pass through as an `int64_t`
pub fn needsACastInC(this: ABIType) bool {
@@ -1414,11 +1414,11 @@ pub const FFI = struct {
// these are not all valid identifiers
try writer.writeAll(self.name);
try writer.writeAll("']:");
- try std.fmt.formatInt(@enumToInt(self.entry), 10, .lower, .{}, writer);
+ try std.fmt.formatInt(@intFromEnum(self.entry), 10, .lower, .{}, writer);
try writer.writeAll(",'");
- try std.fmt.formatInt(@enumToInt(self.entry), 10, .lower, .{}, writer);
+ try std.fmt.formatInt(@intFromEnum(self.entry), 10, .lower, .{}, writer);
try writer.writeAll("':");
- try std.fmt.formatInt(@enumToInt(self.entry), 10, .lower, .{}, writer);
+ try std.fmt.formatInt(@intFromEnum(self.entry), 10, .lower, .{}, writer);
}
};
pub const map_to_js_object = brk: {
@@ -1426,7 +1426,7 @@ pub const FFI = struct {
for (map, 0..) |item, i| {
var fmt = EnumMapFormatter{ .name = item.@"0", .entry = item.@"1" };
count += std.fmt.count("{}", .{fmt});
- count += @boolToInt(i > 0);
+ count += @intFromBool(i > 0);
}
var buf: [count]u8 = undefined;
diff --git a/src/bun.js/api/html_rewriter.zig b/src/bun.js/api/html_rewriter.zig
index bfbdb9a37..b309e07d7 100644
--- a/src/bun.js/api/html_rewriter.zig
+++ b/src/bun.js/api/html_rewriter.zig
@@ -106,7 +106,7 @@ pub const HTMLRewriter = struct {
var selector = LOLHTML.HTMLSelector.parse(selector_slice) catch
return throwLOLHTMLError(global);
- var handler_ = ElementHandler.init(global, listener, exception);
+ var handler_ = ElementHandler.init(global, listener, exception) catch return .zero;
if (exception.* != null) {
selector.deinit();
return JSValue.fromRef(exception.*);
@@ -154,7 +154,7 @@ pub const HTMLRewriter = struct {
thisObject: JSC.C.JSObjectRef,
exception: JSC.C.ExceptionRef,
) JSValue {
- var handler_ = DocumentHandler.init(global, listener, exception);
+ var handler_ = DocumentHandler.init(global, listener, exception) catch return .zero;
if (exception.* != null) {
return JSValue.fromRef(exception.*);
}
@@ -446,10 +446,14 @@ pub const HTMLRewriter = struct {
},
};
- result.body.init.headers = original.body.init.headers;
result.body.init.method = original.body.init.method;
result.body.init.status_code = original.body.init.status_code;
+ // https://github.com/oven-sh/bun/issues/3334
+ if (original.body.init.headers) |headers| {
+ result.body.init.headers = headers.cloneThis(global);
+ }
+
result.url = bun.default_allocator.dupe(u8, original.url) catch unreachable;
result.status_text = bun.default_allocator.dupe(u8, original.status_text) catch unreachable;
@@ -472,13 +476,13 @@ pub const HTMLRewriter = struct {
pub fn onFinishedLoading(sink: *BufferOutputSink, bytes: JSC.WebCore.Blob.Store.ReadFile.ResultType) void {
switch (bytes) {
.err => |err| {
- if (sink.response.body.value == .Locked and @ptrToInt(sink.response.body.value.Locked.task) == @ptrToInt(sink) and
+ if (sink.response.body.value == .Locked and @intFromPtr(sink.response.body.value.Locked.task) == @intFromPtr(sink) and
sink.response.body.value.Locked.promise == null)
{
sink.response.body.value = .{ .Empty = {} };
// is there a pending promise?
// we will need to reject it
- } else if (sink.response.body.value == .Locked and @ptrToInt(sink.response.body.value.Locked.task) == @ptrToInt(sink) and
+ } else if (sink.response.body.value == .Locked and @intFromPtr(sink.response.body.value.Locked.task) == @intFromPtr(sink) and
sink.response.body.value.Locked.promise != null)
{
sink.response.body.value.Locked.onReceiveValue = null;
@@ -723,29 +727,44 @@ const DocumentHandler = struct {
"onEndCallback",
);
- pub fn init(global: *JSGlobalObject, thisObject: JSValue, exception: JSC.C.ExceptionRef) DocumentHandler {
+ pub fn init(global: *JSGlobalObject, thisObject: JSValue, exception: JSC.C.ExceptionRef) !DocumentHandler {
var handler = DocumentHandler{
.thisObject = thisObject,
.global = global,
};
- switch (thisObject.jsType()) {
- .Object, .ProxyObject, .Cell, .FinalObject => {},
- else => |kind| {
- JSC.throwInvalidArguments(
- "Expected object but received {s}",
- .{@as(string, @tagName(kind))},
- global,
- exception,
- );
- return undefined;
- },
+ if (!thisObject.isObject()) {
+ JSC.throwInvalidArguments(
+ "Expected object",
+ .{},
+ global,
+ exception,
+ );
+ return error.InvalidArguments;
+ }
+
+ errdefer {
+ if (handler.onDocTypeCallback) |cb| {
+ cb.unprotect();
+ }
+
+ if (handler.onCommentCallback) |cb| {
+ cb.unprotect();
+ }
+
+ if (handler.onTextCallback) |cb| {
+ cb.unprotect();
+ }
+
+ if (handler.onEndCallback) |cb| {
+ cb.unprotect();
+ }
}
if (thisObject.get(global, "doctype")) |val| {
if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
JSC.throwInvalidArguments("doctype must be a function", .{}, global, exception);
- return undefined;
+ return error.InvalidArguments;
}
JSC.C.JSValueProtect(global, val.asObjectRef());
handler.onDocTypeCallback = val;
@@ -754,7 +773,7 @@ const DocumentHandler = struct {
if (thisObject.get(global, "comments")) |val| {
if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
JSC.throwInvalidArguments("comments must be a function", .{}, global, exception);
- return undefined;
+ return error.InvalidArguments;
}
JSC.C.JSValueProtect(global, val.asObjectRef());
handler.onCommentCallback = val;
@@ -763,7 +782,7 @@ const DocumentHandler = struct {
if (thisObject.get(global, "text")) |val| {
if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
JSC.throwInvalidArguments("text must be a function", .{}, global, exception);
- return undefined;
+ return error.InvalidArguments;
}
JSC.C.JSValueProtect(global, val.asObjectRef());
handler.onTextCallback = val;
@@ -772,7 +791,7 @@ const DocumentHandler = struct {
if (thisObject.get(global, "end")) |val| {
if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
JSC.throwInvalidArguments("end must be a function", .{}, global, exception);
- return undefined;
+ return error.InvalidArguments;
}
JSC.C.JSValueProtect(global, val.asObjectRef());
handler.onEndCallback = val;
@@ -863,29 +882,39 @@ const ElementHandler = struct {
global: *JSGlobalObject,
ctx: ?*HTMLRewriter.BufferOutputSink = null,
- pub fn init(global: *JSGlobalObject, thisObject: JSValue, exception: JSC.C.ExceptionRef) ElementHandler {
+ pub fn init(global: *JSGlobalObject, thisObject: JSValue, exception: JSC.C.ExceptionRef) !ElementHandler {
var handler = ElementHandler{
.thisObject = thisObject,
.global = global,
};
+ errdefer {
+ if (handler.onCommentCallback) |cb| {
+ cb.unprotect();
+ }
- switch (thisObject.jsType()) {
- .Object, .ProxyObject, .Cell, .FinalObject => {},
- else => |kind| {
- JSC.throwInvalidArguments(
- "Expected object but received {s}",
- .{@as(string, @tagName(kind))},
- global,
- exception,
- );
- return undefined;
- },
+ if (handler.onElementCallback) |cb| {
+ cb.unprotect();
+ }
+
+ if (handler.onTextCallback) |cb| {
+ cb.unprotect();
+ }
+ }
+
+ if (!thisObject.isObject()) {
+ JSC.throwInvalidArguments(
+ "Expected object",
+ .{},
+ global,
+ exception,
+ );
+ return error.InvalidArguments;
}
if (thisObject.get(global, "element")) |val| {
if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
JSC.throwInvalidArguments("element must be a function", .{}, global, exception);
- return undefined;
+ return error.InvalidArguments;
}
JSC.C.JSValueProtect(global, val.asObjectRef());
handler.onElementCallback = val;
@@ -894,7 +923,7 @@ const ElementHandler = struct {
if (thisObject.get(global, "comments")) |val| {
if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
JSC.throwInvalidArguments("comments must be a function", .{}, global, exception);
- return undefined;
+ return error.InvalidArguments;
}
JSC.C.JSValueProtect(global, val.asObjectRef());
handler.onCommentCallback = val;
@@ -903,7 +932,7 @@ const ElementHandler = struct {
if (thisObject.get(global, "text")) |val| {
if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
JSC.throwInvalidArguments("text must be a function", .{}, global, exception);
- return undefined;
+ return error.InvalidArguments;
}
JSC.C.JSValueProtect(global, val.asObjectRef());
handler.onTextCallback = val;
@@ -967,26 +996,14 @@ const getterWrap = JSC.getterWrap;
const setterWrap = JSC.setterWrap;
const wrap = JSC.wrapSync;
-pub fn free_html_writer_string(_: ?*anyopaque, ptr: ?*anyopaque, len: usize) callconv(.C) void {
- var str = LOLHTML.HTMLString{ .ptr = bun.cast([*]const u8, ptr.?), .len = len };
- str.deinit();
-}
-
fn throwLOLHTMLError(global: *JSGlobalObject) JSValue {
- var err = LOLHTML.HTMLString.lastError();
- return ZigString.init(err.slice()).toErrorInstance(global);
+ const err = LOLHTML.HTMLString.lastError();
+ defer err.deinit();
+ return ZigString.fromUTF8(err.slice()).toErrorInstance(global);
}
fn htmlStringValue(input: LOLHTML.HTMLString, globalObject: *JSGlobalObject) JSValue {
- var str = ZigString.init(
- input.slice(),
- );
- str.detectEncoding();
-
- return str.toExternalValueWithCallback(
- globalObject,
- free_html_writer_string,
- );
+ return input.toJS(globalObject);
}
pub const TextChunk = struct {
@@ -1016,6 +1033,9 @@ pub const TextChunk = struct {
.removed = .{
.get = getterWrap(TextChunk, "removed"),
},
+ .lastInTextNode = .{
+ .get = getterWrap(TextChunk, "lastInTextNode"),
+ },
.text = .{
.get = getterWrap(TextChunk, "getText"),
},
@@ -1084,6 +1104,10 @@ pub const TextChunk = struct {
return JSC.JSValue.jsBoolean(this.text_chunk.?.isRemoved());
}
+ pub fn lastInTextNode(this: *TextChunk, _: *JSGlobalObject) JSValue {
+ return JSC.JSValue.jsBoolean(this.text_chunk.?.isLastInTextNode());
+ }
+
pub fn finalize(this: *TextChunk) void {
this.text_chunk = null;
bun.default_allocator.destroy(this);
@@ -1292,7 +1316,7 @@ pub const Comment = struct {
pub fn getText(this: *Comment, global: *JSGlobalObject) JSValue {
if (this.comment == null)
return JSValue.jsNull();
- return ZigString.init(this.comment.?.getText().slice()).withEncoding().toValueGC(global);
+ return this.comment.?.getText().toJS(global);
}
pub fn setText(
@@ -1422,7 +1446,7 @@ pub const EndTag = struct {
if (this.end_tag == null)
return JSC.JSValue.jsUndefined();
- return ZigString.init(this.end_tag.?.getName().slice()).withEncoding().toValueGC(global);
+ return this.end_tag.?.getName().toJS(global);
}
pub fn setName(
@@ -1534,27 +1558,16 @@ pub const AttributeIterator = struct {
return JSC.JSValue.jsNull();
};
- // TODO: don't clone here
const value = attribute.value();
const name = attribute.name();
- defer name.deinit();
- defer value.deinit();
- var strs = [2]ZigString{
- ZigString.init(name.slice()),
- ZigString.init(value.slice()),
- };
-
- var valid_strs: []ZigString = strs[0..2];
-
- var array = JSC.JSValue.createStringArray(
+ return bun.String.toJSArray(
globalObject,
- valid_strs.ptr,
- valid_strs.len,
- true,
+ &[_]bun.String{
+ name.toString(),
+ value.toString(),
+ },
);
-
- return array;
}
};
pub const Element = struct {
@@ -1660,19 +1673,12 @@ pub const Element = struct {
var slice = name.toSlice(bun.default_allocator);
defer slice.deinit();
- var attr = this.element.?.getAttribute(slice.slice()).slice();
+ var attr = this.element.?.getAttribute(slice.slice());
if (attr.len == 0)
return JSC.JSValue.jsNull();
- var str = ZigString.init(
- attr,
- );
-
- return str.toExternalValueWithCallback(
- globalObject,
- free_html_writer_string,
- );
+ return attr.toJS(globalObject);
}
/// Returns a boolean indicating whether an attribute exists on the element.
@@ -1847,8 +1853,9 @@ pub const Element = struct {
pub fn getNamespaceURI(this: *Element, globalObject: *JSGlobalObject) JSValue {
if (this.element == null)
return JSValue.jsUndefined();
-
- return ZigString.init(std.mem.span(this.element.?.namespaceURI())).toValueGC(globalObject);
+ var str = bun.String.create(std.mem.span(this.element.?.namespaceURI()));
+ defer str.deref();
+ return str.toJS(globalObject);
}
pub fn getAttributes(this: *Element, globalObject: *JSGlobalObject) JSValue {
diff --git a/src/bun.js/api/server.zig b/src/bun.js/api/server.zig
index 37bc601a5..9625ff693 100644
--- a/src/bun.js/api/server.zig
+++ b/src/bun.js/api/server.zig
@@ -163,12 +163,14 @@ pub const ServerConfig = struct {
request_cert: i32 = 0,
reject_unauthorized: i32 = 0,
ssl_ciphers: [*c]const u8 = null,
+ protos: [*c]const u8 = null,
+ protos_len: usize = 0,
const log = Output.scoped(.SSLConfig, false);
pub fn asUSockets(this_: ?SSLConfig) uws.us_bun_socket_context_options_t {
var ctx_opts: uws.us_bun_socket_context_options_t = undefined;
- @memset(@ptrCast([*]u8, &ctx_opts), 0, @sizeOf(uws.us_bun_socket_context_options_t));
+ @memset(@ptrCast([*]u8, &ctx_opts)[0..@sizeOf(uws.us_bun_socket_context_options_t)], 0);
if (this_) |ssl_config| {
if (ssl_config.key_file_name != null)
@@ -181,7 +183,7 @@ pub const ServerConfig = struct {
ctx_opts.dh_params_file_name = ssl_config.dh_params_file_name;
if (ssl_config.passphrase != null)
ctx_opts.passphrase = ssl_config.passphrase;
- ctx_opts.ssl_prefer_low_memory_usage = @boolToInt(ssl_config.low_memory_mode);
+ ctx_opts.ssl_prefer_low_memory_usage = @intFromBool(ssl_config.low_memory_mode);
if (ssl_config.key) |key| {
ctx_opts.key = key.ptr;
@@ -215,6 +217,7 @@ pub const ServerConfig = struct {
"dh_params_file_name",
"passphrase",
"ssl_ciphers",
+ "protos",
};
inline for (fields) |field| {
@@ -270,6 +273,9 @@ pub const ServerConfig = struct {
pub fn inJS(global: *JSC.JSGlobalObject, obj: JSC.JSValue, exception: JSC.C.ExceptionRef) ?SSLConfig {
var result = zero;
+ var arena: @import("root").bun.ArenaAllocator = @import("root").bun.ArenaAllocator.init(bun.default_allocator);
+ defer arena.deinit();
+
if (!obj.isObject()) {
JSC.throwInvalidArguments("tls option expects an object", .{}, global, exception);
return null;
@@ -301,7 +307,6 @@ pub const ServerConfig = struct {
var i: u32 = 0;
var valid_count: u32 = 0;
- var arena: @import("root").bun.ArenaAllocator = @import("root").bun.ArenaAllocator.init(bun.default_allocator);
while (i < count) : (i += 1) {
const item = js_obj.getIndex(global, i);
if (JSC.Node.StringOrBuffer.fromJS(global, arena.allocator(), item, exception)) |sb| {
@@ -317,7 +322,6 @@ pub const ServerConfig = struct {
valid_count += 1;
any = true;
} else {
- arena.deinit();
// mark and free all CA's
result.cert = native_array;
result.deinit();
@@ -325,7 +329,6 @@ pub const ServerConfig = struct {
}
} else {
global.throwInvalidArguments("key argument must be an string, Buffer, TypedArray, BunFile or an array containing string, Buffer, TypedArray or BunFile", .{});
- arena.deinit();
// mark and free all keys
result.key = native_array;
result.deinit();
@@ -333,8 +336,6 @@ pub const ServerConfig = struct {
}
}
- arena.deinit();
-
if (valid_count == 0) {
bun.default_allocator.free(native_array);
} else {
@@ -356,7 +357,6 @@ pub const ServerConfig = struct {
}
} else {
const native_array = bun.default_allocator.alloc([*c]const u8, 1) catch unreachable;
- var arena: @import("root").bun.ArenaAllocator = @import("root").bun.ArenaAllocator.init(bun.default_allocator);
if (JSC.Node.StringOrBuffer.fromJS(global, arena.allocator(), js_obj, exception)) |sb| {
const sliced = sb.slice();
if (sliced.len > 0) {
@@ -369,14 +369,11 @@ pub const ServerConfig = struct {
}
} else {
global.throwInvalidArguments("key argument must be an string, Buffer, TypedArray, BunFile or an array containing string, Buffer, TypedArray or BunFile", .{});
- arena.deinit();
// mark and free all certs
result.key = native_array;
result.deinit();
return null;
}
-
- arena.deinit();
}
}
@@ -394,6 +391,22 @@ pub const ServerConfig = struct {
}
}
+ if (obj.getTruthy(global, "ALPNProtocols")) |protocols| {
+ if (JSC.Node.StringOrBuffer.fromJS(global, arena.allocator(), protocols, exception)) |sb| {
+ const sliced = sb.slice();
+ if (sliced.len > 0) {
+ result.protos = bun.default_allocator.dupeZ(u8, sliced) catch unreachable;
+ result.protos_len = sliced.len;
+ }
+
+ any = true;
+ } else {
+ global.throwInvalidArguments("ALPNProtocols argument must be an string, Buffer or TypedArray", .{});
+ result.deinit();
+ return null;
+ }
+ }
+
if (obj.getTruthy(global, "cert")) |js_obj| {
if (js_obj.jsType().isArray()) {
const count = js_obj.getLength(global);
@@ -403,7 +416,6 @@ pub const ServerConfig = struct {
var i: u32 = 0;
var valid_count: u32 = 0;
- var arena: @import("root").bun.ArenaAllocator = @import("root").bun.ArenaAllocator.init(bun.default_allocator);
while (i < count) : (i += 1) {
const item = js_obj.getIndex(global, i);
if (JSC.Node.StringOrBuffer.fromJS(global, arena.allocator(), item, exception)) |sb| {
@@ -419,7 +431,6 @@ pub const ServerConfig = struct {
valid_count += 1;
any = true;
} else {
- arena.deinit();
// mark and free all CA's
result.cert = native_array;
result.deinit();
@@ -427,7 +438,6 @@ pub const ServerConfig = struct {
}
} else {
global.throwInvalidArguments("cert argument must be an string, Buffer, TypedArray, BunFile or an array containing string, Buffer, TypedArray or BunFile", .{});
- arena.deinit();
// mark and free all certs
result.cert = native_array;
result.deinit();
@@ -435,8 +445,6 @@ pub const ServerConfig = struct {
}
}
- arena.deinit();
-
if (valid_count == 0) {
bun.default_allocator.free(native_array);
} else {
@@ -458,7 +466,6 @@ pub const ServerConfig = struct {
}
} else {
const native_array = bun.default_allocator.alloc([*c]const u8, 1) catch unreachable;
- var arena: @import("root").bun.ArenaAllocator = @import("root").bun.ArenaAllocator.init(bun.default_allocator);
if (JSC.Node.StringOrBuffer.fromJS(global, arena.allocator(), js_obj, exception)) |sb| {
const sliced = sb.slice();
if (sliced.len > 0) {
@@ -471,14 +478,11 @@ pub const ServerConfig = struct {
}
} else {
global.throwInvalidArguments("cert argument must be an string, Buffer, TypedArray, BunFile or an array containing string, Buffer, TypedArray or BunFile", .{});
- arena.deinit();
// mark and free all certs
result.cert = native_array;
result.deinit();
return null;
}
-
- arena.deinit();
}
}
@@ -518,7 +522,6 @@ pub const ServerConfig = struct {
var i: u32 = 0;
var valid_count: u32 = 0;
- var arena: @import("root").bun.ArenaAllocator = @import("root").bun.ArenaAllocator.init(bun.default_allocator);
while (i < count) : (i += 1) {
const item = js_obj.getIndex(global, i);
if (JSC.Node.StringOrBuffer.fromJS(global, arena.allocator(), item, exception)) |sb| {
@@ -534,7 +537,6 @@ pub const ServerConfig = struct {
valid_count += 1;
any = true;
} else {
- arena.deinit();
// mark and free all CA's
result.cert = native_array;
result.deinit();
@@ -542,7 +544,6 @@ pub const ServerConfig = struct {
}
} else {
global.throwInvalidArguments("ca argument must be an string, Buffer, TypedArray, BunFile or an array containing string, Buffer, TypedArray or BunFile", .{});
- arena.deinit();
// mark and free all CA's
result.cert = native_array;
result.deinit();
@@ -550,8 +551,6 @@ pub const ServerConfig = struct {
}
}
- arena.deinit();
-
if (valid_count == 0) {
bun.default_allocator.free(native_array);
} else {
@@ -573,7 +572,6 @@ pub const ServerConfig = struct {
}
} else {
const native_array = bun.default_allocator.alloc([*c]const u8, 1) catch unreachable;
- var arena: @import("root").bun.ArenaAllocator = @import("root").bun.ArenaAllocator.init(bun.default_allocator);
if (JSC.Node.StringOrBuffer.fromJS(global, arena.allocator(), js_obj, exception)) |sb| {
const sliced = sb.slice();
if (sliced.len > 0) {
@@ -586,13 +584,11 @@ pub const ServerConfig = struct {
}
} else {
JSC.throwInvalidArguments("ca argument must be an string, Buffer, TypedArray, BunFile or an array containing string, Buffer, TypedArray or BunFile", .{}, global, exception);
- arena.deinit();
// mark and free all certs
result.ca = native_array;
result.deinit();
return null;
}
- arena.deinit();
}
}
@@ -1000,6 +996,30 @@ const HTTPStatusText = struct {
}
};
+fn NewFlags(comptime debug_mode: bool) type {
+ return packed struct {
+ has_marked_complete: bool = false,
+ has_marked_pending: bool = false,
+ has_abort_handler: bool = false,
+ has_sendfile_ctx: bool = false,
+ has_called_error_handler: bool = false,
+ needs_content_length: bool = false,
+ needs_content_range: bool = false,
+ /// Used to avoid looking at the uws.Request struct after it's been freed
+ is_transfer_encoding: bool = false,
+
+ /// Used to identify if request can be safely deinitialized
+ is_waiting_body: bool = false,
+ /// Used in renderMissing in debug mode to show the user an HTML page
+ /// Used to avoid looking at the uws.Request struct after it's been freed
+ is_web_browser_navigation: if (debug_mode) bool else void = if (debug_mode) false else {},
+ has_written_status: bool = false,
+ response_protected: bool = false,
+ aborted: bool = false,
+ finalized: bun.DebugOnly(bool) = bun.DebugOnlyDefault(false),
+ };
+}
+
// This is defined separately partially to work-around an LLVM debugger bug.
fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comptime ThisServer: type) type {
return struct {
@@ -1024,63 +1044,42 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
req: *uws.Request,
signal: ?*JSC.WebCore.AbortSignal = null,
method: HTTP.Method,
- aborted: bool = false,
- finalized: bun.DebugOnly(bool) = bun.DebugOnlyDefault(false),
+
+ flags: NewFlags(debug_mode) = .{},
+
upgrade_context: ?*uws.uws_socket_context_t = null,
/// We can only safely free once the request body promise is finalized
/// and the response is rejected
+ response_jsvalue: JSC.JSValue = JSC.JSValue.zero,
pending_promises_for_abort: u8 = 0,
- has_marked_complete: bool = false,
- has_marked_pending: bool = false,
-
- response_jsvalue: JSC.JSValue = JSC.JSValue.zero,
- response_protected: bool = false,
response_ptr: ?*JSC.WebCore.Response = null,
blob: JSC.WebCore.AnyBlob = JSC.WebCore.AnyBlob{ .Blob = .{} },
promise: ?*JSC.JSValue = null,
- has_abort_handler: bool = false,
- has_sendfile_ctx: bool = false,
- has_called_error_handler: bool = false,
- needs_content_length: bool = false,
- needs_content_range: bool = false,
+
sendfile: SendfileContext = undefined,
request_body: ?*JSC.WebCore.BodyValueRef = null,
request_body_buf: std.ArrayListUnmanaged(u8) = .{},
request_body_content_len: usize = 0,
- /// Used to avoid looking at the uws.Request struct after it's been freed
- is_transfer_encoding: bool = false,
-
- /// Used to identify if request can be safely deinitialized
- is_waiting_body: bool = false,
-
- /// Used in renderMissing in debug mode to show the user an HTML page
- /// Used to avoid looking at the uws.Request struct after it's been freed
- is_web_browser_navigation: if (debug_mode) bool else void = if (debug_mode) false else {},
-
sink: ?*ResponseStream.JSSink = null,
byte_stream: ?*JSC.WebCore.ByteStream = null,
/// Used in errors
pathname: []const u8 = "",
- has_written_status: bool = false,
-
/// Used either for temporary blob data or fallback
/// When the response body is a temporary value
response_buf_owned: std.ArrayListUnmanaged(u8) = .{},
- keepalive: bool = true,
-
// TODO: support builtin compression
const can_sendfile = !ssl_enabled;
pub fn setAbortHandler(this: *RequestContext) void {
- if (this.has_abort_handler) return;
+ if (this.flags.has_abort_handler) return;
if (this.resp) |resp| {
- this.has_abort_handler = true;
+ this.flags.has_abort_handler = true;
resp.onAborted(*RequestContext, RequestContext.onAbort, this);
}
}
@@ -1094,7 +1093,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
result.ensureStillAlive();
ctx.pending_promises_for_abort -|= 1;
- if (ctx.aborted) {
+ if (ctx.flags.aborted) {
ctx.finalizeForAbort();
return JSValue.jsUndefined();
}
@@ -1121,8 +1120,8 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
return;
};
ctx.response_jsvalue = value;
- std.debug.assert(!ctx.response_protected);
- ctx.response_protected = true;
+ std.debug.assert(!ctx.flags.response_protected);
+ ctx.flags.response_protected = true;
JSC.C.JSValueProtect(ctx.server.globalThis, value.asObjectRef());
ctx.render(response);
@@ -1143,7 +1142,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
ctx.pending_promises_for_abort -|= 1;
- if (ctx.aborted) {
+ if (ctx.flags.aborted) {
ctx.finalizeForAbort();
return JSValue.jsUndefined();
}
@@ -1163,7 +1162,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
value,
);
- if (ctx.aborted) {
+ if (ctx.flags.aborted) {
ctx.finalizeForAbort();
return;
}
@@ -1174,7 +1173,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
return;
}
- if (!resp.hasResponded() and !ctx.has_marked_pending) {
+ if (!resp.hasResponded() and !ctx.flags.has_marked_pending) {
ctx.renderMissing();
return;
}
@@ -1190,14 +1189,14 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
pub fn renderMissingCorked(ctx: *RequestContext) void {
if (ctx.resp) |resp| {
if (comptime !debug_mode) {
- if (!ctx.has_written_status)
+ if (!ctx.flags.has_written_status)
resp.writeStatus("204 No Content");
- ctx.has_written_status = true;
+ ctx.flags.has_written_status = true;
ctx.end("", ctx.shouldCloseConnection());
} else {
- if (ctx.is_web_browser_navigation) {
+ if (ctx.flags.is_web_browser_navigation) {
resp.writeStatus("200 OK");
- ctx.has_written_status = true;
+ ctx.flags.has_written_status = true;
resp.writeHeader("content-type", MimeType.html.value);
resp.writeHeader("content-encoding", "gzip");
@@ -1206,9 +1205,9 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
return;
}
- if (!ctx.has_written_status)
+ if (!ctx.flags.has_written_status)
resp.writeStatus("200 OK");
- ctx.has_written_status = true;
+ ctx.flags.has_written_status = true;
ctx.end("Welcome to Bun! To get started, return a Response object.", ctx.shouldCloseConnection());
}
}
@@ -1222,8 +1221,8 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
comptime fmt: string,
args: anytype,
) void {
- if (!this.has_written_status) {
- this.has_written_status = true;
+ if (!this.flags.has_written_status) {
+ this.flags.has_written_status = true;
if (this.resp) |resp| {
resp.writeStatus("500 Internal Server Error");
resp.writeHeader("content-type", MimeType.html.value);
@@ -1240,7 +1239,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
.reason = .fetch_event_handler,
.cwd = VirtualMachine.get().bundler.fs.top_level_dir,
.problems = Api.Problems{
- .code = @truncate(u16, @errorToInt(err)),
+ .code = @truncate(u16, @intFromError(err)),
.name = @errorName(err),
.exceptions = exceptions,
.build = log.toAPI(allocator) catch unreachable,
@@ -1265,7 +1264,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
return;
}
- this.has_marked_pending = true;
+ this.flags.has_marked_pending = true;
this.response_buf_owned = std.ArrayListUnmanaged(u8){ .items = bb.items, .capacity = bb.capacity };
if (this.resp) |resp| {
@@ -1290,7 +1289,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
this.response_buf_owned.items.len,
this.shouldCloseConnection(),
)) {
- this.has_marked_pending = true;
+ this.flags.has_marked_pending = true;
resp.onWritable(*RequestContext, onWritableCompleteResponseBuffer, this);
this.setAbortHandler();
return;
@@ -1314,8 +1313,8 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
pub fn end(this: *RequestContext, data: []const u8, closeConnection: bool) void {
if (this.resp) |resp| {
- if (this.is_waiting_body) {
- this.is_waiting_body = false;
+ if (this.flags.is_waiting_body) {
+ this.flags.is_waiting_body = false;
resp.clearOnData();
}
resp.end(data, closeConnection);
@@ -1325,8 +1324,8 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
pub fn endStream(this: *RequestContext, closeConnection: bool) void {
if (this.resp) |resp| {
- if (this.is_waiting_body) {
- this.is_waiting_body = false;
+ if (this.flags.is_waiting_body) {
+ this.flags.is_waiting_body = false;
resp.clearOnData();
}
resp.endStream(closeConnection);
@@ -1336,8 +1335,8 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
pub fn endWithoutBody(this: *RequestContext, closeConnection: bool) void {
if (this.resp) |resp| {
- if (this.is_waiting_body) {
- this.is_waiting_body = false;
+ if (this.flags.is_waiting_body) {
+ this.flags.is_waiting_body = false;
resp.clearOnData();
}
resp.endWithoutBody(closeConnection);
@@ -1347,7 +1346,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
pub fn onWritableResponseBuffer(this: *RequestContext, _: c_ulong, resp: *App.Response) callconv(.C) bool {
std.debug.assert(this.resp == resp);
- if (this.aborted) {
+ if (this.flags.aborted) {
this.finalizeForAbort();
return false;
}
@@ -1360,12 +1359,12 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
pub fn onWritableCompleteResponseBufferAndMetadata(this: *RequestContext, write_offset: c_ulong, resp: *App.Response) callconv(.C) bool {
std.debug.assert(this.resp == resp);
- if (this.aborted) {
+ if (this.flags.aborted) {
this.finalizeForAbort();
return false;
}
- if (!this.has_written_status) {
+ if (!this.flags.has_written_status) {
this.renderMetadata();
}
@@ -1380,7 +1379,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
pub fn onWritableCompleteResponseBuffer(this: *RequestContext, write_offset: c_ulong, resp: *App.Response) callconv(.C) bool {
std.debug.assert(this.resp == resp);
- if (this.aborted) {
+ if (this.flags.aborted) {
this.finalizeForAbort();
return false;
}
@@ -1417,9 +1416,9 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
pub fn onAbort(this: *RequestContext, resp: *App.Response) void {
std.debug.assert(this.resp == resp);
- std.debug.assert(!this.aborted);
+ std.debug.assert(!this.flags.aborted);
//mark request as aborted
- this.aborted = true;
+ this.flags.aborted = true;
// if signal is not aborted, abort the signal
if (this.signal) |signal| {
@@ -1456,12 +1455,11 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
// the promise is pending
if (body.value.Locked.action != .none or body.value.Locked.promise != null) {
this.pending_promises_for_abort += 1;
- body.value.toErrorInstance(JSC.toTypeError(.ABORT_ERR, "Request aborted", .{}, this.server.globalThis), this.server.globalThis);
} else if (body.value.Locked.readable != null) {
body.value.Locked.readable.?.abort(this.server.globalThis);
- body.value.toErrorInstance(JSC.toTypeError(.ABORT_ERR, "Request aborted", .{}, this.server.globalThis), this.server.globalThis);
body.value.Locked.readable = null;
}
+ body.value.toErrorInstance(JSC.toTypeError(.ABORT_ERR, "Request aborted", .{}, this.server.globalThis), this.server.globalThis);
}
}
@@ -1488,8 +1486,8 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
}
pub fn markComplete(this: *RequestContext) void {
- if (!this.has_marked_complete) this.server.onRequestComplete();
- this.has_marked_complete = true;
+ if (!this.flags.has_marked_complete) this.server.onRequestComplete();
+ this.flags.has_marked_complete = true;
}
// This function may be called multiple times
@@ -1499,15 +1497,15 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
this.blob.detach();
if (comptime Environment.allow_assert) {
- std.debug.assert(!this.finalized);
- this.finalized = true;
+ std.debug.assert(!this.flags.finalized);
+ this.flags.finalized = true;
}
if (!this.response_jsvalue.isEmpty()) {
ctxLog("finalizeWithoutDeinit: response_jsvalue != .zero", .{});
- if (this.response_protected) {
+ if (this.flags.response_protected) {
this.response_jsvalue.unprotect();
- this.response_protected = false;
+ this.flags.response_protected = false;
}
this.response_jsvalue = JSC.JSValue.zero;
}
@@ -1515,7 +1513,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
// if signal is not aborted, abort the signal
if (this.signal) |signal| {
this.signal = null;
- if (this.aborted and !signal.aborted()) {
+ if (this.flags.aborted and !signal.aborted()) {
const reason = JSC.WebCore.AbortSignal.createAbortError(JSC.ZigString.static("The user aborted a request"), &JSC.ZigString.Empty, this.server.globalThis);
reason.ensureStillAlive();
_ = signal.signal(reason);
@@ -1558,9 +1556,9 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
// if we are waiting for the body yet and the request was not aborted we can safely clear the onData callback
if (this.resp) |resp| {
- if (this.is_waiting_body and this.aborted == false) {
+ if (this.flags.is_waiting_body and this.flags.aborted == false) {
resp.clearOnData();
- this.is_waiting_body = false;
+ this.flags.is_waiting_body = false;
}
}
}
@@ -1574,10 +1572,10 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
pub fn deinit(this: *RequestContext) void {
ctxLog("deinit<d> ({*})<r>", .{this});
if (comptime Environment.allow_assert)
- std.debug.assert(this.finalized);
+ std.debug.assert(this.flags.finalized);
if (comptime Environment.allow_assert)
- std.debug.assert(this.has_marked_complete);
+ std.debug.assert(this.flags.has_marked_complete);
var server = this.server;
this.request_body_buf.clearAndFree(this.allocator);
@@ -1605,8 +1603,8 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
pub fn writeStatus(this: *RequestContext, status: u16) void {
var status_text_buf: [48]u8 = undefined;
- std.debug.assert(!this.has_written_status);
- this.has_written_status = true;
+ std.debug.assert(!this.flags.has_written_status);
+ this.flags.has_written_status = true;
if (this.resp) |resp| {
if (HTTPStatusText.get(status)) |text| {
@@ -1635,7 +1633,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
}};
pub fn onSendfile(this: *RequestContext) bool {
- if (this.aborted or this.resp == null) {
+ if (this.flags.aborted or this.resp == null) {
this.cleanupAndFinalizeAfterSendfile();
return false;
}
@@ -1657,7 +1655,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
this.sendfile.remain -|= @intCast(Blob.SizeType, this.sendfile.offset -| start);
- if (errcode != .SUCCESS or this.aborted or this.sendfile.remain == 0 or val == 0) {
+ if (errcode != .SUCCESS or this.flags.aborted or this.sendfile.remain == 0 or val == 0) {
if (errcode != .AGAIN and errcode != .SUCCESS and errcode != .PIPE) {
Output.prettyErrorln("Error: {s}", .{@tagName(errcode)});
Output.flush();
@@ -1680,7 +1678,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
const wrote = @intCast(Blob.SizeType, sbytes);
this.sendfile.offset +|= wrote;
this.sendfile.remain -|= wrote;
- if (errcode != .AGAIN or this.aborted or this.sendfile.remain == 0 or sbytes == 0) {
+ if (errcode != .AGAIN or this.flags.aborted or this.sendfile.remain == 0 or sbytes == 0) {
if (errcode != .AGAIN and errcode != .SUCCESS and errcode != .PIPE) {
Output.prettyErrorln("Error: {s}", .{@tagName(errcode)});
Output.flush();
@@ -1692,7 +1690,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
if (!this.sendfile.has_set_on_writable) {
this.sendfile.has_set_on_writable = true;
- this.has_marked_pending = true;
+ this.flags.has_marked_pending = true;
resp.onWritable(*RequestContext, onWritableSendfile, this);
}
@@ -1704,7 +1702,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
pub fn onWritableBytes(this: *RequestContext, write_offset: c_ulong, resp: *App.Response) callconv(.C) bool {
std.debug.assert(this.resp == resp);
- if (this.aborted) {
+ if (this.flags.aborted) {
this.finalizeForAbort();
return false;
}
@@ -1725,7 +1723,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
this.finalize();
return true;
} else {
- this.has_marked_pending = true;
+ this.flags.has_marked_pending = true;
resp.onWritable(*RequestContext, onWritableBytes, this);
return true;
}
@@ -1739,7 +1737,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
this.response_buf_owned.items.len = 0;
this.finalize();
} else {
- this.has_marked_pending = true;
+ this.flags.has_marked_pending = true;
resp.onWritable(*RequestContext, onWritableCompleteResponseBuffer, this);
}
@@ -1790,11 +1788,11 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
}
var err = JSC.Node.Syscall.Error{
- .errno = @intCast(JSC.Node.Syscall.Error.Int, @enumToInt(std.os.E.INVAL)),
+ .errno = @intCast(JSC.Node.Syscall.Error.Int, @intFromEnum(std.os.E.INVAL)),
.syscall = .sendfile,
};
var sys = err.withPathLike(file.pathlike).toSystemError();
- sys.message = ZigString.init("MacOS does not support sending non-regular files");
+ sys.message = bun.String.static("MacOS does not support sending non-regular files");
this.runErrorHandler(sys.toErrorInstance(
this.server.globalThis,
));
@@ -1809,11 +1807,11 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
}
var err = JSC.Node.Syscall.Error{
- .errno = @intCast(JSC.Node.Syscall.Error.Int, @enumToInt(std.os.E.INVAL)),
+ .errno = @intCast(JSC.Node.Syscall.Error.Int, @intFromEnum(std.os.E.INVAL)),
.syscall = .sendfile,
};
var sys = err.withPathLike(file.pathlike).toSystemError();
- sys.message = ZigString.init("File must be regular or FIFO");
+ sys.message = bun.String.static("File must be regular or FIFO");
this.runErrorHandler(sys.toErrorInstance(
this.server.globalThis,
));
@@ -1828,21 +1826,21 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
else
@min(original_size, stat_size);
- this.needs_content_length = true;
+ this.flags.needs_content_length = true;
this.sendfile = .{
.fd = fd,
.remain = this.blob.Blob.offset + original_size,
.offset = this.blob.Blob.offset,
.auto_close = auto_close,
- .socket_fd = if (!this.aborted) resp.getNativeHandle() else -999,
+ .socket_fd = if (!this.flags.aborted) resp.getNativeHandle() else -999,
};
// if we are sending only part of a file, include the content-range header
// only include content-range automatically when using a file path instead of an fd
// this is to better support manually controlling the behavior
if (std.os.S.ISREG(stat.mode) and auto_close) {
- this.needs_content_range = (this.sendfile.remain -| this.sendfile.offset) != stat_size;
+ this.flags.needs_content_range = (this.sendfile.remain -| this.sendfile.offset) != stat_size;
}
// we know the bounds when we are sending a regular file
@@ -1869,14 +1867,14 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
}
pub fn doSendfile(this: *RequestContext, blob: Blob) void {
- if (this.aborted) {
+ if (this.flags.aborted) {
this.finalizeForAbort();
return;
}
- if (this.has_sendfile_ctx) return;
+ if (this.flags.has_sendfile_ctx) return;
- this.has_sendfile_ctx = true;
+ this.flags.has_sendfile_ctx = true;
if (comptime can_sendfile) {
return this.renderSendFile(blob);
@@ -1887,7 +1885,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
}
pub fn onReadFile(this: *RequestContext, result: Blob.Store.ReadFile.ResultType) void {
- if (this.aborted or this.resp == null) {
+ if (this.flags.aborted or this.resp == null) {
this.finalizeForAbort();
return;
}
@@ -1910,8 +1908,8 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
else
@min(original_size, stat_size);
- if (!this.has_written_status)
- this.needs_content_range = true;
+ if (!this.flags.has_written_status)
+ this.flags.needs_content_range = true;
// this is used by content-range
this.sendfile = .{
@@ -1932,14 +1930,14 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
}
fn renderWithBlobFromBodyValue(this: *RequestContext) void {
- if (this.aborted) {
+ if (this.flags.aborted) {
this.finalizeForAbort();
return;
}
if (this.blob.needsToReadFile()) {
this.req.setYield(false);
- if (!this.has_sendfile_ctx)
+ if (!this.flags.has_sendfile_ctx)
this.doSendfile(this.blob.Blob);
return;
}
@@ -1952,7 +1950,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
fn doRenderStream(pair: *StreamPair) void {
var this = pair.this;
var stream = pair.stream;
- if (this.resp == null or this.aborted) {
+ if (this.resp == null or this.flags.aborted) {
stream.value.unprotect();
this.finalizeForAbort();
return;
@@ -2003,11 +2001,11 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
}
}
- this.aborted = this.aborted or response_stream.sink.aborted;
+ this.flags.aborted = this.flags.aborted or response_stream.sink.aborted;
if (assignment_result.toError()) |err_value| {
streamLog("returned an error", .{});
- if (!this.aborted) resp.clearAborted();
+ if (!this.flags.aborted) resp.clearAborted();
response_stream.detach();
this.sink = null;
response_stream.sink.destroy();
@@ -2019,7 +2017,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
// TODO: is there a condition where resp could be freed before done?
resp.hasResponded())
{
- if (!this.aborted) resp.clearAborted();
+ if (!this.flags.aborted) resp.clearAborted();
const wrote_anything = response_stream.sink.wrote > 0;
streamLog("is done", .{});
const responded = resp.hasResponded();
@@ -2027,10 +2025,10 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
response_stream.detach();
this.sink = null;
response_stream.sink.destroy();
- if (!responded and !wrote_anything and !this.aborted) {
+ if (!responded and !wrote_anything and !this.flags.aborted) {
this.renderMissing();
return;
- } else if (wrote_anything and !responded and !this.aborted) {
+ } else if (wrote_anything and !responded and !this.flags.aborted) {
this.endStream(this.shouldCloseConnection());
}
@@ -2078,7 +2076,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
}
}
- if (this.aborted) {
+ if (this.flags.aborted) {
response_stream.detach();
stream.cancel(this.server.globalThis);
response_stream.sink.done = true;
@@ -2113,7 +2111,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
const streamLog = Output.scoped(.ReadableStream, false);
pub fn didUpgradeWebSocket(this: *RequestContext) bool {
- return @ptrToInt(this.upgrade_context) == std.math.maxInt(usize);
+ return @intFromPtr(this.upgrade_context) == std.math.maxInt(usize);
}
pub fn onResponse(
@@ -2127,7 +2125,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
request_value.ensureStillAlive();
response_value.ensureStillAlive();
- if (ctx.aborted) {
+ if (ctx.flags.aborted) {
ctx.finalizeForAbort();
return;
}
@@ -2154,19 +2152,19 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
if (response_value.as(JSC.WebCore.Response)) |response| {
ctx.response_jsvalue = response_value;
ctx.response_jsvalue.ensureStillAlive();
- ctx.response_protected = false;
+ ctx.flags.response_protected = false;
response.body.value.toBlobIfPossible();
switch (response.body.value) {
.Blob => |*blob| {
if (blob.needsToReadFile()) {
response_value.protect();
- ctx.response_protected = true;
+ ctx.flags.response_protected = true;
}
},
.Locked => {
response_value.protect();
- ctx.response_protected = true;
+ ctx.flags.response_protected = true;
},
else => {},
}
@@ -2204,19 +2202,19 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
ctx.response_jsvalue = fulfilled_value;
ctx.response_jsvalue.ensureStillAlive();
- ctx.response_protected = false;
+ ctx.flags.response_protected = false;
ctx.response_ptr = response;
response.body.value.toBlobIfPossible();
switch (response.body.value) {
.Blob => |*blob| {
if (blob.needsToReadFile()) {
fulfilled_value.protect();
- ctx.response_protected = true;
+ ctx.flags.response_protected = true;
}
},
.Locked => {
fulfilled_value.protect();
- ctx.response_protected = true;
+ ctx.flags.response_protected = true;
},
else => {},
}
@@ -2259,7 +2257,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
}
if (ctx.resp) |resp| {
// The user returned something that wasn't a promise or a promise with a response
- if (!resp.hasResponded() and !ctx.has_marked_pending) ctx.renderMissing();
+ if (!resp.hasResponded() and !ctx.flags.has_marked_pending) ctx.renderMissing();
}
}
@@ -2270,7 +2268,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
if (req.sink) |wrapper| {
wrapper.sink.pending_flush = null;
wrapper.sink.done = true;
- req.aborted = req.aborted or wrapper.sink.aborted;
+ req.flags.aborted = req.flags.aborted or wrapper.sink.aborted;
wrote_anything = wrapper.sink.wrote > 0;
wrapper.sink.finalize();
wrapper.detach();
@@ -2288,7 +2286,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
streamLog("onResolve({any})", .{wrote_anything});
//aborted so call finalizeForAbort
- if (req.aborted or req.resp == null) {
+ if (req.flags.aborted or req.resp == null) {
req.finalizeForAbort();
return;
}
@@ -2326,13 +2324,13 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
pub fn handleRejectStream(req: *@This(), globalThis: *JSC.JSGlobalObject, err: JSValue) void {
streamLog("handleRejectStream", .{});
- var wrote_anything = req.has_written_status;
+ var wrote_anything = req.flags.has_written_status;
if (req.sink) |wrapper| {
wrapper.sink.pending_flush = null;
wrapper.sink.done = true;
wrote_anything = wrote_anything or wrapper.sink.wrote > 0;
- req.aborted = req.aborted or wrapper.sink.aborted;
+ req.flags.aborted = req.flags.aborted or wrapper.sink.aborted;
wrapper.sink.finalize();
wrapper.detach();
req.sink = null;
@@ -2349,7 +2347,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
streamLog("onReject({any})", .{wrote_anything});
//aborted so call finalizeForAbort
- if (req.aborted) {
+ if (req.flags.aborted) {
req.finalizeForAbort();
return;
}
@@ -2373,8 +2371,8 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
}
const fallback = JSC.SystemError{
- .code = ZigString.init(@as(string, @tagName(JSC.Node.ErrorCode.ERR_UNHANDLED_ERROR))),
- .message = ZigString.init("Unhandled error in ReadableStream"),
+ .code = bun.String.static(@as(string, @tagName(JSC.Node.ErrorCode.ERR_UNHANDLED_ERROR))),
+ .message = bun.String.static("Unhandled error in ReadableStream"),
};
req.handleReject(fallback.toErrorInstance(globalThis));
}
@@ -2388,7 +2386,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
.Error => {
const err = value.Error;
_ = value.use();
- if (this.aborted) {
+ if (this.flags.aborted) {
this.finalizeForAbort();
return;
}
@@ -2406,7 +2404,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
return;
},
.Locked => |*lock| {
- if (this.aborted) {
+ if (this.flags.aborted) {
this.finalizeForAbort();
return;
}
@@ -2420,8 +2418,8 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
if (stream.isLocked(this.server.globalThis)) {
streamLog("was locked but it shouldn't be", .{});
var err = JSC.SystemError{
- .code = ZigString.init(@as(string, @tagName(JSC.Node.ErrorCode.ERR_STREAM_CANNOT_PIPE))),
- .message = ZigString.init("Stream already used, please create a new one"),
+ .code = bun.String.static(@as(string, @tagName(JSC.Node.ErrorCode.ERR_STREAM_CANNOT_PIPE))),
+ .message = bun.String.static("Stream already used, please create a new one"),
};
stream.value.unprotect();
this.runErrorHandler(err.toErrorInstance(this.server.globalThis));
@@ -2509,7 +2507,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
}
}
- if (this.aborted or this.resp == null) {
+ if (this.flags.aborted or this.resp == null) {
this.finalizeForAbort();
return;
}
@@ -2528,7 +2526,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
} else {
// when it's the last one, we just want to know if it's done
if (stream.isDone()) {
- this.has_marked_pending = true;
+ this.flags.has_marked_pending = true;
resp.onWritable(*RequestContext, onWritableResponseBuffer, this);
}
}
@@ -2540,7 +2538,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
// Faster to do the memcpy than to do the two network calls
// We are not streaming
// This is an important performance optimization
- if (this.has_abort_handler and this.blob.fastSize() < 16384 - 1024) {
+ if (this.flags.has_abort_handler and this.blob.fastSize() < 16384 - 1024) {
if (this.resp) |resp| {
resp.runCorkedWithType(*RequestContext, doRenderBlobCorked, this);
}
@@ -2557,7 +2555,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
pub fn doRender(this: *RequestContext) void {
ctxLog("render", .{});
- if (this.aborted) {
+ if (this.flags.aborted) {
this.finalizeForAbort();
return;
}
@@ -2569,17 +2567,17 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
if (this.resp) |resp| {
switch (status) {
404 => {
- if (!this.has_written_status) {
+ if (!this.flags.has_written_status) {
resp.writeStatus("404 Not Found");
- this.has_written_status = true;
+ this.flags.has_written_status = true;
}
this.endWithoutBody(this.shouldCloseConnection());
},
else => {
- if (!this.has_written_status) {
+ if (!this.flags.has_written_status) {
resp.writeStatus("500 Internal Server Error");
resp.writeHeader("content-type", "text/plain");
- this.has_written_status = true;
+ this.flags.has_written_status = true;
}
this.end("Something went wrong!", this.shouldCloseConnection());
@@ -2600,7 +2598,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
if (this.pathname.len > 0)
return this.pathname;
- if (!this.has_abort_handler) {
+ if (!this.flags.has_abort_handler) {
return this.req.url();
}
@@ -2643,8 +2641,8 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
status: u16,
) void {
JSC.markBinding(@src());
- if (!this.server.config.onError.isEmpty() and !this.has_called_error_handler) {
- this.has_called_error_handler = true;
+ if (!this.server.config.onError.isEmpty() and !this.flags.has_called_error_handler) {
+ this.flags.has_called_error_handler = true;
var args = [_]JSC.C.JSValueRef{value.asObjectRef()};
const result = JSC.C.JSObjectCallAsFunctionReturnValue(this.server.globalThis, this.server.config.onError.asObjectRef(), this.server.thisObject.asObjectRef(), 1, &args);
defer result.ensureStillAlive();
@@ -2679,7 +2677,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
var response: *JSC.WebCore.Response = this.response_ptr.?;
var status = response.statusCode();
- var needs_content_range = this.needs_content_range and this.sendfile.remain < this.blob.size();
+ var needs_content_range = this.flags.needs_content_range and this.sendfile.remain < this.blob.size();
const size = if (needs_content_range)
this.sendfile.remain
@@ -2744,26 +2742,22 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
// 1. Bun.file("foo")
// 2. The content-disposition header is not present
if (!has_content_disposition and content_type.category.autosetFilename()) {
- if (this.blob.store()) |store| {
- if (store.data == .file) {
- if (store.data.file.pathlike == .path) {
- const basename = std.fs.path.basename(store.data.file.pathlike.path.slice());
- if (basename.len > 0) {
- var filename_buf: [1024]u8 = undefined;
-
- resp.writeHeader(
- "content-disposition",
- std.fmt.bufPrint(&filename_buf, "filename=\"{s}\"", .{basename[0..@min(basename.len, 1024 - 32)]}) catch "",
- );
- }
- }
+ if (this.blob.getFileName()) |filename| {
+ const basename = std.fs.path.basename(filename);
+ if (basename.len > 0) {
+ var filename_buf: [1024]u8 = undefined;
+
+ resp.writeHeader(
+ "content-disposition",
+ std.fmt.bufPrint(&filename_buf, "filename=\"{s}\"", .{basename[0..@min(basename.len, 1024 - 32)]}) catch "",
+ );
}
}
}
- if (this.needs_content_length) {
+ if (this.flags.needs_content_length) {
resp.writeHeaderInt("content-length", size);
- this.needs_content_length = false;
+ this.flags.needs_content_length = false;
}
if (needs_content_range) {
@@ -2780,7 +2774,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
.{ this.sendfile.offset, this.sendfile.offset + (this.sendfile.remain -| 1) },
) catch "bytes */*",
);
- this.needs_content_range = false;
+ this.flags.needs_content_range = false;
}
}
@@ -2794,7 +2788,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
bytes.len,
this.shouldCloseConnection(),
)) {
- this.has_marked_pending = true;
+ this.flags.has_marked_pending = true;
resp.onWritable(*RequestContext, onWritableBytes, this);
// given a blob, we might not have set an abort handler yet
this.setAbortHandler();
@@ -2817,8 +2811,8 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
std.debug.assert(this.resp == resp);
- this.is_waiting_body = last == false;
- if (this.aborted or this.has_marked_complete) return;
+ this.flags.is_waiting_body = last == false;
+ if (this.flags.aborted or this.flags.has_marked_complete) return;
if (this.request_body != null) {
var body = this.request_body.?;
@@ -2874,7 +2868,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
const prev_len = bytes.items.len;
bytes.items.len = total;
var slice = bytes.items[prev_len..];
- @memcpy(slice.ptr, chunk.ptr, chunk.len);
+ @memcpy(slice[0..chunk.len], chunk);
body.value = .{
.InternalBlob = .{
.bytes = bytes.toManaged(this.allocator),
@@ -2898,7 +2892,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
pub fn onStartStreamingRequestBody(this: *RequestContext) JSC.WebCore.DrainResult {
ctxLog("onStartStreamingRequestBody", .{});
- if (this.aborted) {
+ if (this.flags.aborted) {
return JSC.WebCore.DrainResult{
.aborted = {},
};
@@ -2928,7 +2922,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
ctxLog("onStartBuffering", .{});
// TODO: check if is someone calling onStartBuffering other than onStartBufferingCallback
// if is not, this should be removed and only keep protect + setAbortHandler
- if (this.is_transfer_encoding == false and this.request_body_content_len == 0) {
+ if (this.flags.is_transfer_encoding == false and this.request_body_content_len == 0) {
// no content-length or 0 content-length
// no transfer-encoding
if (this.request_body != null) {
@@ -3200,7 +3194,7 @@ pub const WebSocketServer = struct {
globalObject.throwInvalidArguments("websocket expects maxPayloadLength to be an integer", .{});
return null;
}
- server.maxPayloadLength = @intCast(u32, @truncate(i33, @max(value.toInt64(), 0)));
+ server.maxPayloadLength = @intCast(u32, @max(value.toInt64(), 0));
}
}
if (object.get(globalObject, "idleTimeout")) |value| {
@@ -3220,7 +3214,7 @@ pub const WebSocketServer = struct {
return null;
}
- server.backpressureLimit = @intCast(u32, @truncate(i33, @max(value.toInt64(), 0)));
+ server.backpressureLimit = @intCast(u32, @max(value.toInt64(), 0));
}
}
// if (object.get(globalObject, "sendPings")) |value| {
@@ -3366,7 +3360,7 @@ pub const ServerWebSocket = struct {
opcode: uws.Opcode,
) void {
log("onMessage({d}): {s}", .{
- @enumToInt(opcode),
+ @intFromEnum(opcode),
message,
});
const onMessageHandler = this.handler.onMessage;
@@ -3566,11 +3560,6 @@ pub const ServerWebSocket = struct {
if (message_value.asArrayBuffer(globalThis)) |array_buffer| {
const buffer = array_buffer.slice();
- if (buffer.len == 0) {
- globalThis.throw("publish requires a non-empty message", .{});
- return .zero;
- }
-
const result = if (!publish_to_self)
this.websocket.publish(topic_slice.slice(), buffer, .binary, compress)
else
@@ -3586,9 +3575,6 @@ pub const ServerWebSocket = struct {
{
var string_slice = message_value.toSlice(globalThis, bun.default_allocator);
defer string_slice.deinit();
- if (string_slice.len == 0) {
- return JSValue.jsNumber(0);
- }
const buffer = string_slice.slice();
@@ -3640,10 +3626,6 @@ pub const ServerWebSocket = struct {
var topic_slice = topic_value.toSlice(globalThis, bun.default_allocator);
defer topic_slice.deinit();
- if (topic_slice.len == 0) {
- globalThis.throw("publishText requires a non-empty topic", .{});
- return .zero;
- }
const compress = args.len > 1 and compress_value.toBoolean();
@@ -3654,9 +3636,6 @@ pub const ServerWebSocket = struct {
var string_slice = message_value.toSlice(globalThis, bun.default_allocator);
defer string_slice.deinit();
- if (string_slice.len == 0) {
- return JSValue.jsNumber(0);
- }
const buffer = string_slice.slice();
@@ -3721,10 +3700,6 @@ pub const ServerWebSocket = struct {
};
const buffer = array_buffer.slice();
- if (buffer.len == 0) {
- return JSC.JSValue.jsNumber(0);
- }
-
const result = if (!publish_to_self)
this.websocket.publish(topic_slice.slice(), buffer, .binary, compress)
else
@@ -3889,10 +3864,6 @@ pub const ServerWebSocket = struct {
}
if (message_value.asArrayBuffer(globalThis)) |buffer| {
- if (buffer.len == 0) {
- return JSValue.jsNumber(0);
- }
-
switch (this.websocket.send(buffer.slice(), .binary, compress, true)) {
.backpressure => {
log("send() backpressure ({d} bytes)", .{buffer.len});
@@ -3912,9 +3883,6 @@ pub const ServerWebSocket = struct {
{
var string_slice = message_value.toSlice(globalThis, bun.default_allocator);
defer string_slice.deinit();
- if (string_slice.len == 0) {
- return JSValue.jsNumber(0);
- }
const buffer = string_slice.slice();
switch (this.websocket.send(buffer, .text, compress, true)) {
@@ -3966,9 +3934,6 @@ pub const ServerWebSocket = struct {
var string_slice = message_value.toSlice(globalThis, bun.default_allocator);
defer string_slice.deinit();
- if (string_slice.len == 0) {
- return JSValue.jsNumber(0);
- }
const buffer = string_slice.slice();
switch (this.websocket.send(buffer, .text, compress, true)) {
@@ -4000,9 +3965,6 @@ pub const ServerWebSocket = struct {
var string_slice = message_str.toSlice(globalThis, bun.default_allocator);
defer string_slice.deinit();
- if (string_slice.len == 0) {
- return JSValue.jsNumber(0);
- }
const buffer = string_slice.slice();
switch (this.websocket.send(buffer, .text, compress, true)) {
@@ -4049,10 +4011,6 @@ pub const ServerWebSocket = struct {
return .zero;
};
- if (buffer.len == 0) {
- return JSValue.jsNumber(0);
- }
-
switch (this.websocket.send(buffer.slice(), .binary, compress, true)) {
.backpressure => {
log("sendBinary() backpressure ({d} bytes)", .{buffer.len});
@@ -4082,10 +4040,6 @@ pub const ServerWebSocket = struct {
const buffer = array_buffer.slice();
- if (buffer.len == 0) {
- return JSValue.jsNumber(0);
- }
-
switch (this.websocket.send(buffer, .binary, compress, true)) {
.backpressure => {
log("sendBinary() backpressure ({d} bytes)", .{buffer.len});
@@ -4422,36 +4376,23 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
const compress = (compress_value orelse JSValue.jsBoolean(true)).toBoolean();
- if (message_value.isEmptyOrUndefinedOrNull()) {
- JSC.JSError(this.vm.allocator, "publish requires a non-empty message", .{}, globalThis, exception);
- return .zero;
- }
-
if (message_value.asArrayBuffer(globalThis)) |buffer| {
- if (buffer.len == 0) {
- JSC.JSError(this.vm.allocator, "publish requires a non-empty message", .{}, globalThis, exception);
- return .zero;
- }
-
return JSValue.jsNumber(
// if 0, return 0
// else return number of bytes sent
- @as(i32, @boolToInt(uws.AnyWebSocket.publishWithOptions(ssl_enabled, app, topic_slice.slice(), buffer.slice(), .binary, compress))) * @intCast(i32, @truncate(u31, buffer.len)),
+ @as(i32, @intFromBool(uws.AnyWebSocket.publishWithOptions(ssl_enabled, app, topic_slice.slice(), buffer.slice(), .binary, compress))) * @intCast(i32, @truncate(u31, buffer.len)),
);
}
{
var string_slice = message_value.toSlice(globalThis, bun.default_allocator);
defer string_slice.deinit();
- if (string_slice.len == 0) {
- return JSValue.jsNumber(0);
- }
const buffer = string_slice.slice();
return JSValue.jsNumber(
// if 0, return 0
// else return number of bytes sent
- @as(i32, @boolToInt(uws.AnyWebSocket.publishWithOptions(ssl_enabled, app, topic_slice.slice(), buffer, .text, compress))) * @intCast(i32, @truncate(u31, buffer.len)),
+ @as(i32, @intFromBool(uws.AnyWebSocket.publishWithOptions(ssl_enabled, app, topic_slice.slice(), buffer, .text, compress))) * @intCast(i32, @truncate(u31, buffer.len)),
);
}
@@ -4484,11 +4425,11 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
}
var upgrader = bun.cast(*RequestContext, request.upgrader.?);
- if (upgrader.aborted or upgrader.resp == null) {
+ if (upgrader.flags.aborted or upgrader.resp == null) {
return JSC.jsBoolean(false);
}
- if (upgrader.upgrade_context == null or @ptrToInt(upgrader.upgrade_context) == std.math.maxInt(usize)) {
+ if (upgrader.upgrade_context == null or @intFromPtr(upgrader.upgrade_context) == std.math.maxInt(usize)) {
return JSC.jsBoolean(false);
}
const resp = upgrader.resp.?;
@@ -4582,7 +4523,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
// See https://github.com/oven-sh/bun/issues/1339
// obviously invalid pointer marks it as used
- upgrader.upgrade_context = @intToPtr(*uws.uws_socket_context_s, std.math.maxInt(usize));
+ upgrader.upgrade_context = @ptrFromInt(*uws.uws_socket_context_s, std.math.maxInt(usize));
request.upgrader = null;
resp.clearAborted();
@@ -4947,7 +4888,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
if (reason.len == 0) {
break;
}
- @memcpy(output_buf[written..].ptr, reason.ptr, reason.len);
+ @memcpy(output_buf[written..][0..reason.len], reason);
written += reason.len;
}
@@ -4958,7 +4899,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
if (reason.len > 0) {
output_buf[written..][0.." via ".len].* = " via ".*;
written += " via ".len;
- @memcpy(output_buf[written..].ptr, reason.ptr, reason.len);
+ @memcpy(output_buf[written..][0..reason.len], reason);
written += reason.len;
}
}
@@ -4970,7 +4911,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
if (reason.len > 0) {
output_buf[written..][0] = ' ';
written += 1;
- @memcpy(output_buf[written..].ptr, reason.ptr, reason.len);
+ @memcpy(output_buf[written..][0..reason.len], reason);
written += reason.len;
}
}
@@ -5110,7 +5051,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
};
if (comptime debug_mode) {
- ctx.is_web_browser_navigation = brk: {
+ ctx.flags.is_web_browser_navigation = brk: {
if (ctx.req.header("sec-fetch-dest")) |fetch_dest| {
if (strings.eqlComptime(fetch_dest, "document")) {
break :brk true;
@@ -5141,8 +5082,8 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
}
ctx.request_body_content_len = req_len;
- ctx.is_transfer_encoding = req.header("transfer-encoding") != null;
- if (req_len > 0 or ctx.is_transfer_encoding) {
+ ctx.flags.is_transfer_encoding = req.header("transfer-encoding") != null;
+ if (req_len > 0 or ctx.flags.is_transfer_encoding) {
// we defer pre-allocating the body until we receive the first chunk
// that way if the client is lying about how big the body is or the client aborts
// we don't waste memory
@@ -5154,7 +5095,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
.onStartStreaming = RequestContext.onStartStreamingRequestBodyCallback,
},
};
- ctx.is_waiting_body = true;
+ ctx.flags.is_waiting_body = true;
resp.onData(*RequestContext, RequestContext.onBufferedBodyChunk, ctx);
}
}
diff --git a/src/bun.js/api/sockets.classes.ts b/src/bun.js/api/sockets.classes.ts
index da07741a3..5bd073b9f 100644
--- a/src/bun.js/api/sockets.classes.ts
+++ b/src/bun.js/api/sockets.classes.ts
@@ -15,10 +15,17 @@ function generate(ssl) {
authorized: {
getter: "getAuthorized",
},
+ alpnProtocol: {
+ getter: "getALPNProtocol",
+ },
write: {
fn: "write",
length: 3,
},
+ upgradeTLS: {
+ fn: "upgradeTLS",
+ length: 1,
+ },
end: {
fn: "end",
length: 3,
@@ -82,6 +89,11 @@ function generate(ssl) {
fn: "reload",
length: 1,
},
+
+ setServername: {
+ fn: "setServername",
+ length: 1,
+ },
},
finalize: true,
construct: true,