Files
proxy-inspector/src/app.rs
2024-03-24 20:53:50 +08:00

81 lines
2.6 KiB
Rust

use async_trait::async_trait;
use base64::Engine;
use base64::engine::general_purpose::STANDARD;
use http::HeaderName;
use log::{debug, info};
use pingora::{Error, ErrorType};
use pingora::prelude::{HttpPeer, ProxyHttp, Result, Session};
use super::service::HostConfig;
pub struct ProxyApp {
host_configs: Vec<HostConfig>,
}
impl ProxyApp {
pub fn new(host_configs: Vec<HostConfig>) -> Self {
ProxyApp { host_configs }
}
}
#[async_trait]
impl ProxyHttp for ProxyApp {
type CTX = ();
fn new_ctx(&self) {}
async fn upstream_peer(&self, session: &mut Session, _ctx: &mut ()) -> Result<Box<HttpPeer>> {
let host_header = session
.get_header(HeaderName::from_static("host"))
.unwrap()
.to_str()
.expect("get host from http header failed");
debug!("host header: {host_header}");
if host_header == "localhost" || host_header.starts_with("localhost:") {
return Err(Error::new(ErrorType::CustomCode("bad host", 400)));
}
let host_config = self
.host_configs
.iter()
.find(|x| x.proxy_hostname == host_header)
.unwrap_or_else(|| panic!("find config for: {} failed", host_header));
let proxy_to = HttpPeer::new(
host_config.proxy_addr.as_str(),
host_config.proxy_tls,
host_config.proxy_hostname.clone(),
);
let peer = Box::new(proxy_to);
Ok(peer)
}
async fn request_filter(&self, session: &mut Session, _ctx: &mut Self::CTX) -> Result<bool>
where Self::CTX: Send + Sync,
{
let request_header = session.req_header();
let mut req = String::with_capacity(512);
req.push_str(request_header.method.as_str());
req.push(' ');
req.push_str(&request_header.uri.to_string());
req.push(' ');
req.push_str(&format!("{:?}\n", request_header.version));
let header_len = request_header.headers.len();
request_header.headers.iter().enumerate().for_each(|(i, (n, v))| {
req.push_str(
&format!("{}: {}{}",
n.as_str(),
v.to_str().unwrap_or("ERROR!BAD-VALUE!"),
if i < header_len - 1 { "\n" } else { "" }
)
);
});
let body = match session.read_request_body().await {
Ok(Some(body_bytes)) => Some(STANDARD.encode(body_bytes)),
_ => None,
};
info!("Request:\n{}\n\n{}", req, body.unwrap_or_else(|| "<None>".into()));
Ok(false)
}
}