aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile13
-rw-r--r--build.zig9
-rw-r--r--integration/bunjs-only-snippets/crypto.test.js28
-rw-r--r--src/boringssl.zig (renamed from src/deps/boringssl.zig)16
m---------src/deps/boringssl0
-rw-r--r--src/deps/boringssl.translated.zig56
-rw-r--r--src/fallback.version2
-rw-r--r--src/io/io_darwin.zig52
-rw-r--r--src/javascript/jsc/api/bun.zig214
-rw-r--r--src/javascript/jsc/base.zig136
-rw-r--r--src/sha.zig145
11 files changed, 601 insertions, 70 deletions
diff --git a/Makefile b/Makefile
index 7b6965d2c..018bedae9 100644
--- a/Makefile
+++ b/Makefile
@@ -548,7 +548,12 @@ fetch:
$(ZIG) build -Drelease-fast fetch-obj
$(CXX) $(PACKAGE_DIR)/fetch.o -g $(OPTIMIZATION_LEVEL) -o ./misctools/fetch $(DEFAULT_LINKER_FLAGS) -lc $(ARCHIVE_FILES)
rm -rf $(PACKAGE_DIR)/fetch.o
-
+
+sha:
+ $(ZIG) build -Drelease-fast sha-bench-obj
+ $(CXX) $(PACKAGE_DIR)/sha.o -g $(OPTIMIZATION_LEVEL) -o ./misctools/sha $(DEFAULT_LINKER_FLAGS) -lc $(ARCHIVE_FILES)
+ rm -rf $(PACKAGE_DIR)/sha.o
+
fetch-debug:
$(ZIG) build fetch-obj
$(CXX) $(DEBUG_PACKAGE_DIR)/fetch.o -g $(OPTIMIZATION_LEVEL) -o ./misctools/fetch $(DEFAULT_LINKER_FLAGS) -lc $(ARCHIVE_FILES)
@@ -979,7 +984,7 @@ mimalloc:
-DMI_OSX_INTERPOSE=OFF \
-DMI_BUILD_OBJECT=ON \
-DMI_USE_CXX=ON \
- -DMI_OVERRIDE=OFF \
+ -DMI_OVERRIDE=ON \
-DCMAKE_C_FLAGS="$(CFLAGS)" \
-DCMAKE_CXX_FLAGS="$(CFLAGS)" \
${MIMALLOC_OVERRIDE_FLAG} \
@@ -1173,7 +1178,7 @@ endif
build-unit:
@rm -rf zig-out/bin/$(testname)
@mkdir -p zig-out/bin
- zig test $(realpath $(testpath)) \
+ zig test $(realpath $(testpath)) \
$(testfilterflag) \
$(PACKAGE_MAP) \
--main-pkg-path $(BUN_DIR) \
@@ -1225,7 +1230,7 @@ copy-to-bun-release-dir-bin:
cp -r $(PACKAGE_DIR)/bun-profile $(BUN_RELEASE_DIR)/bun-profile
-PACKAGE_MAP = --pkg-begin thread_pool $(BUN_DIR)/src/thread_pool.zig --pkg-begin io $(BUN_DIR)/src/io/io_$(OS_NAME).zig --pkg-end --pkg-begin http $(BUN_DIR)/src/http_client_async.zig --pkg-begin strings $(BUN_DIR)/src/string_immutable.zig --pkg-end --pkg-begin picohttp $(BUN_DIR)/src/deps/picohttp.zig --pkg-end --pkg-begin io $(BUN_DIR)/src/io/io_darwin.zig --pkg-end --pkg-begin boringssl $(BUN_DIR)/src/deps/boringssl.zig --pkg-end --pkg-begin thread_pool $(BUN_DIR)/src/thread_pool.zig --pkg-begin io $(BUN_DIR)/src/io/io_darwin.zig --pkg-end --pkg-begin http $(BUN_DIR)/src/http_client_async.zig --pkg-begin strings $(BUN_DIR)/src/string_immutable.zig --pkg-end --pkg-begin picohttp $(BUN_DIR)/src/deps/picohttp.zig --pkg-end --pkg-begin io $(BUN_DIR)/src/io/io_darwin.zig --pkg-end --pkg-begin boringssl $(BUN_DIR)/src/deps/boringssl.zig --pkg-end --pkg-begin thread_pool $(BUN_DIR)/src/thread_pool.zig --pkg-end --pkg-end --pkg-end --pkg-end --pkg-end --pkg-begin picohttp $(BUN_DIR)/src/deps/picohttp.zig --pkg-end --pkg-begin io $(BUN_DIR)/src/io/io_darwin.zig --pkg-end --pkg-begin strings $(BUN_DIR)/src/string_immutable.zig --pkg-end --pkg-begin clap $(BUN_DIR)/src/deps/zig-clap/clap.zig --pkg-end --pkg-begin http $(BUN_DIR)/src/http_client_async.zig --pkg-begin strings $(BUN_DIR)/src/string_immutable.zig --pkg-end --pkg-begin picohttp $(BUN_DIR)/src/deps/picohttp.zig --pkg-end --pkg-begin io $(BUN_DIR)/src/io/io_darwin.zig --pkg-end --pkg-begin boringssl $(BUN_DIR)/src/deps/boringssl.zig --pkg-end --pkg-begin thread_pool $(BUN_DIR)/src/thread_pool.zig --pkg-begin io $(BUN_DIR)/src/io/io_darwin.zig --pkg-end --pkg-begin http $(BUN_DIR)/src/http_client_async.zig --pkg-begin strings $(BUN_DIR)/src/string_immutable.zig --pkg-end --pkg-begin picohttp $(BUN_DIR)/src/deps/picohttp.zig --pkg-end --pkg-begin io $(BUN_DIR)/src/io/io_darwin.zig --pkg-end --pkg-begin boringssl $(BUN_DIR)/src/deps/boringssl.zig --pkg-end --pkg-begin thread_pool $(BUN_DIR)/src/thread_pool.zig --pkg-end --pkg-end --pkg-end --pkg-end --pkg-begin boringssl $(BUN_DIR)/src/deps/boringssl.zig --pkg-end --pkg-begin javascript_core $(BUN_DIR)/src/jsc.zig --pkg-begin http $(BUN_DIR)/src/http_client_async.zig --pkg-end --pkg-begin strings $(BUN_DIR)/src/string_immutable.zig --pkg-end --pkg-begin picohttp $(BUN_DIR)/src/deps/picohttp.zig --pkg-end --pkg-end
+PACKAGE_MAP = --pkg-begin thread_pool $(BUN_DIR)/src/thread_pool.zig --pkg-begin io $(BUN_DIR)/src/io/io_$(OS_NAME).zig --pkg-end --pkg-begin http $(BUN_DIR)/src/http_client_async.zig --pkg-begin strings $(BUN_DIR)/src/string_immutable.zig --pkg-end --pkg-begin picohttp $(BUN_DIR)/src/deps/picohttp.zig --pkg-end --pkg-begin io $(BUN_DIR)/src/io/io_darwin.zig --pkg-end --pkg-begin boringssl $(BUN_DIR)/src/boringssl.zig --pkg-end --pkg-begin thread_pool $(BUN_DIR)/src/thread_pool.zig --pkg-begin io $(BUN_DIR)/src/io/io_darwin.zig --pkg-end --pkg-begin http $(BUN_DIR)/src/http_client_async.zig --pkg-begin strings $(BUN_DIR)/src/string_immutable.zig --pkg-end --pkg-begin picohttp $(BUN_DIR)/src/deps/picohttp.zig --pkg-end --pkg-begin io $(BUN_DIR)/src/io/io_darwin.zig --pkg-end --pkg-begin boringssl $(BUN_DIR)/src/boringssl.zig --pkg-end --pkg-begin thread_pool $(BUN_DIR)/src/thread_pool.zig --pkg-end --pkg-end --pkg-end --pkg-end --pkg-end --pkg-begin picohttp $(BUN_DIR)/src/deps/picohttp.zig --pkg-end --pkg-begin io $(BUN_DIR)/src/io/io_darwin.zig --pkg-end --pkg-begin strings $(BUN_DIR)/src/string_immutable.zig --pkg-end --pkg-begin clap $(BUN_DIR)/src/deps/zig-clap/clap.zig --pkg-end --pkg-begin http $(BUN_DIR)/src/http_client_async.zig --pkg-begin strings $(BUN_DIR)/src/string_immutable.zig --pkg-end --pkg-begin picohttp $(BUN_DIR)/src/deps/picohttp.zig --pkg-end --pkg-begin io $(BUN_DIR)/src/io/io_darwin.zig --pkg-end --pkg-begin boringssl $(BUN_DIR)/src/boringssl.zig --pkg-end --pkg-begin thread_pool $(BUN_DIR)/src/thread_pool.zig --pkg-begin io $(BUN_DIR)/src/io/io_darwin.zig --pkg-end --pkg-begin http $(BUN_DIR)/src/http_client_async.zig --pkg-begin strings $(BUN_DIR)/src/string_immutable.zig --pkg-end --pkg-begin picohttp $(BUN_DIR)/src/deps/picohttp.zig --pkg-end --pkg-begin io $(BUN_DIR)/src/io/io_darwin.zig --pkg-end --pkg-begin boringssl $(BUN_DIR)/src/boringssl.zig --pkg-end --pkg-begin thread_pool $(BUN_DIR)/src/thread_pool.zig --pkg-end --pkg-end --pkg-end --pkg-end --pkg-begin boringssl $(BUN_DIR)/src/boringssl.zig --pkg-end --pkg-begin javascript_core $(BUN_DIR)/src/jsc.zig --pkg-begin http $(BUN_DIR)/src/http_client_async.zig --pkg-end --pkg-begin strings $(BUN_DIR)/src/string_immutable.zig --pkg-end --pkg-begin picohttp $(BUN_DIR)/src/deps/picohttp.zig --pkg-end --pkg-end
bun: vendor identifier-cache build-obj bun-link-lld-release bun-codesign-release-local
diff --git a/build.zig b/build.zig
index 4f1052910..ef6f85534 100644
--- a/build.zig
+++ b/build.zig
@@ -43,7 +43,7 @@ const color_map = std.ComptimeStringMap([]const u8, .{
fn addInternalPackages(step: *std.build.LibExeObjStep, _: std.mem.Allocator, target: anytype) !void {
var boringssl: std.build.Pkg = .{
.name = "boringssl",
- .path = pkgPath("src/deps/boringssl.zig"),
+ .path = pkgPath("src/boringssl.zig"),
};
var datetime: std.build.Pkg = .{
@@ -405,6 +405,13 @@ pub fn build(b: *std.build.Builder) !void {
}
{
+ const headers_step = b.step("sha-bench-obj", "Build sha bench");
+ var headers_obj: *std.build.LibExeObjStep = b.addObject("sha", "src/sha.zig");
+ defer headers_step.dependOn(&headers_obj.step);
+ try configureObjectStep(b, headers_obj, target, obj.main_pkg_path.?);
+ }
+
+ {
const headers_step = b.step("vlq-bench", "Build vlq bench");
var headers_obj: *std.build.LibExeObjStep = b.addExecutable("vlq-bench", "src/sourcemap/vlq_bench.zig");
defer headers_step.dependOn(&headers_obj.step);
diff --git a/integration/bunjs-only-snippets/crypto.test.js b/integration/bunjs-only-snippets/crypto.test.js
new file mode 100644
index 000000000..344d935d5
--- /dev/null
+++ b/integration/bunjs-only-snippets/crypto.test.js
@@ -0,0 +1,28 @@
+import { it, expect } from "bun:test";
+
+for (let Hasher of [
+ Bun.SHA1,
+ Bun.SHA256,
+ Bun.SHA384,
+ Bun.SHA512,
+ Bun.SHA512_256,
+]) {
+ it(`${Hasher.name} instance`, () => {
+ var buf = new Uint8Array(256);
+ const result = new Hasher();
+ result.update("hello world");
+ result.final(buf);
+ });
+}
+
+for (let HashFn of [
+ Bun.sha1,
+ Bun.sha256,
+ Bun.sha384,
+ Bun.sha512,
+ Bun.sha512_256,
+]) {
+ it(`${HashFn.name} instance`, () => {
+ HashFn("hello world");
+ });
+}
diff --git a/src/deps/boringssl.zig b/src/boringssl.zig
index 2089bc1d2..b0a52e358 100644
--- a/src/deps/boringssl.zig
+++ b/src/boringssl.zig
@@ -1,7 +1,8 @@
-const boring = @import("./boringssl.translated.zig");
+const boring = @import("./deps/boringssl.translated.zig");
pub usingnamespace boring;
const std = @import("std");
-const global = @import("../global.zig");
+
+const builtin = @import("builtin");
var loaded = false;
pub fn load() void {
if (loaded) return;
@@ -52,16 +53,19 @@ pub fn initClient() *boring.SSL {
// may result in deadlocks, crashes, or memory corruption.
export fn OPENSSL_memory_alloc(size: usize) ?*anyopaque {
+ const global = @import("./global.zig");
return global.Global.Mimalloc.mi_malloc(size);
}
// BoringSSL always expects memory to be zero'd
export fn OPENSSL_memory_free(ptr: *anyopaque) void {
+ const global = @import("./global.zig");
@memset(@ptrCast([*]u8, ptr), 0, global.Global.Mimalloc.mi_usable_size(ptr));
global.Global.Mimalloc.mi_free(ptr);
}
export fn OPENSSL_memory_get_size(ptr: ?*const anyopaque) usize {
+ const global = @import("./global.zig");
return global.Global.Mimalloc.mi_usable_size(ptr);
}
@@ -70,7 +74,9 @@ test "load" {
}
comptime {
- _ = OPENSSL_memory_alloc;
- _ = OPENSSL_memory_free;
- _ = OPENSSL_memory_get_size;
+ if (!builtin.is_test) {
+ _ = OPENSSL_memory_alloc;
+ _ = OPENSSL_memory_free;
+ _ = OPENSSL_memory_get_size;
+ }
}
diff --git a/src/deps/boringssl b/src/deps/boringssl
-Subproject b3ed071ecc4efb77afd0a025ea1078da19578bf
+Subproject fa3fbda07bbf70925453d6a3c25a7aa455aa1ce
diff --git a/src/deps/boringssl.translated.zig b/src/deps/boringssl.translated.zig
index b30d99e7e..17bb1af9d 100644
--- a/src/deps/boringssl.translated.zig
+++ b/src/deps/boringssl.translated.zig
@@ -2747,34 +2747,34 @@ pub extern fn RSA_verify_PKCS1_PSS(rsa: ?*const RSA, mHash: [*c]const u8, Hash:
pub extern fn RSA_padding_add_PKCS1_OAEP(to: [*c]u8, to_len: usize, from: [*c]const u8, from_len: usize, param: [*c]const u8, param_len: usize) c_int;
pub extern fn RSA_print(bio: [*c]BIO, rsa: ?*const RSA, indent: c_int) c_int;
pub extern fn RSA_get0_pss_params(rsa: ?*const RSA) [*c]const RSA_PSS_PARAMS;
-pub extern fn SHA1_Init(sha: [*c]SHA_CTX) c_int;
-pub extern fn SHA1_Update(sha: [*c]SHA_CTX, data: ?*const anyopaque, len: usize) c_int;
-pub extern fn SHA1_Final(out: [*c]u8, sha: [*c]SHA_CTX) c_int;
-pub extern fn SHA1(data: [*c]const u8, len: usize, out: [*c]u8) [*c]u8;
-pub extern fn SHA1_Transform(sha: [*c]SHA_CTX, block: [*c]const u8) void;
-pub extern fn SHA224_Init(sha: [*c]SHA256_CTX) c_int;
-pub extern fn SHA224_Update(sha: [*c]SHA256_CTX, data: ?*const anyopaque, len: usize) c_int;
-pub extern fn SHA224_Final(out: [*c]u8, sha: [*c]SHA256_CTX) c_int;
-pub extern fn SHA224(data: [*c]const u8, len: usize, out: [*c]u8) [*c]u8;
-pub extern fn SHA256_Init(sha: [*c]SHA256_CTX) c_int;
-pub extern fn SHA256_Update(sha: [*c]SHA256_CTX, data: ?*const anyopaque, len: usize) c_int;
-pub extern fn SHA256_Final(out: [*c]u8, sha: [*c]SHA256_CTX) c_int;
-pub extern fn SHA256(data: [*c]const u8, len: usize, out: [*c]u8) [*c]u8;
-pub extern fn SHA256_Transform(sha: [*c]SHA256_CTX, block: [*c]const u8) void;
-pub extern fn SHA256_TransformBlocks(state: [*c]u32, data: [*c]const u8, num_blocks: usize) void;
-pub extern fn SHA384_Init(sha: [*c]SHA512_CTX) c_int;
-pub extern fn SHA384_Update(sha: [*c]SHA512_CTX, data: ?*const anyopaque, len: usize) c_int;
-pub extern fn SHA384_Final(out: [*c]u8, sha: [*c]SHA512_CTX) c_int;
-pub extern fn SHA384(data: [*c]const u8, len: usize, out: [*c]u8) [*c]u8;
-pub extern fn SHA512_Init(sha: [*c]SHA512_CTX) c_int;
-pub extern fn SHA512_Update(sha: [*c]SHA512_CTX, data: ?*const anyopaque, len: usize) c_int;
-pub extern fn SHA512_Final(out: [*c]u8, sha: [*c]SHA512_CTX) c_int;
-pub extern fn SHA512(data: [*c]const u8, len: usize, out: [*c]u8) [*c]u8;
-pub extern fn SHA512_Transform(sha: [*c]SHA512_CTX, block: [*c]const u8) void;
-pub extern fn SHA512_256_Init(sha: [*c]SHA512_CTX) c_int;
-pub extern fn SHA512_256_Update(sha: [*c]SHA512_CTX, data: ?*const anyopaque, len: usize) c_int;
-pub extern fn SHA512_256_Final(out: [*c]u8, sha: [*c]SHA512_CTX) c_int;
-pub extern fn SHA512_256(data: [*c]const u8, len: usize, out: [*c]u8) [*c]u8;
+pub extern fn SHA1_Init(sha: *SHA_CTX) c_int;
+pub extern fn SHA1_Update(sha: *SHA_CTX, data: ?*const anyopaque, len: usize) c_int;
+pub extern fn SHA1_Final(out: [*]u8, sha: *SHA_CTX) c_int;
+pub extern fn SHA1(data: [*]const u8, len: usize, out: [*]u8) [*]u8;
+pub extern fn SHA1_Transform(sha: *SHA_CTX, block: [*]const u8) void;
+pub extern fn SHA224_Init(sha: *SHA256_CTX) c_int;
+pub extern fn SHA224_Update(sha: *SHA256_CTX, data: ?*const anyopaque, len: usize) c_int;
+pub extern fn SHA224_Final(out: [*]u8, sha: *SHA256_CTX) c_int;
+pub extern fn SHA224(data: [*]const u8, len: usize, out: [*]u8) [*]u8;
+pub extern fn SHA256_Init(sha: *SHA256_CTX) c_int;
+pub extern fn SHA256_Update(sha: *SHA256_CTX, data: ?*const anyopaque, len: usize) c_int;
+pub extern fn SHA256_Final(out: [*]u8, sha: *SHA256_CTX) c_int;
+pub extern fn SHA256(data: [*]const u8, len: usize, out: [*]u8) [*]u8;
+pub extern fn SHA256_Transform(sha: *SHA256_CTX, block: [*]const u8) void;
+pub extern fn SHA256_TransformBlocks(state: [*c]u32, data: [*]const u8, num_blocks: usize) void;
+pub extern fn SHA384_Init(sha: *SHA512_CTX) c_int;
+pub extern fn SHA384_Update(sha: *SHA512_CTX, data: ?*const anyopaque, len: usize) c_int;
+pub extern fn SHA384_Final(out: [*]u8, sha: *SHA512_CTX) c_int;
+pub extern fn SHA384(data: [*]const u8, len: usize, out: [*]u8) [*]u8;
+pub extern fn SHA512_Init(sha: *SHA512_CTX) c_int;
+pub extern fn SHA512_Update(sha: *SHA512_CTX, data: ?*const anyopaque, len: usize) c_int;
+pub extern fn SHA512_Final(out: [*]u8, sha: *SHA512_CTX) c_int;
+pub extern fn SHA512(data: [*]const u8, len: usize, out: [*]u8) [*]u8;
+pub extern fn SHA512_Transform(sha: *SHA512_CTX, block: [*]const u8) void;
+pub extern fn SHA512_256_Init(sha: *SHA512_CTX) c_int;
+pub extern fn SHA512_256_Update(sha: *SHA512_CTX, data: ?*const anyopaque, len: usize) c_int;
+pub extern fn SHA512_256_Final(out: [*]u8, sha: *SHA512_CTX) c_int;
+pub extern fn SHA512_256(data: [*]const u8, len: usize, out: [*]u8) [*]u8;
pub extern fn X509_ALGOR_new() [*c]X509_ALGOR;
pub extern fn X509_ALGOR_free(a: [*c]X509_ALGOR) void;
pub extern fn d2i_X509_ALGOR(a: [*c][*c]X509_ALGOR, in: [*c][*c]const u8, len: c_long) [*c]X509_ALGOR;
diff --git a/src/fallback.version b/src/fallback.version
index b07ec851e..36b21d826 100644
--- a/src/fallback.version
+++ b/src/fallback.version
@@ -1 +1 @@
-3c32b2da4ba87f18 \ No newline at end of file
+871e1d1d6a2e7805 \ No newline at end of file
diff --git a/src/io/io_darwin.zig b/src/io/io_darwin.zig
index b399ce62f..17cf9cca6 100644
--- a/src/io/io_darwin.zig
+++ b/src/io/io_darwin.zig
@@ -484,9 +484,10 @@ timeouts: FIFO(Completion) = .{},
completed: FIFO(Completion) = .{},
io_pending: FIFO(Completion) = .{},
last_event_fd: std.atomic.Atomic(u32) = std.atomic.Atomic(u32).init(32),
+pending_count: usize = 0,
pub fn hasNoWork(this: *IO) bool {
- return this.io_inflight == 0 and this.io_pending.peek() == null and this.completed.peek() == null and this.timeouts.peek() == null;
+ return this.pending_count == 0 and this.io_inflight == 0 and this.io_pending.peek() == null and this.completed.peek() == null and this.timeouts.peek() == null;
}
pub fn init(_: u12, _: u32) !IO {
@@ -523,7 +524,7 @@ pub fn run_for_ns(self: *IO, nanoseconds: u63) !void {
}.callback;
// Submit a timeout which sets the timed_out value to true to terminate the loop below.
- self.timeout(
+ self.timeoutInternal(
*bool,
&timed_out,
on_timeout,
@@ -756,6 +757,21 @@ fn submit(
operation_data: anytype,
comptime OperationImpl: type,
) void {
+ submitWithIncrementPending(self, context, callback, completion, operation_tag, operation_data, OperationImpl, true);
+}
+
+fn submitWithIncrementPending(
+ self: *IO,
+ context: anytype,
+ comptime callback: anytype,
+ completion: *Completion,
+ comptime operation_tag: std.meta.Tag(Operation),
+ operation_data: anytype,
+ comptime OperationImpl: type,
+ comptime increment_pending: bool,
+) void {
+ if (comptime increment_pending)
+ self.pending_count += 1;
const Context = @TypeOf(context);
const onCompleteFn = struct {
fn onComplete(io: *IO, _completion: *Completion) void {
@@ -778,6 +794,9 @@ fn submit(
else => {},
}
+ if (comptime increment_pending)
+ io.pending_count -= 1;
+
// Complete the Completion
return callback(
@intToPtr(Context, @ptrToInt(_completion.context)),
@@ -1334,6 +1353,35 @@ pub fn timeout(
);
}
+fn timeoutInternal(
+ self: *IO,
+ comptime Context: type,
+ context: Context,
+ comptime callback: fn (
+ context: Context,
+ completion: *Completion,
+ result: TimeoutError!void,
+ ) void,
+ completion: *Completion,
+ nanoseconds: u63,
+) void {
+ self.submitWithIncrementPending(
+ context,
+ callback,
+ completion,
+ .timeout,
+ .{
+ .expires = self.time.monotonic() + nanoseconds,
+ },
+ struct {
+ fn doOperation(_: anytype) TimeoutError!void {
+ return; // timeouts don't have errors for now
+ }
+ },
+ false,
+ );
+}
+
pub const WriteError = os.PWriteError;
pub fn write(
diff --git a/src/javascript/jsc/api/bun.zig b/src/javascript/jsc/api/bun.zig
index f0d483e1f..011314644 100644
--- a/src/javascript/jsc/api/bun.zig
+++ b/src/javascript/jsc/api/bun.zig
@@ -1118,6 +1118,21 @@ pub const Class = NewClass(
.rfn = JSC.WebCore.Blob.writeFile,
.ts = d.ts{},
},
+ .sha1 = .{
+ .rfn = JSC.wrapWithHasContainer(Crypto.SHA1, "hash", false, false),
+ },
+ .sha256 = .{
+ .rfn = JSC.wrapWithHasContainer(Crypto.SHA256, "hash", false, false),
+ },
+ .sha384 = .{
+ .rfn = JSC.wrapWithHasContainer(Crypto.SHA384, "hash", false, false),
+ },
+ .sha512 = .{
+ .rfn = JSC.wrapWithHasContainer(Crypto.SHA512, "hash", false, false),
+ },
+ .sha512_256 = .{
+ .rfn = JSC.wrapWithHasContainer(Crypto.SHA512_256, "hash", false, false),
+ },
},
.{
.main = .{
@@ -1174,9 +1189,208 @@ pub const Class = NewClass(
.unsafe = .{
.get = getUnsafe,
},
+ .SHA1 = .{
+ .get = Crypto.SHA1.getter,
+ },
+ .SHA256 = .{
+ .get = Crypto.SHA256.getter,
+ },
+ .SHA384 = .{
+ .get = Crypto.SHA384.getter,
+ },
+ .SHA512 = .{
+ .get = Crypto.SHA512.getter,
+ },
+ .SHA512_256 = .{
+ .get = Crypto.SHA512_256.getter,
+ },
},
);
+pub const Crypto = struct {
+ const Hashers = @import("../../../sha.zig");
+
+ fn CryptoHasher(comptime Hasher: type, comptime name: [:0]const u8, cached_constructor_name: []const u8) type {
+ return struct {
+ hashing: Hasher = Hasher{},
+
+ pub fn byteLength(
+ _: void,
+ _: js.JSContextRef,
+ _: js.JSValueRef,
+ _: js.JSStringRef,
+ _: js.ExceptionRef,
+ ) js.JSValueRef {
+ return JSC.JSValue.jsNumber(@as(u16, Hasher.digest)).asObjectRef();
+ }
+
+ pub fn byteLength2(
+ _: *@This(),
+ _: js.JSContextRef,
+ _: js.JSValueRef,
+ _: js.JSStringRef,
+ _: js.ExceptionRef,
+ ) js.JSValueRef {
+ return JSC.JSValue.jsNumber(@as(u16, Hasher.digest)).asObjectRef();
+ }
+
+ pub const Constructor = JSC.NewConstructor(
+ @This(),
+ .{
+ .hash = .{
+ .rfn = JSC.wrapSync(@This(), "hash"),
+ },
+ .constructor = .{ .rfn = constructor },
+ },
+ .{
+ .byteLength = .{
+ .get = byteLength,
+ },
+ },
+ );
+
+ pub const Class = JSC.NewClass(
+ @This(),
+ .{
+ .name = name,
+ },
+ .{
+ .update = .{
+ .rfn = JSC.wrapSync(@This(), "update"),
+ },
+ .final = .{
+ .rfn = JSC.wrapSync(@This(), "final"),
+ },
+ .finalize = finalize,
+ },
+ .{
+ .byteLength = .{
+ .get = byteLength2,
+ },
+ },
+ );
+
+ pub fn hash(
+ globalThis: *JSGlobalObject,
+ input: JSC.Node.StringOrBuffer,
+ output: ?JSC.ArrayBuffer,
+ exception: JSC.C.ExceptionRef,
+ ) JSC.JSValue {
+ var output_digest_buf: Hasher.Digest = undefined;
+ var output_digest_slice: *Hasher.Digest = &output_digest_buf;
+ if (output) |output_buf| {
+ var bytes = output_buf.byteSlice();
+ if (bytes.len < Hasher.digest) {
+ JSC.JSError(
+ bun.default_allocator,
+ comptime std.fmt.comptimePrint("TypedArray must be at least {d} bytes", .{Hasher.digest}),
+ .{},
+ globalThis.ref(),
+ exception,
+ );
+ return JSC.JSValue.zero;
+ }
+ output_digest_slice = bytes[0..Hasher.digest];
+ }
+
+ Hasher.hash(input.slice(), output_digest_slice);
+
+ if (output) |output_buf| {
+ return output_buf.value;
+ } else {
+ var array_buffer_out = JSC.ArrayBuffer.fromBytes(bun.default_allocator.dupe(u8, output_digest_slice) catch unreachable, .Uint8Array);
+ return array_buffer_out.toJSUnchecked(globalThis.ref(), exception);
+ }
+ }
+
+ pub fn constructor(
+ ctx: js.JSContextRef,
+ _: js.JSObjectRef,
+ _: []const js.JSValueRef,
+ exception: js.ExceptionRef,
+ ) js.JSObjectRef {
+ var this = bun.default_allocator.create(@This()) catch {
+ JSC.JSError(bun.default_allocator, "Failed to create new object", .{}, ctx, exception);
+ return null;
+ };
+
+ this.* = .{ .hashing = Hasher.init() };
+ return @This().Class.make(ctx, this);
+ }
+
+ pub fn getter(
+ _: void,
+ ctx: js.JSContextRef,
+ _: js.JSValueRef,
+ _: js.JSStringRef,
+ _: js.ExceptionRef,
+ ) js.JSValueRef {
+ var existing = ctx.ptr().getCachedObject(&ZigString.init(cached_constructor_name));
+ if (existing.isEmpty()) {
+ return ctx.ptr().putCachedObject(
+ &ZigString.init(cached_constructor_name),
+ JSC.JSValue.fromRef(@This().Constructor.constructor(ctx)),
+ ).asObjectRef();
+ }
+
+ return existing.asObjectRef();
+ }
+
+ pub fn update(this: *@This(), buffer: JSC.Node.StringOrBuffer) JSC.JSValue {
+ this.hashing.update(buffer.slice());
+ return JSC.JSValue.jsUndefined();
+ }
+
+ pub fn final(this: *@This(), globalThis: *JSGlobalObject, exception: JSC.C.ExceptionRef, output: ?JSC.ArrayBuffer) JSC.JSValue {
+ var output_digest_buf: Hasher.Digest = undefined;
+ var output_digest_slice: *Hasher.Digest = &output_digest_buf;
+ if (output) |output_buf| {
+ var bytes = output_buf.byteSlice();
+ if (bytes.len < Hasher.digest) {
+ JSC.JSError(
+ bun.default_allocator,
+ comptime std.fmt.comptimePrint("TypedArray must be at least {d} bytes", .{@as(usize, Hasher.digest)}),
+ .{},
+ globalThis.ref(),
+ exception,
+ );
+ return JSC.JSValue.zero;
+ }
+ output_digest_slice = bytes[0..Hasher.digest];
+ } else {
+ output_digest_buf = comptime brk: {
+ var bytes: Hasher.Digest = undefined;
+ var i: usize = 0;
+ while (i < Hasher.digest) {
+ bytes[i] = 0;
+ i += 1;
+ }
+ break :brk bytes;
+ };
+ }
+
+ this.hashing.final(output_digest_slice);
+ if (output) |output_buf| {
+ return output_buf.value;
+ } else {
+ var array_buffer_out = JSC.ArrayBuffer.fromBytes(bun.default_allocator.dupe(u8, &output_digest_buf) catch unreachable, .Uint8Array);
+ return array_buffer_out.toJSUnchecked(globalThis.ref(), exception);
+ }
+ }
+
+ pub fn finalize(this: *@This()) void {
+ VirtualMachine.vm.allocator.destroy(this);
+ }
+ };
+ }
+
+ pub const SHA1 = CryptoHasher(Hashers.SHA1, "SHA1", "Bun_SHA1");
+ pub const SHA256 = CryptoHasher(Hashers.SHA256, "SHA256", "Bun_SHA256");
+ pub const SHA384 = CryptoHasher(Hashers.SHA384, "SHA384", "Bun_SHA384");
+ pub const SHA512 = CryptoHasher(Hashers.SHA512, "SHA512", "Bun_SHA512");
+ pub const SHA512_256 = CryptoHasher(Hashers.SHA512_256, "SHA512_256", "Bun_SHA512_256");
+};
+
pub fn serve(
_: void,
ctx: js.JSContextRef,
diff --git a/src/javascript/jsc/base.zig b/src/javascript/jsc/base.zig
index 70feecb76..9c07e9b37 100644
--- a/src/javascript/jsc/base.zig
+++ b/src/javascript/jsc/base.zig
@@ -2248,6 +2248,29 @@ pub const ArrayBuffer = extern struct {
return ArrayBuffer{ .offset = 0, .len = @intCast(u32, bytes.len), .byte_len = @intCast(u32, bytes.len), .typed_array_type = typed_array_type, .ptr = bytes.ptr };
}
+ pub fn toJSUnchecked(this: ArrayBuffer, ctx: JSC.C.JSContextRef, exception: JSC.C.ExceptionRef) JSC.JSValue {
+ if (this.typed_array_type == .ArrayBuffer) {
+ return JSC.JSValue.fromRef(JSC.C.JSObjectMakeArrayBufferWithBytesNoCopy(
+ ctx,
+ this.ptr,
+ this.byte_len,
+ MarkedArrayBuffer_deallocator,
+ @intToPtr(*anyopaque, @ptrToInt(&bun.default_allocator)),
+ exception,
+ ));
+ }
+
+ return JSC.JSValue.fromRef(JSC.C.JSObjectMakeTypedArrayWithBytesNoCopy(
+ ctx,
+ this.typed_array_type.toC(),
+ this.ptr,
+ this.byte_len,
+ MarkedArrayBuffer_deallocator,
+ @intToPtr(*anyopaque, @ptrToInt(&bun.default_allocator)),
+ exception,
+ ));
+ }
+
pub fn toJS(this: ArrayBuffer, ctx: JSC.C.JSContextRef, exception: JSC.C.ExceptionRef) JSC.JSValue {
if (!this.value.isEmpty()) {
return this.value;
@@ -2277,26 +2300,7 @@ pub const ArrayBuffer = extern struct {
));
}
- if (this.typed_array_type == .ArrayBuffer) {
- return JSC.JSValue.fromRef(JSC.C.JSObjectMakeArrayBufferWithBytesNoCopy(
- ctx,
- this.ptr,
- this.byte_len,
- MarkedArrayBuffer_deallocator,
- @intToPtr(*anyopaque, @ptrToInt(&bun.default_allocator)),
- exception,
- ));
- }
-
- return JSC.JSValue.fromRef(JSC.C.JSObjectMakeTypedArrayWithBytesNoCopy(
- ctx,
- this.typed_array_type.toC(),
- this.ptr,
- this.byte_len,
- MarkedArrayBuffer_deallocator,
- @intToPtr(*anyopaque, @ptrToInt(&bun.default_allocator)),
- exception,
- ));
+ return this.toJSUnchecked(ctx, exception);
}
pub fn toJSWithContext(
@@ -2552,6 +2556,11 @@ const Server = JSC.API.Server;
const SSLServer = JSC.API.SSLServer;
const DebugServer = JSC.API.DebugServer;
const DebugSSLServer = JSC.API.DebugSSLServer;
+const SHA1 = JSC.API.Bun.Crypto.SHA1;
+const SHA256 = JSC.API.Bun.Crypto.SHA256;
+const SHA384 = JSC.API.Bun.Crypto.SHA384;
+const SHA512 = JSC.API.Bun.Crypto.SHA512;
+const SHA512_256 = JSC.API.Bun.Crypto.SHA512_256;
pub const JSPrivateDataPtr = TaggedPointerUnion(.{
AttributeIterator,
@@ -2589,6 +2598,11 @@ pub const JSPrivateDataPtr = TaggedPointerUnion(.{
TextEncoder,
TimeoutTask,
Transpiler,
+ SHA1,
+ SHA256,
+ SHA384,
+ SHA512,
+ SHA512_256,
});
pub inline fn GetJSPrivateData(comptime Type: type, ref: js.JSObjectRef) ?*Type {
@@ -2678,9 +2692,9 @@ fn SetterType(comptime Container: type) type {
) bool;
}
-fn MethodType(comptime Container: type) type {
+fn MethodType(comptime Container: type, comptime has_container: bool) type {
return fn (
- this: *Container,
+ this: if (has_container) *Container else void,
ctx: js.JSContextRef,
thisObject: js.JSObjectRef,
target: js.JSObjectRef,
@@ -2692,14 +2706,14 @@ fn MethodType(comptime Container: type) type {
pub fn wrapSync(
comptime Container: type,
comptime name: string,
-) MethodType(Container) {
+) MethodType(Container, true) {
return wrap(Container, name, false);
}
pub fn wrapAsync(
comptime Container: type,
comptime name: string,
-) MethodType(Container) {
+) MethodType(Container, true) {
return wrap(Container, name, true);
}
@@ -2707,13 +2721,23 @@ pub fn wrap(
comptime Container: type,
comptime name: string,
comptime maybe_async: bool,
-) MethodType(Container) {
+) MethodType(Container, true) {
+ return wrapWithHasContainer(Container, name, maybe_async, true);
+}
+
+pub fn wrapWithHasContainer(
+ comptime Container: type,
+ comptime name: string,
+ comptime maybe_async: bool,
+ comptime has_container: bool,
+) MethodType(Container, has_container) {
return struct {
const FunctionType = @TypeOf(@field(Container, name));
const FunctionTypeInfo: std.builtin.TypeInfo.Fn = @typeInfo(FunctionType).Fn;
+ const Args = std.meta.ArgsTuple(FunctionType);
pub fn callback(
- this: *Container,
+ this: if (has_container) *Container else void,
ctx: js.JSContextRef,
_: js.JSObjectRef,
thisObject: js.JSObjectRef,
@@ -2721,12 +2745,11 @@ pub fn wrap(
exception: js.ExceptionRef,
) js.JSObjectRef {
var iter = JSC.Node.ArgumentsSlice.from(arguments);
- var args: std.meta.ArgsTuple(FunctionType) = undefined;
+ var args: Args = undefined;
comptime var i: usize = 0;
inline while (i < FunctionTypeInfo.args.len) : (i += 1) {
const ArgType = comptime FunctionTypeInfo.args[i].arg_type.?;
-
switch (comptime ArgType) {
*Container => {
args[i] = this;
@@ -2734,14 +2757,63 @@ pub fn wrap(
*JSC.JSGlobalObject => {
args[i] = ctx.ptr();
},
+ JSC.Node.StringOrBuffer => {
+ const arg = iter.nextEat() orelse {
+ exception.* = JSC.toInvalidArguments("expected string or buffer", .{}, ctx).asObjectRef();
+ iter.deinit();
+ return null;
+ };
+ args[i] = JSC.Node.StringOrBuffer.fromJS(ctx.ptr(), iter.arena.allocator(), arg, exception) orelse {
+ exception.* = JSC.toInvalidArguments("expected string or buffer", .{}, ctx).asObjectRef();
+ iter.deinit();
+ return null;
+ };
+ },
+ ?JSC.Node.StringOrBuffer => {
+ if (iter.nextEat()) |arg| {
+ args[i] = JSC.Node.StringOrBuffer.fromJS(ctx.ptr(), iter.arena.allocator(), arg, exception) orelse {
+ exception.* = JSC.toInvalidArguments("expected string or buffer", .{}, ctx).asObjectRef();
+ iter.deinit();
+ return null;
+ };
+ } else {
+ args[i] = null;
+ }
+ },
+ JSC.ArrayBuffer => {
+ if (iter.nextEat()) |arg| {
+ args[i] = arg.asArrayBuffer(ctx.ptr()) orelse {
+ exception.* = JSC.toInvalidArguments("expected TypedArray", .{}, ctx).asObjectRef();
+ iter.deinit();
+ return null;
+ };
+ } else {
+ exception.* = JSC.toInvalidArguments("expected TypedArray", .{}, ctx).asObjectRef();
+ iter.deinit();
+ return null;
+ }
+ },
+ ?JSC.ArrayBuffer => {
+ if (iter.nextEat()) |arg| {
+ args[i] = arg.asArrayBuffer(ctx.ptr()) orelse {
+ exception.* = JSC.toInvalidArguments("expected TypedArray", .{}, ctx).asObjectRef();
+ iter.deinit();
+ return null;
+ };
+ } else {
+ args[i] = null;
+ }
+ },
ZigString => {
var string_value = iter.protectEatNext() orelse {
JSC.throwInvalidArguments("Missing argument", .{}, ctx, exception);
+ iter.deinit();
return null;
};
if (string_value.isUndefinedOrNull()) {
JSC.throwInvalidArguments("Expected string", .{}, ctx, exception);
+ iter.deinit();
return null;
}
@@ -2759,18 +2831,22 @@ pub fn wrap(
*Response => {
args[i] = (iter.protectEatNext() orelse {
JSC.throwInvalidArguments("Missing Response object", .{}, ctx, exception);
+ iter.deinit();
return null;
}).as(Response) orelse {
JSC.throwInvalidArguments("Expected Response object", .{}, ctx, exception);
+ iter.deinit();
return null;
};
},
*Request => {
args[i] = (iter.protectEatNext() orelse {
JSC.throwInvalidArguments("Missing Request object", .{}, ctx, exception);
+ iter.deinit();
return null;
}).as(Request) orelse {
JSC.throwInvalidArguments("Expected Request object", .{}, ctx, exception);
+ iter.deinit();
return null;
};
},
@@ -2778,6 +2854,7 @@ pub fn wrap(
args[i] = thisObject;
if (!JSValue.fromRef(thisObject).isCell() or !JSValue.fromRef(thisObject).isObject()) {
JSC.throwInvalidArguments("Expected object", .{}, ctx, exception);
+ iter.deinit();
return null;
}
},
@@ -2787,6 +2864,7 @@ pub fn wrap(
JSValue => {
const val = iter.protectEatNext() orelse {
JSC.throwInvalidArguments("Missing argument", .{}, ctx, exception);
+ iter.deinit();
return null;
};
args[i] = val;
@@ -2796,7 +2874,7 @@ pub fn wrap(
}
var result: JSValue = @call(.{}, @field(Container, name), args);
- if (result.isError()) {
+ if (!result.isEmptyOrUndefinedOrNull() and result.isError()) {
exception.* = result.asObjectRef();
iter.deinit();
return null;
diff --git a/src/sha.zig b/src/sha.zig
new file mode 100644
index 000000000..525392a30
--- /dev/null
+++ b/src/sha.zig
@@ -0,0 +1,145 @@
+const BoringSSL = @import("boringssl");
+const std = @import("std");
+
+fn NewHasher(comptime digest_size: comptime_int, comptime ContextType: type, comptime Full: anytype, comptime Init: anytype, comptime Update: anytype, comptime Final: anytype) type {
+ return struct {
+ hasher: ContextType = undefined,
+
+ pub const Digest = [digest_size]u8;
+ pub const digest: comptime_int = digest_size;
+
+ pub fn init() @This() {
+ var this: @This() = .{
+ .hasher = undefined,
+ };
+
+ std.debug.assert(Init(&this.hasher) == 1);
+ return this;
+ }
+
+ pub fn hash(bytes: []const u8, out: *Digest) void {
+ _ = Full(bytes.ptr, bytes.len, out);
+ }
+
+ pub fn update(this: *@This(), data: []const u8) void {
+ std.debug.assert(Update(&this.hasher, data.ptr, data.len) == 1);
+ }
+
+ pub fn final(this: *@This(), out: *Digest) void {
+ std.debug.assert(Final(out, &this.hasher) == 1);
+ }
+ };
+}
+
+pub const SHA1 = NewHasher(
+ std.crypto.hash.Sha1.digest_length,
+ BoringSSL.SHA_CTX,
+ BoringSSL.SHA1,
+ BoringSSL.SHA1_Init,
+ BoringSSL.SHA1_Update,
+ BoringSSL.SHA1_Final,
+);
+
+pub const SHA512 = NewHasher(
+ std.crypto.hash.sha2.Sha512.digest_length,
+ BoringSSL.SHA512_CTX,
+ BoringSSL.SHA512,
+ BoringSSL.SHA512_Init,
+ BoringSSL.SHA512_Update,
+ BoringSSL.SHA512_Final,
+);
+
+pub const SHA384 = NewHasher(
+ std.crypto.hash.sha2.Sha384.digest_length,
+ BoringSSL.SHA512_CTX,
+ BoringSSL.SHA384,
+ BoringSSL.SHA384_Init,
+ BoringSSL.SHA384_Update,
+ BoringSSL.SHA384_Final,
+);
+
+pub const SHA256 = NewHasher(
+ std.crypto.hash.sha2.Sha256.digest_length,
+ BoringSSL.SHA256_CTX,
+ BoringSSL.SHA256,
+ BoringSSL.SHA256_Init,
+ BoringSSL.SHA256_Update,
+ BoringSSL.SHA256_Final,
+);
+
+pub const SHA512_256 = NewHasher(
+ std.crypto.hash.sha2.Sha512256.digest_length,
+ BoringSSL.SHA512_CTX,
+ BoringSSL.SHA512_256,
+ BoringSSL.SHA512_256_Init,
+ BoringSSL.SHA512_256_Update,
+ BoringSSL.SHA512_256_Final,
+);
+
+pub fn main() anyerror!void {
+ var file = try std.fs.cwd().openFileZ(std.os.argv[std.os.argv.len - 1], .{});
+ var bytes = try file.readToEndAlloc(std.heap.c_allocator, std.math.maxInt(usize));
+
+ const boring = [_]type{
+ SHA1,
+ SHA512,
+ SHA384,
+ SHA256,
+ SHA512_256,
+ };
+
+ const zig = [_]type{
+ std.crypto.hash.Sha1,
+ std.crypto.hash.sha2.Sha512,
+ std.crypto.hash.sha2.Sha384,
+ std.crypto.hash.sha2.Sha256,
+ std.crypto.hash.sha2.Sha512256,
+ };
+
+ const labels = [_][]const u8{
+ "SHA1",
+ "SHA512",
+ "SHA384",
+ "SHA256",
+ "SHA512_256",
+ };
+
+ inline for (boring) |BoringHasher, i| {
+ const ZigHasher = zig[i];
+ std.debug.print(
+ comptime labels[i] ++ " - hashing {.3f}:\n",
+ .{std.fmt.fmtIntSizeBin(bytes.len)},
+ );
+ var digest1: BoringHasher.Digest = undefined;
+ var digest2: BoringHasher.Digest = undefined;
+ var clock1 = try std.time.Timer.start();
+ ZigHasher.hash(bytes, &digest1, .{});
+ const zig_time = clock1.read();
+
+ var clock2 = try std.time.Timer.start();
+ BoringHasher.hash(bytes, &digest2);
+ const boring_time = clock2.read();
+
+ std.debug.print(
+ " zig: {}\n",
+ .{std.fmt.fmtDuration(zig_time)},
+ );
+ std.debug.print(
+ " boring: {}\n\n",
+ .{std.fmt.fmtDuration(boring_time)},
+ );
+
+ if (!std.mem.eql(u8, &digest1, &digest2)) {
+ @panic("\ndigests don't match! for " ++ labels[i]);
+ }
+ }
+}
+
+test "sha256" {
+ const value: []const u8 = "hello, world! hello, world! hello, world! hello, world! hello, world! hello, world! hello, world! hello, world! hello, world! hello, world! hello, world! hello, world! hello, world! hello, world! hello, world! hello, world! hello, world! hello, world! hello, world! hello, world!";
+ var hash: SHA256.Digest = undefined;
+ var hash2: SHA256.Digest = undefined;
+ SHA256.hash(value, &hash);
+ std.crypto.hash.sha2.Sha256.hash(value, &hash2, .{});
+ try std.testing.expectEqual(hash, hash2);
+}