aboutsummaryrefslogtreecommitdiff
path: root/src/deps
diff options
context:
space:
mode:
Diffstat (limited to 'src/deps')
-rw-r--r--src/deps/_libusockets.h5
-rw-r--r--src/deps/c_ares.zig134
-rw-r--r--src/deps/libuwsockets.cpp64
-rw-r--r--src/deps/lol-html.zig2
-rw-r--r--src/deps/uws.zig151
5 files changed, 323 insertions, 33 deletions
diff --git a/src/deps/_libusockets.h b/src/deps/_libusockets.h
index 5ca0e7df8..e9dbb6938 100644
--- a/src/deps/_libusockets.h
+++ b/src/deps/_libusockets.h
@@ -264,7 +264,7 @@ void uws_res_write_header(int ssl, uws_res_t *res, const char *key,
void uws_res_write_header_int(int ssl, uws_res_t *res, const char *key,
size_t key_length, uint64_t value);
-void uws_res_end_without_body(int ssl, uws_res_t *res);
+void uws_res_end_without_body(int ssl, uws_res_t *res, bool close_connection);
void uws_res_end_stream(int ssl, uws_res_t *res, bool close_connection);
bool uws_res_write(int ssl, uws_res_t *res, const char *data, size_t length);
uintmax_t uws_res_get_write_offset(int ssl, uws_res_t *res);
@@ -304,7 +304,6 @@ size_t uws_req_get_parameter(uws_req_t *res, unsigned short index,
const char **dest);
void uws_req_for_each_header(uws_req_t *res, uws_get_headers_server_handler handler, void *user_data);
-
struct us_loop_t *uws_get_loop();
struct us_loop_t *uws_get_loop_with_native(void* existing_native_loop);
@@ -336,4 +335,4 @@ void uws_app_close(int ssl, uws_app_t *app);
}
#endif
-#endif \ No newline at end of file
+#endif
diff --git a/src/deps/c_ares.zig b/src/deps/c_ares.zig
index 457fcef0e..5290ffcc8 100644
--- a/src/deps/c_ares.zig
+++ b/src/deps/c_ares.zig
@@ -181,7 +181,7 @@ pub const struct_hostent = extern struct {
h_length: c_int,
h_addr_list: [*c][*c]u8,
- pub fn toJSReponse(this: *struct_hostent, _: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime lookup_name: []const u8) JSC.JSValue {
+ pub fn toJSResponse(this: *struct_hostent, _: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime lookup_name: []const u8) JSC.JSValue {
// A cname lookup always returns a single record but we follow the common API here.
if (comptime strings.eqlComptime(lookup_name, "cname")) {
@@ -284,6 +284,55 @@ pub const struct_hostent = extern struct {
ares_free_hostent(this);
}
};
+
+pub const struct_nameinfo = extern struct {
+ node: [*c]u8,
+ service: [*c]u8,
+
+ pub fn toJSResponse(this: *struct_nameinfo, _: std.mem.Allocator, globalThis: *JSC.JSGlobalObject) JSC.JSValue {
+ const array = JSC.JSValue.createEmptyArray(globalThis, 2); // [node, service]
+
+ if (this.node != null) {
+ const node_len = bun.len(this.node);
+ const node_slice = this.node[0..node_len];
+ array.putIndex(globalThis, 0, JSC.ZigString.fromUTF8(node_slice).toValueGC(globalThis));
+ } else {
+ array.putIndex(globalThis, 0, JSC.JSValue.jsUndefined());
+ }
+
+ if (this.service != null) {
+ const service_len = bun.len(this.service);
+ const service_slice = this.service[0..service_len];
+ array.putIndex(globalThis, 1, JSC.ZigString.fromUTF8(service_slice).toValueGC(globalThis));
+ } else {
+ array.putIndex(globalThis, 1, JSC.JSValue.jsUndefined());
+ }
+
+ return array;
+ }
+
+ pub fn Callback(comptime Type: type) type {
+ return fn (*Type, status: ?Error, timeouts: i32, node: ?struct_nameinfo) void;
+ }
+
+ pub fn CallbackWrapper(
+ comptime Type: type,
+ comptime function: Callback(Type),
+ ) ares_nameinfo_callback {
+ return &struct {
+ pub fn handle(ctx: ?*anyopaque, status: c_int, timeouts: c_int, node: [*c]u8, service: [*c]u8) callconv(.C) void {
+ var this = bun.cast(*Type, ctx.?);
+ if (status != ARES_SUCCESS) {
+ function(this, Error.get(status), timeouts, null);
+ return;
+ }
+ function(this, null, timeouts, .{ .node = node, .service = service });
+ return;
+ }
+ }.handle;
+ }
+};
+
pub const struct_timeval = opaque {};
pub const struct_Channeldata = opaque {};
pub const AddrInfo_cname = extern struct {
@@ -524,11 +573,12 @@ pub const Channel = opaque {
}
pub fn resolve(this: *Channel, name: []const u8, comptime lookup_name: []const u8, comptime Type: type, ctx: *Type, comptime cares_type: type, comptime callback: cares_type.Callback(Type)) void {
+ if (name.len >= 1023 or (name.len == 0 and !(bun.strings.eqlComptime(lookup_name, "ns") or bun.strings.eqlComptime(lookup_name, "soa")))) {
+ return cares_type.callbackWrapper(lookup_name, Type, callback).?(ctx, ARES_EBADNAME, 0, null, 0);
+ }
+
var name_buf: [1024]u8 = undefined;
- const name_ptr: ?[*:0]const u8 = brk: {
- if (name.len == 0 or name.len >= 1023) {
- break :brk null;
- }
+ const name_ptr: [*:0]const u8 = brk: {
const len = @min(name.len, name_buf.len - 1);
@memcpy(name_buf[0..len], name[0..len]);
@@ -571,6 +621,20 @@ pub const Channel = opaque {
struct_hostent.hostCallbackWrapper(Type, callback).?(ctx, ARES_ENOTIMP, 0, null);
}
+ // https://c-ares.org/ares_getnameinfo.html
+ pub fn getNameInfo(this: *Channel, sa: *std.os.sockaddr, comptime Type: type, ctx: *Type, comptime callback: struct_nameinfo.Callback(Type)) void {
+ return ares_getnameinfo(
+ this,
+ sa,
+ if (sa.*.family == std.os.AF.INET) @sizeOf(std.os.sockaddr.in) else @sizeOf(std.os.sockaddr.in6),
+ // node returns ENOTFOUND for addresses like 255.255.255.255:80
+ // So, it requires setting the ARES_NI_NAMEREQD flag
+ ARES_NI_NAMEREQD | ARES_NI_LOOKUPHOST | ARES_NI_LOOKUPSERVICE,
+ struct_nameinfo.CallbackWrapper(Type, callback),
+ ctx,
+ );
+ }
+
pub inline fn process(this: *Channel, fd: i32, readable: bool, writable: bool) void {
ares_process_fd(
this,
@@ -669,7 +733,7 @@ pub const struct_ares_caa_reply = extern struct {
value: [*c]u8,
length: usize,
- pub fn toJSReponse(this: *struct_ares_caa_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue {
+ pub fn toJSResponse(this: *struct_ares_caa_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue {
var stack = std.heap.stackFallback(2048, parent_allocator);
var arena = @import("root").bun.ArenaAllocator.init(stack.get());
defer arena.deinit();
@@ -747,7 +811,7 @@ pub const struct_ares_srv_reply = extern struct {
weight: c_ushort,
port: c_ushort,
- pub fn toJSReponse(this: *struct_ares_srv_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue {
+ pub fn toJSResponse(this: *struct_ares_srv_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue {
var stack = std.heap.stackFallback(2048, parent_allocator);
var arena = @import("root").bun.ArenaAllocator.init(stack.get());
defer arena.deinit();
@@ -830,7 +894,7 @@ pub const struct_ares_mx_reply = extern struct {
host: [*c]u8,
priority: c_ushort,
- pub fn toJSReponse(this: *struct_ares_mx_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue {
+ pub fn toJSResponse(this: *struct_ares_mx_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue {
var stack = std.heap.stackFallback(2048, parent_allocator);
var arena = @import("root").bun.ArenaAllocator.init(stack.get());
defer arena.deinit();
@@ -904,7 +968,7 @@ pub const struct_ares_txt_reply = extern struct {
txt: [*c]u8,
length: usize,
- pub fn toJSReponse(this: *struct_ares_txt_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue {
+ pub fn toJSResponse(this: *struct_ares_txt_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue {
var stack = std.heap.stackFallback(2048, parent_allocator);
var arena = @import("root").bun.ArenaAllocator.init(stack.get());
defer arena.deinit();
@@ -984,7 +1048,7 @@ pub const struct_ares_naptr_reply = extern struct {
order: c_ushort,
preference: c_ushort,
- pub fn toJSReponse(this: *struct_ares_naptr_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue {
+ pub fn toJSResponse(this: *struct_ares_naptr_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue {
var stack = std.heap.stackFallback(2048, parent_allocator);
var arena = @import("root").bun.ArenaAllocator.init(stack.get());
defer arena.deinit();
@@ -1076,7 +1140,7 @@ pub const struct_ares_soa_reply = extern struct {
expire: c_uint,
minttl: c_uint,
- pub fn toJSReponse(this: *struct_ares_soa_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue {
+ pub fn toJSResponse(this: *struct_ares_soa_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue {
var stack = std.heap.stackFallback(2048, parent_allocator);
var arena = @import("root").bun.ArenaAllocator.init(stack.get());
defer arena.deinit();
@@ -1188,7 +1252,7 @@ pub extern fn ares_set_servers_csv(channel: *Channel, servers: [*c]const u8) c_i
pub extern fn ares_set_servers_ports_csv(channel: *Channel, servers: [*c]const u8) c_int;
pub extern fn ares_get_servers(channel: *Channel, servers: *?*struct_ares_addr_port_node) c_int;
pub extern fn ares_get_servers_ports(channel: *Channel, servers: *?*struct_ares_addr_port_node) c_int;
-pub extern fn ares_inet_ntop(af: c_int, src: ?*const anyopaque, dst: [*c]u8, size: ares_socklen_t) [*c]const u8;
+pub extern fn ares_inet_ntop(af: c_int, src: ?*const anyopaque, dst: [*c]u8, size: ares_socklen_t) ?[*:0]const u8;
pub extern fn ares_inet_pton(af: c_int, src: [*c]const u8, dst: ?*anyopaque) c_int;
pub const ARES_SUCCESS = 0;
pub const ARES_ENODATA = 1;
@@ -1470,6 +1534,52 @@ pub export fn Bun__canonicalizeIP(
return .zero;
}
}
+
+/// Creates a sockaddr structure from an address, port.
+///
+/// # Parameters
+/// - `addr`: A byte slice representing the IP address.
+/// - `port`: A 16-bit unsigned integer representing the port number.
+/// - `sa`: A pointer to a sockaddr structure where the result will be stored.
+///
+/// # Returns
+///
+/// This function returns 0 on success.
+pub fn getSockaddr(addr: []const u8, port: u16, sa: *std.os.sockaddr) c_int {
+ const buf_size = 128;
+
+ var buf: [buf_size]u8 = undefined;
+ const addr_ptr: [*:0]const u8 = brk: {
+ if (addr.len == 0 or addr.len >= buf_size) {
+ return -1;
+ }
+ const len = @min(addr.len, buf.len - 1);
+ @memcpy(buf[0..len], addr[0..len]);
+
+ buf[len] = 0;
+ break :brk buf[0..len :0];
+ };
+
+ {
+ const in: *std.os.sockaddr.in = @as(*std.os.sockaddr.in, @alignCast(@ptrCast(sa)));
+ if (ares_inet_pton(std.os.AF.INET, addr_ptr, &in.addr) == 1) {
+ in.*.family = std.os.AF.INET;
+ in.*.port = std.mem.nativeToBig(u16, port);
+ return 0;
+ }
+ }
+ {
+ const in6: *std.os.sockaddr.in6 = @as(*std.os.sockaddr.in6, @alignCast(@ptrCast(sa)));
+ if (ares_inet_pton(std.os.AF.INET6, addr_ptr, &in6.addr) == 1) {
+ in6.*.family = std.os.AF.INET6;
+ in6.*.port = std.mem.nativeToBig(u16, port);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
comptime {
if (!JSC.is_bindgen) {
_ = Bun__canonicalizeIP;
diff --git a/src/deps/libuwsockets.cpp b/src/deps/libuwsockets.cpp
index 67778c3e3..a815e87df 100644
--- a/src/deps/libuwsockets.cpp
+++ b/src/deps/libuwsockets.cpp
@@ -1,11 +1,12 @@
+// clang-format off
#include "_libusockets.h"
-
#include <bun-uws/src/App.h>
#include <bun-uws/src/AsyncSocket.h>
-
#include <bun-usockets/src/internal/internal.h>
#include <string_view>
+extern "C" const char* ares_inet_ntop(int af, const char *src, char *dst, size_t size);
+
extern "C"
{
@@ -1040,14 +1041,14 @@ extern "C"
uWS::HttpResponse<true> *uwsRes = (uWS::HttpResponse<true> *)res;
uwsRes->getHttpResponseData()->onWritable = nullptr;
uwsRes->onAborted(nullptr);
- uwsRes->endWithoutBody(std::nullopt, close_connection);
+ uwsRes->sendTerminatingChunk(close_connection);
}
else
{
uWS::HttpResponse<false> *uwsRes = (uWS::HttpResponse<false> *)res;
uwsRes->getHttpResponseData()->onWritable = nullptr;
uwsRes->onAborted(nullptr);
- uwsRes->endWithoutBody(std::nullopt, close_connection);
+ uwsRes->sendTerminatingChunk(close_connection);
}
}
@@ -1141,21 +1142,46 @@ extern "C"
}
}
- void uws_res_end_without_body(int ssl, uws_res_t *res)
+ void uws_res_end_without_body(int ssl, uws_res_t *res, bool close_connection)
{
if (ssl)
{
uWS::HttpResponse<true> *uwsRes = (uWS::HttpResponse<true> *)res;
auto *data = uwsRes->getHttpResponseData();
+ if (close_connection)
+ {
+ if (!(data->state & uWS::HttpResponseData<true>::HTTP_CONNECTION_CLOSE))
+ {
+ uwsRes->writeHeader("Connection", "close");
+ }
+ data->state |= uWS::HttpResponseData<true>::HTTP_CONNECTION_CLOSE;
+ }
+ if (!(data->state & uWS::HttpResponseData<true>::HTTP_END_CALLED))
+ {
+ uwsRes->AsyncSocket<true>::write("\r\n", 2);
+ }
data->state |= uWS::HttpResponseData<true>::HTTP_END_CALLED;
data->markDone();
us_socket_timeout(true, (us_socket_t *)uwsRes, uWS::HTTP_TIMEOUT_S);
}
else
{
-
uWS::HttpResponse<false> *uwsRes = (uWS::HttpResponse<false> *)res;
auto *data = uwsRes->getHttpResponseData();
+ if (close_connection)
+ {
+ if (!(data->state & uWS::HttpResponseData<false>::HTTP_CONNECTION_CLOSE))
+ {
+ uwsRes->writeHeader("Connection", "close");
+ }
+ data->state |= uWS::HttpResponseData<false>::HTTP_CONNECTION_CLOSE;
+ }
+ if (!(data->state & uWS::HttpResponseData<false>::HTTP_END_CALLED))
+ {
+ // Some HTTP clients require the complete "<header>\r\n\r\n" to be sent.
+ // If not, they may throw a ConnectionError.
+ uwsRes->AsyncSocket<false>::write("\r\n", 2);
+ }
data->state |= uWS::HttpResponseData<false>::HTTP_END_CALLED;
data->markDone();
us_socket_timeout(false, (us_socket_t *)uwsRes, uWS::HTTP_TIMEOUT_S);
@@ -1577,4 +1603,30 @@ extern "C"
s->context->loop->data.last_write_failed = 1;
us_poll_change(&s->p, s->context->loop, LIBUS_SOCKET_READABLE | LIBUS_SOCKET_WRITABLE);
}
+
+ // Gets the remote address and port
+ // Returns 0 if failure / unix socket
+ uint64_t uws_res_get_remote_address_info(uws_res_t *res, const char **dest, int *port, bool *is_ipv6)
+ {
+ // This function is manual inlining + modification of
+ // us_socket_remote_address
+ // AsyncSocket::getRemoteAddress
+ // AsyncSocket::addressAsText
+ // To get { ip, port, is_ipv6 } for Bun.serve().requestIP()
+ static thread_local char b[64];
+ auto length = us_get_remote_address_info(b, (us_socket_t *)res, dest, port, (int*)is_ipv6);
+
+ if (length == 0) return 0;
+ if (length == 4) {
+ length = snprintf(b, 64, "%u.%u.%u.%u", b[0], b[1], b[2], b[3]);
+ *dest = b;
+ *is_ipv6 = false;
+ return length;
+ } else {
+ ares_inet_ntop(AF_INET6, b, &b[16], 64 - 16);
+ *dest = &b[16];
+ *is_ipv6 = true;
+ return strlen(*dest);
+ }
+ }
}
diff --git a/src/deps/lol-html.zig b/src/deps/lol-html.zig
index 9a9137856..12604d4e0 100644
--- a/src/deps/lol-html.zig
+++ b/src/deps/lol-html.zig
@@ -582,7 +582,7 @@ pub const HTMLString = extern struct {
pub fn toString(this: HTMLString) bun.String {
const bytes = this.slice();
- if (bun.strings.isAllASCII(bytes)) {
+ if (bytes.len > 0 and bun.strings.isAllASCII(bytes)) {
return bun.String.createExternal(bytes, true, @constCast(bytes.ptr), &deinit_external);
}
defer this.deinit();
diff --git a/src/deps/uws.zig b/src/deps/uws.zig
index 032e5f6e6..6d3fb4613 100644
--- a/src/deps/uws.zig
+++ b/src/deps/uws.zig
@@ -40,6 +40,20 @@ pub fn NewSocketHandler(comptime is_ssl: bool) type {
return us_socket_timeout(comptime ssl_int, this.socket, seconds);
}
+ pub fn setTimeout(this: ThisSocket, seconds: c_uint) void {
+ if (seconds > 240) {
+ us_socket_timeout(comptime ssl_int, this.socket, 0);
+ us_socket_long_timeout(comptime ssl_int, this.socket, seconds / 60);
+ } else {
+ us_socket_timeout(comptime ssl_int, this.socket, seconds);
+ us_socket_long_timeout(comptime ssl_int, this.socket, 0);
+ }
+ }
+
+ pub fn setTimeoutMinutes(this: ThisSocket, minutes: c_uint) void {
+ return us_socket_long_timeout(comptime ssl_int, this.socket, minutes);
+ }
+
pub fn startTLS(this: ThisSocket, is_client: bool) void {
_ = us_socket_open(comptime ssl_int, this.socket, @intFromBool(is_client), null, 0);
}
@@ -126,6 +140,13 @@ pub fn NewSocketHandler(comptime is_ssl: bool) type {
);
return socket;
}
+ pub fn on_long_timeout(socket: *Socket) callconv(.C) ?*Socket {
+ Fields.onLongTimeout(
+ getValue(socket),
+ TLSSocket{ .socket = socket },
+ );
+ return socket;
+ }
pub fn on_connect_error(socket: *Socket, code: i32) callconv(.C) ?*Socket {
Fields.onConnectError(
getValue(socket),
@@ -155,6 +176,7 @@ pub fn NewSocketHandler(comptime is_ssl: bool) type {
.on_connect_error = SocketHandler.on_connect_error,
.on_end = SocketHandler.on_end,
.on_handshake = SocketHandler.on_handshake,
+ .on_long_timeout = SocketHandler.on_long_timeout,
};
const socket = us_socket_wrap_with_tls(ssl_int, this.socket, options, events, socket_ext_size) orelse return null;
@@ -284,6 +306,64 @@ pub fn NewSocketHandler(comptime is_ssl: bool) type {
);
}
+ /// Get the local address of a socket in binary format.
+ ///
+ /// # Arguments
+ /// - `buf`: A buffer to store the binary address data.
+ ///
+ /// # Returns
+ /// This function returns a slice of the buffer on success, or null on failure.
+ pub fn localAddressBinary(this: ThisSocket, buf: []u8) ?[]const u8 {
+ var length: i32 = @intCast(buf.len);
+ us_socket_local_address(
+ comptime ssl_int,
+ this.socket,
+ buf.ptr,
+ &length,
+ );
+
+ if (length <= 0) {
+ return null;
+ }
+ return buf[0..@intCast(length)];
+ }
+
+ /// Get the local address of a socket in text format.
+ ///
+ /// # Arguments
+ /// - `buf`: A buffer to store the text address data.
+ /// - `is_ipv6`: A pointer to a boolean representing whether the address is IPv6.
+ ///
+ /// # Returns
+ /// This function returns a slice of the buffer on success, or null on failure.
+ pub fn localAddressText(this: ThisSocket, buf: []u8, is_ipv6: *bool) ?[]const u8 {
+ const addr_v4_len = @sizeOf(std.meta.FieldType(std.os.sockaddr.in, .addr));
+ const addr_v6_len = @sizeOf(std.meta.FieldType(std.os.sockaddr.in6, .addr));
+
+ var sa_buf: [addr_v6_len + 1]u8 = undefined;
+ const binary = this.localAddressBinary(&sa_buf);
+ if (binary == null) {
+ return null;
+ }
+ const addr_len: usize = binary.?.len;
+ sa_buf[addr_len] = 0;
+
+ var ret: ?[*:0]const u8 = null;
+ if (addr_len == addr_v4_len) {
+ ret = bun.c_ares.ares_inet_ntop(std.os.AF.INET, &sa_buf, buf.ptr, @as(u32, @intCast(buf.len)));
+ is_ipv6.* = false;
+ } else if (addr_len == addr_v6_len) {
+ ret = bun.c_ares.ares_inet_ntop(std.os.AF.INET6, &sa_buf, buf.ptr, @as(u32, @intCast(buf.len)));
+ is_ipv6.* = true;
+ }
+
+ if (ret) |_| {
+ const length: usize = @intCast(bun.len(bun.cast([*:0]u8, buf)));
+ return buf[0..length];
+ }
+ return null;
+ }
+
pub fn connect(
host: []const u8,
port: i32,
@@ -578,6 +658,13 @@ pub fn NewSocketHandler(comptime is_ssl: bool) type {
);
return socket;
}
+ pub fn on_long_timeout(socket: *Socket) callconv(.C) ?*Socket {
+ Fields.onLongTimeout(
+ getValue(socket),
+ ThisSocket{ .socket = socket },
+ );
+ return socket;
+ }
pub fn on_connect_error(socket: *Socket, code: i32) callconv(.C) ?*Socket {
Fields.onConnectError(
getValue(socket),
@@ -614,6 +701,8 @@ pub fn NewSocketHandler(comptime is_ssl: bool) type {
us_socket_context_on_end(ssl_int, ctx, SocketHandler.on_end);
if (comptime @hasDecl(Type, "onHandshake") and @typeInfo(@TypeOf(Type.onHandshake)) != .Null)
us_socket_context_on_handshake(ssl_int, ctx, SocketHandler.on_handshake, null);
+ if (comptime @hasDecl(Type, "onLongTimeout") and @typeInfo(@TypeOf(Type.onLongTimeout)) != .Null)
+ us_socket_context_on_long_timeout(ssl_int, ctx, SocketHandler.on_long_timeout);
}
pub fn from(socket: *Socket) ThisSocket {
@@ -669,9 +758,9 @@ pub const Timer = opaque {
@as(*@TypeOf(ptr), @ptrCast(@alignCast(value_ptr))).* = ptr;
}
- pub fn deinit(this: *Timer) void {
+ pub fn deinit(this: *Timer, comptime fallthrough: bool) void {
debug("Timer.deinit()", .{});
- us_timer_close(this);
+ us_timer_close(this, @intFromBool(fallthrough));
}
pub fn ext(this: *Timer, comptime Type: type) ?*Type {
@@ -836,12 +925,12 @@ pub const Loop = extern struct {
return us_wakeup_loop(this);
}
- pub fn tick(this: *Loop) void {
- us_loop_run_bun_tick(this, 0);
+ pub fn tick(this: *Loop, ctx: ?*anyopaque) void {
+ us_loop_run_bun_tick(this, 0, ctx);
}
- pub fn tickWithTimeout(this: *Loop, timeoutMs: i64) void {
- us_loop_run_bun_tick(this, timeoutMs);
+ pub fn tickWithTimeout(this: *Loop, timeoutMs: i64, ctx: ?*anyopaque) void {
+ us_loop_run_bun_tick(this, timeoutMs, ctx);
}
pub fn nextTick(this: *Loop, comptime UserType: type, user_data: UserType, comptime deferCallback: fn (ctx: UserType) void) void {
@@ -903,7 +992,7 @@ pub const Loop = extern struct {
extern fn us_loop_free(loop: ?*Loop) void;
extern fn us_loop_ext(loop: ?*Loop) ?*anyopaque;
extern fn us_loop_run(loop: ?*Loop) void;
- extern fn us_loop_run_bun_tick(loop: ?*Loop, timeoutMs: i64) void;
+ extern fn us_loop_run_bun_tick(loop: ?*Loop, timouetMs: i64, ?*anyopaque) void;
extern fn us_wakeup_loop(loop: ?*Loop) void;
extern fn us_loop_integrate(loop: ?*Loop) void;
extern fn us_loop_iteration_number(loop: ?*Loop) c_longlong;
@@ -916,7 +1005,7 @@ const uintmax_t = c_ulong;
extern fn us_create_timer(loop: ?*Loop, fallthrough: i32, ext_size: c_uint) *Timer;
extern fn us_timer_ext(timer: ?*Timer) *?*anyopaque;
-extern fn us_timer_close(timer: ?*Timer) void;
+extern fn us_timer_close(timer: ?*Timer, fallthrough: i32) void;
extern fn us_timer_set(timer: ?*Timer, cb: ?*const fn (*Timer) callconv(.C) void, ms: i32, repeat_ms: i32) void;
extern fn us_timer_loop(t: ?*Timer) ?*Loop;
pub const us_socket_context_options_t = extern struct {
@@ -986,6 +1075,7 @@ extern fn us_socket_context_on_writable(ssl: i32, context: ?*SocketContext, on_w
extern fn us_socket_context_on_handshake(ssl: i32, context: ?*SocketContext, on_handshake: *const fn (*Socket, i32, us_bun_verify_error_t, ?*anyopaque) callconv(.C) void, ?*anyopaque) void;
extern fn us_socket_context_on_timeout(ssl: i32, context: ?*SocketContext, on_timeout: *const fn (*Socket) callconv(.C) ?*Socket) void;
+extern fn us_socket_context_on_long_timeout(ssl: i32, context: ?*SocketContext, on_timeout: *const fn (*Socket) callconv(.C) ?*Socket) void;
extern fn us_socket_context_on_connect_error(ssl: i32, context: ?*SocketContext, on_connect_error: *const fn (*Socket, i32) callconv(.C) ?*Socket) void;
extern fn us_socket_context_on_end(ssl: i32, context: ?*SocketContext, on_end: *const fn (*Socket) callconv(.C) ?*Socket) void;
extern fn us_socket_context_ext(ssl: i32, context: ?*SocketContext) ?*anyopaque;
@@ -1090,6 +1180,7 @@ pub const Poll = opaque {
extern fn us_socket_get_native_handle(ssl: i32, s: ?*Socket) ?*anyopaque;
extern fn us_socket_timeout(ssl: i32, s: ?*Socket, seconds: c_uint) void;
+extern fn us_socket_long_timeout(ssl: i32, s: ?*Socket, seconds: c_uint) void;
extern fn us_socket_ext(ssl: i32, s: ?*Socket) ?*anyopaque;
extern fn us_socket_context(ssl: i32, s: ?*Socket) ?*SocketContext;
extern fn us_socket_flush(ssl: i32, s: ?*Socket) void;
@@ -1106,6 +1197,7 @@ extern fn us_socket_open(ssl: i32, s: ?*Socket, is_client: i32, ip: [*c]const u8
extern fn us_socket_local_port(ssl: i32, s: ?*Socket) i32;
extern fn us_socket_remote_address(ssl: i32, s: ?*Socket, buf: [*c]u8, length: [*c]i32) void;
+extern fn us_socket_local_address(ssl: i32, s: ?*Socket, buf: [*c]u8, length: [*c]i32) void;
pub const uws_app_s = opaque {};
pub const uws_req_s = opaque {};
pub const uws_header_iterator_s = opaque {};
@@ -1405,6 +1497,12 @@ extern fn us_listen_socket_close(ssl: i32, ls: *ListenSocket) void;
extern fn uws_app_close(ssl: i32, app: *uws_app_s) void;
extern fn us_socket_context_close(ssl: i32, ctx: *anyopaque) void;
+pub const SocketAddress = struct {
+ ip: []const u8,
+ port: i32,
+ is_ipv6: bool,
+};
+
pub fn NewApp(comptime ssl: bool) type {
return opaque {
const ssl_flag = @as(i32, @intFromBool(ssl));
@@ -1768,8 +1866,8 @@ pub fn NewApp(comptime ssl: bool) type {
pub fn writeHeaderInt(res: *Response, key: []const u8, value: u64) void {
uws_res_write_header_int(ssl_flag, res.downcast(), key.ptr, key.len, value);
}
- pub fn endWithoutBody(res: *Response, _: bool) void {
- uws_res_end_without_body(ssl_flag, res.downcast());
+ pub fn endWithoutBody(res: *Response, close_connection: bool) void {
+ uws_res_end_without_body(ssl_flag, res.downcast(), close_connection);
}
pub fn write(res: *Response, data: []const u8) bool {
return uws_res_write(ssl_flag, res.downcast(), data.ptr, data.len);
@@ -1787,6 +1885,33 @@ pub fn NewApp(comptime ssl: bool) type {
pub fn getNativeHandle(res: *Response) i32 {
return @as(i32, @intCast(@intFromPtr(uws_res_get_native_handle(ssl_flag, res.downcast()))));
}
+ pub fn getRemoteAddress(res: *Response) ?[]const u8 {
+ var buf: [*]const u8 = undefined;
+ const size = uws_res_get_remote_address(ssl_flag, res.downcast(), &buf);
+ return if (size > 0) buf[0..size] else null;
+ }
+ pub fn getRemoteAddressAsText(res: *Response) ?[]const u8 {
+ var buf: [*]const u8 = undefined;
+ const size = uws_res_get_remote_address_as_text(ssl_flag, res.downcast(), &buf);
+ return if (size > 0) buf[0..size] else null;
+ }
+ pub fn getRemoteSocketInfo(res: *Response) ?SocketAddress {
+ var address = SocketAddress{
+ .ip = undefined,
+ .port = undefined,
+ .is_ipv6 = undefined,
+ };
+ // This function will fill in the slots and return len.
+ // if len is zero it will not fill in the slots so it is ub to
+ // return the struct in that case.
+ address.ip.len = uws_res_get_remote_address_info(
+ res.downcast(),
+ &address.ip.ptr,
+ &address.port,
+ &address.is_ipv6,
+ );
+ return if (address.ip.len > 0) address else null;
+ }
pub fn onWritable(
res: *Response,
comptime UserDataType: type,
@@ -2070,6 +2195,8 @@ pub fn NewApp(comptime ssl: bool) type {
extern fn uws_res_end_stream(ssl: i32, res: *uws_res, close_connection: bool) void;
extern fn uws_res_prepare_for_sendfile(ssl: i32, res: *uws_res) void;
extern fn uws_res_get_native_handle(ssl: i32, res: *uws_res) *Socket;
+extern fn uws_res_get_remote_address(ssl: i32, res: *uws_res, dest: *[*]const u8) usize;
+extern fn uws_res_get_remote_address_as_text(ssl: i32, res: *uws_res, dest: *[*]const u8) usize;
extern fn uws_create_app(ssl: i32, options: us_bun_socket_context_options_t) *uws_app_t;
extern fn uws_app_destroy(ssl: i32, app: *uws_app_t) void;
extern fn uws_app_get(ssl: i32, app: *uws_app_t, pattern: [*c]const u8, handler: uws_method_handler, user_data: ?*anyopaque) void;
@@ -2123,6 +2250,8 @@ extern fn uws_ws_publish_with_options(ssl: i32, ws: ?*RawWebSocket, topic: [*c]c
extern fn uws_ws_get_buffered_amount(ssl: i32, ws: ?*RawWebSocket) c_uint;
extern fn uws_ws_get_remote_address(ssl: i32, ws: ?*RawWebSocket, dest: *[*]u8) usize;
extern fn uws_ws_get_remote_address_as_text(ssl: i32, ws: ?*RawWebSocket, dest: *[*]u8) usize;
+extern fn uws_res_get_remote_address_info(res: *uws_res, dest: *[*]const u8, port: *i32, is_ipv6: *bool) usize;
+
const uws_res = opaque {};
extern fn uws_res_uncork(ssl: i32, res: *uws_res) void;
extern fn uws_res_end(ssl: i32, res: *uws_res, data: [*c]const u8, length: usize, close_connection: bool) void;
@@ -2140,7 +2269,7 @@ extern fn uws_res_write_continue(ssl: i32, res: *uws_res) void;
extern fn uws_res_write_status(ssl: i32, res: *uws_res, status: [*c]const u8, length: usize) void;
extern fn uws_res_write_header(ssl: i32, res: *uws_res, key: [*c]const u8, key_length: usize, value: [*c]const u8, value_length: usize) void;
extern fn uws_res_write_header_int(ssl: i32, res: *uws_res, key: [*c]const u8, key_length: usize, value: u64) void;
-extern fn uws_res_end_without_body(ssl: i32, res: *uws_res) void;
+extern fn uws_res_end_without_body(ssl: i32, res: *uws_res, close_connection: bool) void;
extern fn uws_res_write(ssl: i32, res: *uws_res, data: [*c]const u8, length: usize) bool;
extern fn uws_res_get_write_offset(ssl: i32, res: *uws_res) uintmax_t;
extern fn uws_res_override_write_offset(ssl: i32, res: *uws_res, uintmax_t) void;