#[cfg(feature = "decoder")]
#[allow(dead_code)]
mod decoder;
mod proxy;
mod rewind;
pub mod certificate_authority;
use hyper::{Request, Response, Uri};
use std::future::Future;
use std::net::SocketAddr;
use tokio_tungstenite::tungstenite::Message;
pub(crate) use rewind::Rewind;
pub use hyper;
use product_os_http_body::BodyBytes as Body;
pub use product_os_http_body::BodyError as Error;
pub use tokio_rustls::rustls;
pub use tokio_tungstenite;
#[cfg(feature = "decoder")]
#[allow(unused_imports)]
pub use decoder::{decode_request, decode_response};
#[cfg(feature = "vpn")]
use hyper::header::{HeaderName, HeaderValue};
#[cfg(feature = "vpn")]
use product_os_http::HeaderMap;
#[cfg(feature = "vpn")]
use product_os_http_body::Bytes;
#[cfg(feature = "vpn")]
use product_os_request::ProductOSResponse;
pub use proxy::*;
#[derive(Debug)]
pub enum RequestOrResponse {
Request(Request<Body>),
Response(Response<Body>),
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct HttpContext {
pub client_addr: SocketAddr,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum WebSocketContext {
ClientToServer {
src: SocketAddr,
dst: Uri,
},
ServerToClient {
src: Uri,
dst: SocketAddr,
},
}
pub trait HttpHandler: Clone + Send + Sync + 'static {
fn handle_request(
&mut self,
_ctx: &HttpContext,
request: Request<Body>,
) -> impl Future<Output = RequestOrResponse> + Send {
async { RequestOrResponse::Request(request) }
}
fn handle_response(
&mut self,
_ctx: &HttpContext,
_: Request<Body>, response: Response<Body>,
) -> impl Future<Output = Response<Body>> + Send {
async { response }
}
#[cfg(feature = "vpn")]
#[allow(dead_code)]
fn handle_product_os_response(
&mut self,
_ctx: &HttpContext,
_: Request<Body>, response: ProductOSResponse<Body>,
) -> impl Future<Output = Response<Body>> + Send {
async {
let status = response
.try_status()
.unwrap_or(hyper::StatusCode::INTERNAL_SERVER_ERROR);
let mut headers = HeaderMap::new();
for (name, value) in &response.try_get_headers().unwrap_or_default() {
let header_name = match HeaderName::from_bytes(name.as_bytes()) {
Ok(name) => name,
Err(e) => {
tracing::error!("Error with header kind: {:?}", e);
continue;
}
};
let header_value = match HeaderValue::from_str(value.as_str()) {
Ok(v) => v,
Err(e) => {
tracing::error!("Invalid header value for '{}': {:?}", name, e);
continue;
}
};
headers.insert(header_name, header_value);
}
let Some((_, mut body)) = response.try_parts() else {
return Response::builder()
.status(hyper::StatusCode::INTERNAL_SERVER_ERROR)
.body(Body::empty())
.unwrap_or_else(|_| Response::new(Body::empty()));
};
let body_bytes = match body.as_bytes().await {
Ok(bytes) => bytes.to_vec(),
Err(e) => {
tracing::error!("Error converting body to bytes: {:?}", e);
Vec::new()
}
};
let response_body = Body::new(Bytes::from(body_bytes));
let mut response_to_return = Response::builder();
let mut last_name: Option<HeaderName> = None;
for (name, value) in headers {
let header_name = match name {
Some(n) => {
last_name = Some(n.clone());
n
}
None => match &last_name {
Some(n) => n.clone(),
None => continue,
},
};
response_to_return = response_to_return.header(header_name, value);
}
response_to_return = response_to_return.status(status);
response_to_return
.body(response_body)
.unwrap_or_else(|_| Response::new(Body::empty()))
}
}
fn should_intercept(
&mut self,
_ctx: &HttpContext,
_req: &Request<Body>,
) -> impl Future<Output = bool> + Send {
async { true }
}
}
pub trait WebSocketHandler: Clone + Send + Sync + 'static {
fn handle_message(
&mut self,
_ctx: &WebSocketContext,
message: Message,
) -> impl Future<Output = Option<Message>> + Send {
async { Some(message) }
}
}