aboutsummaryrefslogtreecommitdiff
path: root/misctools
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-12-18 21:07:07 -0800
committerGravatar GitHub <noreply@github.com> 2021-12-18 21:07:07 -0800
commit0cee57f1d997fe21e519d5e771df0877ab489d5f (patch)
tree417d044ebbc47cc9b6ef49213620c07ae2927e0a /misctools
parentd1783babd99ff2a8020765837b3b9b3099137024 (diff)
parenteab99b3bae9a810d76e6eb16afd9fb32cd7672bd (diff)
downloadbun-0cee57f1d997fe21e519d5e771df0877ab489d5f.tar.gz
bun-0cee57f1d997fe21e519d5e771df0877ab489d5f.tar.zst
bun-0cee57f1d997fe21e519d5e771df0877ab489d5f.zip
Merge pull request #80 from Jarred-Sumner/jarred/npm-install
bun install
Diffstat (limited to 'misctools')
-rw-r--r--misctools/.gitignore7
-rw-r--r--misctools/fetch.zig79
-rw-r--r--misctools/http_bench.zig296
-rw-r--r--misctools/readlink-getfd.zig56
-rw-r--r--misctools/readlink-realpath.zig31
5 files changed, 426 insertions, 43 deletions
diff --git a/misctools/.gitignore b/misctools/.gitignore
index 41cdc1338..247e7e6e7 100644
--- a/misctools/.gitignore
+++ b/misctools/.gitignore
@@ -1,3 +1,10 @@
*.tgz
tgz
readlink-getfd
+readlink-realpath
+http_bench
+httpbench
+fetch
+tgz2hop
+hop
+bun.lockb
diff --git a/misctools/fetch.zig b/misctools/fetch.zig
index 59bd3320a..776ac3950 100644
--- a/misctools/fetch.zig
+++ b/misctools/fetch.zig
@@ -2,14 +2,14 @@ const std = @import("std");
usingnamespace @import("../src/global.zig");
const clap = @import("../src/deps/zig-clap/clap.zig");
-const HTTPClient = @import("../src/http_client.zig");
const URL = @import("../src/query_string_map.zig").URL;
const Headers = @import("../src/javascript/jsc/webcore/response.zig").Headers;
const Method = @import("../src/http/method.zig").Method;
const ColonListType = @import("../src/cli/colon_list_type.zig").ColonListType;
const HeadersTuple = ColonListType(string, noop_resolver);
const path_handler = @import("../src/resolver/resolve_path.zig");
-
+const NetworkThread = @import("network_thread");
+const HTTP = @import("http");
fn noop_resolver(in: string) !string {
return in;
}
@@ -162,24 +162,67 @@ pub fn main() anyerror!void {
defer Output.flush();
var args = try Arguments.parse(default_allocator);
- var client = HTTPClient.init(default_allocator, args.method, args.url, args.headers, args.headers_buf);
- client.verbose = args.verbose;
- client.disable_shutdown = args.turbo;
var body_out_str = try MutableString.init(default_allocator, 1024);
- var response = try client.send(args.body, &body_out_str);
-
- switch (response.status_code) {
- 200, 302 => {},
- else => {
- if (!client.verbose) {
- Output.prettyErrorln("{}", .{response});
+ var body_in_str = try MutableString.init(default_allocator, args.body.len);
+ body_in_str.appendAssumeCapacity(args.body);
+ var channel = try default_allocator.create(HTTP.HTTPChannel);
+ channel.* = HTTP.HTTPChannel.init();
+
+ var response_body_string = try default_allocator.create(MutableString);
+ response_body_string.* = body_out_str;
+ var request_body_string = try default_allocator.create(MutableString);
+ request_body_string.* = body_in_str;
+
+ try channel.buffer.ensureCapacity(1);
+
+ try NetworkThread.init();
+
+ var ctx = try default_allocator.create(HTTP.HTTPChannelContext);
+ ctx.* = .{
+ .channel = channel,
+ .http = try HTTP.AsyncHTTP.init(
+ default_allocator,
+ args.method,
+ args.url,
+ args.headers,
+ args.headers_buf,
+ response_body_string,
+ request_body_string,
+
+ 0,
+ ),
+ };
+ ctx.http.callback = HTTP.HTTPChannelContext.callback;
+ var batch = NetworkThread.Batch{};
+ ctx.http.schedule(default_allocator, &batch);
+ ctx.http.client.verbose = args.verbose;
+
+ ctx.http.verbose = args.verbose;
+ NetworkThread.global.pool.schedule(batch);
+
+ while (true) {
+ while (channel.tryReadItem() catch null) |http| {
+ var response = http.response orelse {
+ Output.printErrorln("<r><red>error<r><d>:<r> <b>HTTP response missing<r>", .{});
+ Output.flush();
+ std.os.exit(1);
+ };
+
+ switch (response.status_code) {
+ 200, 302 => {},
+ else => {
+ if (args.verbose) {
+ Output.prettyErrorln("{}", .{response});
+ }
+ },
}
- },
- }
- Output.flush();
- Output.disableBuffering();
- try Output.writer().writeAll(body_out_str.list.items);
- Output.enableBuffering();
+ Output.flush();
+ Output.disableBuffering();
+ try Output.writer().writeAll(response_body_string.list.items);
+ Output.enableBuffering();
+ return;
+ }
+ }
}
diff --git a/misctools/http_bench.zig b/misctools/http_bench.zig
new file mode 100644
index 000000000..10965f66a
--- /dev/null
+++ b/misctools/http_bench.zig
@@ -0,0 +1,296 @@
+const std = @import("std");
+usingnamespace @import("../src/global.zig");
+const clap = @import("../src/deps/zig-clap/clap.zig");
+
+const URL = @import("../src/query_string_map.zig").URL;
+const Headers = @import("../src/javascript/jsc/webcore/response.zig").Headers;
+const Method = @import("../src/http/method.zig").Method;
+const ColonListType = @import("../src/cli/colon_list_type.zig").ColonListType;
+const HeadersTuple = ColonListType(string, noop_resolver);
+const path_handler = @import("../src/resolver/resolve_path.zig");
+
+fn noop_resolver(in: string) !string {
+ return in;
+}
+
+const VERSION = "0.0.0";
+
+const params = [_]clap.Param(clap.Help){
+ clap.parseParam("-v, --verbose Show headers & status code") catch unreachable,
+ clap.parseParam("-H, --header <STR>... Add a header") catch unreachable,
+ clap.parseParam("-r, --max-redirects <STR> Maximum number of redirects to follow (default: 128)") catch unreachable,
+ clap.parseParam("-b, --body <STR> HTTP request body as a string") catch unreachable,
+ clap.parseParam("-f, --file <STR> File path to load as body") catch unreachable,
+ clap.parseParam("-n, --count <INT> How many runs? Default 10") catch unreachable,
+ clap.parseParam("-t, --timeout <INT> Max duration per request") catch unreachable,
+ clap.parseParam("-r, --retry <INT> Max retry count") catch unreachable,
+ clap.parseParam("--no-gzip Disable gzip") catch unreachable,
+ clap.parseParam("--no-deflate Disable deflate") catch unreachable,
+ clap.parseParam("--no-compression Disable gzip & deflate") catch unreachable,
+ clap.parseParam("--version Print the version and exit") catch unreachable,
+ clap.parseParam("--turbo Skip sending TLS shutdown signals") catch unreachable,
+ clap.parseParam("<POS>... ") catch unreachable,
+};
+
+const MethodNames = std.ComptimeStringMap(Method, .{
+ .{ "GET", Method.GET },
+ .{ "get", Method.GET },
+
+ .{ "POST", Method.POST },
+ .{ "post", Method.POST },
+
+ .{ "PUT", Method.PUT },
+ .{ "put", Method.PUT },
+
+ .{ "PATCH", Method.PATCH },
+ .{ "patch", Method.PATCH },
+
+ .{ "OPTIONS", Method.OPTIONS },
+ .{ "options", Method.OPTIONS },
+
+ .{ "HEAD", Method.HEAD },
+ .{ "head", Method.HEAD },
+});
+
+var file_path_buf: [std.fs.MAX_PATH_BYTES + 1]u8 = undefined;
+var cwd_buf: [std.fs.MAX_PATH_BYTES + 1]u8 = undefined;
+
+pub const Arguments = struct {
+ url: URL,
+ method: Method,
+ verbose: bool = false,
+ headers: Headers.Entries,
+ headers_buf: string,
+ body: string = "",
+ turbo: bool = false,
+ count: usize = 10,
+ timeout: usize = 0,
+
+ pub fn parse(allocator: *std.mem.Allocator) !Arguments {
+ var diag = clap.Diagnostic{};
+
+ var args = clap.parse(clap.Help, &params, .{
+ .diagnostic = &diag,
+ .allocator = allocator,
+ }) catch |err| {
+ // Report useful error and exit
+ diag.report(Output.errorWriter(), err) catch {};
+ return err;
+ };
+
+ var positionals = args.positionals();
+ var raw_args: std.ArrayListUnmanaged(string) = undefined;
+
+ if (positionals.len > 0) {
+ raw_args = .{ .capacity = positionals.len, .items = @intToPtr([*][]const u8, @ptrToInt(positionals.ptr))[0..positionals.len] };
+ } else {
+ raw_args = .{};
+ }
+
+ if (args.flag("--version")) {
+ try Output.writer().writeAll(VERSION);
+ std.os.exit(0);
+ }
+
+ var method = Method.GET;
+ var url: URL = .{};
+ var body_string: string = args.option("--body") orelse "";
+
+ if (args.option("--file")) |file_path| {
+ if (file_path.len > 0) {
+ var cwd = try std.process.getCwd(&cwd_buf);
+ var parts = [_]string{std.mem.span(file_path)};
+ var absolute_path = path_handler.joinAbsStringBuf(cwd, &file_path_buf, &parts, .auto);
+ file_path_buf[absolute_path.len] = 0;
+ file_path_buf[absolute_path.len + 1] = 0;
+ var absolute_path_len = absolute_path.len;
+ var absolute_path_ = file_path_buf[0..absolute_path_len :0];
+
+ var body_file = std.fs.openFileAbsoluteZ(absolute_path_, .{ .read = true }) catch |err| {
+ Output.printErrorln("<r><red>{s}<r> opening file {s}", .{ @errorName(err), absolute_path });
+ Output.flush();
+ std.os.exit(1);
+ };
+
+ var file_contents = body_file.readToEndAlloc(allocator, try body_file.getEndPos()) catch |err| {
+ Output.printErrorln("<r><red>{s}<r> reading file {s}", .{ @errorName(err), absolute_path });
+ Output.flush();
+ std.os.exit(1);
+ };
+ body_string = file_contents;
+ }
+ }
+
+ {
+ var raw_arg_i: usize = 0;
+ while (raw_arg_i < raw_args.items.len) : (raw_arg_i += 1) {
+ const arg = raw_args.items[raw_arg_i];
+ if (MethodNames.get(std.mem.span(arg))) |method_| {
+ method = method_;
+ _ = raw_args.swapRemove(raw_arg_i);
+ }
+ }
+
+ if (raw_args.items.len == 0) {
+ Output.prettyErrorln("<r><red>error<r><d>:<r> <b>Missing URL<r>\n\nExample:\n<r><b>fetch GET https://example.com<r>\n\n<b>fetch example.com/foo<r>\n\n", .{});
+ Output.flush();
+ std.os.exit(1);
+ }
+
+ const url_position = raw_args.items.len - 1;
+ url = URL.parse(raw_args.swapRemove(url_position));
+ if (!url.isAbsolute()) {
+ Output.prettyErrorln("<r><red>error<r><d>:<r> <b>Invalid URL<r>\n\nExample:\n<r><b>fetch GET https://example.com<r>\n\n<b>fetch example.com/foo<r>\n\n", .{});
+ Output.flush();
+ std.os.exit(1);
+ }
+ }
+
+ return Arguments{
+ .url = url,
+ .method = method,
+ .verbose = args.flag("--verbose"),
+ .headers = .{},
+ .headers_buf = "",
+ .body = body_string,
+ .turbo = args.flag("--turbo"),
+ .timeout = std.fmt.parseInt(usize, args.option("--timeout") orelse "0", 10) catch |err| {
+ Output.prettyErrorln("<r><red>{s}<r> parsing timeout", .{@errorName(err)});
+ Output.flush();
+ std.os.exit(1);
+ },
+ .count = std.fmt.parseInt(usize, args.option("--count") orelse "10", 10) catch |err| {
+ Output.prettyErrorln("<r><red>{s}<r> parsing count", .{@errorName(err)});
+ Output.flush();
+ std.os.exit(1);
+ },
+ };
+ }
+};
+
+const NetworkThread = @import("network_thread");
+const HTTP = @import("http");
+
+var stdout_: std.fs.File = undefined;
+var stderr_: std.fs.File = undefined;
+pub fn main() anyerror!void {
+ stdout_ = std.io.getStdOut();
+ stderr_ = std.io.getStdErr();
+ var output_source = Output.Source.init(stdout_, stderr_);
+ Output.Source.set(&output_source);
+
+ defer Output.flush();
+
+ var args = try Arguments.parse(default_allocator);
+
+ var channel = try default_allocator.create(HTTP.HTTPChannel);
+ channel.* = HTTP.HTTPChannel.init();
+
+ try channel.buffer.ensureCapacity(args.count);
+
+ try NetworkThread.init();
+
+ const Group = struct {
+ response_body: MutableString = undefined,
+ request_body: MutableString = undefined,
+ context: HTTP.HTTPChannelContext = undefined,
+ };
+ var groups = try default_allocator.alloc(Group, args.count);
+ var i: usize = 0;
+ const Batch = @import("../src/thread_pool.zig").Batch;
+ var batch = Batch{};
+ while (i < args.count) : (i += 1) {
+ groups[i] = Group{};
+ var response_body = &groups[i].response_body;
+ response_body.* = try MutableString.init(default_allocator, 1024);
+ var request_body = &groups[i].request_body;
+ request_body.* = try MutableString.init(default_allocator, 0);
+
+ var ctx = &groups[i].context;
+ ctx.* = .{
+ .channel = channel,
+ .http = try HTTP.AsyncHTTP.init(
+ default_allocator,
+ args.method,
+ args.url,
+ args.headers,
+ args.headers_buf,
+ request_body,
+ response_body,
+ args.timeout,
+ ),
+ };
+ ctx.http.callback = HTTP.HTTPChannelContext.callback;
+ ctx.http.schedule(default_allocator, &batch);
+
+ }
+ NetworkThread.global.pool.schedule(batch);
+
+ var read_count: usize = 0;
+ var success_count: usize = 0;
+ var fail_count: usize = 0;
+ var min_duration: usize = std.math.maxInt(usize);
+ var max_duration: usize = 0;
+ var timer = try std.time.Timer.start();
+ while (read_count < args.count) {
+ while (channel.tryReadItem() catch null) |http| {
+ read_count += 1;
+
+ Output.printElapsed(@floatCast(f64, @intToFloat(f128, http.elapsed) / std.time.ns_per_ms));
+ if (http.response) |resp| {
+ if (resp.status_code == 200) {
+ success_count += 1;
+ } else {
+ fail_count += 1;
+ }
+
+ max_duration = @maximum(max_duration, http.elapsed);
+ min_duration = @minimum(min_duration, http.elapsed);
+
+ switch (resp.status_code) {
+ 200, 202, 302 => {
+ Output.prettyError(" <r><green>{d}<r>", .{resp.status_code});
+ },
+ else => {
+ Output.prettyError(" <r><red>{d}<r>", .{resp.status_code});
+ },
+ }
+
+ if (http.gzip_elapsed > 0) {
+ Output.prettyError(" <d>{s}<r><d> - {s}<r> <d>({d} bytes, ", .{
+ @tagName(http.client.method),
+ http.client.url.href,
+ http.response_buffer.list.items.len,
+ });
+ Output.printElapsed(@floatCast(f64, @intToFloat(f128, http.gzip_elapsed) / std.time.ns_per_ms));
+ Output.prettyError("<d> gzip)<r>\n", .{});
+ } else {
+ Output.prettyError(" <d>{s}<r><d> - {s}<r> <d>({d} bytes)<r>\n", .{
+ @tagName(http.client.method),
+ http.client.url.href,
+ http.response_buffer.list.items.len,
+ });
+ }
+ } else if (http.err) |err| {
+ fail_count += 1;
+ Output.printError(" err: {s}\n", .{@errorName(err)});
+ } else {
+ fail_count += 1;
+ Output.prettyError(" Uh-oh: {s}\n", .{@tagName(http.state.loadUnchecked())});
+ }
+
+ Output.flush();
+ }
+ }
+ Output.prettyErrorln("\n<d>------<r>\n\n", .{});
+ Output.prettyErrorln("Success: <b><green>{d}<r>\nFailure: <b><red>{d}<r>\n\n", .{
+ success_count,
+ fail_count,
+ });
+
+ Output.printElapsed(@floatCast(f64, @intToFloat(f128, timer.read()) / std.time.ns_per_ms));
+ Output.prettyErrorln(" {d} requests", .{
+ read_count,
+ });
+ Output.flush();
+}
diff --git a/misctools/readlink-getfd.zig b/misctools/readlink-getfd.zig
index a267e0cd8..cd97cb2d0 100644
--- a/misctools/readlink-getfd.zig
+++ b/misctools/readlink-getfd.zig
@@ -19,32 +19,38 @@ pub fn main() anyerror!void {
const to_resolve = args[args.len - 1];
const cwd = try std.process.getCwdAlloc(allocator);
- var parts = [1][]const u8{std.mem.span(to_resolve)};
- var joined_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
- var joined = path_handler.joinAbsStringBuf(
- cwd,
- &joined_buf,
- &parts,
- .loose,
- );
- joined_buf[joined.len] = 0;
- const joined_z: [:0]const u8 = joined_buf[0..joined.len :0];
-
- var file = std.fs.openFileAbsoluteZ(joined_z, .{ .read = false }) catch |err| {
- switch (err) {
- error.NotDir, error.FileNotFound => {
- Output.prettyError("<r><red>404 Not Found<r>: <b>\"{s}\"<r>", .{joined_z});
- Output.flush();
- std.process.exit(1);
- },
- else => {
- return err;
- },
- }
- };
-
+ var path: []u8 = undefined;
var out_buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
- var path = try std.os.getFdPath(file.handle, &out_buffer);
+
+ var j: usize = 0;
+ while (j < 100000) : (j += 1) {
+ var parts = [1][]const u8{std.mem.span(to_resolve)};
+ var joined_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
+ var joined = path_handler.joinAbsStringBuf(
+ cwd,
+ &joined_buf,
+ &parts,
+ .loose,
+ );
+ joined_buf[joined.len] = 0;
+ const joined_z: [:0]const u8 = joined_buf[0..joined.len :0];
+
+ var file = std.fs.openFileAbsoluteZ(joined_z, .{ .read = false }) catch |err| {
+ switch (err) {
+ error.NotDir, error.FileNotFound => {
+ Output.prettyError("<r><red>404 Not Found<r>: <b>\"{s}\"<r>", .{joined_z});
+ Output.flush();
+ std.process.exit(1);
+ },
+ else => {
+ return err;
+ },
+ }
+ };
+
+ path = try std.os.getFdPath(file.handle, &out_buffer);
+ file.close();
+ }
Output.print("{s}", .{path});
}
diff --git a/misctools/readlink-realpath.zig b/misctools/readlink-realpath.zig
new file mode 100644
index 000000000..ed7fd14cf
--- /dev/null
+++ b/misctools/readlink-realpath.zig
@@ -0,0 +1,31 @@
+const std = @import("std");
+
+const path_handler = @import("../src/resolver/resolve_path.zig");
+usingnamespace @import("../src/global.zig");
+
+// zig build-exe -Drelease-fast --main-pkg-path ../ ./readlink-getfd.zig
+pub fn main() anyerror!void {
+ var stdout_ = std.io.getStdOut();
+ var stderr_ = std.io.getStdErr();
+ var output_source = Output.Source.init(stdout_, stderr_);
+ Output.Source.set(&output_source);
+ defer Output.flush();
+
+ var args_buffer: [8096 * 2]u8 = undefined;
+ var fixed_buffer = std.heap.FixedBufferAllocator.init(&args_buffer);
+ var allocator = &fixed_buffer.allocator;
+
+ var args = std.mem.span(try std.process.argsAlloc(allocator));
+
+ const to_resolve = args[args.len - 1];
+ const cwd = try std.process.getCwdAlloc(allocator);
+ var out_buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
+ var path: []u8 = undefined;
+
+ var j: usize = 0;
+ while (j < 100000) : (j += 1) {
+ path = try std.os.realpathZ(to_resolve, &out_buffer);
+ }
+
+ Output.print("{s}", .{path});
+}