ugi 0.2.1

Runtime-agnostic Rust request client with HTTP/1.1, HTTP/2, HTTP/3, H2C, WebSocket, SSE, and gRPC support
Documentation
#[cfg(feature = "emulation")]
use futures_lite::future::block_on;
#[cfg(feature = "emulation")]
use ugi::{
    BoringTlsFingerprint, BrowserFamily, EmulationProfile, Http1Fingerprint, Http2Fingerprint,
};

#[cfg(feature = "emulation")]
fn main() -> Result<(), Box<dyn std::error::Error>> {
    block_on(async move {
        let profile = EmulationProfile::builder()
            .profile_id("custom-api-profile")
            .browser_family(BrowserFamily::Custom("api".to_owned()))
            .browser_version("1")
            .platform("Linux x86_64")
            .default_header(
                "user-agent",
                "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36",
            )?
            .default_header("accept", "*/*")?
            .http1_fingerprint(Http1Fingerprint {
                header_order: vec![
                    "host".into(),
                    "user-agent".into(),
                    "accept".into(),
                    "accept-encoding".into(),
                ],
                original_header_case: vec![
                    ("host".into(), "Host".into()),
                    ("user-agent".into(), "User-Agent".into()),
                    ("accept".into(), "Accept".into()),
                    ("accept-encoding".into(), "Accept-Encoding".into()),
                ],
            })
            .http2_fingerprint(Http2Fingerprint {
                pseudo_header_order: vec![
                    ":method".into(),
                    ":authority".into(),
                    ":scheme".into(),
                    ":path".into(),
                ],
                regular_header_order: vec![
                    "user-agent".into(),
                    "accept".into(),
                    "accept-encoding".into(),
                ],
                ..Default::default()
            })
            .boring_tls_fingerprint(BoringTlsFingerprint {
                grease_enabled: Some(true),
                permute_extensions: Some(true),
                ..Default::default()
            })
            .build();

        let client = ugi::Client::builder().emulation(profile).build()?;
        let response = client.get("https://api.example.com/health").await?;

        println!("status={}", response.status().as_u16());
        Ok(())
    })
}

#[cfg(not(feature = "emulation"))]
fn main() {
    eprintln!(
        "This example requires the `emulation` feature:\n  cargo run --example emulation_custom --features emulation"
    );
}