Skip to content

Commit eb8d9d6

Browse files
committed
Add HTTPS proxy support
The addition of HTTPS proxy support requires a change of the `connect_host` interface. The return type is changed, but since this is only used internally in this one file and has visibility pub(crate) this should not be a breaking change.
1 parent 2300a5b commit eb8d9d6

File tree

2 files changed

+35
-10
lines changed

2 files changed

+35
-10
lines changed

src/proxy.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::{
99
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1010
pub enum Proto {
1111
HTTP,
12+
HTTPS,
1213
SOCKS4,
1314
SOCKS4A,
1415
SOCKS5,
@@ -119,6 +120,7 @@ impl Proxy {
119120
let proto = if proxy_parts.len() == 2 {
120121
match proxy_parts.next() {
121122
Some("http") => Proto::HTTP,
123+
Some("https") => Proto::HTTPS,
122124
Some("socks4") => Proto::SOCKS4,
123125
Some("socks4a") => Proto::SOCKS4A,
124126
Some("socks") => Proto::SOCKS5,
@@ -153,7 +155,10 @@ impl Proxy {
153155
server,
154156
user,
155157
password,
156-
port: port.unwrap_or(8080),
158+
port: port.unwrap_or(match proto {
159+
Proto::HTTPS => 443,
160+
_ => 8080,
161+
}),
157162
proto,
158163
})
159164
}
@@ -228,6 +233,13 @@ mod tests {
228233
assert_eq!(proxy.proto, Proto::HTTP);
229234
}
230235

236+
#[test]
237+
fn parse_proxy_https_server() {
238+
let proxy = Proxy::new("https://localhost").unwrap();
239+
assert_eq!(proxy.server, String::from("localhost"));
240+
assert_eq!(proxy.proto, Proto::HTTPS);
241+
}
242+
231243
#[cfg(feature = "socks-proxy")]
232244
#[test]
233245
fn parse_proxy_socks4_user_pass_server_port() {

src/stream.rs

+22-9
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ pub(crate) fn connect_https(unit: &Unit, hostname: &str) -> Result<Stream, Error
336336
let (sock, remote_addr) = connect_host(unit, hostname, port)?;
337337

338338
let tls_conf = &unit.agent.config.tls_config;
339-
let https_stream = tls_conf.connect(hostname, Box::new(sock))?;
339+
let https_stream = tls_conf.connect(hostname, sock)?;
340340
let pool_key = PoolKey::from_parts("https", hostname, port);
341341
let pool_returner = PoolReturner::new(&unit.agent, pool_key);
342342
Ok(Stream::new(https_stream, remote_addr, pool_returner))
@@ -347,7 +347,7 @@ pub(crate) fn connect_host(
347347
unit: &Unit,
348348
hostname: &str,
349349
port: u16,
350-
) -> Result<(TcpStream, SocketAddr), Error> {
350+
) -> Result<(Box<dyn ReadWrite>, SocketAddr), Error> {
351351
let connect_deadline: Option<Instant> =
352352
if let Some(timeout_connect) = unit.agent.config.timeout_connect {
353353
Instant::now().checked_add(timeout_connect)
@@ -395,7 +395,8 @@ pub(crate) fn connect_host(
395395

396396
// connect with a configured timeout.
397397
#[allow(clippy::unnecessary_unwrap)]
398-
let stream = if proto.is_some() && Some(Proto::HTTP) != proto {
398+
let stream = if proto.is_some() && Some(Proto::HTTP) != proto && Some(Proto::HTTPS) != proto
399+
{
399400
connect_socks(
400401
unit,
401402
proxy.clone().unwrap(),
@@ -419,7 +420,7 @@ pub(crate) fn connect_host(
419420
}
420421
}
421422

422-
let (mut stream, remote_addr) = if let Some(stream_and_addr) = any_stream_and_addr {
423+
let (stream, remote_addr) = if let Some(stream_and_addr) = any_stream_and_addr {
423424
stream_and_addr
424425
} else if let Some(e) = any_err {
425426
return Err(ErrorKind::ConnectionFailed.msg("Connect error").src(e));
@@ -441,26 +442,38 @@ pub(crate) fn connect_host(
441442
stream.set_write_timeout(unit.agent.config.timeout_write)?;
442443
}
443444

444-
if proto == Some(Proto::HTTP) && unit.url.scheme() == "https" {
445+
if (proto == Some(Proto::HTTP) || proto == Some(Proto::HTTPS)) && unit.url.scheme() == "https" {
445446
if let Some(ref proxy) = proxy {
447+
let stream = stream.try_clone()?;
448+
let mut s;
449+
if proto == Some(Proto::HTTPS) {
450+
s = unit
451+
.agent
452+
.config
453+
.tls_config
454+
.connect(&proxy.server, Box::new(stream))?;
455+
} else {
456+
s = Box::new(stream);
457+
}
446458
write!(
447-
stream,
459+
s,
448460
"{}",
449461
proxy.connect(hostname, port, &unit.agent.config.user_agent)
450462
)
451463
.unwrap();
452-
stream.flush()?;
464+
s.flush()?;
453465

454-
let s = stream.try_clone()?;
466+
// let s = s.try_clone()?; FIXME enable something like this so that we can return the stream
455467
let pool_key = PoolKey::from_parts(unit.url.scheme(), hostname, port);
456468
let pool_returner = PoolReturner::new(&unit.agent, pool_key);
457469
let s = Stream::new(s, remote_addr, pool_returner);
458470
let response = Response::do_from_stream(s, unit.clone())?;
459471
Proxy::verify_response(&response)?;
472+
// TODO! return Ok((Box::new(s), remote_addr)) otherwise this tunnel is not used
460473
}
461474
}
462475

463-
Ok((stream, remote_addr))
476+
Ok((Box::new(stream), remote_addr))
464477
}
465478

466479
#[cfg(feature = "socks-proxy")]

0 commit comments

Comments
 (0)