### 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();
```