diff options
author | 2021-12-18 21:07:07 -0800 | |
---|---|---|
committer | 2021-12-18 21:07:07 -0800 | |
commit | 0cee57f1d997fe21e519d5e771df0877ab489d5f (patch) | |
tree | 417d044ebbc47cc9b6ef49213620c07ae2927e0a /misctools | |
parent | d1783babd99ff2a8020765837b3b9b3099137024 (diff) | |
parent | eab99b3bae9a810d76e6eb16afd9fb32cd7672bd (diff) | |
download | bun-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/.gitignore | 7 | ||||
-rw-r--r-- | misctools/fetch.zig | 79 | ||||
-rw-r--r-- | misctools/http_bench.zig | 296 | ||||
-rw-r--r-- | misctools/readlink-getfd.zig | 56 | ||||
-rw-r--r-- | misctools/readlink-realpath.zig | 31 |
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, ¶ms, .{ + .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}); +} |