| Crates.io | echw |
| lib.rs | echw |
| version | 0.1.0 |
| created_at | 2025-08-19 03:34:11.130896+00 |
| updated_at | 2025-08-19 03:34:11.130896+00 |
| description | Encrypted Client Hello Wrapper - Library for making HTTP requests with ECH support |
| homepage | |
| repository | |
| max_upload_size | |
| id | 1801333 |
| size | 90,785 |
A Rust library for making HTTP GET and POST requests with Encrypted Client Hello (ECH) support using rustls and hickory-dns.
Add to your Cargo.toml:
[dependencies]
echw = "0.1.0"
tokio = { version = "1.0", features = ["full"] }
env_logger = "0.11"
use echw::EchClient;
use std::error::Error;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
env_logger::init();
let client = EchClient::builder(
"public.test.defo.ie".to_string(), // outer hostname
"min-ng.test.defo.ie".to_string(), // inner hostname (ECH protected)
)
.port(443)
.build();
let response = client.get("echstat.php?format=json").await?;
println!("Status: {}", response.status);
println!("ECH Status: {:?}", response.ech_status);
println!("Body: {}", response.body_as_string()?);
Ok(())
}
use echw::EchClient;
use std::error::Error;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
env_logger::init();
let client = EchClient::builder(
"public.test.defo.ie".to_string(),
"min-ng.test.defo.ie".to_string(),
)
.build();
let json_data = r#"{"message": "Hello ECH!"}"#;
let headers = vec![
("Content-Type".to_string(), "application/json".to_string()),
];
let response = client.post_with_headers("api/test", json_data, headers).await?;
println!("Response: {}", response.body_as_string()?);
Ok(())
}
The main client for making ECH-enabled HTTP requests.
EchClient::builder(outer_hostname, inner_hostname) - Create a new client builder.port(port) - Set the port (default: 443).cloudflare_dns() - Use Cloudflare DNS for ECH config lookup (default: Google DNS).grease() - Use GREASE ECH for testing.ech_config_file(path) - Load ECH config from file.ca_file(path) - Use custom CA certificate fileclient.get(path) - Make a GET requestclient.post(path, body) - Make a POST requestclient.post_with_headers(path, body, headers) - Make a POST request with custom headersResponse object containing:
status: String - HTTP status lineheaders: Vec<String> - Response headersbody: Vec<u8> - Response body as bytesech_status: EchStatus - ECH negotiation statusbody_as_string() - Convert body to UTF-8 stringECH negotiation status:
EchStatus::Accepted - ECH was successfully negotiatedEchStatus::Grease - GREASE ECH extension was usedEchStatus::NotOffered - ECH was not offeredRun the included examples:
# Simple GET request
cargo run --example simple_get
# JSON POST request
cargo run --example json_post
ECH is a TLS extension that encrypts the Server Name Indication (SNI) and other identifying parts of the TLS Client Hello message. This prevents network observers from seeing which specific server within a host the client is trying to reach.
The library includes support for ECH GREASE extensions for testing environments where real ECH configs are not available.
MIT License - see LICENSE file for details.