hexz_core/store/http/mod.rs
1//! HTTP/HTTPS storage backend for remote snapshot access.
2//!
3//! This module provides a `StorageBackend` implementation that fetches snapshot data
4//! from HTTP/HTTPS servers using RFC 7233 range requests. It enables accessing
5//! remote snapshots without downloading entire files, making it ideal for cloud-native
6//! deployments, CI/CD pipelines, and distributed systems.
7//!
8//! # Architecture
9//!
10//! The [`HttpBackend`] wraps the `reqwest` async client in an embedded Tokio runtime,
11//! presenting a synchronous `StorageBackend` interface while leveraging async I/O
12//! internally for efficient concurrent operations.
13//!
14//! It uses HTTP range requests (`Range: bytes=start-end`) to fetch only the
15//! requested byte ranges, avoiding unnecessary data transfer. The backend maintains
16//! persistent HTTP connection pools for optimal performance.
17//!
18//! # Security
19//!
20//! To prevent SSRF (Server-Side Request Forgery) attacks, the backend implements
21//! URL validation that blocks access to:
22//! - **Loopback addresses**: 127.0.0.0/8, ::1
23//! - **Private networks**: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16
24//! - **Link-local addresses**: 169.254.0.0/16 (including AWS metadata at 169.254.169.254)
25//! - **IPv6 private ranges**: fc00::/7, fe80::/10
26//!
27//! Use `allow_restricted: true` only in trusted environments (e.g., local development,
28//! trusted internal networks).
29//!
30//! # Thread Safety
31//!
32//! The backend is fully thread-safe (`Send + Sync`):
33//! - The underlying `reqwest::Client` uses connection pooling and is designed for sharing
34//! - Multiple threads can call `read_exact()` concurrently without coordination
35//! - Each request is independent and does not affect others
36//!
37//! # Examples
38//!
39//! ```no_run
40//! use hexz_core::store::http::HttpBackend;
41//! use hexz_core::store::StorageBackend;
42//!
43//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
44//! let backend = HttpBackend::new(
45//! "https://cdn.example.com/snapshots/data.hxz".to_string(),
46//! false // block restricted IPs
47//! )?;
48//!
49//! let header = backend.read_exact(0, 512)?;
50//! assert_eq!(header.len(), 512);
51//! # Ok(())
52//! # }
53//! ```
54
55/// HTTP storage backend using async reqwest + Tokio.
56pub mod async_client;
57
58pub use async_client::HttpBackend;