Skip to content

Commit 5b02ed7

Browse files
committed
TLS connect proxy WIP
1 parent a2565a7 commit 5b02ed7

File tree

1 file changed

+66
-14
lines changed

1 file changed

+66
-14
lines changed

src/http/client.zig

Lines changed: 66 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -322,11 +322,19 @@ const Connection = struct {
322322

323323
const TLSClient = union(enum) {
324324
blocking: tls.Connection(std.net.Stream),
325+
blocking_tls_in_tls: struct {
326+
proxy: tls.Connection(std.net.Stream),
327+
destination: tls.Connection(*tls.Connection(std.net.Stream)),
328+
},
325329
nonblocking: tls.nonblock.Connection,
326330

327331
fn close(self: *TLSClient) void {
328332
switch (self.*) {
329333
.blocking => |*tls_client| tls_client.close() catch {},
334+
.blocking_tls_in_tls => {}, // |*tls_in_tls| {
335+
// tls_in_tls.destination.close() catch {}; // Crashes
336+
// tls_in_tls.proxy.close() catch {};
337+
// },
330338
.nonblocking => {},
331339
}
332340
}
@@ -657,18 +665,32 @@ pub const Request = struct {
657665

658666
const is_connect_proxy = self._client.isConnectProxy();
659667
if (is_connect_proxy) {
660-
try SyncHandler.connect(self);
661-
}
662-
663-
if (self._secure) {
664-
self._connection.?.tls = .{
665-
.blocking = try tls.client(std.net.Stream{ .handle = socket }, .{
666-
.host = if (is_connect_proxy) self._request_host else self._connect_host,
668+
var connect_connection = try SyncHandler.connect(self);
669+
if (self._secure) { // TODO separate _secure for proxy and desination
670+
const tls_in_tls = try tls.client(&connect_connection, .{
671+
.host = self._request_host,
667672
.root_ca = self._client.root_ca,
668673
.insecure_skip_verify = self._tls_verify_host == false,
669674
// .key_log_callback = tls.config.key_log.callback,
670-
}),
671-
};
675+
});
676+
self._connection.?.tls = .{
677+
.blocking_tls_in_tls = .{
678+
.proxy = connect_connection,
679+
.destination = tls_in_tls,
680+
},
681+
};
682+
}
683+
} else {
684+
if (self._secure) {
685+
self._connection.?.tls = .{
686+
.blocking = try tls.client(std.net.Stream{ .handle = socket }, .{
687+
.host = if (is_connect_proxy) self._request_host else self._connect_host,
688+
.root_ca = self._client.root_ca,
689+
.insecure_skip_verify = self._tls_verify_host == false,
690+
// .key_log_callback = tls.config.key_log.callback,
691+
}),
692+
};
693+
}
672694
}
673695

674696
self._connection_from_keepalive = false;
@@ -1721,7 +1743,15 @@ const SyncHandler = struct {
17211743
var conn: Conn = blk: {
17221744
const c = request._connection.?;
17231745
if (c.tls) |*tls_client| {
1724-
break :blk .{ .tls = &tls_client.blocking };
1746+
switch (tls_client.*) {
1747+
.nonblocking => unreachable,
1748+
.blocking => |*blocking| {
1749+
break :blk .{ .tls = blocking };
1750+
},
1751+
.blocking_tls_in_tls => |*blocking_tls_in_tls| {
1752+
break :blk .{ .tls_in_tls = &blocking_tls_in_tls.destination };
1753+
},
1754+
}
17251755
}
17261756
break :blk .{ .plain = c.socket };
17271757
};
@@ -1804,11 +1834,18 @@ const SyncHandler = struct {
18041834

18051835
// Unfortunately, this is called from the Request doSendSync since we need
18061836
// to do this before setting up our TLS connection.
1807-
fn connect(request: *Request) !void {
1837+
fn connect(request: *Request) !tls.Connection(std.net.Stream) {
18081838
const socket = request._connection.?.socket;
18091839

18101840
const header = try request.buildConnectHeader();
1811-
try Conn.writeAll(socket, header);
1841+
// try Conn.writeAll(socket, header);
1842+
var tls_client = try tls.client(std.net.Stream{ .handle = socket }, .{
1843+
.host = request._connect_host,
1844+
.root_ca = request._client.root_ca,
1845+
.insecure_skip_verify = request._tls_verify_host == false,
1846+
.key_log_callback = tls.config.key_log.callback,
1847+
});
1848+
try tls_client.writeAll(header);
18121849

18131850
var pos: usize = 0;
18141851
var reader = request.newReader();
@@ -1819,18 +1856,24 @@ const SyncHandler = struct {
18191856
// we only send CONNECT requests on newly established connections
18201857
// and maybeRetryOrErr is only for connections that might have been
18211858
// closed while being kept-alive
1822-
const n = try posix.read(socket, read_buf[pos..]);
1859+
// const n = try posix.read(socket, read_buf[pos..]);
1860+
// const n = switch (self.*) {
1861+
// .tls => |tls_client| try tls_client.read(buf),
1862+
// .plain => |socket| try posix.read(socket, buf),
1863+
// };
1864+
const n = try tls_client.read(read_buf[pos..]);
18231865
if (n == 0) {
18241866
return error.ConnectionResetByPeer;
18251867
}
18261868
pos += n;
18271869
if (try reader.connectResponse(read_buf[0..pos])) {
18281870
// returns true if we have a successful connect response
1829-
return;
1871+
return tls_client;
18301872
}
18311873

18321874
// we don't have enough data yet.
18331875
}
1876+
return tls_client;
18341877
}
18351878

18361879
fn maybeRetryOrErr(self: *SyncHandler, err: anyerror) !Response {
@@ -1880,11 +1923,18 @@ const SyncHandler = struct {
18801923
}
18811924

18821925
const Conn = union(enum) {
1926+
tls_in_tls: *tls.Connection(*tls.Connection(std.net.Stream)),
18831927
tls: *tls.Connection(std.net.Stream),
18841928
plain: posix.socket_t,
18851929

18861930
fn sendRequest(self: *Conn, header: []const u8, body: ?[]const u8) !void {
18871931
switch (self.*) {
1932+
.tls_in_tls => |tls_client| {
1933+
try tls_client.writeAll(header);
1934+
if (body) |b| {
1935+
try tls_client.writeAll(b);
1936+
}
1937+
},
18881938
.tls => |tls_client| {
18891939
try tls_client.writeAll(header);
18901940
if (body) |b| {
@@ -1906,6 +1956,7 @@ const SyncHandler = struct {
19061956

19071957
fn read(self: *Conn, buf: []u8) !usize {
19081958
const n = switch (self.*) {
1959+
.tls_in_tls => |tls_client| try tls_client.read(buf),
19091960
.tls => |tls_client| try tls_client.read(buf),
19101961
.plain => |socket| try posix.read(socket, buf),
19111962
};
@@ -2081,6 +2132,7 @@ const Reader = struct {
20812132
if (result.done == false) {
20822133
// CONNECT responses should not have a body. If the header is
20832134
// done, then the entire response should be done.
2135+
log.err(.http_client, "InvalidConnectResponse", .{ .unprocessed = result.unprocessed.? });
20842136
return error.InvalidConnectResponse;
20852137
}
20862138

0 commit comments

Comments
 (0)