use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::{TcpListener, TcpStream};
pub fn content(host: &str, proxy_port: u16) -> String {
let host = host.trim().trim_end_matches('.').to_ascii_lowercase();
let host_cond = format!("host === \"{host}\" || host.endsWith(\".{host}\")");
r#"function FindProxyForURL(url, host) {
host = host.toLowerCase();
if (__HOST_COND__) {
return "PROXY 127.0.0.1:__PORT__";
}
return "DIRECT";
}
"#
.replace("__HOST_COND__", &host_cond)
.replace("__PORT__", &proxy_port.to_string())
}
pub async fn serve(listener: TcpListener, content: String) {
loop {
let Ok((socket, _)) = listener.accept().await else {
continue;
};
let content = content.clone();
tokio::spawn(handle(socket, content));
}
}
async fn handle(mut socket: TcpStream, content: String) {
let mut buf = [0u8; 1024];
let mut seen = 0usize;
loop {
match socket.read(&mut buf[seen..]).await {
Ok(0) => break,
Ok(n) => {
seen += n;
if buf[..seen].windows(4).any(|w| w == b"\r\n\r\n") || seen == buf.len() {
break;
}
}
Err(_) => break,
}
}
let response = format!(
"HTTP/1.1 200 OK\r\nContent-Type: application/x-ns-proxy-autoconfig\r\nContent-Length: {}\r\nCache-Control: no-cache\r\nConnection: close\r\n\r\n{}",
content.len(),
content
);
let _ = socket.write_all(response.as_bytes()).await;
let _ = socket.shutdown().await;
}