tiny_http_client 0.1.2

Tiny synchronous HTTP/HTTPS GET and POST client
docs.rs failed to build tiny_http_client-0.1.2
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Visit the last successful build: tiny_http_client-0.1.3

tiny_http_client

Crates.io License: MIT

A small synchronous HTTP/HTTPS GET/POST client written in Rust.

tiny_http_client is designed for small applications and utilities that need basic HTTP/HTTPS functionality without pulling in a full-featured HTTP client stack.

The client uses:

Features

The crate provides the following Cargo features:

  • http-get — enables HTTP GET requests;
  • http-post — enables HTTP POST requests;
  • linux-native-tls — enables native-tls on Linux and uses the operating system certificate store;
  • linux-own-cert-list — enables an embedded CA certificate list on Linux.

By default, only http-get is enabled.

On Windows and macOS, native-tls is always used. On Linux, rustls is used by default.

[features]
default = ["http-get"]
http-get = []
http-post = []
linux-native-tls = ["dep:native-tls"]
linux-own-cert-list = []

To enable both GET and POST:

[dependencies]
tiny_http_client = {
    version = "0.1",
    features = ["http-get", "http-post"]
}

If only POST is required:

[dependencies]
tiny_http_client = {
    version = "0.1",
    default-features = false,
    features = ["http-post"]
}

Installation

Add the following dependency to Cargo.toml:

[dependencies]
tiny_http_client = { version = "0.1" }

Linux native TLS

On Linux, enable the linux-native-tls feature to use native-tls and the operating system certificate store:

[dependencies]
tiny_http_client = {
    version = "0.1",
    default-features = false,
    features = ["http-get", "linux-native-tls"]
}

The linux-native-tls and linux-own-cert-list features are mutually exclusive.

CA certificate list

The crate supports an optional linux-own-cert-list feature that embeds a selected set of CA root certificates directly into the binary.

This can be useful for small applications that only connect to a known set of HTTPS services and do not need the complete system or webpki-roots certificate store.

Enable the feature in Cargo.toml:

[dependencies]
tiny_http_client = {
    version = "0.1",
    features = ["linux-own-cert-list"]
}

When linux-own-cert-list is enabled:

  • only certificates from the crate's certs/ directory are embedded;
  • the certificates are stored in DER format;
  • the normal webpki-roots certificate list is not used;
  • on Windows / macOS, the feature has no effect and the native OS certificate store is used;
  • on Linux, the embedded certificates are used as the TLS trust anchors.

The feature is intentionally disabled by default.

Certificate files

