### Complete Hudsucker Proxy Configuration Example Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/configuration.md A comprehensive example demonstrating how to set up and run a Hudsucker proxy with custom HTTP handling, certificate authority, and graceful shutdown. Ensure you have `ca/key.pem` and `ca/cert.pem` files for CA setup. ```rust use hudsucker::{Proxy, HttpHandler, RequestOrResponse, HttpContext, Body, certificate_authority::RcgenAuthority, rustls::crypto::aws_lc_rs, rcgen::{Issuer, KeyPair}}; use hyper::Request; use std::net::SocketAddr; #[derive(Clone)] struct MyHandler; impl HttpHandler for MyHandler { async fn handle_request(&mut self, _ctx: &HttpContext, req: Request) -> RequestOrResponse { RequestOrResponse::Request(req) } } #[tokio::main] async fn main() -> Result<(), Box> { // Setup CA let key_pair = KeyPair::from_pem(include_str!("ca/key.pem"))?; let issuer = Issuer::from_ca_cert_pem(include_str!("ca/cert.pem"), key_pair)?; let ca = RcgenAuthority::new(issuer, 1_000, aws_lc_rs::default_provider()); // Setup shutdown signal let (tx, rx) = tokio::sync::oneshot::channel(); // Build proxy with all options let proxy = Proxy::builder() .with_addr(SocketAddr::from(([127, 0, 0, 1], 3000))) .with_ca(ca) .with_rustls_connector(aws_lc_rs::default_provider()) .with_http_handler(MyHandler) .with_graceful_shutdown(async move { rx.await.ok(); }) .build()?; // Start proxy let proxy_task = tokio::spawn(proxy.start()); // Shutdown after 1 hour or on signal tokio::time::sleep(tokio::time::Duration::from_secs(3600)).await; tx.send(()).ok(); proxy_task.await??; Ok(()) } ``` -------------------------------- ### Example: Building Proxy with Native TLS Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/errors.md Demonstrates how to build a Hudsucker proxy using the native TLS connector and handle potential TLS setup errors. ```rust use hudsucker::Proxy; let proxy = Proxy::builder() .with_addr(addr) .with_ca(ca) .with_native_tls_connector() .build(); match proxy { Err(hudsucker::Error::Builder(e)) => { eprintln!("TLS setup failed: {}", e); } _ => {} } ``` -------------------------------- ### Complete Build Example Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/api-reference/proxy-builder.md A comprehensive example demonstrating the complete build process for a proxy, including setting up a custom HTTP handler and graceful shutdown. ```APIDOC ## Complete Build Example ```rust use hudsucker::{Proxy, HttpHandler, RequestOrResponse, HttpContext, Body, certificate_authority::RcgenAuthority, rustls::crypto::aws_lc_rs, rcgen::{Issuer, KeyPair}}; use hyper::Request; use std::net::SocketAddr; #[derive(Clone)] struct LoggingHandler; impl HttpHandler for LoggingHandler { async fn handle_request( &mut self, ctx: &HttpContext, req: Request, ) -> RequestOrResponse { println!("Request from {}: {}", ctx.client_addr, req.uri()); RequestOrResponse::Request(req) } } #[tokio::main] async fn main() -> Result<(), Box> { let key_pair = KeyPair::from_pem(include_str!("ca/key.pem"))?; let issuer = Issuer::from_ca_cert_pem(include_str!("ca/cert.pem"), key_pair)?; let ca = RcgenAuthority::new(issuer, 1_000, aws_lc_rs::default_provider()); let (shutdown_tx, shutdown_rx) = tokio::sync::oneshot::channel(); let proxy = Proxy::builder() .with_addr(SocketAddr::from(([127, 0, 0, 1], 3000))) .with_ca(ca) .with_rustls_connector(aws_lc_rs::default_provider()) .with_http_handler(LoggingHandler) .with_graceful_shutdown(async { shutdown_rx.await.ok(); }) .build()?; let proxy_task = tokio::spawn(proxy.start()); tokio::time::sleep(tokio::time::Duration::from_secs(60)).await; shutdown_tx.send(()).ok(); proxy_task.await??; Ok(()) } ``` ``` -------------------------------- ### Proxy::start() Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/exports.md Starts the proxy server, making it ready to handle incoming connections. ```APIDOC ## Proxy::start() ### Description Starts the proxy server, making it ready to handle incoming connections. ### Method Associated Function ### Parameters None ### Response - **Result**: A future that resolves when the proxy server has started or returns an error if it fails. ``` -------------------------------- ### Complete Proxy Build Example with HTTP Handler and Graceful Shutdown Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/api-reference/proxy-builder.md A comprehensive example showing how to build a proxy with a custom HTTP handler, TLS configuration, and graceful shutdown mechanism. This requires features like `rustls-client` and `tokio`. ```rust use hudsucker::{Proxy, HttpHandler, RequestOrResponse, HttpContext, Body, certificate_authority::RcgenAuthority, rustls::crypto::aws_lc_rs, rcgen::{Issuer, KeyPair}}; use hyper::Request; use std::net::SocketAddr; #[derive(Clone)] struct LoggingHandler; impl HttpHandler for LoggingHandler { async fn handle_request( &mut self, ctx: &HttpContext, req: Request, ) -> RequestOrResponse { println!("Request from {}: {}", ctx.client_addr, req.uri()); RequestOrResponse::Request(req) } } #[tokio::main] async fn main() -> Result<(), Box> { let key_pair = KeyPair::from_pem(include_str!("ca/key.pem"))?; let issuer = Issuer::from_ca_cert_pem(include_str!("ca/cert.pem"), key_pair)?; let ca = RcgenAuthority::new(issuer, 1_000, aws_lc_rs::default_provider()); let (shutdown_tx, shutdown_rx) = tokio::sync::oneshot::channel(); let proxy = Proxy::builder() .with_addr(SocketAddr::from(([127, 0, 0, 1], 3000))) .with_ca(ca) .with_rustls_connector(aws_lc_rs::default_provider()) .with_http_handler(LoggingHandler) .with_graceful_shutdown(async { shutdown_rx.await.ok(); }) .build()?; let proxy_task = tokio::spawn(proxy.start()); tokio::time::sleep(tokio::time::Duration::from_secs(60)).await; shutdown_tx.send(()).ok(); proxy_task.await??; Ok(()) } ``` -------------------------------- ### Basic Transparent Proxy Setup in Rust Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/README.md This snippet demonstrates how to set up a minimal Hudsucker proxy that passes all traffic through without modification. It requires loading a CA certificate and key, creating a certificate authority, and then building and starting the proxy server. ```rust use hudsucker::{Proxy, certificate_authority::RcgenAuthority, rustls::crypto::aws_lc_rs, rcgen::{Issuer, KeyPair}}; use std::net::SocketAddr; #[tokio::main] async fn main() -> Result<(), Box> { // Load CA certificate and key let key_pair = KeyPair::from_pem(include_str!("ca/hudsucker.key"))?; let issuer = Issuer::from_ca_cert_pem(include_str!("ca/hudsucker.cer"), key_pair)?; // Create certificate authority let ca = RcgenAuthority::new(issuer, 1_000, aws_lc_rs::default_provider()); // Build and start proxy let proxy = Proxy::builder() .with_addr(SocketAddr::from(([127, 0, 0, 1], 3000))) .with_ca(ca) .with_rustls_connector(aws_lc_rs::default_provider()) .build()?; println!("Proxy listening on 127.0.0.1:3000"); proxy.start().await?; Ok(()) } ``` -------------------------------- ### HttpContext Usage Example Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/types.md Example of implementing HttpHandler and accessing client address from HttpContext. ```rust use hudsucker::{HttpContext, HttpHandler, RequestOrResponse, Body}; use hyper::Request; use std::net::SocketAddr; impl HttpHandler for MyHandler { async fn handle_request( &mut self, ctx: &HttpContext, req: Request, ) -> RequestOrResponse { println!("Request from {}", ctx.client_addr.ip()); RequestOrResponse::Request(req) } } ``` -------------------------------- ### ProxyBuilder::new Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/exports.md Creates a new instance of the ProxyBuilder, starting the proxy configuration process. ```APIDOC ## ProxyBuilder::new ### Description Create new builder. ### Method `new()` ### Returns `Self` ``` -------------------------------- ### Start Hudsucker Proxy Server Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/api-reference/proxy.md Use this to start the proxy server and begin accepting connections. The call is blocking and runs until graceful shutdown. ```rust use hudsucker::{Proxy, certificate_authority::RcgenAuthority, rustls::crypto::aws_lc_rs, rcgen::{Issuer, KeyPair}}; use std::net::SocketAddr; #[tokio::main] async fn main() -> Result<(), Box> { let key_pair = KeyPair::generate_for(&rcgen::PKCS_ECDSA_P256_SHA256)?; let params = rcgen::CertificateParams::new(vec!["example.com".to_string()])?; let issuer = rcgen::Certificate::from_params(params)?; let ca = RcgenAuthority::new(issuer.into(), 1_000, aws_lc_rs::default_provider()); let proxy = Proxy::builder() .with_addr(SocketAddr::from(([127, 0, 0, 1], 3000))) .with_ca(ca) .with_rustls_connector(aws_lc_rs::default_provider()) .build()?; tokio::spawn(async { tokio::time::sleep(tokio::time::Duration::from_secs(60)).await; }); proxy.start().await?; Ok(()) } ``` -------------------------------- ### Proxy::start Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/api-reference/proxy.md Starts the proxy server and begins accepting incoming connections. This call is blocking and will run until the graceful shutdown future completes. ```APIDOC ## Method: Proxy::start ### Description Starts the proxy server and begins accepting incoming connections. This call is blocking and will run until the graceful shutdown future completes. ### Returns `Result<(), Error>` — Success or an error if the server fails to start. ### Error Cases | Error | Condition | |-------|-----------| | `Error::Io` | Failed to bind to the address or accept connections | | `Error::Network` | Network-level error during operation | ### Example ```rust use hudsucker::{Proxy, certificate_authority::RcgenAuthority, rustls::crypto::aws_lc_rs, rcgen::{Issuer, KeyPair}}; use std::net::SocketAddr; #[tokio::main] async fn main() -> Result<(), Box> { let key_pair = KeyPair::generate_for(&rcgen::PKCS_ECDSA_P256_SHA256)?; let params = rcgen::CertificateParams::new(vec!["example.com".to_string()])?; let issuer = rcgen::Certificate::from_params(params)?; let ca = RcgenAuthority::new(issuer.into(), 1_000, aws_lc_rs::default_provider()); let proxy = Proxy::builder() .with_addr(SocketAddr::from(([127, 0, 0, 1], 3000))) .with_ca(ca) .with_rustls_connector(aws_lc_rs::default_provider()) .build()?; tokio::spawn(async {{ tokio::time::sleep(tokio::time::Duration::from_secs(60)).await; }}); proxy.start().await?; Ok(()) } ``` ``` -------------------------------- ### Create a new ProxyBuilder Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/api-reference/proxy-builder.md Use `Proxy::builder()` to start building a new proxy configuration. This initializes the builder in the `WantsAddr` state. ```rust use hudsucker::Proxy; let builder = Proxy::builder(); ``` -------------------------------- ### Example: Building Proxy with Rustls Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/errors.md Shows how to construct a Hudsucker proxy with a Rustls connector, including specifying a crypto provider, and how to catch configuration errors. ```rust use hudsucker::Proxy; use hudsucker::rustls::crypto::aws_lc_rs; let proxy = Proxy::builder() .with_addr(addr) .with_ca(ca) .with_rustls_connector(aws_lc_rs::default_provider()) .build(); match proxy { Err(hudsucker::Error::Builder(e)) => { eprintln!("TLS configuration error: {}", e); } _ => {} } ``` -------------------------------- ### Initialize Rustls CryptoProvider Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/types.md Example of initializing and using the default AWS LibCrypto provider from rustls. ```rust use hudsucker::rustls::crypto::aws_lc_rs; let provider = aws_lc_rs::default_provider(); let ca = RcgenAuthority::new(issuer, 1_000, provider); ``` -------------------------------- ### Setup Native TLS Connector Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/README.md Configure the proxy to use the system's native TLS capabilities for its connector. ```rust let proxy = Proxy::builder() .with_addr(addr) .with_ca(ca) .with_native_tls_connector() .build()?; ``` -------------------------------- ### WebSocketContext Usage Example Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/types.md Example of implementing WebSocketHandler and using WebSocketContext to determine message direction. ```rust use hudsucker::{WebSocketContext, WebSocketHandler}; use tokio_tungstenite::tungstenite::Message; impl WebSocketHandler for MyHandler { async fn handle_message( &mut self, ctx: &WebSocketContext, message: Message, ) -> Option { match ctx { WebSocketContext::ClientToServer { src, dst } => { println!("Client {} -> Server {}", src, dst.authority().unwrap()); } WebSocketContext::ServerToClient { src, dst } => { println!("Server {} -> Client {}", src, dst.authority().unwrap()); } } Some(message) } } ``` -------------------------------- ### Proxy Builder Initialization Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/api-reference/proxy.md Initiates the proxy configuration process by creating a ProxyBuilder. Use this to start defining the proxy's address, handlers, and other settings. ```rust use hudsucker::Proxy; use std::net::SocketAddr; let builder = Proxy::builder(); let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); let next_builder = builder.with_addr(addr); ``` -------------------------------- ### Setup Rustls Connector Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/README.md Configure the proxy to use Rustls for its TLS connector. This is a pure Rust implementation. ```rust use hudsucker::rustls::crypto::aws_lc_rs; let proxy = Proxy::builder() .with_addr(addr) .with_ca(ca) .with_rustls_connector(aws_lc_rs::default_provider()) .build()?; ``` -------------------------------- ### Initialize RcgenAuthority with CA Files Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/api-reference/certificate-authority.md Shows how to load a CA private key and certificate from files and use them to initialize RcgenAuthority in Rust. This is a common setup step for Hudsucker. ```rust let key_pair = include_str!("ca/hudsucker.key"); let ca_cert = include_str!("ca/hudsucker.cer"); let key_pair = KeyPair::from_pem(key_pair).expect("Failed to parse private key"); let issuer = Issuer::from_ca_cert_pem(ca_cert, key_pair).expect("Failed to parse CA certificate"); let ca = RcgenAuthority::new(issuer, 1_000, aws_lc_rs::default_provider()); ``` -------------------------------- ### Proxy::builder Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/api-reference/proxy.md Initiates the construction of a Proxy instance by returning a ProxyBuilder. This is the starting point for configuring proxy settings such as address, handlers, and connectors. ```APIDOC ## Method: Proxy::builder ### Description Creates a new `ProxyBuilder` to configure and build a proxy instance. ### Returns `ProxyBuilder` — Builder in the initial state requiring an address or listener. ### Example ```rust use hudsucker::Proxy; use std::net::SocketAddr; let builder = Proxy::builder(); let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); let next_builder = builder.with_addr(addr); ``` ``` -------------------------------- ### RequestOrResponse Usage Example Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/types.md Demonstrates converting a hyper::Request or hyper::Response into the RequestOrResponse enum. ```rust use hudsucker::{RequestOrResponse, Body}; use hyper::{Request, Response, StatusCode}; // Forward request let req = Request::builder().body(Body::empty()).unwrap(); let result: RequestOrResponse = req.into(); // Return response let res = Response::builder() .status(StatusCode::FORBIDDEN) .body(Body::from("Access denied")) .unwrap(); let result: RequestOrResponse = res.into(); ``` -------------------------------- ### ProxyBuilder::build Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/api-reference/proxy-builder.md Builds the proxy from the configured builder. This method returns a Result which can be either the configured proxy or an error if the connector setup failed. ```APIDOC ## Method: ProxyBuilder::build ### Description Builds the proxy from the configured builder. This method returns a `Result` which can be either the configured proxy or an error if the connector setup failed. ### Returns `Result, Error>` — Configured proxy or error if connector setup failed. ### Error Cases | Error | |---|---| | `Error::Builder(Rustls(_))` | Rustls configuration error (with `rustls-client` feature) | | `Error::Builder(NativeTls(_))` | Native TLS initialization error (with `native-tls-client` feature) | ### Example ```rust use hudsucker::{Proxy, certificate_authority::RcgenAuthority, rustls::crypto::aws_lc_rs}; use std::net::SocketAddr; let ca = RcgenAuthority::new(issuer, 1_000, aws_lc_rs::default_provider()); let proxy = Proxy::builder() .with_addr(SocketAddr::from(([127, 0, 0, 1], 3000))) .with_ca(ca) .with_rustls_connector(aws_lc_rs::default_provider()) .build()?; proxy.start().await?; ``` ``` -------------------------------- ### Creating Binary Response Body Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/api-reference/body.md Example of creating an HTTP response with a binary body, such as an image. It demonstrates setting the Content-Type header and using Body::from with a byte vector. ```rust // Binary response let data = vec![0x89, 0x50, 0x4E, 0x47]; // PNG header let response = Response::builder() .status(200) .header("Content-Type", "image/png") .body(Body::from(data)) .unwrap(); ``` -------------------------------- ### Catching Builder Errors during Proxy Configuration Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/errors.md Illustrates how to catch errors that occur during the proxy builder phase, such as TLS or cryptographic initialization failures. This pattern is used when starting the proxy server. ```rust use hudsucker::Error; match proxy.start().await { Err(Error::Builder(e)) => { eprintln!("Configuration error: {}", e); } Err(e) => eprintln!("Runtime error: {}", e), Ok(_) => {} // Proxy started successfully } ``` -------------------------------- ### Creating JSON Response Body Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/api-reference/body.md Example of creating an HTTP response with a JSON body. It uses Response::builder to construct the response and Body::from to set the JSON payload. ```rust use hudsucker::{Body, HttpHandler}; use hyper::Response; // JSON response let json = r#"{"status":"ok"}"#; let response = Response::builder() .status(200) .body(Body::from(json)) .unwrap(); ``` -------------------------------- ### HTTP Request Logging with NoopHandler for WebSockets Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/api-reference/noop-handler.md Configures a proxy to log HTTP requests while using NoopHandler for transparent WebSocket traffic. This example shows how to integrate a custom HttpHandler for specific protocols. ```rust use hudsucker::{Proxy, HttpHandler, HttpContext, RequestOrResponse, Body}; use hyper::Request; use std::net::SocketAddr; #[derive(Clone)] struct RequestLogger; impl HttpHandler for RequestLogger { async fn handle_request( &mut self, _ctx: &HttpContext, req: Request, ) -> RequestOrResponse { println!("{} {}", req.method(), req.uri()); RequestOrResponse::Request(req) } } let proxy = Proxy::builder() .with_addr(SocketAddr::from(([127, 0, 0, 1], 3000))) .with_ca(ca) .with_rustls_connector(provider) .with_http_handler(RequestLogger) // WebSocket handler uses NoopHandler (no logging) .build()?; ``` -------------------------------- ### Catching Network Errors Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/errors.md Example of how to catch and handle network-specific errors that occur during proxy operations. This pattern is useful for logging or taking specific actions when a network issue arises. ```rust use hudsucker::Error; match error { Error::Network(e) => { eprintln!("Network error: {}", e); } _ => {} } ``` -------------------------------- ### Setup OpensslAuthority CA Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/README.md Configure a Certificate Authority using OpensslAuthority for OpenSSL-based TLS interception. Requires a PEM-encoded private key and certificate, and specifies a message digest algorithm. ```rust use hudsucker::certificate_authority::OpensslAuthority; use hudsucker::openssl::{pkey::PKey, x509::X509, hash::MessageDigest}; use hudsucker::rustls::crypto::aws_lc_rs; let pkey = PKey::private_key_from_pem(pem_key)?; let cert = X509::from_pem(pem_cert)?; let ca = OpensslAuthority::new( pkey, cert, MessageDigest::sha256(), 1_000, aws_lc_rs::default_provider() ); ``` -------------------------------- ### Handle Hudsucker Errors Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/types.md Example of how to match and handle different variants of the Hudsucker Error enum after attempting to start the proxy. This pattern is useful for graceful error management. ```rust use hudsucker::{Proxy, Error}; use std::net::SocketAddr; match proxy.start().await { Ok(_) => println!("Proxy exited gracefully"), Err(Error::Io(e)) => eprintln!("I/O error: {}", e), Err(Error::Network(e)) => eprintln!("Network error: {}", e), Err(Error::Builder(e)) => eprintln!("Build error: {}", e), Err(e) => eprintln!("Error: {:?}", e), } ``` -------------------------------- ### Build Proxy with Basic Configuration Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/api-reference/proxy-builder.md Demonstrates building a proxy with a CA and Rustls connector. Ensure the necessary features like `rustls-client` are enabled. ```rust use hudsucker::{Proxy, certificate_authority::RcgenAuthority, rustls::crypto::aws_lc_rs}; use std::net::SocketAddr; let ca = RcgenAuthority::new(issuer, 1_000, aws_lc_rs::default_provider()); let proxy = Proxy::builder() .with_addr(SocketAddr::from(([127, 0, 0, 1], 3000))) .with_ca(ca) .with_rustls_connector(aws_lc_rs::default_provider()) .build()?; proxy.start().await?; ``` -------------------------------- ### ProxyBuilder::build Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/exports.md Builds and returns the configured proxy, or an error if configuration is invalid. ```APIDOC ## ProxyBuilder::build ### Description Build proxy. ### Method `build()` ### Returns `Result, Error>` ``` -------------------------------- ### Instantiating and Copying NoopHandler Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/api-reference/noop-handler.md Demonstrates how to create a NoopHandler and shows that it implements the Copy trait, allowing for trivial cloning. ```rust use hudsucker::NoopHandler; let handler = NoopHandler::new(); let cloned = handler; // Copy, not clone assert_eq!(handler, cloned); ``` -------------------------------- ### ProxyBuilder::new Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/api-reference/proxy-builder.md Initializes a new ProxyBuilder in the `WantsAddr` state, ready to accept an address or TCP listener. ```APIDOC ## ProxyBuilder::new ### Description Creates a new builder instance in the initial state, requiring an address or TCP listener. ### Method `ProxyBuilder::new()` ### Returns `ProxyBuilder` - Builder in the initial state. ### Example ```rust use hudsucker::Proxy; let builder = Proxy::builder(); ``` ``` -------------------------------- ### Implement WebSocketHandler Trait Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/api-reference/proxy.md Example of implementing the WebSocketHandler trait to customize message handling. This handler logs received text, binary, and close messages. ```rust use hudsucker::{WebSocketHandler, WebSocketContext}; use tokio_tungstenite::tungstenite::Message; #[derive(Clone)] struct MyWebSocketHandler; impl WebSocketHandler for MyWebSocketHandler { async fn handle_message( &mut self, ctx: &WebSocketContext, message: Message, ) -> Option { match message { Message::Text(ref text) => { println!("Text message: {}", text); Some(message) } Message::Binary(ref data) => { println!("Binary message of {} bytes", data.len()); Some(message) } Message::Close(_) => { println!("Connection closing"); Some(message) } _ => Some(message), } } } ``` -------------------------------- ### Catching I/O Errors with Kind Matching Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/errors.md Demonstrates how to catch and handle I/O errors, specifically checking for common kinds like AddrInUse and PermissionDenied. This allows for more granular error handling based on the specific I/O issue. ```rust use hudsucker::Error; use std::io::ErrorKind; match error { Error::Io(io_err) => { match io_err.kind() { ErrorKind::AddrInUse => { eprintln!("Address already in use"); } ErrorKind::PermissionDenied => { eprintln!("Permission denied"); } _ => eprintln!("I/O error: {}", io_err), } } _ => {} } ``` -------------------------------- ### Modifying Request Body in Handler Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/api-reference/body.md Example of how to modify the request body within an HTTP handler. It demonstrates accessing and replacing the body of an incoming Request. ```rust use hudsucker::{HttpHandler, HttpContext, Body, RequestOrResponse}; use hyper::Request; #[derive(Clone)] struct MyHandler; impl HttpHandler for MyHandler { async fn handle_request( &mut self, _ctx: &HttpContext, mut req: Request, ) -> RequestOrResponse { // Modify body *req.body_mut() = Body::from("Modified body"); RequestOrResponse::Request(req) } } ``` -------------------------------- ### Common Body Conversions Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/api-reference/body.md Demonstrates various ways to create a `Body` using `From` implementations for common types like strings, byte vectors, static slices, and requests. Also shows creating an empty body. ```rust use hudsucker::Body; // From string let body = Body::from("Hello, World!"); // From bytes let body = Body::from(vec![1, 2, 3]); // From static slice let body = Body::from(&b"data"[..]); // Empty body let body = Body::empty(); // From request use hyper::Request; let req = Request::builder().body("body").unwrap(); let body = Body::from(req); ``` -------------------------------- ### Setup RcgenAuthority CA Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/README.md Configure a Certificate Authority using RcgenAuthority for pure Rust TLS interception. Requires a PEM-encoded private key and certificate. ```rust use hudsucker::certificate_authority::RcgenAuthority; use hudsucker::rcgen::{Issuer, KeyPair}; use hudsucker::rustls::crypto::aws_lc_rs; let key_pair = KeyPair::from_pem(pem_key)?; let issuer = Issuer::from_ca_cert_pem(pem_cert, key_pair)?; let ca = RcgenAuthority::new(issuer, 1_000, aws_lc_rs::default_provider()); ``` -------------------------------- ### Configure Custom Hyper Server Builder Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/configuration.md Use `with_server` to provide a custom `ServerBuilder` for advanced HTTP server configuration. This allows fine-tuning server behavior and HTTP version handling. ```rust pub fn with_server(self, server: ServerBuilder) -> Self ``` ```rust use hyper_util::server::conn::auto::Builder as ServerBuilder; use hyper_util::rt::TokioExecutor; let mut server = ServerBuilder::new(TokioExecutor::new()); server.http1().title_case_headers(true); let proxy = Proxy::builder() .with_addr(addr) .with_ca(ca) .with_rustls_connector(provider) .with_server(server) .build()?; ``` -------------------------------- ### Implement HttpHandler for Request Interception Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/api-reference/proxy.md Implement the HttpHandler trait to intercept and modify incoming HTTP requests before they are forwarded. This example adds a custom header to the request. ```rust use hudsucker::{HttpHandler, HttpContext, RequestOrResponse, Body}; use hyper::Request; #[derive(Clone)] struct MyHandler; impl HttpHandler for MyHandler { async fn handle_request( &mut self, ctx: &HttpContext, mut req: Request, ) -> RequestOrResponse { println!("Request from: {}", ctx.client_addr); // Add a header req.headers_mut().insert("X-Proxy", "hudsucker".parse().unwrap()); RequestOrResponse::Request(req) } } ``` -------------------------------- ### Body From Implementations Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/api-reference/body.md Demonstrates common conversions to the Body type from various source types. ```APIDOC ## From Implementations `Body` provides `From` implementations for common types: | Source Type | Behavior | Example | |-------------|----------|---------| | `String` | Converts string to body | `Body::from("hello".to_string())` | | `&'static str` | Static string lifetime | `Body::from("hello")` | | `&'static [u8]` | Static byte slice | `Body::from(b"bytes")` | | `Box<[u8]>` | Boxed byte slice | `Body::from(vec![1,2,3].into_boxed_slice())` | | `Vec` | Owned byte vector | `Body::from(vec![1,2,3])` | | `Bytes` | Efficient bytes type | `Body::from(Bytes::from("data"))` | | `Empty` | Empty body | `Body::from(Empty::new())` | | `Full` | Complete buffer | `Body::from(Full::new(Bytes::new()))` | | `Collected` | Collected body | `Body::from(collected)` | | `Incoming` | Hyper incoming body | `Body::from(incoming)` | | `StreamBody` | Stream-backed body | `Body::from(StreamBody::new(stream))` | | `BoxBody` | Boxed body | `Body::from(boxed)` | | `Request` | From request body | `Body::from(request)` | | `Response` | From response body | `Body::from(response)` | ### Common Conversions ```rust use hudsucker::Body; // From string let body = Body::from("Hello, World!"); // From bytes let body = Body::from(vec![1, 2, 3]); // From static slice let body = Body::from(&b"data"[..]); // Empty body let body = Body::empty(); // From request use hyper::Request; let req = Request::builder().body("body").unwrap(); let body = Body::from(req); ``` ``` -------------------------------- ### Implement HttpHandler for Response Modification Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/api-reference/proxy.md Implement the HttpHandler trait to intercept and modify outgoing HTTP responses before they are sent to the client. This example adds a custom header to the response. ```rust use hudsucker::{HttpHandler, HttpContext}; use hyper::Response; impl HttpHandler for MyHandler { async fn handle_response( &mut self, _ctx: &HttpContext, mut res: Response, ) -> Response { // Add response header res.headers_mut().insert("X-Intercepted", "true".parse().unwrap()); res } } ``` -------------------------------- ### Handling WebSocket Messages in Rust Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/types.md Example implementation of the `WebSocketHandler` trait to process incoming WebSocket messages. It demonstrates matching on different message types and returning a response. ```rust use hudsucker::{WebSocketHandler, WebSocketContext}; use tokio_tungstenite::tungstenite::Message; impl WebSocketHandler for MyHandler { async fn handle_message( &mut self, _ctx: &WebSocketContext, message: Message, ) -> Option { match message { Message::Text(text) => { println!("Text: {}", text); Some(Message::Text(text.to_uppercase())) } Message::Binary(data) => { println!("Binary: {} bytes", data.len()); Some(Message::Binary(data)) } Message::Close(_) => { println!("Close"); Some(message) } _ => Some(message), } } } ``` -------------------------------- ### Configure ProxyBuilder with an address Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/api-reference/proxy-builder.md Set the address for the proxy to listen on using `with_addr`. This transitions the builder to the `WantsCa` state, requiring certificate authority configuration next. ```rust use hudsucker::Proxy; use std::net::SocketAddr; let proxy = Proxy::builder() .with_addr(SocketAddr::from(([127, 0, 0, 1], 3000))); ``` -------------------------------- ### Configure Custom Client Builder with ProxyBuilder Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/api-reference/proxy-builder.md Provides a custom hyper ClientBuilder for fine-tuned HTTP client configuration. This allows for advanced settings like connection pooling or custom timeouts. ```rust use hyper_util::client::legacy::Builder as ClientBuilder; use hudsucker::Proxy; let mut client = ClientBuilder::new(); // Configure client... let proxy = Proxy::builder() .with_addr(addr) .with_ca(ca) .with_rustls_connector(provider) .with_client(client); ``` -------------------------------- ### Simple Transparent HTTPS Proxy with NoopHandler Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/api-reference/noop-handler.md Sets up a basic HTTPS proxy using Hudsucker, demonstrating the default usage of NoopHandler for transparent proxying. ```rust use hudsucker::{Proxy, NoopHandler, certificate_authority::RcgenAuthority, rustls::crypto::aws_lc_rs, rcgen::{Issuer, KeyPair}}; use std::net::SocketAddr; #[tokio::main] async fn main() -> Result<(), Box> { let key_pair = KeyPair::from_pem(include_str!("ca/key.pem"))?; let issuer = Issuer::from_ca_cert_pem(include_str!("ca/cert.pem"), key_pair)?; let ca = RcgenAuthority::new(issuer, 1_000, aws_lc_rs::default_provider()); let proxy = Proxy::builder() .with_addr(SocketAddr::from(([127, 0, 0, 1], 3000))) .with_ca(ca) .with_rustls_connector(aws_lc_rs::default_provider()) // NoopHandler is the default .build()?; println!("Proxy listening on 127.0.0.1:3000"); proxy.start().await?; Ok(()) } ``` -------------------------------- ### Triggering a Decode Error with Unknown Content-Encoding Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/errors.md An example that intentionally triggers a `Decode` error by setting an unsupported `Content-Encoding` header on a request. This is useful for testing error handling logic. ```rust use hudsucker::{decode_request, Body, Error}; use hyper::Request; let req = Request::builder() .header("Content-Encoding", "unknown-codec") .body(Body::from("data")) .unwrap(); match decode_request(req) { Err(Error::Decode) => println!("Unsupported encoding"), _ => {} } ``` -------------------------------- ### Configure Connector with Rustls Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/types.md Demonstrates how to configure a WebSocket connector using Rustls with the AWS LibCrypto provider. ```rust use tokio_tungstenite::Connector; use hudsucker::rustls::crypto::aws_lc_rs; // Use with Rustls let provider = aws_lc_rs::default_provider(); let config = rustls::ClientConfig::builder_with_provider(...) .build(); let connector = Connector::Rustls(Arc::new(config)); ``` -------------------------------- ### Configure ProxyBuilder with a TcpListener Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/api-reference/proxy-builder.md Provide an existing `TcpListener` using `with_listener` instead of binding to an address. This is useful for advanced scenarios and also transitions the builder to the `WantsCa` state. ```rust use hudsucker::Proxy; use tokio::net::TcpListener; #[tokio::main] async fn main() -> Result<(), Box> { let listener = TcpListener::bind("127.0.0.1:3000").await?; let proxy = Proxy::builder() .with_listener(listener); Ok(()) } ``` -------------------------------- ### Proxy::builder() Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/exports.md Creates a new ProxyBuilder to configure and build a Proxy instance. ```APIDOC ## Proxy::builder() ### Description Creates a new ProxyBuilder to configure and build a Proxy instance. ### Method Associated Function ### Parameters None ### Response - **ProxyBuilder**: A builder object for configuring the proxy. ``` -------------------------------- ### with_server Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/configuration.md Provides a custom hyper ServerBuilder for advanced HTTP server configuration. This allows for fine-tuning server behavior or HTTP version handling. ```APIDOC ## with_server ### Description Provides a custom hyper `ServerBuilder` for advanced HTTP server configuration. ### Method `with_server(self, server: ServerBuilder) -> Self` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```rust use hyper_util::server::conn::auto::Builder as ServerBuilder; use hyper_util::rt::TokioExecutor; let mut server = ServerBuilder::new(TokioExecutor::new()); server.http1().title_case_headers(true); let proxy = Proxy::builder() .with_addr(addr) .with_ca(ca) .with_rustls_connector(provider) .with_server(server) .build()?; ``` ### Response #### Success Response (200) Not applicable for builder methods. #### Response Example Not applicable for builder methods. ``` -------------------------------- ### Modify HTML Content with Rust Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/api-reference/decoder.md This example demonstrates how to intercept and modify HTML responses. It checks the 'content-type' header for 'text/html', decodes the body, performs string replacements, and returns the modified response. ```rust use hudsucker::{HttpHandler, HttpContext, decode_response, Body}; use hyper::Response; use http_body_util::BodyExt; impl HttpHandler for MyHandler { async fn handle_response( &mut self, _ctx: &HttpContext, res: Response, ) -> Response { let is_html = res.headers() .get("content-type") .and_then(|h| h.to_str().ok()) .map(|s| s.contains("text/html")) .unwrap_or(false); if !is_html { return res; } let res = decode_response(res).unwrap_or(res); let (mut parts, body) = res.into_parts(); match body.collect().await { Ok(collected) => { let mut html = String::from_utf8_lossy(&collected.to_bytes()).into_owned(); // Modify HTML html = html.replace("", ""); // Return modified response parts.headers.remove("content-encoding"); return Response::from_parts(parts, Body::from(html)); } Err(_) => {} } Response::from_parts(parts, body) } } ``` -------------------------------- ### Initialize OpensslAuthority Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/api-reference/certificate-authority.md Creates a new OpenSSL-based certificate authority. Ensure the necessary private key, CA certificate, and hash algorithm are provided. The crypto provider is sourced from rustls. ```rust use hudsucker::{ certificate_authority::OpensslAuthority, openssl::{hash::MessageDigest, pkey::PKey, x509::X509}, rustls::crypto::aws_lc_rs, }; let private_key_bytes: &[u8] = include_bytes!("ca/hudsucker.key"); let ca_cert_bytes: &[u8] = include_bytes!("ca/hudsucker.cer"); let private_key = PKey::private_key_from_pem(private_key_bytes).unwrap(); let ca_cert = X509::from_pem(ca_cert_bytes).unwrap(); let ca = OpensslAuthority::new( private_key, ca_cert, MessageDigest::sha256(), 1_000, aws_lc_rs::default_provider(), ); ``` -------------------------------- ### Builder Error Enum for TLS Configuration Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/types.md Defines errors that can occur during proxy builder configuration, specifically related to TLS setup. This enum is returned by ProxyBuilder::build() if TLS initialization fails. ```rust pub enum Error { #[cfg(feature = "native-tls-client")] NativeTls(hyper_tls::native_tls::Error), #[cfg(feature = "rustls-client")] Rustls(tokio_rustls::rustls::Error), } ``` -------------------------------- ### Integrate RcgenAuthority with ProxyBuilder Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/api-reference/certificate-authority.md Demonstrates how to initialize and use RcgenAuthority with ProxyBuilder to handle certificate generation for proxied HTTPS connections. Ensure the CA key and certificate files are accessible. ```rust use hudsucker::{Proxy, certificate_authority::RcgenAuthority, rustls::crypto::aws_lc_rs, rcgen::{Issuer, KeyPair}}; use std::net::SocketAddr; let key_pair = KeyPair::from_pem(include_str!("ca/hudsucker.key"))?; let issuer = Issuer::from_ca_cert_pem(include_str!("ca/hudsucker.cer"), key_pair)?; let ca = RcgenAuthority::new(issuer, 1_000, aws_lc_rs::default_provider()); let proxy = Proxy::builder() .with_addr(SocketAddr::from(([127, 0, 0, 1], 3000))) .with_ca(ca) .with_rustls_connector(aws_lc_rs::default_provider()) .build()?; ``` -------------------------------- ### Custom Request Handler in Rust Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/README.md This example shows how to implement a custom HTTP handler in Rust to intercept and modify requests. It defines a `RequestInterceptor` struct that implements the `HttpHandler` trait, allowing modification of request headers before they are processed by the proxy. ```rust use hudsucker::{ Proxy, HttpHandler, RequestOrResponse, HttpContext, Body, certificate_authority::RcgenAuthority, rustls::crypto::aws_lc_rs, rcgen::{Issuer, KeyPair} }; use hyper::Request; use std::net::SocketAddr; #[derive(Clone)] struct RequestInterceptor; impl HttpHandler for RequestInterceptor { async fn handle_request( &mut self, ctx: &HttpContext, mut req: Request, ) -> RequestOrResponse { println!("Request from {}: {} {}", ctx.client_addr, req.method(), req.uri() ); // Modify request if needed req.headers_mut().insert("X-Via-Proxy", "hudsucker".parse().unwrap()); RequestOrResponse::Request(req) } } #[tokio::main] async fn main() -> Result<(), Box> { let key_pair = KeyPair::from_pem(include_str!("ca/hudsucker.key"))?; let issuer = Issuer::from_ca_cert_pem(include_str!("ca/hudsucker.cer"), key_pair)?; let ca = RcgenAuthority::new(issuer, 1_000, aws_lc_rs::default_provider()); let proxy = Proxy::builder() .with_addr(SocketAddr::from(([127, 0, 0, 1], 3000))) .with_ca(ca) .with_rustls_connector(aws_lc_rs::default_provider()) .with_http_handler(RequestInterceptor) .build()?; proxy.start().await?; Ok(()) } ``` -------------------------------- ### Generate CA Private Key and Certificate using OpenSSL Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/api-reference/certificate-authority.md Provides bash commands to generate a private key and a self-signed root CA certificate using OpenSSL. These files are essential for setting up a custom CA. ```bash # Generate a private key openssl genrsa -out hudsucker.key 2048 # Generate a self-signed certificate valid for 10 years openssl req -new -x509 -key hudsucker.key -out hudsucker.cer -days 3650 \ -subj "/CN=Hudsucker/O=MITM Proxy" ``` -------------------------------- ### with_listener Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/configuration.md Alternative to `with_addr`: provide a pre-bound `TcpListener`. This is useful when you need to customize the listener before binding. ```APIDOC ## with_listener ### Description Alternative to `with_addr`: provide a pre-bound `TcpListener`. ### Signature ```rust pub fn with_listener(self, listener: TcpListener) -> ProxyBuilder ``` ### Parameters #### Path Parameters - **listener** (`TcpListener`) - Required (alternative to `with_addr`) - Pre-configured TCP listener. ### Use Case When you need to customize the listener (socket options, file descriptor reuse, etc.) ### Example ```rust use tokio::net::TcpListener; let listener = TcpListener::bind("127.0.0.1:3000").await?; // Optionally set socket options here let proxy = Proxy::builder() .with_listener(listener) .with_ca(ca) .with_rustls_connector(provider) .build()?; ``` ``` -------------------------------- ### ProxyBuilder::with_server Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/exports.md Sets a custom hyper server for the proxy. ```APIDOC ## ProxyBuilder::with_server ### Description Set custom hyper server. ### Method `with_server(server)` ### Returns `Self` ``` -------------------------------- ### Configure Native TLS Connector for ProxyBuilder Source: https://github.com/omjadas/hudsucker/blob/main/_autodocs/api-reference/proxy-builder.md Use `with_native_tls_connector` to configure the proxy to use the system's native TLS implementation. This requires the `native-tls-client` feature. ```rust use hudsucker::Proxy; use std::net::SocketAddr; let proxy = Proxy::builder() .with_addr(SocketAddr::from(([127, 0, 0, 1], 3000))) .with_ca(ca) .with_native_tls_connector(); ```