logprox 0.3.0

A blazing-fast HTTP proxy with conditional logging and request control
Documentation
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

LogProx is a blazing-fast HTTP proxy written in Rust that intercepts and processes requests based on configurable rules. Three core features:
1. **Conditional Logging**: Log requests matching pattern rules (by path, method, headers, body)
2. **Request Control**: Drop requests based on rules, returning custom responses
3. **Response Logging**: Log responses based on status codes and other conditions

Proxy format: `http://localhost:PORT/https://upstream-domain/path` — everything after the first `/` is the upstream URL.

## Build & Test Commands

```bash
# Build release binary (optimized)
cargo build --release

# Run tests (unit + integration)
cargo test

# Run specific test file
cargo test --test config_tests

# Run a single test
cargo test test_name -- --nocapture

# Run benchmarks
cargo bench

# Run specific benchmark
cargo bench --bench performance_microbenchmarks

# Start development server (debug build)
cargo run

# Start with custom config and port
PORT=8080 CONFIG_FILE=custom.yaml cargo run
```

## Project Structure

```
src/
├── main.rs              # Entry point, server setup, router config
├── lib.rs               # Crate-level docs, module exports
├── config/
│   ├── mod.rs          # Config, ConfigHolder (RwLock wrapper), rule matching logic, regex cache
│   ├── request.rs      # LoggingConfig, DropConfig, MatchConditions, CaptureConfig
│   └── response.rs     # ResponseLoggingConfig, ResponseMatchConditions, ResponseCaptureConfig
├── handlers/
│   ├── mod.rs          # Module exports
│   ├── api.rs          # Health, config, reload endpoints
│   └── proxy.rs        # proxy_handler, SSRF validation, header filtering, error types

benches/                 # Criterion benchmarks
├── proxy_latency.rs    # End-to-end proxy latency (direct vs proxied)
├── performance_microbenchmarks.rs  # Micro-benchmarks (regex, headers, locks)
└── comprehensive_performance.rs    # Regex, header iteration, YAML parsing

tests/                   # Integration & unit tests
```

## Architecture Patterns

**Configuration System**: `Config` struct loaded from YAML via `serde_norway`, wrapped in `ConfigHolder` (`parking_lot::RwLock` for hot reload). Environment variables substituted via `${VAR_NAME}` in drop rule response bodies.

**Request Matching**: `matches_conditions_parts()` evaluates `MatchConditions`. Path/body patterns are regex (OR — any one match suffices). Method matching is case-insensitive. Headers are regex (AND — all must match). Different condition types are ANDed together.

**Proxy Handler Order**: body read → drop check → URL extract → SSRF validate → log request → forward → log response. Drop check runs before URL extraction so drop rules apply to any path (including malformed/non-URL paths).

**SSRF Protection**: `validate_upstream_ssrf` in `proxy.rs` runs before forwarding. Default policy: http/https only, private/loopback IPs blocked. Controlled via `upstream:` config section (`UpstreamConfig`). Set `allow_private_networks: true` when proxying to internal services. Benchmarks proxy localhost so they use `UpstreamConfig { allow_private_networks: true, ..Default::default() }`.

**Lazy Static HTTP Client**: `static HTTP_CLIENT: LazyLock<reqwest::Client>` — single global client, initialized on first use.

## Key Implementation Details

- **Regex Caching**: `static REGEX_CACHE: LazyLock<RwLock<HashMap<String, Arc<Regex>>>>` — compiled once, reused across all requests and threads. Pre-warmed at config load via `prewarm_regex_cache`. Fast path checks read lock first; slow path upgrades to write lock to insert.
- **Header Filtering**: `HOP_BY_HOP` const applied to both forwarded request headers and proxied response headers (RFC 7230 §6.1).
- **RwLock**: `parking_lot::RwLock` — no poisoning, faster than std. Readers only block on config reload writes.
- **Body Size Cap**: `MAX_BODY_SIZE = 10MB` — returns 413 if exceeded, prevents OOM.
- **Error Handling**: `ProxyError` enum with JSON responses. URL never echoed back in error messages (prevents info leakage).

## Testing Notes

- Unit tests in `tests/config_tests.rs` for rule matching logic
- Integration tests in `tests/integration_tests.rs` for end-to-end flow
- Proxy-specific tests in `tests/proxy_unit_tests.rs` for URL extraction and duration parsing

Use `--nocapture` flag to see test output.

## Performance Considerations

- Actual benchmark results: ~40µs direct (loopback), ~75µs proxied, ~35µs proxy overhead
- Micro-benchmarks track regex cache lookup, header iteration, lock contention, YAML parsing
- `parking_lot` used for faster locks with no poisoning risk

## Configuration

- Load from `CONFIG_FILE` env var (default: `config.yaml`)
- Hot reload via `POST /config/reload` endpoint
- Patterns are regex; evaluation order matters (first rule match wins)
- Default behaviors: `logging.default` and `drop.default` apply if no rules match
- Full config reference served at runtime via `GET /config/docs`