Certificates used by linux-own-cert-list are stored in: certs/*.der

Each file should contain one CA certificate in DER format.

The certificate filenames are not important. The build script automatically finds all .der files in the certs/ directory and generates the Rust source code required to embed them into the binary.

Generating the certificate list

The repository contains a get-certs.sh script for generating a minimal CA certificate list for a specific set of HTTPS hosts.

The hosts are configured near the beginning of the script:

HOSTS="
github.com
api.github.com
objects.githubusercontent.com
github-releases.githubusercontent.com
"

The script:

  1. connects to each HTTPS host;
  2. obtains the certificates sent by the server;
  3. verifies the certificate chain using the system OpenSSL trust store;
  4. determines the root CA of the verified chain;
  5. extracts the root CA from the system trust store;
  6. converts it to DER format;
  7. saves it in the certs/ directory.

For example:

certs/
├── ISRG_Root_X1_96bcec06264976f3.der
├── USERTrust_ECC_Certification_Authority_4ff460d54b9c86da.der
└── ...

The script does not blindly trust certificates received from the server. Server-provided certificates are used only to determine and verify the certificate chain. The root CA is extracted from the local system trust store.

Run:

./get-certs.sh

The script requires OpenSSL and uses the system CA store to verify the certificate chains.

After updating the certificates, build the application with:

cargo build --release --features linux-own-cert-list

Why use an own certificate list?

Embedding only the root certificates required by an application can reduce the amount of CA data included in the binary and makes the trust store independent of the operating system.

It is especially useful for small standalone utilities that communicate only with a limited number of HTTPS services.

For example, an application that only communicates with GitHub may only need the root CAs required by GitHub and its release/download infrastructure rather than a complete collection of public root certificates.

The application should regenerate the certificate list when the HTTPS services it uses change their certificate chains or when the relevant root certificates change.

Basic GET usage

use tiny_http_client::get;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let response = get("https://example.com/")?;

    println!("HTTP status: {}", response.status);

    println!("{}", response.as_str()?);

    Ok(())
}

GET request headers

Use get_with_headers() when custom HTTP headers are required:

use tiny_http_client::get_with_headers;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let response = get_with_headers(
        "https://api.github.com/repos/ygguser/peers_updater/releases/latest",
        &[
            ("User-Agent", "peers_updater"),
            ("Accept", "application/json"),
        ],
    )?;

    println!("HTTP status: {}", response.status);

    println!("{}", response.as_str()?);

    Ok(())
}

Header names and values containing CR or LF characters are rejected to prevent HTTP header injection.

POST request

POST requests are enabled by the http-post feature.

The basic post() function sends a request body:

use tiny_http_client::post;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let response = post(
        "https://example.com/api",
        b"hello=world",
    )?;

    println!("HTTP status: {}", response.status);

    println!("{}", response.as_str()?);

    Ok(())
}

The request body is provided as a byte slice, so binary data can also be sent.

POST request with headers

Use post_with_headers() when custom HTTP headers are required:

use tiny_http_client::post_with_headers;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let response = post_with_headers(
        "https://example.com/api",
        &[
            ("Content-Type", "application/x-www-form-urlencoded"),
            ("User-Agent", "my-client"),
        ],
        b"hello=world",
    )?;

    println!("HTTP status: {}", response.status);

    println!("{}", response.as_str()?);

    Ok(())
}

JSON POST request

JSON can be sent by providing the appropriate Content-Type header:

use tiny_http_client::post_with_headers;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let body = br#"{"name":"test","value":123}"#;


    let response = post_with_headers(
        "https://example.com/api",
        &[
            ("Content-Type", "application/json"),
            ("Accept", "application/json"),
        ],
        body,
    )?;

    println!("HTTP status: {}", response.status);

    println!("{}", response.as_str()?);

    Ok(())
}

The crate does not provide JSON serialization or deserialization. Applications can use any JSON library they prefer, or construct JSON manually when appropriate.

Response

The Response structure contains:

pub struct Response {
    pub status: u16,
    pub headers: Vec<(String, String)>,
    pub body: Vec<u8>,
}

Status code

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

Response body as bytes

let data: &[u8] = response.as_bytes();

Response body as UTF-8

let text = response.as_str()?;
println!("{}", text);

Response headers

Use header() to retrieve a header without worrying about capitalization:

if let Some(content_type) = response.header("Content-Type") {
    println!("Content-Type: {}", content_type);
}

Linux TLS options

On Windows and macOS, HTTPS connections always use native-tls and the native operating system certificate store.

On Linux, TLS implementation can be selected using features:

  • no Linux TLS feature — rustls with Mozilla root certificates from webpki-roots;
  • linux-own-cert-listrustls with CA certificates embedded from the crate's certs/ directory;
  • linux-native-tlsnative-tls with the operating system certificate store.

The linux-native-tls and linux-own-cert-list features are mutually exclusive.

The TLS connection performs normal server certificate verification against the selected root store.

No client certificates are required.

Redirects

Supported HTTP redirects:

  • 301 Moved Permanently
  • 302 Found
  • 303 See Other
  • 307 Temporary Redirect
  • 308 Permanent Redirect

Up to 5 redirects are followed automatically.

const MAX_REDIRECTS: usize = 5;

Timeouts

The connection timeout is:

const CONNECT_TIMEOUT: Duration = Duration::from_secs(30);

The same timeout is also applied to socket reads and writes.

Design goals

The main goal of this crate is to provide a small dependency footprint and a simple API for applications that only need basic synchronous HTTP/HTTPS GET and POST requests.

The crate intentionally uses platform-specific TLS implementations:

  • native TLS on Windows;
  • native TLS on macOS;
  • rustls on Linux.

This keeps each platform's implementation simple and lets Windows and macOS use their native TLS implementations and certificate stores.

It intentionally does not attempt to implement a complete HTTP client.

The crate currently does not provide:

  • asynchronous I/O
  • HTTP/2
  • HTTP/3
  • proxy support
  • cookies
  • connection pooling
  • multipart requests
  • PUT/PATCH/DELETE helpers
  • automatic content compression
  • automatic decompression
  • authentication helpers

These features can be implemented by the application when needed.

Error handling

All public request functions return:

Result<Response, Box<dyn std::error::Error>>

Examples of errors include:

  • unsupported URL scheme
  • DNS resolution failure
  • TCP connection failure
  • connection timeout
  • TLS errors
  • invalid HTTP responses
  • invalid HTTP headers
  • invalid chunked encoding
  • too many redirects
  • non-2xx HTTP status codes

For example:

match tiny_http_client::get("https://example.com/") {
    Ok(response) => {
        println!("Status: {}", response.status);
    }


    Err(error) => {
        eprintln!("HTTP request failed: {}", error);
    }
}

Non-2xx responses

Responses with a status code outside the 200..=299 range are returned as errors.

License

MIT License.

Copyright (C) ygguser 2026.

See LICENSE for the full license text.