use crate::handler::handler::{Handler, HandlerFactory};
use crate::hteapot::{HttpMethod, HttpResponse, HttpResponseCommon, HttpStatus, TunnelResponse};
use crate::utils::Context;
pub struct ProxyHandler {
new_path: String,
url: String,
}
impl Handler for ProxyHandler {
fn run(&self, ctx: &mut Context) -> Box<dyn HttpResponseCommon> {
let _proxy_logger = &ctx.log.with_component("proxy");
if ctx.request.method == HttpMethod::OPTIONS {
return TunnelResponse::new(&ctx.request.path);
}
let mut proxy_req = ctx.request.clone();
proxy_req.path = self.new_path.clone();
proxy_req.headers.remove("Host");
let host_parts: Vec<&str> = self.url.split("://").collect();
let host = if host_parts.len() == 1 {
host_parts.first().unwrap()
} else {
host_parts.last().unwrap()
};
proxy_req.headers.insert("host", host);
let response = proxy_req.brew(&self.url).unwrap_or(HttpResponse::new(
HttpStatus::NotAcceptable,
"",
None,
));
if let Some(cache) = ctx.cache.as_deref_mut() {
cache.set(ctx.request.clone(), (*response).clone());
}
response
}
}
impl HandlerFactory for ProxyHandler {
fn is(ctx: &Context) -> Option<Box<dyn Handler>> {
if ctx.request.method == HttpMethod::OPTIONS {
return Some(Box::new(ProxyHandler {
url: String::new(),
new_path: String::new(),
}));
}
for proxy_path in ctx.config.proxy_rules.keys() {
if let Some(path_match) = ctx.request.path.strip_prefix(proxy_path) {
let new_path = path_match.to_string();
let url = ctx.config.proxy_rules.get(proxy_path).unwrap();
let url = if url.is_empty() {
let proxy_url = ctx.request.headers.get("host")?;
proxy_url.to_owned()
} else {
url.to_string()
};
return Some(Box::new(ProxyHandler { url, new_path }));
}
}
None
}
}