diff options
-rw-r--r-- | Makefile | 24 | ||||
-rw-r--r-- | src/http.zig | 87 | ||||
-rw-r--r-- | src/io/io_darwin.zig | 2 | ||||
-rw-r--r-- | src/javascript/jsc/node/syscall.zig | 46 |
4 files changed, 116 insertions, 43 deletions
@@ -61,11 +61,11 @@ CC = $(shell which clang-13 || which clang) CXX = $(shell which clang++-13 || which clang++) ifeq ($(OS_NAME),darwin) -# LLVM_PREFIX = $(shell brew --prefix llvm) -# LDFLAGS += " -L$(LLVM_PREFIX)/lib" -# CPPFLAGS += " -I$(LLVM_PREFIX)/include" -CC = /usr/bin/clang -CXX = /usr/bin/clang++ +LLVM_PREFIX = $(shell brew --prefix llvm) +LDFLAGS += " -L$(LLVM_PREFIX)/lib" +CPPFLAGS += " -I$(LLVM_PREFIX)/include" +CC = $(LLVM_PREFIX)/bin/clang +CXX = $(LLVM_PREFIX)/bin/clang++ CODESIGN_IDENTITY ?= $(shell security find-identity -v -p codesigning | awk '/Apple Development/ { print $$2 }') endif @@ -948,19 +948,21 @@ jsc-bindings-mac: $(OBJ_FILES) $(WEBCORE_OBJ_FILES) mimalloc-debug: rm -rf $(BUN_DEPS_DIR)/mimalloc/CMakeCache* $(BUN_DEPS_DIR)/mimalloc/CMakeFiles cd $(BUN_DEPS_DIR)/mimalloc; make clean || echo ""; \ - CFLAGS="$(CFLAGS)" cmake $(CMAKE_FLAGS_WITHOUT_RELEASE) \ + CFLAGS="$(CFLAGS)" cmake $(CMAKE_FLAGS_WITHOUT_RELEASE) ${MIMALLOC_OVERRIDE_FLAG} \ -DCMAKE_BUILD_TYPE=Debug \ -DMI_DEBUG_FULL=1 \ -DMI_SKIP_COLLECT_ON_EXIT=1 \ -DMI_BUILD_SHARED=OFF \ -DMI_BUILD_STATIC=ON \ -DMI_BUILD_TESTS=OFF \ - -DMI_BUILD_OBJECT=ON \ - -DMI_BUILD_OBJECT=ON \ -DMI_OSX_ZONE=OFF \ -DMI_OSX_INTERPOSE=OFF \ - ${MIMALLOC_OVERRIDE_FLAG} \ - -DMI_USE_CXX=OFF .\ + -DMI_BUILD_OBJECT=ON \ + -DMI_USE_CXX=ON \ + -DMI_OVERRIDE=OFF \ + -DCMAKE_C_FLAGS="$(CFLAGS)" \ + -DCMAKE_CXX_FLAGS="$(CFLAGS)" \ + . \ && make -j $(CPUS); cp $(BUN_DEPS_DIR)/mimalloc/$(_MIMALLOC_DEBUG_FILE) $(BUN_DEPS_OUT_DIR)/$(MIMALLOC_FILE) @@ -980,7 +982,7 @@ mimalloc: -DMI_OSX_INTERPOSE=OFF \ -DMI_BUILD_OBJECT=ON \ -DMI_USE_CXX=ON \ - -DMI_OVERRIDE=ON \ + -DMI_OVERRIDE=OFF \ -DCMAKE_C_FLAGS="$(CFLAGS)" \ -DCMAKE_CXX_FLAGS="$(CFLAGS)" \ ${MIMALLOC_OVERRIDE_FLAG} \ diff --git a/src/http.zig b/src/http.zig index 973b0532f..430a72a6e 100644 --- a/src/http.zig +++ b/src/http.zig @@ -73,6 +73,7 @@ threadlocal var res_headers_buf: [100]picohttp.Header = undefined; const sync = @import("./sync.zig"); const JavaScript = @import("javascript_core"); const JavaScriptCore = JavaScriptCore.C; +const Syscall = JavaScript.Node.Syscall; const Router = @import("./router.zig"); pub const Watcher = watcher.NewWatcher(*Server); const ZigURL = @import("./url.zig").URL; @@ -663,18 +664,29 @@ pub const RequestContext = struct { _ = try ctx.writeSocket(writer.getWritten(), SOCKET_FLAGS); } + const AsyncIO = @import("io"); pub fn writeSocket(ctx: *RequestContext, buf: anytype, _: anytype) !usize { // ctx.conn.client.setWriteBufferSize(@intCast(u32, buf.len)) catch {}; - const written = ctx.conn.client.write(buf, SOCKET_FLAGS) catch |err| { - Output.printError("Write error: {s}", .{@errorName(err)}); - return err; - }; - if (written == 0) { - return error.SocketClosed; - } + switch (Syscall.send(ctx.conn.client.socket.fd, buf, SOCKET_FLAGS)) { + .err => |err| { + const erro = AsyncIO.asError(err.getErrno()); + if (erro == error.EBADF or erro == error.ECONNABORTED or erro == error.ECONNREFUSED) { + return error.SocketClosed; + } + + Output.prettyErrorln("send() error: {s}", .{err.toSystemError().message.slice()}); + + return erro; + }, + .result => |written| { + if (written == 0) { + return error.SocketClosed; + } - return written; + return written; + }, + } } pub fn writeBodyBuf(ctx: *RequestContext, body: []const u8) !void { @@ -707,14 +719,15 @@ pub const RequestContext = struct { } pub fn init( + this: *RequestContext, req: Request, arena: ThreadlocalArena, conn: *tcp.Connection, bundler_: *Bundler, watcher_: *Watcher, timer: std.time.Timer, - ) !RequestContext { - var ctx = RequestContext{ + ) !void { + this.* = RequestContext{ .request = req, .arena = arena, .bundler = bundler_, @@ -727,8 +740,6 @@ pub const RequestContext = struct { .timer = timer, .origin = bundler_.options.origin, }; - - return ctx; } // not all browsers send this @@ -1676,8 +1687,8 @@ pub const RequestContext = struct { clone.websocket = Websocket.Websocket.create(&clone.conn, SOCKET_FLAGS); clone.tombstone = false; - clone.ctx.allocator = undefined; - clone.ctx.arena.deinit(); + ctx.allocator = undefined; + ctx.arena.deinit(); try open_websockets.append(clone); return clone; @@ -1771,25 +1782,27 @@ pub const RequestContext = struct { websocket_printer, ); - _handle(self) catch {}; - } + self.ctx.arena = ThreadlocalArena.init() catch unreachable; + self.ctx.allocator = self.ctx.arena.allocator(); + self.builder.bundler.resolver.caches = CacheSet.init(self.ctx.allocator); + self.builder.bundler.resolver.caches.fs.stream = true; - fn _handle(handler: *WebsocketHandler) !void { - var ctx = &handler.ctx; - ctx.arena = ThreadlocalArena.init() catch unreachable; - ctx.allocator = ctx.arena.allocator(); - handler.builder.bundler.resolver.caches = CacheSet.init(ctx.allocator); - handler.builder.bundler.resolver.caches.fs.stream = true; + _handle(self, &self.ctx) catch {}; + } + fn _handle(handler: *WebsocketHandler, ctx: *RequestContext) !void { var is_socket_closed = false; + const fd = ctx.conn.client.socket.fd; defer { websocket_printer = handler.builder.printer.ctx; handler.tombstone = true; removeWebsocket(handler); + ctx.arena.deinit(); if (!is_socket_closed) { - ctx.conn.deinit(); + _ = Syscall.close(fd); } + bun.default_allocator.destroy(handler); Output.flush(); } @@ -1826,8 +1839,20 @@ pub const RequestContext = struct { ctx.appendHeader("Upgrade", "websocket"); ctx.appendHeader("Sec-WebSocket-Accept", key); ctx.appendHeader("Sec-WebSocket-Protocol", "bun-hmr"); - try ctx.writeStatus(101); - try ctx.flushHeaders(); + ctx.writeStatus(101) catch |err| { + if (err == error.SocketClosed) { + is_socket_closed = true; + } + + return; + }; + ctx.flushHeaders() catch |err| { + if (err == error.SocketClosed) { + is_socket_closed = true; + } + + return; + }; // Output.prettyErrorln("<r><green>101<r><d> Hot Module Reloading connected.<r>", .{}); // Output.flush(); Analytics.Features.hot_module_reloading = true; @@ -3656,14 +3681,16 @@ pub const Server = struct { var req = picohttp.Request.parse(req_buf_node.data[0..read_size], &req_headers_buf) catch |err| { _ = conn.client.write(RequestContext.printStatusLine(400) ++ "\r\n\r\n", SOCKET_FLAGS) catch {}; - conn.client.deinit(); + _ = Syscall.close(conn.client.socket.fd); Output.printErrorln("ERR: {s}", .{@errorName(err)}); return; }; var request_arena = ThreadlocalArena.init() catch unreachable; + var request_allocator = request_arena.allocator(); + var req_ctx = request_allocator.create(RequestContext) catch unreachable; - req_ctx_ = RequestContext.init( + req_ctx.init( req, request_arena, conn, @@ -3672,15 +3699,15 @@ pub const Server = struct { server.timer, ) catch |err| { Output.prettyErrorln("<r>[<red>{s}<r>] - <b>{s}<r>: {s}", .{ @errorName(err), req.method, req.path }); - conn.client.deinit(); + _ = Syscall.close(conn.client.socket.fd); + request_arena.deinit(); return; }; - var req_ctx = &req_ctx_; req_ctx.req_body_node = req_buf_node; req_ctx.timer.reset(); - const is_navigation_request = req_ctx_.isBrowserNavigation(); + const is_navigation_request = req_ctx.isBrowserNavigation(); defer if (is_navigation_request == .yes) Analytics.enqueue(Analytics.EventName.http_build); req_ctx.parseOrigin(); // req_ctx.appendHeader("Date", value: string) diff --git a/src/io/io_darwin.zig b/src/io/io_darwin.zig index c3175a0ed..b399ce62f 100644 --- a/src/io/io_darwin.zig +++ b/src/io/io_darwin.zig @@ -259,7 +259,7 @@ const fd_t = os.fd_t; const mem = std.mem; const assert = std.debug.assert; const c = std.c; -const darwin = struct { +pub const darwin = struct { pub usingnamespace os.darwin; pub extern "c" fn @"recvfrom$NOCANCEL"(sockfd: c.fd_t, noalias buf: *anyopaque, len: usize, flags: u32, noalias src_addr: ?*c.sockaddr, noalias addrlen: ?*c.socklen_t) isize; pub extern "c" fn @"sendto$NOCANCEL"(sockfd: c.fd_t, buf: *const anyopaque, len: usize, flags: u32, dest_addr: ?*const c.sockaddr, addrlen: c.socklen_t) isize; diff --git a/src/javascript/jsc/node/syscall.zig b/src/javascript/jsc/node/syscall.zig index d51062a83..cd7a56157 100644 --- a/src/javascript/jsc/node/syscall.zig +++ b/src/javascript/jsc/node/syscall.zig @@ -17,7 +17,7 @@ const C = @import("../../../global.zig").C; const linux = os.linux; const Maybe = JSC.Node.Maybe; -pub const system = if (Environment.isLinux) linux else darwin; +pub const system = if (Environment.isLinux) linux else @import("io").darwin; pub const S = struct { pub usingnamespace if (Environment.isLinux) linux.S else std.os.S; }; @@ -88,6 +88,8 @@ pub const Tag = enum(u8) { getcwd, chdir, fcopyfile, + recv, + send, pub var strings = std.EnumMap(Tag, JSC.C.JSStringRef).initFull(null); }; @@ -273,6 +275,48 @@ pub fn read(fd: os.fd_t, buf: []u8) Maybe(usize) { unreachable; } +pub fn recv(fd: os.fd_t, buf: []u8, flag: u32) Maybe(usize) { + if (comptime Environment.isMac) { + const rc = system.@"recvfrom$NOCANCEL"(fd, buf.ptr, bun.len, flag, null, null); + if (Maybe(usize).errnoSys(rc, .recv)) |err| { + return err; + } + return Maybe(usize){ .result = @intCast(usize, rc) }; + } else { + while (true) { + const rc = linux.recvfrom(fd, buf.ptr, bun.len, flag | os.SOCK.CLOEXEC | os.MSG.NOSIGNAL, null, null); + if (Maybe(usize).errnoSys(rc, .recv)) |err| { + if (err.getErrno() == .INTR) continue; + return err; + } + return Maybe(usize){ .result = @intCast(usize, rc) }; + } + } + unreachable; +} + +pub fn send(fd: os.fd_t, buf: []const u8, flag: u32) Maybe(usize) { + if (comptime Environment.isMac) { + const rc = system.@"sendto$NOCANCEL"(fd, buf.ptr, buf.len, flag, null, 0); + if (Maybe(usize).errnoSys(rc, .send)) |err| { + return err; + } + return Maybe(usize){ .result = @intCast(usize, rc) }; + } else { + while (true) { + const rc = linux.sendto(fd, buf.ptr, buf.len, flag | os.SOCK.CLOEXEC | os.MSG.NOSIGNAL, null, 0); + + if (Maybe(usize).errnoSys(rc, .send)) |err| { + if (err.getErrno() == .INTR) continue; + return err; + } + + return Maybe(usize){ .result = @intCast(usize, rc) }; + } + } + unreachable; +} + pub fn readlink(in: [:0]const u8, buf: []u8) Maybe(usize) { while (true) { const rc = sys.readlink(in, buf.ptr, buf.len); |