Created
May 3, 2020 17:00
-
-
Save Plecra/d95f170bc8f42ed80158f3dcc19bcc9a to your computer and use it in GitHub Desktop.
A smol proxy server
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use anyhow::*; | |
use futures::io::{copy, AsyncReadExt, AsyncWriteExt}; | |
use futures::stream::StreamExt; | |
use log::*; | |
use smol::Async; | |
use std::net; | |
const PORT: u16 = 5000; | |
async fn handle_client(mut stream: Async<net::TcpStream>) -> Result<()> { | |
info!("Request from {:?}", stream); | |
// Open a TCP connection to the website | |
let tunnel = { | |
// Read the CONNECT request | |
let mut buf = [0; 4096]; | |
let nbytes = stream.read(&mut buf).await?; | |
let req = std::str::from_utf8(&buf[..nbytes])?; | |
info!("Received request\n{}", req); | |
let website = req | |
.split_whitespace() | |
.nth(1) | |
.ok_or(anyhow!("invalid request"))?; | |
info!("Connecting to {}", website); | |
Async::<net::TcpStream>::connect(website).await? | |
}; | |
// Send an acknowledgement to the client | |
stream | |
.write_all(b"HTTP/1.1 200 Connection established\r\n\r\n") | |
.await?; | |
// Keep copying data back and forth | |
futures::future::try_join( | |
copy(&mut &stream, &mut &tunnel), | |
copy(&mut &tunnel, &mut &stream), | |
) | |
.await?; | |
Ok(()) | |
} | |
fn main() { | |
env_logger::init(); | |
smol::run(async { | |
// Create a server | |
let server = | |
Async::<net::TcpListener>::bind(format!("127.0.0.1:{}", PORT)).unwrap_or_else(|e| { | |
if e.kind() == std::io::ErrorKind::AddrInUse { | |
error!("Port {} is already being used by another program", PORT); | |
std::process::exit(1); | |
} else { | |
panic!("{:?}", e); | |
} | |
}); | |
info!( | |
"Listening on port {}", | |
server.get_ref().local_addr().unwrap().port() | |
); | |
// Handle incoming connections | |
server | |
.incoming() | |
.for_each_concurrent(None, |ev| async move { | |
if let Ok(stream) = ev { | |
if let Err(error) = handle_client(stream).await { | |
error!("error while handling stream: {}", error); | |
} | |
} | |
}) | |
.await; | |
}) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
For now, smol's API is still young and has some growing to do. This should be improved with smol-rs/smol#77