librespot_core/
proxytunnel.rs1use std::io;
2
3use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
4
5pub async fn proxy_connect<T: AsyncRead + AsyncWrite + Unpin>(
6 mut proxy_connection: T,
7 connect_host: &str,
8 connect_port: &str,
9) -> io::Result<T> {
10 let mut buffer = Vec::new();
11 buffer.extend_from_slice(b"CONNECT ");
12 buffer.extend_from_slice(connect_host.as_bytes());
13 buffer.push(b':');
14 buffer.extend_from_slice(connect_port.as_bytes());
15 buffer.extend_from_slice(b" HTTP/1.1\r\n\r\n");
16
17 proxy_connection.write_all(buffer.as_ref()).await?;
18
19 buffer.resize(buffer.capacity(), 0);
20
21 let mut offset = 0;
22 loop {
23 let bytes_read = proxy_connection.read(&mut buffer[offset..]).await?;
24 if bytes_read == 0 {
25 return Err(io::Error::other("Early EOF from proxy"));
26 }
27 offset += bytes_read;
28
29 let mut headers = [httparse::EMPTY_HEADER; 16];
30 let mut response = httparse::Response::new(&mut headers);
31
32 let status = response
33 .parse(&buffer[..offset])
34 .map_err(io::Error::other)?;
35
36 if status.is_complete() {
37 return match response.code {
38 Some(200) => Ok(proxy_connection), Some(code) => {
40 let reason = response.reason.unwrap_or("no reason");
41 let msg = format!("Proxy responded with {code}: {reason}");
42 Err(io::Error::other(msg))
43 }
44 None => Err(io::Error::other("Malformed response from proxy")),
45 };
46 }
47
48 if offset >= buffer.len() {
49 buffer.resize(buffer.len() + 100, 0);
50 }
51 }
52}