netune-http1 0.0.1

HTTP/1.1 codec: owned request/response framing, differential-tested against hyper
Documentation

netune

An owned, observable, and intervention-capable network stack in Rust.

netune owns every layer from DNS to the HTTP/1.1 message — no third-party HTTP implementation in the production dependency graph — and makes the transport itself an object you can inspect, fingerprint, and change:

Crate What it is
netune-trace The trace model and pure derivations. Every timing a surface shows is a pure function of a recorded trace. Also: TLS ClientHello parsing and JA3/JA4 fingerprints.
netune-http1 The HTTP/1.1 codec. Differential-tested against hyper (dev-dependency only) over recorded byte streams.
netune-http2 HTTP/2 wire protocol placeholder and design reservation (ADR-0003). Reserved at 0.0.1; no I/O implementation.
netune-ws Pure RFC 6455 WebSocket codec: role-enforced masking, fragmented-message reassembly, SHA-1 handshake keys. No I/O runtime.
netune The transport: DNS, TCP, TLS (rustls), the syscall tap (TimedIo), connection pool (Pool), TLS fingerprint presets and routing (TlsProfile, Preset), proxies (HTTP CONNECT & SOCKS5), redirects, decompression, client WebSocket upgrade (connect_ws), stale-socket absorption — and FaultIo, the chaos twin that injects delays, splits, truncations, and resets.
netune-probe The L2 probe: pure Ethernet/IPv4/TCP parse and build (forge) plus an opt-in inject feature for frame transmission.

Capability surface

Observe — a three-level tap with graceful degradation:

  • L0 protocol events, portable, always on
  • L1 syscall boundaries (TimedIo) + TCP_INFO sampling (RTT, retransmits, cwnd)
  • L2 per-segment capture (Linux, CAP_NET_RAW, opt-in)

Fingerprint — inspect and configure TLS identity:

  • Pure wire parser: netune-trace::ja4 parses ClientHello bytes and computes the JA4 fingerprint, cross-tool anchored against FoxIO's published test vectors.
  • Profile presets: named presets (netune-default, codex-reqwest, codex-network-proxy) configure ALPN, protocol versions, ciphers, and key-exchange groups.
  • Per-request selection: Target::with_tls_profile picks the identity at request time; unknown profile names fail loudly.
  • Pool isolation: connection pool keys on authority#profile, preventing connection reuse across disparate TLS identities.

Intervene — change behaviour at two privilege levels:

  • In-process, zero privileges (netune::FaultIo): script delays, split reads, truncations, and connection resets against any stream to test retry policies and streaming pipelines hermetically.
  • On the wire, feature-gated (netune-probe with --features inject): build arbitrary TCP frames (forged seq/ack, RSTs, window games) with pure, fully tested functions; transmit them only when the feature is compiled in and CAP_NET_RAW is held. The default build has no transmit path at all.

Resilience — culled keep-alive absorption:

  • Shortened idle pool bound (20 s) prevents handing out connections about to be culled by intermediate gateways.
  • Transparent single retry on stale pooled sockets before receiving a response head (INV-TRANSPORT-01), eliminating spurious keep-alive failures without request replay hazard.
  • Precise error classification (HttpError::Incomplete) distinguishing peer socket closure from protocol smuggling or violations.

The privilege boundary is structural

                 default build      --features inject + CAP_NET_RAW
parse/build      ✅ present         ✅ present        (pure, tested)
transmit         ❌ not compiled    ✅ present        (socket)

Injection changes the network rather than measuring it; it is never a default capability of anything long-running.

Quick Start

Build and Test

# Run unit and integration tests across all workspace crates
cargo test

# Run tests with nextest
cargo nextest run

Basic Request & Trace Inspection

use http::Method;
use netune::{Client, ClientConfig, Pool, RequestHead, Target, TcpConnector};
use netune_trace::{Recorder, derive};
use std::sync::{Arc, Mutex};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::new(TcpConnector, Pool::default(), ClientConfig::default());
    let target = Target::http("127.0.0.1", 8080);
    let head = RequestHead::new(Method::GET, "/health");
    let recorder = Arc::new(Mutex::new(Recorder::new(1024)));

    let mut response = client.send(target, head, recorder.clone()).await?;
    let body = response.body().read_to_end(64 * 1024).await?;
    println!("Status: {}, Body len: {}", response.status(), body.len());

    // Inspect derived microsecond timings from the recorded trace
    let trace = recorder.lock().unwrap().take();
    let timings = derive(&trace);
    println!("TTFB: {:?} µs", timings.ttfb_us);
    Ok(())
}

Documentation Map

Status

Pre-1.0. Every workspace crate is lockstep-versioned at 0.0.1, except netune-http2, which ships at 0.0.2 because the registry's 0.0.1 slot is held by its earlier name-reservation stub.

MSRV: 1.95. License: MIT.