pub use crate::auth::Auth;
use crate::{errors, is_ok_status};
use errors::Error;
use http::Uri;
use std::net::SocketAddrV4;
use tokio::{
io::{AsyncReadExt, AsyncWriteExt},
net::TcpStream,
};
pub async fn tunnel(
dest: &Uri,
proxy_server: SocketAddrV4,
auth: Auth,
) -> crate::Result<TcpStream> {
let host = dest.host().ok_or(Error::InvalidURI)?;
let port = dest.port().ok_or(Error::InvalidURI)?;
let mut conn = TcpStream::connect(proxy_server).await?;
let mut packet = format!(
"GET {dest} HTTP/1.1\r\nHost: {host}:{port}\r\nConnection: Upgrade\r\nUpgrade: connect-ip\r\n",
);
if let Auth::HTTPAuthorizationHeader(header) = auth {
packet.push_str(&format!("{}\r\n", header));
}
packet.push_str("\r\n");
conn.write_all(packet.as_bytes()).await?;
conn.flush().await?;
let mut response = Vec::new();
loop {
let mut buf = [0u8; 1024];
let n = conn.read(&mut buf).await?;
if n == 0 {
break;
}
response.extend_from_slice(&buf[..n]);
if response.ends_with(b"\r\n\r\n") {
break;
}
}
let response = String::from_utf8_lossy(&response);
if !is_ok_status(response.clone()) {
return Err(Error::ProxyResponseNotOk(response.to_string()));
}
Ok(conn)
}