penumbra-x / rquest

A high-performance asynchronous Rust HTTP client with TLS, JA3/JA4, and HTTP2 fingerprint spoof
Apache License 2.0
64 stars 12 forks source link
akamai akamai-fingerprint boringssl client fingerprint http http-client http2 http2-fingerprint https ja3 ja3-fingerprint ja4 ja4-fingerprint rust ssl tls tls-fingerprint websocket websocket-client

rquest

Crates.io License crates.io Crates.io Total Downloads

🚀 Support my journey to full-time open-source development by sponsoring me on GitHub

An ergonomic, all-in-one JA3/JA4/HTTP2 fingerprint HTTP/WebSocket client.

Additional learning resources include:

Usage

This asynchronous example uses Tokio and enables some optional features, so your Cargo.toml could look like this:

HTTP

[dependencies]
tokio = { version = "1", features = ["full"] }
rquest = "0.27"
use rquest::tls::Impersonate;

#[tokio::main]
async fn main() -> Result<(), rquest::Error> {
    // Build a client to mimic Chrome130
    let client = rquest::Client::builder()
        .impersonate(Impersonate::Chrome130)
        .build()?;

    // Use the API you're already familiar with
    let resp = client.get("https://tls.peet.ws/api/all").send().await?;
    println!("{}", resp.text().await?);

    Ok(())
}

WebSocket

[dependencies]
tokio = { version = "1", features = ["full"] }
rquest = { version = "0.27", features = ["websocket"] }
use futures_util::{SinkExt, StreamExt, TryStreamExt};
use rquest::{tls::Impersonate, Client, Message};

#[tokio::main]
async fn main() -> Result<(), rquest::Error> {
    // Build a client to mimic Chrome130
    let client = Client::builder()
        .impersonate(Impersonate::Chrome130)
        .build()?;

    // Use the API you're already familiar with
    let websocket = client
        .websocket("wss://echo.websocket.org")
        .send()
        .await?
        .into_websocket()
        .await?;

    let (mut tx, mut rx) = websocket.split();

    tokio::spawn(async move {
        for i in 1..11 {
            tx.send(Message::Text(format!("Hello, World! #{i}")))
                .await
                .unwrap();
        }
    });

    while let Some(message) = rx.try_next().await? {
        match message {
            Message::Text(text) => println!("received: {text}"),
            _ => {}
        }
    }

    Ok(())
}

Preconfigured TLS/HTTP2

[dependencies]
tokio = { version = "1", features = ["full"] }
rquest = "0.27"
use boring::ssl::{SslConnector, SslCurve, SslMethod, SslOptions};
use http::{header, HeaderValue};
use rquest::{
    tls::{Http2Settings, ImpersonateSettings, TlsSettings, Version},
    HttpVersionPref,
};
use rquest::{PseudoOrder::*, SettingsOrder::*};

#[tokio::main]
async fn main() -> Result<(), rquest::Error> {
    // Create a pre-configured TLS settings
    let settings = ImpersonateSettings::builder()
        .tls(
            TlsSettings::builder()
                .connector(Box::new(|| {
                    let mut builder = SslConnector::builder(SslMethod::tls_client())?;
                    builder.set_curves(&[SslCurve::SECP224R1, SslCurve::SECP521R1])?;
                    builder.set_options(SslOptions::NO_TICKET);
                    Ok(builder)
                }))
                .tls_sni(true)
                .http_version_pref(HttpVersionPref::All)
                .application_settings(true)
                .pre_shared_key(true)
                .enable_ech_grease(true)
                .permute_extensions(true)
                .min_tls_version(Version::TLS_1_0)
                .max_tls_version(Version::TLS_1_3)
                .build(),
        )
        .http2(
            Http2Settings::builder()
                .initial_stream_window_size(6291456)
                .initial_connection_window_size(15728640)
                .max_concurrent_streams(1000)
                .max_header_list_size(262144)
                .header_table_size(65536)
                .enable_push(false)
                .headers_priority((0, 255, true))
                .headers_pseudo_order([Method, Scheme, Authority, Path])
                .settings_order([
                    HeaderTableSize,
                    EnablePush,
                    MaxConcurrentStreams,
                    InitialWindowSize,
                    MaxFrameSize,
                    MaxHeaderListSize,
                    UnknownSetting8,
                    UnknownSetting9,
                ])
                .build(),
        )
        .headers(Box::new(|headers| {
            headers.insert(header::USER_AGENT, HeaderValue::from_static("rquest"));
        }))
        .build();

    // Build a client with pre-configured TLS settings
    let client = rquest::Client::builder()
        .use_preconfigured_tls(settings)
        .build()?;

    // Use the API you're already familiar with
    let resp = client.get("https://tls.peet.ws/api/all").send().await?;
    println!("{}", resp.text().await?);

    Ok(())
}

Device

Currently supported impersonate device types

Chrome100,Chrome101,Chrome104,Chrome105,Chrome106,Chrome107,Chrome108,Chrome109,Chrome114,Chrome116,Chrome117,Chrome118,Chrome119,Chrome120,Chrome123,Chrome124,Chrome126,Chrome127,Chrome128,Chrome129,Chrome130

Edge101,Edge122,Edge127

SafariIos17_2,SafariIos17_4_1,SafariIos16_5,Safari15_3,Safari15_5,Safari15_6_1,Safari16,Safari16_5,Safari17_0,Safari17_2_1,Safari17_4_1,Safari17_5,Safari18,SafariIPad18

OkHttp3_9,OkHttp3_11,OkHttp3_13,OkHttp3_14,OkHttp4_9,OkHttp4_10,OkHttp5

Requirement

Install the environment required to build BoringSSL

Do not compile with crates that depend on OpenSSL; their prefixing symbols are the same and may cause linking failures.

If both OpenSSL and BoringSSL are used as dependencies simultaneously, even if the compilation succeeds, strange issues may still arise.

Building

sudo apt-get install build-essential cmake perl pkg-config libclang-dev musl-tools -y

cargo build --release

You can also use this GitHub Actions workflow to compile your project on Linux, Windows, and macOS.

Contributing

If you would like to submit your contribution, please open a Pull Request.

Getting help

Your question might already be answered on the issues

License

Apache-2.0 LICENSE

Accolades

The project is based on a fork of reqwest.