#websocket #websocket-client #async-http #tls-client #socket-client #ja3

rquest

An fast asynchronous Rust HTTP/WebSocket Client with TLS/JA3/JA4/HTTP2 fingerprint impersonate

14 releases

new 0.21.11 Sep 27, 2024
0.21.10 Sep 23, 2024
0.20.85 Sep 8, 2024
0.20.50 Aug 16, 2024
0.11.98 Jul 29, 2024

#47 in HTTP client

Download history 499/week @ 2024-07-25 938/week @ 2024-08-01 3392/week @ 2024-08-08 1879/week @ 2024-08-15 235/week @ 2024-08-22 374/week @ 2024-08-29 413/week @ 2024-09-05 241/week @ 2024-09-12 977/week @ 2024-09-19 506/week @ 2024-09-26

2,199 downloads per month

Apache-2.0

500KB
11K SLoC

rquest

Email Badge Crates.io License crates.io Documentation Crates.io Total Downloads

An fast asynchronous Rust HTTP/WebSocket Client with TLS/JA3/JA4/HTTP2 fingerprint impersonate

  • Async Client
  • Plain, JSON, urlencoded, multipart bodies
  • Headers Order
  • Customizable redirect policy
  • Cookie Store
  • HTTP/WebSocket Proxies
  • HTTPS/WebSocket via BoringSSL
  • Preconfigured TLS/HTTP2/Headers settings
  • Changelog

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.21"
use std::error::Error;
use rquest::tls::Impersonate;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    // Build a client to mimic Chrome129
    let client = rquest::Client::builder()
        .impersonate(Impersonate::Chrome129)
        .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.21", features = ["websocket"] }
use futures_util::{SinkExt, StreamExt, TryStreamExt};
use rquest::{tls::Impersonate, Client, Message};
use std::error::Error;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let websocket = rquest::websocket("wss://echo.websocket.org").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.21"
use boring::ssl::{SslConnector, SslMethod};
use http::{header, HeaderValue};
use rquest::{
    tls::{Http2Settings, ImpersonateSettings, TlsExtensionSettings},
    HttpVersionPref,
};
use rquest::{PseudoOrder::*, SettingsOrder::*};
use std::error::Error;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    // Create a pre-configured TLS settings
    let settings = ImpersonateSettings::builder()
        .tls((
            SslConnector::builder(SslMethod::tls_client())?,
            TlsExtensionSettings::builder()
                .tls_sni(true)
                .http_version_pref(HttpVersionPref::Http2)
                .application_settings(true)
                .pre_shared_key(true)
                .enable_ech_grease(true)
                .permute_extensions(true)
                .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(vec![
                    HeaderTableSize,
                    EnablePush,
                    MaxConcurrentStreams,
                    InitialWindowSize,
                    MaxFrameSize,
                    MaxHeaderListSize,
                    EnableConnectProtocol,
                ])
                .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

  • Chrome

Chrome100Chrome101Chrome104Chrome105Chrome106Chrome107Chrome108Chrome109Chrome114Chrome116Chrome117Chrome118Chrome119Chrome120Chrome123Chrome124Chrome126Chrome127Chrome128Chrome129

  • Edge

Edge101Edge122Edge127

  • Safari

SafariIos17_2SafariIos17_4_1SafariIos16_5Safari15_3Safari15_5Safari15_6_1Safari16Safari16_5Safari17_0Safari17_2_1Safari17_4_1Safari17_5Safari18SafariIPad18

  • OkHttp

OkHttp3_9OkHttp3_11OkHttp3_13OkHttp3_14OkHttp4_9OkHttp4_10OkHttp5

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.

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.

Dependencies

~11–27MB
~565K SLoC