scanclient 0.1.0

High-performance, observable HTTP client for Santh security scanners
Documentation
# scanclient — HTTP client tuned for security scanning

[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT) [![Tests](https://img.shields.io/badge/tests-13%20passing-brightgreen.svg)](https://img.shields.io/badge/tests-13%20passing-brightgreen.svg) [![Crates.io](https://img.shields.io/crates/v/scanclient.svg)](https://crates.io/crates/scanclient)

## Why
Security scanners perform huge numbers of HTTP requests under strict resource constraints and retry semantics. `scanclient` gives one production-oriented client with timeout, retry, proxy, rate limiting, and request observability baked into the crate.

It wraps `reqwest` but keeps a small, scan-specific API focused on scan workloads: easy defaults, bounded retries, response helpers, and typed errors.

## Quick Start
```rust
use scanclient::{HttpConfig, ScanClient};

#[tokio::main]
async fn main() -> scanclient::Result<()> {
    let mut config = HttpConfig::default();
    config.timeout_secs = 5;
    config.max_retries = 2;

    let client = ScanClient::from_config(config)?;
    let response = client.get("https://example.com").await?;

    println!("status={}", response.status());
    if let Ok(body) = response.body_text() {
        println!("len={}", body.len());
    }
    Ok(())
}
```

## Features
- Thin `ScanClient` API (`get`, `head`, `post`, `request`, `execute`).
- Configurable retries with exponential backoff and idempotent status retry policy.
- Optional rate limiting and proxy support.
- Request/response helpers (`body_text`, `contains`, header lookup).
- TOML load/parse for client configuration.

## TOML Configuration
Use `HttpConfig::from_toml` or `HttpConfig::load`.

```toml
timeout_secs = 10
max_retries = 3
retry_delay_ms = 250
max_redirects = 5
user_agent = "SanthScanner/1.0"
tls_verify = false
rate_limit_per_sec = 8

[custom_headers]
X-Scanner = "santh"
```

```rust
use scanclient::{HttpConfig, ScanClient};

let cfg = HttpConfig::from_toml(r#"timeout_secs=12\nrate_limit_per_sec=5\n"#).unwrap();
let _client = ScanClient::from_config(cfg);
```

## API Overview
- `HttpConfig`: configuration model.
- `ScanClient::from_config`: create client.
- `ScanClient::get`, `head`, `post`, `request`, `execute`.
- `ScanResponse`: typed response wrapper (`status`, `headers`, `body_*`, `contains`).
- `Error`, `Result`: crate-level error handling.

## Examples
### 1) Submit a POST and inspect response
```rust
use scanclient::{HttpConfig, ScanClient};

#[tokio::main]
async fn main() -> scanclient::Result<()> {
    let client = ScanClient::from_config(HttpConfig::default())?;
    let response = client.post("https://httpbin.org/post", "a=b&c=d").await?;

    println!("status={} contains=a={}", response.status(), response.contains("args"));
    Ok(())
}
```

### 2) Reuse a custom request with method + execute
```rust
use reqwest::Method;
use scanclient::{HttpConfig, ScanClient};

#[tokio::main]
async fn main() -> scanclient::Result<()> {
    let client = ScanClient::from_config(HttpConfig::default())?;
    let builder = client.request(Method::HEAD, "https://example.com");
    let response = client.execute(builder).await?;
    println!("ok={}", response.status().is_success());
    Ok(())
}
```

### 3) Load settings from TOML in scanner bootstrap
```rust
use scanclient::HttpConfig;

let cfg = HttpConfig::from_toml(r#"
user_agent = "MyScanner/2.0"
timeout_secs = 8
max_redirects = 2
"#).unwrap();
println!("ua={}", cfg.user_agent);
```

## Traits
`scanclient` does not define custom traits in the public API.

## Related Crates
- [secreport]https://docs.rs/secreport
- [multimatch]https://docs.rs/multimatch
- [scanstate]https://docs.rs/scanstate

## License
MIT, Corum Collective LLC

Docs: https://docs.rs/scanclient

Santh ecosystem: https://santh.io