diff options
Diffstat (limited to 'src/deps')
-rw-r--r-- | src/deps/_libusockets.h | 5 | ||||
-rw-r--r-- | src/deps/c_ares.zig | 134 | ||||
-rw-r--r-- | src/deps/libuwsockets.cpp | 64 | ||||
-rw-r--r-- | src/deps/lol-html.zig | 2 | ||||
-rw-r--r-- | src/deps/uws.zig | 151 |
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; |