Function connectTunnel [src]
Connect to tunnel_host:tunnel_port using the specified proxy with HTTP
CONNECT. This will reuse a connection if one is already open.
This function is threadsafe.
Prototype
pub fn connectTunnel( client: *Client, proxy: *Proxy, tunnel_host: []const u8, tunnel_port: u16, ) !*Connection
Parameters
client: *Client
proxy: *Proxy
tunnel_host: []const u8
tunnel_port: u16
Source
pub fn connectTunnel(
client: *Client,
proxy: *Proxy,
tunnel_host: []const u8,
tunnel_port: u16,
) !*Connection {
if (!proxy.supports_connect) return error.TunnelNotSupported;
if (client.connection_pool.findConnection(.{
.host = tunnel_host,
.port = tunnel_port,
.protocol = proxy.protocol,
})) |node|
return node;
var maybe_valid = false;
(tunnel: {
const conn = try client.connectTcp(proxy.host, proxy.port, proxy.protocol);
errdefer {
conn.closing = true;
client.connection_pool.release(client.allocator, conn);
}
var buffer: [8096]u8 = undefined;
var req = client.open(.CONNECT, .{
.scheme = "http",
.host = .{ .raw = tunnel_host },
.port = tunnel_port,
}, .{
.redirect_behavior = .unhandled,
.connection = conn,
.server_header_buffer = &buffer,
}) catch |err| {
std.log.debug("err {}", .{err});
break :tunnel err;
};
defer req.deinit();
req.send() catch |err| break :tunnel err;
req.wait() catch |err| break :tunnel err;
if (req.response.status.class() == .server_error) {
maybe_valid = true;
break :tunnel error.ServerError;
}
if (req.response.status != .ok) break :tunnel error.ConnectionRefused;
// this connection is now a tunnel, so we can't use it for anything else, it will only be released when the client is de-initialized.
req.connection = null;
client.allocator.free(conn.host);
conn.host = try client.allocator.dupe(u8, tunnel_host);
errdefer client.allocator.free(conn.host);
conn.port = tunnel_port;
conn.closing = false;
return conn;
}) catch {
// something went wrong with the tunnel
proxy.supports_connect = maybe_valid;
return error.TunnelNotSupported;
};
}