mirror of
https://github.com/oven-sh/bun
synced 2026-02-11 03:18:53 +00:00
Fixes ENG-21287
Build times, from `bun run build && echo '//' >> src/main.zig && time
bun run build`
|Platform|0.14.1|0.15.2|Speedup|
|-|-|-|-|
|macos debug asan|126.90s|106.27s|1.19x|
|macos debug noasan|60.62s|50.85s|1.19x|
|linux debug asan|292.77s|241.45s|1.21x|
|linux debug noasan|146.58s|130.94s|1.12x|
|linux debug use_llvm=false|n/a|78.27s|1.87x|
|windows debug asan|177.13s|142.55s|1.24x|
Runtime performance:
- next build memory usage may have gone up by 5%. Otherwise seems the
same. Some code with writers may have gotten slower, especially one
instance of a counting writer and a few instances of unbuffered writers
that now have vtable overhead.
- File size reduced by 800kb (from 100.2mb to 99.4mb)
Improvements:
- `@export` hack is no longer needed for watch
- native x86_64 backend for linux builds faster. to use it, set use_llvm
false and no_link_obj false. also set `ASAN_OPTIONS=detect_leaks=0`
otherwise it will spam the output with tens of thousands of lines of
debug info errors. may need to use the zig lldb fork for debugging.
- zig test-obj, which we will be able to use for zig unit tests
Still an issue:
- false 'dependency loop' errors remain in watch mode
- watch mode crashes observed
Follow-up:
- [ ] search `comptime Writer: type` and `comptime W: type` and remove
- [ ] remove format_mode in our zig fork
- [ ] remove deprecated.zig autoFormatLabelFallback
- [ ] remove deprecated.zig autoFormatLabel
- [ ] remove deprecated.BufferedWriter and BufferedReader
- [ ] remove override_no_export_cpp_apis as it is no longer needed
- [ ] css Parser(W) -> Parser, and remove all the comptime writer: type
params
- [ ] remove deprecated writer fully
Files that add lines:
```
649 src/deprecated.zig
167 scripts/pack-codegen-for-zig-team.ts
54 scripts/cleartrace-impl.js
46 scripts/cleartrace.ts
43 src/windows.zig
18 src/fs.zig
17 src/bun.js/ConsoleObject.zig
16 src/output.zig
12 src/bun.js/test/debug.zig
12 src/bun.js/node/node_fs.zig
8 src/env_loader.zig
7 src/css/printer.zig
7 src/cli/init_command.zig
7 src/bun.js/node.zig
6 src/string/escapeRegExp.zig
6 src/install/PnpmMatcher.zig
5 src/bun.js/webcore/Blob.zig
4 src/crash_handler.zig
4 src/bun.zig
3 src/install/lockfile/bun.lock.zig
3 src/cli/update_interactive_command.zig
3 src/cli/pack_command.zig
3 build.zig
2 src/Progress.zig
2 src/install/lockfile/lockfile_json_stringify_for_debugging.zig
2 src/css/small_list.zig
2 src/bun.js/webcore/prompt.zig
1 test/internal/ban-words.test.ts
1 test/internal/ban-limits.json
1 src/watcher/WatcherTrace.zig
1 src/transpiler.zig
1 src/shell/builtin/cp.zig
1 src/js_printer.zig
1 src/io/PipeReader.zig
1 src/install/bin.zig
1 src/css/selectors/selector.zig
1 src/cli/run_command.zig
1 src/bun.js/RuntimeTranspilerStore.zig
1 src/bun.js/bindings/JSRef.zig
1 src/bake/DevServer.zig
```
Files that remove lines:
```
-1 src/test/recover.zig
-1 src/sql/postgres/SocketMonitor.zig
-1 src/sql/mysql/MySQLRequestQueue.zig
-1 src/sourcemap/CodeCoverage.zig
-1 src/css/values/color_js.zig
-1 src/compile_target.zig
-1 src/bundler/linker_context/convertStmtsForChunk.zig
-1 src/bundler/bundle_v2.zig
-1 src/bun.js/webcore/blob/read_file.zig
-1 src/ast/base.zig
-2 src/sql/postgres/protocol/ArrayList.zig
-2 src/shell/builtin/mkdir.zig
-2 src/install/PackageManager/patchPackage.zig
-2 src/install/PackageManager/PackageManagerDirectories.zig
-2 src/fmt.zig
-2 src/css/declaration.zig
-2 src/css/css_parser.zig
-2 src/collections/baby_list.zig
-2 src/bun.js/bindings/ZigStackFrame.zig
-2 src/ast/E.zig
-3 src/StandaloneModuleGraph.zig
-3 src/deps/picohttp.zig
-3 src/deps/libuv.zig
-3 src/btjs.zig
-4 src/threading/Futex.zig
-4 src/shell/builtin/touch.zig
-4 src/meta.zig
-4 src/install/lockfile.zig
-4 src/css/selectors/parser.zig
-5 src/shell/interpreter.zig
-5 src/css/error.zig
-5 src/bun.js/web_worker.zig
-5 src/bun.js.zig
-6 src/cli/test_command.zig
-6 src/bun.js/VirtualMachine.zig
-6 src/bun.js/uuid.zig
-6 src/bun.js/bindings/JSValue.zig
-9 src/bun.js/test/pretty_format.zig
-9 src/bun.js/api/BunObject.zig
-14 src/install/install_binding.zig
-14 src/fd.zig
-14 src/bun.js/node/path.zig
-14 scripts/pack-codegen-for-zig-team.sh
-17 src/bun.js/test/diff_format.zig
```
`git diff --numstat origin/main...HEAD | awk '{ print ($1-$2)"\t"$3 }' |
sort -rn`
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
Co-authored-by: Meghan Denny <meghan@bun.com>
Co-authored-by: tayor.fish <contact@taylor.fish>
505 lines
20 KiB
Zig
505 lines
20 KiB
Zig
pub fn NewHTTPContext(comptime ssl: bool) type {
|
|
return struct {
|
|
const pool_size = 64;
|
|
const PooledSocket = struct {
|
|
http_socket: HTTPSocket,
|
|
hostname_buf: [MAX_KEEPALIVE_HOSTNAME]u8 = undefined,
|
|
hostname_len: u8 = 0,
|
|
port: u16 = 0,
|
|
/// If you set `rejectUnauthorized` to `false`, the connection fails to verify,
|
|
did_have_handshaking_error_while_reject_unauthorized_is_false: bool = false,
|
|
};
|
|
|
|
pub fn markTaggedSocketAsDead(socket: HTTPSocket, tagged: ActiveSocket) void {
|
|
if (tagged.is(PooledSocket)) {
|
|
Handler.addMemoryBackToPool(tagged.as(PooledSocket));
|
|
}
|
|
|
|
if (socket.ext(**anyopaque)) |ctx| {
|
|
ctx.* = bun.cast(**anyopaque, ActiveSocket.init(dead_socket).ptr());
|
|
}
|
|
}
|
|
|
|
pub fn markSocketAsDead(socket: HTTPSocket) void {
|
|
markTaggedSocketAsDead(socket, getTaggedFromSocket(socket));
|
|
}
|
|
|
|
pub fn terminateSocket(socket: HTTPSocket) void {
|
|
markSocketAsDead(socket);
|
|
socket.close(.failure);
|
|
}
|
|
|
|
pub fn closeSocket(socket: HTTPSocket) void {
|
|
markSocketAsDead(socket);
|
|
socket.close(.normal);
|
|
}
|
|
|
|
fn getTagged(ptr: *anyopaque) ActiveSocket {
|
|
return ActiveSocket.from(bun.cast(**anyopaque, ptr).*);
|
|
}
|
|
|
|
pub fn getTaggedFromSocket(socket: HTTPSocket) ActiveSocket {
|
|
if (socket.ext(anyopaque)) |ctx| {
|
|
return getTagged(ctx);
|
|
}
|
|
return ActiveSocket.init(dead_socket);
|
|
}
|
|
|
|
pub const PooledSocketHiveAllocator = bun.HiveArray(PooledSocket, pool_size);
|
|
|
|
pending_sockets: PooledSocketHiveAllocator,
|
|
us_socket_context: *uws.SocketContext,
|
|
|
|
const Context = @This();
|
|
pub const HTTPSocket = uws.NewSocketHandler(ssl);
|
|
|
|
pub fn context() *@This() {
|
|
if (comptime ssl) {
|
|
return &bun.http.http_thread.https_context;
|
|
} else {
|
|
return &bun.http.http_thread.http_context;
|
|
}
|
|
}
|
|
|
|
const ActiveSocket = TaggedPointerUnion(.{
|
|
DeadSocket,
|
|
HTTPClient,
|
|
PooledSocket,
|
|
});
|
|
const ssl_int = @as(c_int, @intFromBool(ssl));
|
|
|
|
const MAX_KEEPALIVE_HOSTNAME = 128;
|
|
|
|
pub fn sslCtx(this: *@This()) *BoringSSL.SSL_CTX {
|
|
if (comptime !ssl) {
|
|
unreachable;
|
|
}
|
|
|
|
return @as(*BoringSSL.SSL_CTX, @ptrCast(this.us_socket_context.getNativeHandle(true)));
|
|
}
|
|
|
|
pub fn deinit(this: *@This()) void {
|
|
this.us_socket_context.deinit(ssl);
|
|
bun.default_allocator.destroy(this);
|
|
}
|
|
|
|
pub fn initWithClientConfig(this: *@This(), client: *HTTPClient) InitError!void {
|
|
if (!comptime ssl) {
|
|
@compileError("ssl only");
|
|
}
|
|
var opts = client.tls_props.?.asUSockets();
|
|
opts.request_cert = 1;
|
|
opts.reject_unauthorized = 0;
|
|
try this.initWithOpts(&opts);
|
|
}
|
|
|
|
fn initWithOpts(this: *@This(), opts: *const uws.SocketContext.BunSocketContextOptions) InitError!void {
|
|
if (!comptime ssl) {
|
|
@compileError("ssl only");
|
|
}
|
|
|
|
var err: uws.create_bun_socket_error_t = .none;
|
|
const socket = uws.SocketContext.createSSLContext(bun.http.http_thread.loop.loop, @sizeOf(usize), opts.*, &err);
|
|
if (socket == null) {
|
|
return switch (err) {
|
|
.load_ca_file => error.LoadCAFile,
|
|
.invalid_ca_file => error.InvalidCAFile,
|
|
.invalid_ca => error.InvalidCA,
|
|
else => error.FailedToOpenSocket,
|
|
};
|
|
}
|
|
this.us_socket_context = socket.?;
|
|
this.sslCtx().setup();
|
|
|
|
HTTPSocket.configure(
|
|
this.us_socket_context,
|
|
false,
|
|
anyopaque,
|
|
Handler,
|
|
);
|
|
}
|
|
|
|
pub fn initWithThreadOpts(this: *@This(), init_opts: *const HTTPThread.InitOpts) InitError!void {
|
|
if (!comptime ssl) {
|
|
@compileError("ssl only");
|
|
}
|
|
var opts: uws.SocketContext.BunSocketContextOptions = .{
|
|
.ca = if (init_opts.ca.len > 0) @ptrCast(init_opts.ca) else null,
|
|
.ca_count = @intCast(init_opts.ca.len),
|
|
.ca_file_name = if (init_opts.abs_ca_file_name.len > 0) init_opts.abs_ca_file_name else null,
|
|
.request_cert = 1,
|
|
};
|
|
|
|
try this.initWithOpts(&opts);
|
|
}
|
|
|
|
pub fn init(this: *@This()) void {
|
|
if (comptime ssl) {
|
|
const opts: uws.SocketContext.BunSocketContextOptions = .{
|
|
// we request the cert so we load root certs and can verify it
|
|
.request_cert = 1,
|
|
// we manually abort the connection if the hostname doesn't match
|
|
.reject_unauthorized = 0,
|
|
};
|
|
var err: uws.create_bun_socket_error_t = .none;
|
|
this.us_socket_context = uws.SocketContext.createSSLContext(bun.http.http_thread.loop.loop, @sizeOf(usize), opts, &err).?;
|
|
|
|
this.sslCtx().setup();
|
|
} else {
|
|
this.us_socket_context = uws.SocketContext.createNoSSLContext(bun.http.http_thread.loop.loop, @sizeOf(usize)).?;
|
|
}
|
|
|
|
HTTPSocket.configure(
|
|
this.us_socket_context,
|
|
false,
|
|
anyopaque,
|
|
Handler,
|
|
);
|
|
}
|
|
|
|
/// Attempt to keep the socket alive by reusing it for another request.
|
|
/// If no space is available, close the socket.
|
|
///
|
|
/// If `did_have_handshaking_error_while_reject_unauthorized_is_false`
|
|
/// is set, then we can only reuse the socket for HTTP Keep Alive if
|
|
/// `reject_unauthorized` is set to `false`.
|
|
pub fn releaseSocket(this: *@This(), socket: HTTPSocket, did_have_handshaking_error_while_reject_unauthorized_is_false: bool, hostname: []const u8, port: u16) void {
|
|
// log("releaseSocket(0x{f})", .{bun.fmt.hexIntUpper(@intFromPtr(socket.socket))});
|
|
|
|
if (comptime Environment.allow_assert) {
|
|
assert(!socket.isClosed());
|
|
assert(!socket.isShutdown());
|
|
assert(socket.isEstablished());
|
|
}
|
|
assert(hostname.len > 0);
|
|
assert(port > 0);
|
|
|
|
if (hostname.len <= MAX_KEEPALIVE_HOSTNAME and !socket.isClosedOrHasError() and socket.isEstablished()) {
|
|
if (this.pending_sockets.get()) |pending| {
|
|
if (socket.ext(**anyopaque)) |ctx| {
|
|
ctx.* = bun.cast(**anyopaque, ActiveSocket.init(pending).ptr());
|
|
}
|
|
socket.flush();
|
|
socket.timeout(0);
|
|
socket.setTimeoutMinutes(5);
|
|
|
|
pending.http_socket = socket;
|
|
pending.did_have_handshaking_error_while_reject_unauthorized_is_false = did_have_handshaking_error_while_reject_unauthorized_is_false;
|
|
@memcpy(pending.hostname_buf[0..hostname.len], hostname);
|
|
pending.hostname_len = @as(u8, @truncate(hostname.len));
|
|
pending.port = port;
|
|
|
|
log("Keep-Alive release {s}:{d}", .{
|
|
hostname,
|
|
port,
|
|
});
|
|
return;
|
|
}
|
|
}
|
|
log("close socket", .{});
|
|
closeSocket(socket);
|
|
}
|
|
|
|
pub const Handler = struct {
|
|
pub fn onOpen(
|
|
ptr: *anyopaque,
|
|
socket: HTTPSocket,
|
|
) void {
|
|
const active = getTagged(ptr);
|
|
if (active.get(HTTPClient)) |client| {
|
|
if (client.onOpen(comptime ssl, socket)) |_| {
|
|
return;
|
|
} else |_| {
|
|
log("Unable to open socket", .{});
|
|
terminateSocket(socket);
|
|
return;
|
|
}
|
|
}
|
|
|
|
log("Unexpected open on unknown socket", .{});
|
|
terminateSocket(socket);
|
|
}
|
|
pub fn onHandshake(
|
|
ptr: *anyopaque,
|
|
socket: HTTPSocket,
|
|
success: i32,
|
|
ssl_error: uws.us_bun_verify_error_t,
|
|
) void {
|
|
const handshake_success = if (success == 1) true else false;
|
|
|
|
const handshake_error = HTTPCertError{
|
|
.error_no = ssl_error.error_no,
|
|
.code = if (ssl_error.code == null) "" else ssl_error.code[0..bun.len(ssl_error.code) :0],
|
|
.reason = if (ssl_error.code == null) "" else ssl_error.reason[0..bun.len(ssl_error.reason) :0],
|
|
};
|
|
|
|
const active = getTagged(ptr);
|
|
if (active.get(HTTPClient)) |client| {
|
|
// handshake completed but we may have ssl errors
|
|
client.flags.did_have_handshaking_error = handshake_error.error_no != 0;
|
|
if (handshake_success) {
|
|
if (client.flags.reject_unauthorized) {
|
|
// only reject the connection if reject_unauthorized == true
|
|
if (client.flags.did_have_handshaking_error) {
|
|
client.closeAndFail(BoringSSL.getCertErrorFromNo(handshake_error.error_no), comptime ssl, socket);
|
|
return;
|
|
}
|
|
|
|
// if checkServerIdentity returns false, we dont call open this means that the connection was rejected
|
|
const ssl_ptr = @as(*BoringSSL.SSL, @ptrCast(socket.getNativeHandle()));
|
|
if (!client.checkServerIdentity(comptime ssl, socket, handshake_error, ssl_ptr, true)) {
|
|
client.flags.did_have_handshaking_error = true;
|
|
client.unregisterAbortTracker();
|
|
if (!socket.isClosed()) terminateSocket(socket);
|
|
return;
|
|
}
|
|
}
|
|
|
|
return client.firstCall(comptime ssl, socket);
|
|
} else {
|
|
// if we are here is because server rejected us, and the error_no is the cause of this
|
|
// if we set reject_unauthorized == false this means the server requires custom CA aka NODE_EXTRA_CA_CERTS
|
|
if (client.flags.did_have_handshaking_error) {
|
|
client.closeAndFail(BoringSSL.getCertErrorFromNo(handshake_error.error_no), comptime ssl, socket);
|
|
return;
|
|
}
|
|
// if handshake_success it self is false, this means that the connection was rejected
|
|
client.closeAndFail(error.ConnectionRefused, comptime ssl, socket);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (socket.isClosed()) {
|
|
markSocketAsDead(socket);
|
|
|
|
return;
|
|
}
|
|
|
|
if (handshake_success) {
|
|
if (active.is(PooledSocket)) {
|
|
// Allow pooled sockets to be reused if the handshake was successful.
|
|
socket.setTimeout(0);
|
|
socket.setTimeoutMinutes(5);
|
|
return;
|
|
}
|
|
}
|
|
|
|
terminateSocket(socket);
|
|
}
|
|
pub fn onClose(
|
|
ptr: *anyopaque,
|
|
socket: HTTPSocket,
|
|
_: c_int,
|
|
_: ?*anyopaque,
|
|
) void {
|
|
const tagged = getTagged(ptr);
|
|
markSocketAsDead(socket);
|
|
|
|
if (tagged.get(HTTPClient)) |client| {
|
|
return client.onClose(comptime ssl, socket);
|
|
}
|
|
}
|
|
|
|
fn addMemoryBackToPool(pooled: *PooledSocket) void {
|
|
assert(context().pending_sockets.put(pooled));
|
|
}
|
|
|
|
pub fn onData(
|
|
ptr: *anyopaque,
|
|
socket: HTTPSocket,
|
|
buf: []const u8,
|
|
) void {
|
|
const tagged = getTagged(ptr);
|
|
if (tagged.get(HTTPClient)) |client| {
|
|
return client.onData(
|
|
comptime ssl,
|
|
buf,
|
|
if (comptime ssl) &bun.http.http_thread.https_context else &bun.http.http_thread.http_context,
|
|
socket,
|
|
);
|
|
} else if (tagged.is(PooledSocket)) {
|
|
// trailing zero is fine to ignore
|
|
if (strings.eqlComptime(buf, bun.http.end_of_chunked_http1_1_encoding_response_body)) {
|
|
return;
|
|
}
|
|
|
|
log("Unexpected data on socket", .{});
|
|
|
|
return;
|
|
}
|
|
log("Unexpected data on unknown socket", .{});
|
|
terminateSocket(socket);
|
|
}
|
|
pub fn onWritable(
|
|
ptr: *anyopaque,
|
|
socket: HTTPSocket,
|
|
) void {
|
|
const tagged = getTagged(ptr);
|
|
if (tagged.get(HTTPClient)) |client| {
|
|
return client.onWritable(
|
|
false,
|
|
comptime ssl,
|
|
socket,
|
|
);
|
|
} else if (tagged.is(PooledSocket)) {
|
|
// it's a keep-alive socket
|
|
} else {
|
|
// don't know what this is, let's close it
|
|
log("Unexpected writable on socket", .{});
|
|
terminateSocket(socket);
|
|
}
|
|
}
|
|
pub fn onLongTimeout(
|
|
ptr: *anyopaque,
|
|
socket: HTTPSocket,
|
|
) void {
|
|
const tagged = getTagged(ptr);
|
|
if (tagged.get(HTTPClient)) |client| {
|
|
return client.onTimeout(comptime ssl, socket);
|
|
}
|
|
|
|
terminateSocket(socket);
|
|
}
|
|
pub fn onConnectError(
|
|
ptr: *anyopaque,
|
|
socket: HTTPSocket,
|
|
_: c_int,
|
|
) void {
|
|
const tagged = getTagged(ptr);
|
|
markTaggedSocketAsDead(socket, tagged);
|
|
if (tagged.get(HTTPClient)) |client| {
|
|
client.onConnectError();
|
|
}
|
|
// us_connecting_socket_close is always called internally by uSockets
|
|
}
|
|
pub fn onEnd(
|
|
ptr: *anyopaque,
|
|
socket: HTTPSocket,
|
|
) void {
|
|
// TCP fin must be closed, but we must keep the original tagged
|
|
// pointer so that their onClose callback is called.
|
|
//
|
|
// Three possible states:
|
|
// 1. HTTP Keep-Alive socket: it must be removed from the pool
|
|
// 2. HTTP Client socket: it might need to be retried
|
|
// 3. Dead socket: it is already marked as dead
|
|
const tagged = getTagged(ptr);
|
|
markTaggedSocketAsDead(socket, tagged);
|
|
socket.close(.failure);
|
|
|
|
if (tagged.get(HTTPClient)) |client| {
|
|
client.onClose(comptime ssl, socket);
|
|
return;
|
|
}
|
|
}
|
|
};
|
|
|
|
fn existingSocket(this: *@This(), reject_unauthorized: bool, hostname: []const u8, port: u16) ?HTTPSocket {
|
|
if (hostname.len > MAX_KEEPALIVE_HOSTNAME)
|
|
return null;
|
|
|
|
var iter = this.pending_sockets.used.iterator(.{ .kind = .set });
|
|
|
|
while (iter.next()) |pending_socket_index| {
|
|
var socket = this.pending_sockets.at(@as(u16, @intCast(pending_socket_index)));
|
|
if (socket.port != port) {
|
|
continue;
|
|
}
|
|
|
|
if (socket.did_have_handshaking_error_while_reject_unauthorized_is_false and reject_unauthorized) {
|
|
continue;
|
|
}
|
|
|
|
if (strings.eqlLong(socket.hostname_buf[0..socket.hostname_len], hostname, true)) {
|
|
const http_socket = socket.http_socket;
|
|
|
|
if (http_socket.isClosed()) {
|
|
markSocketAsDead(http_socket);
|
|
continue;
|
|
}
|
|
|
|
if (http_socket.isShutdown() or http_socket.getError() != 0) {
|
|
terminateSocket(http_socket);
|
|
continue;
|
|
}
|
|
|
|
assert(context().pending_sockets.put(socket));
|
|
log("+ Keep-Alive reuse {s}:{d}", .{ hostname, port });
|
|
return http_socket;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
pub fn connectSocket(this: *@This(), client: *HTTPClient, socket_path: []const u8) !HTTPSocket {
|
|
client.connected_url = if (client.http_proxy) |proxy| proxy else client.url;
|
|
const socket = try HTTPSocket.connectUnixAnon(
|
|
socket_path,
|
|
this.us_socket_context,
|
|
ActiveSocket.init(client).ptr(),
|
|
false, // dont allow half-open sockets
|
|
);
|
|
client.allow_retry = false;
|
|
return socket;
|
|
}
|
|
|
|
pub fn connect(this: *@This(), client: *HTTPClient, hostname_: []const u8, port: u16) !HTTPSocket {
|
|
const hostname = if (FeatureFlags.hardcode_localhost_to_127_0_0_1 and strings.eqlComptime(hostname_, "localhost"))
|
|
"127.0.0.1"
|
|
else
|
|
hostname_;
|
|
|
|
client.connected_url = if (client.http_proxy) |proxy| proxy else client.url;
|
|
client.connected_url.hostname = hostname;
|
|
|
|
if (client.isKeepAlivePossible()) {
|
|
if (this.existingSocket(client.flags.reject_unauthorized, hostname, port)) |sock| {
|
|
if (sock.ext(**anyopaque)) |ctx| {
|
|
ctx.* = bun.cast(**anyopaque, ActiveSocket.init(client).ptr());
|
|
}
|
|
client.allow_retry = true;
|
|
try client.onOpen(comptime ssl, sock);
|
|
if (comptime ssl) {
|
|
client.firstCall(comptime ssl, sock);
|
|
}
|
|
return sock;
|
|
}
|
|
}
|
|
|
|
const socket = try HTTPSocket.connectAnon(
|
|
hostname,
|
|
port,
|
|
this.us_socket_context,
|
|
ActiveSocket.init(client).ptr(),
|
|
false,
|
|
);
|
|
client.allow_retry = false;
|
|
return socket;
|
|
}
|
|
};
|
|
}
|
|
|
|
const DeadSocket = struct {
|
|
garbage: u8 = 0,
|
|
pub var dead_socket: DeadSocket = .{};
|
|
};
|
|
|
|
var dead_socket = &DeadSocket.dead_socket;
|
|
const log = bun.Output.scoped(.HTTPContext, .hidden);
|
|
|
|
const HTTPCertError = @import("./HTTPCertError.zig");
|
|
const HTTPThread = @import("./HTTPThread.zig");
|
|
const TaggedPointerUnion = @import("../ptr.zig").TaggedPointerUnion;
|
|
|
|
const bun = @import("bun");
|
|
const Environment = bun.Environment;
|
|
const FeatureFlags = bun.FeatureFlags;
|
|
const assert = bun.assert;
|
|
const strings = bun.strings;
|
|
const uws = bun.uws;
|
|
const BoringSSL = bun.BoringSSL.c;
|
|
|
|
const HTTPClient = bun.http;
|
|
const InitError = HTTPClient.InitError;
|