2021-01-30 13:45:31 +00:00
|
|
|
use futures::Future;
|
2018-03-23 15:52:24 +00:00
|
|
|
use hyper::Uri;
|
2021-01-30 13:45:31 +00:00
|
|
|
use std::{
|
|
|
|
io,
|
|
|
|
net::{SocketAddr, ToSocketAddrs},
|
|
|
|
pin::Pin,
|
|
|
|
task::Poll,
|
|
|
|
};
|
|
|
|
use tokio::{
|
|
|
|
io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt},
|
|
|
|
net::TcpStream,
|
|
|
|
};
|
|
|
|
use tower_service::Service;
|
2021-01-21 20:49:39 +00:00
|
|
|
|
|
|
|
pub async fn connect<T: AsyncRead + AsyncWrite + Unpin>(
|
2021-01-30 13:45:31 +00:00
|
|
|
mut proxy_connection: T,
|
|
|
|
connect_host: &str,
|
|
|
|
connect_port: u16,
|
2021-01-21 20:49:39 +00:00
|
|
|
) -> io::Result<T> {
|
2021-01-30 13:45:31 +00:00
|
|
|
let mut buffer = Vec::new();
|
|
|
|
buffer.extend_from_slice(b"CONNECT ");
|
|
|
|
buffer.extend_from_slice(connect_host.as_bytes());
|
|
|
|
buffer.push(b':');
|
|
|
|
buffer.extend_from_slice(connect_port.to_string().as_bytes());
|
|
|
|
buffer.extend_from_slice(b" HTTP/1.1\r\n\r\n");
|
|
|
|
|
|
|
|
proxy_connection.write_all(buffer.as_ref()).await?;
|
2018-03-23 05:15:15 +00:00
|
|
|
|
2021-01-30 13:03:34 +00:00
|
|
|
buffer.resize(buffer.capacity(), 0);
|
|
|
|
|
|
|
|
let mut offset = 0;
|
|
|
|
loop {
|
2021-01-30 13:45:31 +00:00
|
|
|
let bytes_read = proxy_connection.read(&mut buffer[offset..]).await?;
|
2021-01-30 13:03:34 +00:00
|
|
|
if bytes_read == 0 {
|
|
|
|
return Err(io::Error::new(io::ErrorKind::Other, "Early EOF from proxy"));
|
|
|
|
}
|
|
|
|
offset += bytes_read;
|
2018-03-23 05:15:15 +00:00
|
|
|
|
2021-01-30 13:03:34 +00:00
|
|
|
let mut headers = [httparse::EMPTY_HEADER; 16];
|
|
|
|
let mut response = httparse::Response::new(&mut headers);
|
2018-03-23 05:15:15 +00:00
|
|
|
|
2021-01-30 13:03:34 +00:00
|
|
|
let status = response
|
|
|
|
.parse(&buffer[..offset])
|
|
|
|
.map_err(|err| io::Error::new(io::ErrorKind::Other, err))?;
|
|
|
|
|
|
|
|
if status.is_complete() {
|
|
|
|
return match response.code {
|
2021-01-30 13:45:31 +00:00
|
|
|
Some(200) => Ok(proxy_connection), // Proxy says all is well
|
2021-01-30 13:03:34 +00:00
|
|
|
Some(code) => {
|
|
|
|
let reason = response.reason.unwrap_or("no reason");
|
|
|
|
let msg = format!("Proxy responded with {}: {}", code, reason);
|
|
|
|
Err(io::Error::new(io::ErrorKind::Other, msg))
|
|
|
|
}
|
|
|
|
None => Err(io::Error::new(
|
|
|
|
io::ErrorKind::Other,
|
|
|
|
"Malformed response from proxy",
|
|
|
|
)),
|
|
|
|
};
|
|
|
|
}
|
2018-03-23 05:15:15 +00:00
|
|
|
|
2021-01-30 13:03:34 +00:00
|
|
|
if offset >= buffer.len() {
|
|
|
|
buffer.resize(buffer.len() * 2, 0);
|
2018-03-23 05:15:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-01-30 13:45:31 +00:00
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct ProxyTunnel {
|
|
|
|
proxy_addr: SocketAddr,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ProxyTunnel {
|
|
|
|
pub fn new<T: ToSocketAddrs>(addr: T) -> io::Result<Self> {
|
|
|
|
let addr = addr.to_socket_addrs()?.next().ok_or_else(|| {
|
|
|
|
io::Error::new(io::ErrorKind::InvalidInput, "No socket address given")
|
|
|
|
})?;
|
|
|
|
Ok(Self { proxy_addr: addr })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Service<Uri> for ProxyTunnel {
|
|
|
|
type Response = TcpStream;
|
|
|
|
type Error = io::Error;
|
|
|
|
type Future = Pin<Box<dyn Future<Output = io::Result<TcpStream>> + Send>>;
|
|
|
|
|
|
|
|
fn poll_ready(&mut self, _: &mut std::task::Context<'_>) -> Poll<io::Result<()>> {
|
|
|
|
Poll::Ready(Ok(()))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn call(&mut self, url: Uri) -> Self::Future {
|
|
|
|
let proxy_addr = self.proxy_addr;
|
|
|
|
let fut = async move {
|
|
|
|
let host = url
|
|
|
|
.host()
|
|
|
|
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Host is missing"))?;
|
|
|
|
let port = url
|
|
|
|
.port()
|
|
|
|
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Port is missing"))?;
|
|
|
|
|
|
|
|
let conn = TcpStream::connect(proxy_addr).await?;
|
|
|
|
connect(conn, host, port.as_u16()).await
|
|
|
|
};
|
|
|
|
|
|
|
|
Box::pin(fut)
|
|
|
|
}
|
|
|
|
}
|