icap-rs — ICAP protocol for Rust (client & mini server)
A Rust implementation of the ICAP protocol (RFC 3507) providing a client API and a server.
Status
Work in progress.
- Client: functional — supports
OPTIONS,REQMOD,RESPMOD, Preview (includingieof), embedded HTTP/1.x messages, streaming bodies, and optional connection reuse. - Server: per-service routing, automatic
OPTIONSresponses (with optional dynamic ISTag), duplicate-route detection, safe reading of chunked bodies before invoking handlers, and an RFC-friendly 200 echo fallback whenAllow: 204is absent andPreviewis not used.
Features
- Client with builder (
Client::builder()). - ICAP requests:
OPTIONS,REQMOD,RESPMOD. - Embedded HTTP request/response serialization on the ICAP wire.
- Preview negotiation (incl.
Preview: 0andieoffast path). - Chunked uploads, streaming large bodies after
100 Continue. - Keep-Alive: reuse a single idle connection.
- ICAPS (TLS) with either
rustls
Client
Builder-based configuration (host/port, keep-alive, default headers, timeouts).
Generate exact wire bytes for debugging without sending.
Quick start — OPTIONS
use ;
async
REQMOD with embedded HTTP and Preview
use Request as HttpRequest;
use ;
async
Streaming from disk after 100 Continue
use ;
use ;
async
TLS (ICAPS) — Client
The client supports TLS (“ICAPS”). You can enable one of two TLS stacks:
- rustls (recommended):
- Enable
tls-rustlsand pick exactly one provider:tls-rustls-ringortls-rustls-aws-lc
- Enable
If you enable both rustls providers or none, the crate fails to compile with a clear error.
When you use anicaps://…URI but build without any TLS feature, the client returns an error.
Cargo features
# Choose ONE rustls provider:
[]
= "actual-version"
= ["tls-rustls", "tls-rustls-ring"] # or: ["tls-rustls", "tls-rustls-aws-lc"]
ICAPS quick start (system roots)
icaps:// switches the client into TLS mode automatically. If you omit the port, the default for ICAPS is 11344.
use ;
async
rustls: trust a local CA (self-signed)
If your server uses a self-signed certificate, add its CA to the client trust store (PEM).
This method is available only with the tls-rustls feature.
use ;
async
SNI override
By default SNI is the ICAP host (or host_override if set). You can override it:
use Client;
#
Notes & limitations (client)
- rustls 0.23: certificate verification cannot be disabled via public API.
The builder’sdanger_disable_cert_verify(true)flag is ignored under rustls (kept only for API compatibility). - Client auth (mTLS): the client currently does not present a certificate (no client-auth).
If your server requires a client certificate, the handshake will fail. - Default ICAPS port: if no port is specified for
icaps://host, the client uses 11344.
To avoid surprises, specify the port explicitly to match your server (e.g.,icaps://host:13443/...).
Server
- Minimal async ICAP server built on Tokio.
- Routing per service, with one handler able to serve multiple methods.
- Automatic
OPTIONSper service:Methodsinjected from registered routes;Max-Connectionsinherited from global limit. - Dynamic ISTag provider:
ServiceOptions::with_istag_providerlets you computeISTagper request (incl.OPTIONS). - RFC guard: if the request has no
Allow: 204and noPreview, the server must not reply204; it will automatically send200 OKand echo back the embedded HTTP message (request forREQMOD, response forRESPMOD). - Duplicate route detection: registering the same
(service, method)twice panics with a clear message (axum-like DX). - Reads encapsulated chunked bodies to completion before invoking handlers.
ICAP status codes (re-exported from http)
ICAP reuses the HTTP numeric status codes (RFC 3507). This crate exposes them via a type alias:
pub type StatusCode = StatusCode;
Use StatusCode::OK, StatusCode::NO_CONTENT, etc. ICAP-specific rules (e.g., **ISTag is required on 2xx,
Encapsulatedconstraints, and **204 must not carry a body**) are enforced byicap-rs` during parsing and
serialization.
Quick start — Server (plaintext)
A minimal server exposing two services (reqmod, respmod) and replying 204 No Content.
use ;
use ServiceOptions;
const ISTAG: &str = "example-1.0";
async
One handler for both methods
You can route by strings (case-insensitive) or enums. The same handler can handle both REQMOD and RESPMOD:
use ;
use ServiceOptions;
use IcapResult;
use ;
const ISTAG: &str = "test-1.0";
async
TLS (ICAPS) — Server
The server can terminate TLS (“ICAPS”) directly using rustls (recommended)
Port choice: there is no official IANA port for ICAPS.
This README uses 13443 for the TLS server examples.
Make sure the client specifies the same port explicitly (e.g.icaps://host:13443/...), otherwise the client’s default11344may not match.
Cargo features
Choose exactly one TLS stack:
# RUSTLS (recommended): enable rustls and choose ONE provider
[]
= "actual-version"
= ["tls-rustls", "tls-rustls-ring"] # or: ["tls-rustls", "tls-rustls-aws-lc"]
Example: ICAPS server (TLS, no client-auth)
use ;
use ServiceOptions;
const ISTAG: &str = "scan-1.0";
async
Example: ICAPS server with mTLS (require client cert)
use ;
use ServiceOptions;
const ISTAG: &str = "scan-1.0";
async
Interop & notes
- ICAP and embedded HTTP headers are case-insensitive. When serializing ICAP headers, this crate uses canonical
title-casing (e.g.,
ISTag,Encapsulated). Embedded HTTP header names follow thehttpcrate’s representation. - ICAP status line formatting: you must format
ICAP/1.0 <code> <reason>yourself; do not printStatusCodewithDisplayto avoid getting"200 OK"as the code token. - Connections are kept open by default on the server side; the client can reuse a single idle connection when configured
to
keep_alive(true). - For preview handling, servers typically respond with
100 Continuebefore the client streams the remaining body. - Ports: client default for
icaps://hostwith no port is 11344. Server examples here use 13443.
To avoid mismatch, specify the port explicitly in the client URI (icaps://host:13443/...).
Roadmap
- OpenSSL TLS backend (
tls-openssl) with feature-gated builds, test coverage, and docs (parity withtls-rustls). - Richer server APIs (streaming to handler, trailers, backpressure, graceful shutdown).
- More complete
OPTIONShelpers and better defaults. - TLS client auth (mTLS).
- Connection pooling beyond a single keep-alive connection.