From 5dd892f15c1c719b9e543755ec51ac448df52f97 Mon Sep 17 00:00:00 2001 From: vanten-s Date: Wed, 22 Nov 2023 10:13:00 +0100 Subject: [PATCH] Added web server --- Cargo.toml | 1 + src/http_lib.rs | 113 ------------------------------------------- src/main.rs | 125 +++++++++++++++++++++++++++++++++++++++++------- src/types.rs | 1 + 4 files changed, 111 insertions(+), 129 deletions(-) delete mode 100644 src/http_lib.rs create mode 100644 src/types.rs diff --git a/Cargo.toml b/Cargo.toml index daeb379..b06b33e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +actix-web = "4.4.0" arti-client = "0.11.0" eyre = "0.6.8" tokio = { version = "1.34.0", features = ["full"] } diff --git a/src/http_lib.rs b/src/http_lib.rs deleted file mode 100644 index da4e33a..0000000 --- a/src/http_lib.rs +++ /dev/null @@ -1,113 +0,0 @@ -use arti_client::TorClient; -use eyre::Result; -use tokio::io::{AsyncWriteExt, AsyncReadExt}; - -trait Serialize { - fn serialize(&self) -> Vec; -} - -#[derive(Clone, Debug)] -pub struct HTTPRequest { - pub method: HTTPMethod, - pub location: String, - pub version: String, - pub headers: Vec, - pub body: Option>, -} - -#[derive(Clone, Debug)] -pub struct HTTPResponse { - pub version: String, - pub status_code: u16, - pub status: String, - pub headers: Vec, - pub body: Option>, -} - -#[derive(Clone, Copy, Debug)] -pub enum HTTPMethod { - Get, -} - -#[derive(Clone, Debug)] -pub struct HTTPHeader { - pub key: String, - pub value: String, -} - -impl Serialize for HTTPRequest { - fn serialize(&self) -> Vec { - let mut result = vec![]; - - let mut method_vec_u8 = self.method.serialize(); - let mut location_vec_u8 = self.location.as_bytes().to_vec(); - let mut version_vec_u8 = self.version.as_bytes().to_vec(); - let mut headers = self - .headers - .iter() - .map(|x| x.serialize()) - .collect::>() - .concat(); - - result.append(&mut method_vec_u8); - result.push(b' '); - result.append(&mut location_vec_u8); - result.push(b' '); - result.append(&mut version_vec_u8); - result.append(&mut headers); - result.push(b'\n'); - result.push(b'\n'); - - if let Some(body) = &self.body { - let mut body = body.clone(); - result.append(&mut body) - } - - println!("{}", match String::from_utf8(result.clone()) { - Ok(v) => v, - Err(v) => format!("{}", v), - }); - result - } -} - -impl Serialize for HTTPMethod { - fn serialize(&self) -> Vec { - use HTTPMethod as M; - match self { - M::Get => b"GET" - }.to_vec() - } -} - -impl Serialize for HTTPHeader { - fn serialize(&self) -> Vec { - format!("\n{}: {}", self.key, self.value).into_bytes() - } -} - -pub async fn get_website( - address: &str, - port: u16, - request: HTTPRequest, - tor_client: TorClient, -) -> Result> { - let mut stream = tor_client.connect((address, port)).await?; - stream.write_all(&request.serialize()).await?; - stream.flush().await?; - - println!("Sent request for {} to {address}", request.location); - let mut response_status: Vec = Vec::new(); - - loop { - let response = stream.read_u8().await?; - response_status.push(dbg!(response)); - if response == b'\n' { - break; - } - } - - let _ = dbg!(String::from_utf8(response_status)); - - todo!(); -} diff --git a/src/main.rs b/src/main.rs index 241a2af..42d469f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,26 +1,119 @@ +use actix_web::{ + get, post, + web::{self, BufMut}, + App, HttpRequest, HttpResponse, HttpServer, Responder, HttpResponseBuilder, http::StatusCode, +}; use arti_client::{TorClient, TorClientConfig}; -use eyre::Result; +use eyre::{ErrReport, Result}; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; -mod http_lib; -use http_lib::*; +mod types; + +struct State { + tor_client: TorClient, +} + +#[get("/{tail:.*}")] +async fn get(req: HttpRequest, data: web::Data, path: web::Path) -> impl Responder { + let tail = "/".to_string() + &path.into_inner(); + + let host = match req.uri().host() { + Some(v) => v.replace(".vanten-s.com", ""), + None => return HttpResponse::InternalServerError().body("How did you manage to get an invalid URI??") + }; + + let raw_website_response = match get_website(&host, 80, &req, None, &data.tor_client).await { + Ok(v) => v, + Err(e) => return HttpResponse::InternalServerError().body(format!("hihi, {e}")), + }; + + HttpResponse::Ok().body("Hi!") +} #[tokio::main] async fn main() -> Result<()> { let config = TorClientConfig::default(); - let tor_client = TorClient::create_bootstrapped(config).await?; - println!("Tor Client Created!"); - let test_request = HTTPRequest { - method: HTTPMethod::Get, - location: "/".to_string(), - version: "HTTP/1.1".to_string(), - headers: vec![HTTPHeader { - key: "Host".to_string(), - value: "vanten-s.com".to_string(), - }], - body: None, - }; - dbg!(get_website("94.255.138.67", 80, test_request, tor_client).await?); + let tor_client = TorClient::create_bootstrapped(config).await?; + let server = HttpServer::new(move || App::new().app_data(State { tor_client: tor_client.clone() }).service(get)) + .bind(("127.0.0.1", 8080))? + .run(); + let server = server.await; + + println!("Everything Started!"); Ok(()) } + +async fn get_website( + address: &str, + port: u16, + request: &HttpRequest, + body: Option, + tor_client: &TorClient, +) -> Result> { + let mut stream = tor_client.connect((address, port)).await?; + stream.write_all(&request_to_bytes(request, body)?).await?; + stream.flush().await?; + + println!("Sent request to {address}"); + let mut response_status: Vec = Vec::new(); + + loop { + let response = stream.read_u8().await?; + response_status.push(dbg!(response)); + if response == b'\n' { + break; + } + } + + let _ = dbg!(String::from_utf8(response_status)); + + todo!(); +} + +fn request_to_bytes(request: &HttpRequest, body: Option) -> Result> { + let mut finished = vec![]; + + // First Line + { + use actix_web::http::Version as V; + let method = request.method().to_string().as_bytes(); + let path = request.path().as_bytes(); + let version = match request.version() { + V::HTTP_09 => "HTTP/0.9", + V::HTTP_10 => "HTTP/1", + V::HTTP_11 => "HTTP/1.1", + V::HTTP_2 => "HTTP/2", + V::HTTP_3 => "HTTP/3", + } + .as_bytes(); + + finished.put_slice(method); + finished.push(b' '); + finished.put_slice(path); + finished.push(b' '); + finished.put_slice(version); + finished.push(b'\n'); + } + + // Headers + { + for header in request.headers() { + let name = header.0.to_string().as_bytes(); + let value = header.1.as_bytes(); + finished.put_slice(name); + finished.put_slice(b": "); + finished.put_slice(value); + finished.push(b'\n'); + } + finished.push(b'\n'); + } + + match body { + Some(v) => finished.put_slice(v.as_bytes()), + None => {}, + } + + Ok(finished) +} diff --git a/src/types.rs b/src/types.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/types.rs @@ -0,0 +1 @@ +