diff options
author | 2022-02-03 21:01:14 -0800 | |
---|---|---|
committer | 2022-02-03 21:01:14 -0800 | |
commit | baffe26dd1e8da568fc77da53d36cd9c77d38c1d (patch) | |
tree | 827c6915b46f996673379c4be4d785d32942d16a /src/http/async_socket.zig | |
parent | 1993f9f9a5f3b62ec55ee605d15dfce63afecbcd (diff) | |
download | bun-baffe26dd1e8da568fc77da53d36cd9c77d38c1d.tar.gz bun-baffe26dd1e8da568fc77da53d36cd9c77d38c1d.tar.zst bun-baffe26dd1e8da568fc77da53d36cd9c77d38c1d.zip |
Fix bug with http client
Diffstat (limited to 'src/http/async_socket.zig')
-rw-r--r-- | src/http/async_socket.zig | 112 |
1 files changed, 77 insertions, 35 deletions
diff --git a/src/http/async_socket.zig b/src/http/async_socket.zig index db4964fc0..e58462b09 100644 --- a/src/http/async_socket.zig +++ b/src/http/async_socket.zig @@ -196,6 +196,11 @@ pub const SendError = AsyncIO.SendError; pub fn deinit(this: *AsyncSocket) void { this.head.release(); + this.err = null; + this.queued = 0; + this.sent = 0; + this.read_context = &[_]u8{}; + this.read_offset = 0; } pub fn send(this: *AsyncSocket) SendError!usize { @@ -309,7 +314,7 @@ pub const SSL = struct { ssl_loaded: bool = false, socket: AsyncSocket, handshake_complete: bool = false, - ssl_bio: ?*AsyncBIO = null, + ssl_bio: AsyncBIO = undefined, unencrypted_bytes_to_send: ?*AsyncMessage = null, connect_frame: Yield(SSL.handshake) = Yield(SSL.handshake){}, send_frame: Yield(SSL.send) = Yield(SSL.send){}, @@ -330,6 +335,8 @@ pub const SSL = struct { pending_read_result: anyerror!u32 = 0, pending_write_result: anyerror!u32 = 0, + handshake_retry_count: u16 = 5, + first_post_handshake_write: bool = true, handshake_result: ?anyerror = null, @@ -371,18 +378,16 @@ pub const SSL = struct { ssl.setHostname(name_); } - var bio = try AsyncBIO.init(this.socket.allocator); - errdefer bio.release(); - bio.onReady = AsyncBIO.Callback.Wrap(SSL, SSL.retryAll).get(this); - bio.socket_fd = this.socket.socket; - this.ssl_bio = bio; + try this.ssl_bio.init(); + this.ssl_bio.onReady = AsyncBIO.Callback.Wrap(SSL, SSL.retryAll).get(this); + this.ssl_bio.socket_fd = this.socket.socket; - boring.SSL_set_bio(ssl, bio.bio, bio.bio); + boring.SSL_set_bio(ssl, this.ssl_bio.bio.?, this.ssl_bio.bio.?); // boring.SSL_set_early_data_enabled(ssl, 1); _ = boring.SSL_clear_options(ssl, boring.SSL_OP_NO_COMPRESSION | boring.SSL_OP_LEGACY_SERVER_CONNECT); _ = boring.SSL_set_options(ssl, boring.SSL_OP_NO_COMPRESSION | boring.SSL_OP_LEGACY_SERVER_CONNECT); - const mode = boring.SSL_MODE_RELEASE_BUFFERS | boring.SSL_MODE_CBC_RECORD_SPLITTING | boring.SSL_MODE_ENABLE_FALSE_START; + const mode = boring.SSL_MODE_CBC_RECORD_SPLITTING | boring.SSL_MODE_ENABLE_FALSE_START; _ = boring.SSL_set_mode(ssl, mode); _ = boring.SSL_clear_mode(ssl, mode); @@ -407,7 +412,7 @@ pub const SSL = struct { boring.SSL_set_shed_handshake_config(ssl, 1); - this.unencrypted_bytes_to_send = AsyncMessage.get(this.socket.allocator); + this.unencrypted_bytes_to_send = this.socket.head; try this.handshake(); @@ -497,9 +502,9 @@ pub const SSL = struct { } pub fn doPayloadRead(this: *SSL, buffer: []u8, count: *u32) anyerror!u32 { - if (this.ssl_bio.?.socket_recv_error != null) { - const pending = this.ssl_bio.?.socket_recv_error.?; - this.ssl_bio.?.socket_recv_error = null; + if (this.ssl_bio.socket_recv_error != null) { + const pending = this.ssl_bio.socket_recv_error.?; + this.ssl_bio.socket_recv_error = null; return pending; } @@ -508,6 +513,7 @@ pub const SSL = struct { var ssl_err: c_int = 0; const buf_len = @truncate(u32, buffer.len); while (true) { + boring.ERR_clear_error(); ssl_ret = boring.SSL_read(this.ssl, buffer.ptr + total_bytes_read, @intCast(c_int, buf_len - total_bytes_read)); ssl_err = boring.SSL_get_error(this.ssl, ssl_ret); @@ -521,7 +527,7 @@ pub const SSL = struct { // Continue processing records as long as there is more data available // synchronously. - if (!(ssl_err == boring.SSL_ERROR_WANT_RENEGOTIATE or (total_bytes_read < buf_len and ssl_ret > 0 and this.ssl_bio.?.hasPendingReadData()))) break; + if (!(ssl_err == boring.SSL_ERROR_WANT_RENEGOTIATE or (total_bytes_read < buf_len and ssl_ret > 0 and this.ssl_bio.hasPendingReadData()))) break; } // Although only the final SSL_read call may have failed, the failure needs to @@ -547,6 +553,13 @@ pub const SSL = struct { result = error.WouldBlock; }, else => { + if (extremely_verbose) { + const err = boring.ERR_get_error(); + + const version = std.mem.span(boring.SSL_get_version(this.ssl)); + var hostname = std.mem.span(std.mem.sliceTo(&this.hostname, 0)); + Output.prettyErrorln("[{s}] OpenSSLError reading (version: {s}, total read: {d}) - code: {d}", .{ hostname, version, total_bytes_read, err }); + } result = error.OpenSSLError; }, } @@ -556,8 +569,8 @@ pub const SSL = struct { // a connection, and instead terminate the TCP connection. This is reported // as ERR_CONNECTION_CLOSED. Because of this, map the unclean shutdown to a // graceful EOF, instead of treating it as an error as it should be. - if (this.ssl_bio.?.socket_recv_error) |err| { - this.ssl_bio.?.socket_recv_error = null; + if (this.ssl_bio.socket_recv_error) |err| { + this.ssl_bio.socket_recv_error = null; return err; } @@ -630,6 +643,7 @@ pub const SSL = struct { } var byte: u8 = 0; + boring.ERR_clear_error(); var rv = boring.SSL_peek(this.ssl, &byte, 1); var ssl_error = boring.SSL_get_error(this.ssl, rv); switch (ssl_error) { @@ -641,6 +655,8 @@ pub const SSL = struct { } fn doHandshake(this: *SSL) HandshakeError!void { + boring.ERR_clear_error(); + const rv = boring.SSL_do_handshake(this.ssl); if (rv <= 0) { const ssl_error = boring.SSL_get_error(this.ssl, rv); @@ -658,7 +674,25 @@ pub const SSL = struct { this.next_handshake_state = HandshakeState.handshake; return error.WouldBlock; }, - else => return error.OpenSSLError, + boring.SSL_ERROR_SYSCALL => { + this.handshake_retry_count -|= 1; + if (this.handshake_retry_count > 0) { + this.next_handshake_state = HandshakeState.handshake; + return error.WouldBlock; + } + + return error.OpenSSLError; + }, + else => { + if (extremely_verbose) { + const err = boring.ERR_get_error(); + var error_buf: [1024]u8 = undefined; + @memset(&error_buf, 0, 1024); + var err_msg = std.mem.span(boring.ERR_error_string(err, &error_buf)); + Output.prettyErrorln("Handshaking error {s}", .{err_msg}); + } + return error.OpenSSLError; + }, } } @@ -748,38 +782,46 @@ pub const SSL = struct { pub inline fn init(allocator: std.mem.Allocator, io: *AsyncIO) !SSL { return SSL{ + .ssl_bio = AsyncBIO{ + .allocator = allocator, + }, .socket = try AsyncSocket.init(io, 0, allocator), }; } pub fn deinit(this: *SSL) void { this.socket.deinit(); - if (!this.is_ssl) return; - - if (this.ssl_bio) |bio| { - _ = boring.BIO_set_data(bio.bio, null); - bio.socket_fd = 0; - bio.onReady = null; - bio.release(); - this.ssl_bio = null; - } if (this.ssl_loaded) { + _ = boring.SSL_shutdown(this.ssl); this.ssl.deinit(); this.ssl_loaded = false; } - this.handshake_complete = false; - - if (this.unencrypted_bytes_to_send) |bio| { - var next_ = bio.next; - while (next_) |next| { - next.release(); - next_ = next.next; - } + if (this.ssl_bio.recv_buffer) |recv| { + recv.release(); + } - bio.release(); - this.unencrypted_bytes_to_send = null; + if (this.ssl_bio.send_buffer) |recv| { + recv.release(); } + + this.ssl_bio.pending_reads = 0; + this.ssl_bio.pending_sends = 0; + this.ssl_bio.socket_recv_len = 0; + this.ssl_bio.socket_send_len = 0; + this.ssl_bio.bio_write_offset = 0; + this.ssl_bio.bio_read_offset = 0; + this.ssl_bio.socket_send_error = null; + this.ssl_bio.socket_recv_error = null; + + this.ssl_bio.socket_fd = 0; + this.ssl_bio.onReady = null; + + this.handshake_complete = false; + + this.* = SSL{ + .socket = this.socket, + }; } }; |