1#[cfg(test)]
22mod tests;
23
24use std::sync::Arc;
25use std::net::SocketAddr;
26use std::convert::Infallible;
27use tokio::sync::RwLock;
28use hyper::body::Incoming;
29use hyper::{Request, Response};
30use hyper_util::server::conn::auto::Builder as AutoBuilder;
31use hyper_util::rt::TokioExecutor;
32use hyper::service::service_fn;
33use hyper_util::rt::TokioIo;
34use bytes::Bytes;
35use futures_util::TryStreamExt;
36use http_body_util::{BodyExt, Full};
37use reqwest::Body;
38use serde::{Serialize, Deserialize};
39use log::{debug};
40
41use crate::core::{ProxyCore, ProxyRequest, ProxyResponse, ProxyError, HttpMethod, RequestContext};
42
43#[derive(Debug, Clone, Serialize, Deserialize)]
45pub struct ServerConfig {
46 #[serde(default = "default_host")]
48 pub host: String,
49
50 #[serde(default = "default_port")]
52 pub port: u16,
53}
54
55fn default_host() -> String {
56 "127.0.0.1".to_string()
57}
58
59fn default_port() -> u16 {
60 8080
61}
62
63impl Default for ServerConfig {
64 fn default() -> Self {
65 Self {
66 host: default_host(),
67 port: default_port(),
68 }
69 }
70}
71
72#[derive(Debug, Clone)]
74pub struct ProxyServer {
75 config: ServerConfig,
77 core: Arc<ProxyCore>,
79}
80
81impl ProxyServer {
82 pub fn new(config: ServerConfig, core: Arc<ProxyCore>) -> Self {
84 Self { config, core }
85 }
86
87 pub async fn start(&self) -> Result<(), ProxyError> {
89 let addr: SocketAddr = format!("{}:{}", self.config.host, self.config.port)
90 .parse()
91 .map_err(|e| ProxyError::Other(format!("Invalid server address: {}", e)))?;
92
93 let core = self.core.clone();
94
95 let listener = tokio::net::TcpListener::bind(addr).await
97 .map_err(|e| ProxyError::Other(format!("Failed to bind to address: {}", e)))?;
98
99 log::info!("Foxy proxy server listening on http://{}", addr);
100
101 loop {
103 let (stream, remote_addr) = match listener.accept().await {
104 Ok(conn) => conn,
105 Err(e) => {
106 log::error!("Failed to accept connection: {}", e);
107 continue;
108 }
109 };
110
111 let core = core.clone();
112 let client_ip = remote_addr.ip().to_string();
113
114 tokio::spawn(async move {
116 let service = service_fn(move |req| {
117 debug!("Incoming request over {:?}", req.version());
118 let core = core.clone();
119 let client_ip = client_ip.clone();
120 handle_request(req, core, client_ip)
121 });
122
123 let io = TokioIo::new(stream);
125
126 if let Err(e) = AutoBuilder::new(TokioExecutor::new())
128 .serve_connection(io, service)
129 .await
130 {
131 log::error!("Error serving connection: {}", e);
132 }
133 });
134 }
135 }
136}
137
138async fn convert_hyper_request(
140 req: Request<Incoming>,
141 client_ip: String,
142) -> Result<ProxyRequest, ProxyError> {
143 let method = HttpMethod::from(req.method());
144 let uri = req.uri().clone();
145 let path = uri.path().to_owned();
146 let query = uri.query().map(|q| q.to_owned());
147 let headers = req.headers().clone();
148
149 let hyper_stream = req.into_body().into_data_stream();
151 let byte_stream = hyper_stream.map_ok(Bytes::from);
152 let body = reqwest::Body::wrap_stream(byte_stream);
153
154 Ok(ProxyRequest {
155 method,
156 path,
157 query,
158 headers,
159 body,
160 context: Arc::new(RwLock::new(RequestContext {
161 client_ip: Some(client_ip),
162 start_time: Some(std::time::Instant::now()),
163 attributes: std::collections::HashMap::new(),
164 })),
165 })
166}
167
168fn convert_proxy_response(resp: ProxyResponse) -> Result<Response<Body>, ProxyError> {
170 let stream = resp
171 .body
172 .into_data_stream()
173 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e));
174
175 let body = Body::wrap_stream(stream);
176
177 let mut builder = Response::builder().status(resp.status);
178 *builder
179 .headers_mut()
180 .ok_or_else(|| ProxyError::Other("unable to set headers".into()))? = resp.headers;
181
182 Ok(builder
183 .body(body)
184 .map_err(|e| ProxyError::Other(e.to_string()))?)
185}
186
187async fn handle_request(
189 req: Request<Incoming>,
190 core: Arc<ProxyCore>,
191 client_ip: String,
192) -> Result<Response<Body>, Infallible> {
193 let proxy_req = match convert_hyper_request(req, client_ip).await {
195 Ok(r) => r,
196 Err(e) => {
197 log::error!("convert request: {e}");
198 return Ok(Response::builder()
199 .status(500)
200 .body(Body::from("Internal Server Error"))
201 .unwrap());
202 }
203 };
204
205 match core.process_request(proxy_req).await {
207 Ok(proxy_resp) => match convert_proxy_response(proxy_resp) {
208 Ok(resp) => Ok(resp),
209 Err(e) => {
210 log::error!("convert response: {e}");
211 Ok(Response::builder()
212 .status(500)
213 .body(Body::from("Internal Server Error"))
214 .unwrap())
215 }
216 },
217 Err(e) => {
218 log::error!("proxy error: {e}");
219 let (status, msg) = match e {
220 ProxyError::Timeout(d) => (504, format!("Gateway Timeout after {d:?}")),
221 ProxyError::RoutingError(_) => (404, "Route not found".into()),
222 _ => (500, "Internal Server Error".into()),
223 };
224 Ok(Response::builder()
225 .status(status)
226 .body(Body::from(msg))
227 .unwrap())
228 }
229 }
230}