zeloxy 0.5.2

A library for creating lightweight, async, and lag-free proxy connections.
Documentation
use std::time::Duration;

use base64::Engine;
use base64::engine::general_purpose::STANDARD;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::TcpStream;

use crate::proxy::ProxyAuth;
use crate::{ErrorKind, ProxyError, ProxyResult};

/// Функция валидации ответа прокси
fn validate_proxy_response(resp: &[u8]) -> ProxyResult<()> {
  let resp_str = String::from_utf8_lossy(&resp);
  let status_line = resp_str.lines().next().unwrap_or("");

  if !status_line.contains("200") && !status_line.contains("Connection established") {
    return Err(ProxyError::new(
      ErrorKind::NotConnected,
      format!("unsuccessful proxy response status: {}", status_line),
    ));
  }

  Ok(())
}

/// Функция создания подключения с HTTP прокси
pub async fn connect_http(stream: &mut TcpStream, target_host: String, target_port: u16, auth: &Option<ProxyAuth>) -> ProxyResult<()> {
  let mut req = format!(
    "GET http://{}:{} HTTP/1.1\r\n\
    Host: {}\r\n",
    target_host, target_port, target_host
  );

  if let Some(a) = auth {
    let auth_str = match a {
      ProxyAuth::Basic { username, password } => {
        let credentials = format!("{}:{}", username, password);
        format!("Basic {}", STANDARD.encode(&credentials))
      }
      ProxyAuth::Bearer { token } => {
        format!("Bearer {}", token)
      }
      _ => {
        return Err(ProxyError::new(
          ErrorKind::AuthFailed,
          "specified incorrect authorization method for HTTP",
        ));
      }
    };

    req.push_str(&format!("Proxy-Authorization: {}\r\n", auth_str));
  }

  req.push_str("\r\n");

  stream.write_all(req.as_bytes()).await?;

  let mut resp = vec![0; 8192];

  let n = match tokio::time::timeout(Duration::from_secs(14), stream.read(&mut resp)).await {
    Ok(n) => n?,
    Err(_) => return Err(ProxyError::new(ErrorKind::Timeout, "failed to read buffer from stream")),
  };

  resp.truncate(n);

  validate_proxy_response(&resp)
}