510 lines
16 KiB
Rust
510 lines
16 KiB
Rust
use std::{collections::HashMap, path::PathBuf};
|
|
|
|
pub use crate::auth::{
|
|
AuthChallengeModel as AuthChallenge, AuthCredentialModel as AuthCredential, AuthScheme,
|
|
};
|
|
|
|
/// Classifies how one header participates in an HTTP exchange.
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
pub enum HeaderKind {
|
|
/// Header belongs to the request.
|
|
Request,
|
|
/// Header belongs to the response.
|
|
Response,
|
|
/// Header is valid for both directions.
|
|
General,
|
|
}
|
|
|
|
/// One normalized HTTP header field.
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
pub struct HttpHeader {
|
|
/// Lower-level header name.
|
|
pub name: String,
|
|
/// Raw header value.
|
|
pub value: String,
|
|
/// Header classification within the exchange.
|
|
pub kind: HeaderKind,
|
|
}
|
|
|
|
/// HTTP methods supported by the protocol layer.
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
pub enum HttpMethod {
|
|
/// `GET`
|
|
Get,
|
|
/// `HEAD`
|
|
Head,
|
|
/// `POST`
|
|
Post,
|
|
/// `PUT`
|
|
Put,
|
|
/// `DELETE`
|
|
Delete,
|
|
}
|
|
|
|
/// HTTP versions surfaced by the transport layer.
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
pub enum HttpVersion {
|
|
/// HTTP/1.0
|
|
Http10,
|
|
/// HTTP/1.1
|
|
Http11,
|
|
/// HTTP/2
|
|
Http2,
|
|
/// HTTP/3
|
|
Http3,
|
|
}
|
|
|
|
/// One request byte or piece range.
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
pub struct RangeSpec {
|
|
/// Inclusive start offset.
|
|
pub start: u64,
|
|
/// Optional inclusive end offset.
|
|
pub end_inclusive: Option<u64>,
|
|
/// Unit used by the range.
|
|
pub unit: RangeUnit,
|
|
}
|
|
|
|
impl RangeSpec {
|
|
#[must_use]
|
|
/// Returns whether the range omits an explicit end bound.
|
|
pub const fn is_open_ended(&self) -> bool {
|
|
self.end_inclusive.is_none()
|
|
}
|
|
|
|
#[must_use]
|
|
/// Returns the requested length when the end bound is known.
|
|
pub fn length_hint(&self) -> Option<u64> {
|
|
self.end_inclusive
|
|
.map(|end| end.saturating_sub(self.start).saturating_add(1))
|
|
}
|
|
}
|
|
|
|
/// Units supported by HTTP-style range models.
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
pub enum RangeUnit {
|
|
/// Byte-oriented ranges.
|
|
Bytes,
|
|
/// Piece-oriented ranges used by higher-level scheduling.
|
|
Pieces,
|
|
}
|
|
|
|
/// Parsed `Content-Range` response metadata.
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
pub struct ContentRangeSpec {
|
|
/// Unit reported by the server.
|
|
pub unit: RangeUnit,
|
|
/// Inclusive start offset returned by the server.
|
|
pub start: u64,
|
|
/// Inclusive end offset returned by the server.
|
|
pub end_inclusive: u64,
|
|
/// Total object size when known.
|
|
pub total_size: Option<u64>,
|
|
/// Whether the response represents an unsatisfied range.
|
|
pub unsatisfied: bool,
|
|
}
|
|
|
|
impl ContentRangeSpec {
|
|
#[must_use]
|
|
/// Returns the completed length implied by the range payload.
|
|
pub const fn completed_length(&self) -> u64 {
|
|
if self.unsatisfied {
|
|
0
|
|
} else {
|
|
self.end_inclusive.saturating_add(1)
|
|
}
|
|
}
|
|
|
|
#[must_use]
|
|
/// Returns whether the range is explicitly unsatisfied.
|
|
pub const fn is_unsatisfied(&self) -> bool {
|
|
self.unsatisfied
|
|
}
|
|
}
|
|
|
|
/// Resume metadata carried into one HTTP transfer attempt.
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
pub struct ResumeState {
|
|
/// Requested starting offset for the retry or resumed request.
|
|
pub requested_offset: u64,
|
|
/// Offset actually accepted by the remote server.
|
|
pub accepted_offset: Option<u64>,
|
|
/// Whether the attempt truly resumed instead of restarting from zero.
|
|
pub resumed: bool,
|
|
}
|
|
|
|
/// Retry policy knobs applied to HTTP work.
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
pub struct RetryPolicy {
|
|
/// Maximum number of attempts.
|
|
pub max_attempts: u32,
|
|
/// Initial backoff delay in milliseconds.
|
|
pub initial_backoff_ms: u64,
|
|
/// Maximum backoff delay in milliseconds.
|
|
pub max_backoff_ms: u64,
|
|
/// Whether `3xx` responses are retryable.
|
|
pub retry_on_3xx: bool,
|
|
/// Whether `4xx` responses are retryable.
|
|
pub retry_on_4xx: bool,
|
|
/// Whether `5xx` responses are retryable.
|
|
pub retry_on_5xx: bool,
|
|
/// Whether transport-level network errors are retryable.
|
|
pub retry_on_network_error: bool,
|
|
/// Whether timeout failures are retryable.
|
|
pub retry_on_timeout: bool,
|
|
}
|
|
|
|
/// Fully-resolved retry behavior for one request.
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
pub struct RetryStrategy {
|
|
/// Base retry policy.
|
|
pub policy: RetryPolicy,
|
|
/// Optional jitter value in milliseconds.
|
|
pub jitter: Option<u64>,
|
|
/// Optional upper bound on total retry elapsed time in milliseconds.
|
|
pub max_elapsed_ms: Option<u64>,
|
|
}
|
|
|
|
/// Normalized reasons for retrying one transfer attempt.
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
pub enum RetryReason {
|
|
/// A transport-level network failure occurred.
|
|
NetworkError,
|
|
/// The request timed out.
|
|
Timeout,
|
|
/// The server responded with a retryable `3xx`.
|
|
Http3xx,
|
|
/// The server responded with a retryable `4xx`.
|
|
Http4xx,
|
|
/// The server responded with a retryable `5xx`.
|
|
Http5xx,
|
|
/// Partial-content semantics did not match the requested resume state.
|
|
PartialContentMismatch,
|
|
/// Another retryable condition occurred.
|
|
Other,
|
|
}
|
|
|
|
/// One recorded retry attempt.
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
pub struct RetryAttempt {
|
|
/// Attempt number starting at one.
|
|
pub attempt: u32,
|
|
/// Retry reason for the attempt.
|
|
pub reason: RetryReason,
|
|
/// Optional HTTP status observed during the attempt.
|
|
pub status: Option<u16>,
|
|
/// Optional backoff delay in milliseconds before the next attempt.
|
|
pub backoff_ms: Option<u64>,
|
|
}
|
|
|
|
/// Final or intermediate completion state for one HTTP response.
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
pub enum HttpCompletionState {
|
|
/// Response is not yet complete.
|
|
Incomplete,
|
|
/// Response is usable but only partial.
|
|
Partial,
|
|
/// Response is complete without checksum verification.
|
|
Complete,
|
|
/// Response is complete and checksum-verified.
|
|
Verified,
|
|
}
|
|
|
|
/// Derived completion summary for one HTTP response.
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
pub struct HttpCompletionModel {
|
|
/// Overall completion state.
|
|
pub state: HttpCompletionState,
|
|
/// Total payload length when known.
|
|
pub total_length: Option<u64>,
|
|
/// Number of completed bytes.
|
|
pub completed_length: u64,
|
|
/// Whether the response used partial-content semantics.
|
|
pub partial_content: bool,
|
|
/// Whether the status code indicates terminal success.
|
|
pub terminal_success: bool,
|
|
/// Whether checksum metadata was present.
|
|
pub checksum_seen: bool,
|
|
/// Whether the checksum could be verified successfully.
|
|
pub checksum_verified: bool,
|
|
}
|
|
|
|
/// Segment-level progress view for one transfer snapshot.
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
pub struct HttpSegmentProgressModel {
|
|
/// Range originally requested from the server.
|
|
pub requested_range: Option<RangeSpec>,
|
|
/// Requested starting offset.
|
|
pub requested_offset: u64,
|
|
/// Offset accepted by the server when present.
|
|
pub accepted_offset: Option<u64>,
|
|
/// Completed offset derived from the current response.
|
|
pub completed_offset: Option<u64>,
|
|
/// Whether the transfer is actively resuming instead of restarting.
|
|
pub resumed: bool,
|
|
}
|
|
|
|
/// Retry-attempt detail enriched with segment and resume context.
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
pub struct HttpRetryAttemptDetailModel {
|
|
/// Base retry-attempt data.
|
|
pub base: RetryAttempt,
|
|
/// Range requested for the attempt.
|
|
pub requested_range: Option<RangeSpec>,
|
|
/// Requested starting offset for the attempt.
|
|
pub requested_offset: u64,
|
|
/// Offset accepted by the server when present.
|
|
pub accepted_offset: Option<u64>,
|
|
/// Resume metadata captured for the attempt.
|
|
pub resume_state: Option<ResumeState>,
|
|
}
|
|
|
|
/// Snapshot of one in-flight or completed HTTP transfer.
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
pub struct HttpTransferProgressModel {
|
|
/// Stable task identifier.
|
|
pub task_id: String,
|
|
/// Request model associated with the transfer.
|
|
pub request: HttpRequestModel,
|
|
/// Segment-level progress details.
|
|
pub segment: HttpSegmentProgressModel,
|
|
/// Retry-attempt history with contextual detail.
|
|
pub retry_attempts: Vec<HttpRetryAttemptDetailModel>,
|
|
/// Maximum number of concurrent connections permitted for the task.
|
|
pub max_connections: u16,
|
|
/// Optional checksum hook attached to the transfer.
|
|
pub checksum_hook: Option<ChecksumHookModel>,
|
|
/// Derived completion summary when a response exists.
|
|
pub completion: Option<HttpCompletionModel>,
|
|
}
|
|
|
|
/// Proxy configuration projected into HTTP requests.
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
pub struct ProxyConfig {
|
|
/// Proxy scheme such as `http` or `socks5`.
|
|
pub scheme: String,
|
|
/// Proxy host name or IP.
|
|
pub host: String,
|
|
/// Proxy port.
|
|
pub port: u16,
|
|
/// Optional proxy username.
|
|
pub username: Option<String>,
|
|
/// Optional proxy password.
|
|
pub password: Option<String>,
|
|
/// Hosts that should bypass the proxy.
|
|
pub bypass_hosts: Vec<String>,
|
|
/// Whether proxying is disabled for the request.
|
|
pub no_proxy: bool,
|
|
}
|
|
|
|
/// One normalized HTTP cookie.
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
pub struct Cookie {
|
|
/// Cookie name.
|
|
pub name: String,
|
|
/// Cookie value.
|
|
pub value: String,
|
|
/// Optional domain constraint.
|
|
pub domain: Option<String>,
|
|
/// Optional path constraint.
|
|
pub path: Option<String>,
|
|
/// Whether the cookie requires a secure transport.
|
|
pub secure: bool,
|
|
/// Whether the cookie is `HttpOnly`.
|
|
pub http_only: bool,
|
|
/// Optional same-site policy marker.
|
|
pub same_site: Option<String>,
|
|
/// Expiration time as a Unix timestamp when present.
|
|
pub expires_unix_epoch: Option<u64>,
|
|
}
|
|
|
|
/// TLS behavior attached to one HTTP session.
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
pub struct TlsConfig {
|
|
/// Whether peer certificates must be verified.
|
|
pub verify_peer: bool,
|
|
/// Whether host name verification is enabled.
|
|
pub verify_host: bool,
|
|
/// Minimum TLS version when constrained.
|
|
pub min_version: Option<String>,
|
|
/// Maximum TLS version when constrained.
|
|
pub max_version: Option<String>,
|
|
/// Optional CA bundle path.
|
|
pub ca_file: Option<String>,
|
|
/// Optional client certificate path.
|
|
pub cert_file: Option<String>,
|
|
/// Optional client key path.
|
|
pub key_file: Option<String>,
|
|
}
|
|
|
|
/// Ordered collection of request headers.
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
pub struct HttpRequestHeaders {
|
|
/// Stored request headers.
|
|
pub headers: Vec<HttpHeader>,
|
|
}
|
|
|
|
/// Ordered collection of response headers.
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
pub struct HttpResponseHeaders {
|
|
/// Stored response headers.
|
|
pub headers: Vec<HttpHeader>,
|
|
}
|
|
|
|
/// Request-body representation for HTTP transfers.
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
pub enum HttpBody {
|
|
/// No request body.
|
|
Empty,
|
|
/// UTF-8 text request body.
|
|
Text(String),
|
|
/// Arbitrary binary request body.
|
|
Binary(Vec<u8>),
|
|
/// Streaming body with an optional declared length.
|
|
Stream {
|
|
/// Declared body length when the caller knows it.
|
|
expected_len: Option<u64>,
|
|
},
|
|
}
|
|
|
|
/// Expected and observed checksum metadata for one payload.
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
pub struct ChecksumSpec {
|
|
/// Hash algorithm name.
|
|
pub algorithm: String,
|
|
/// Expected digest hex string.
|
|
pub expected_hex: String,
|
|
/// Observed digest hex string when known.
|
|
pub actual_hex: Option<String>,
|
|
}
|
|
|
|
/// Optional checksum hook attached to a transfer.
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
pub struct ChecksumHookModel {
|
|
/// Checksum specification to evaluate.
|
|
pub spec: ChecksumSpec,
|
|
/// Whether the hook is enabled.
|
|
pub enabled: bool,
|
|
}
|
|
|
|
/// Optional direct-write target for one live HTTP response body.
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
pub struct HttpResponseSinkTarget {
|
|
/// Final output path that should receive the response body directly.
|
|
pub target_path: PathBuf,
|
|
}
|
|
|
|
/// Fully normalized HTTP request model.
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
pub struct HttpRequestModel {
|
|
/// HTTP method.
|
|
pub method: HttpMethod,
|
|
/// Fully-qualified request URL.
|
|
pub url: String,
|
|
/// Requested HTTP version.
|
|
pub version: HttpVersion,
|
|
/// Explicit request headers.
|
|
pub headers: HttpRequestHeaders,
|
|
/// Query parameters to attach to the URL.
|
|
pub query: HashMap<String, String>,
|
|
/// Optional range metadata.
|
|
pub range: Option<RangeSpec>,
|
|
/// Request body.
|
|
pub body: HttpBody,
|
|
/// Retry strategy for the request.
|
|
pub retry: RetryStrategy,
|
|
/// Optional origin credential.
|
|
pub auth: Option<AuthCredential>,
|
|
/// Optional proxy configuration.
|
|
pub proxy: Option<ProxyConfig>,
|
|
/// Optional direct-write sink for live response persistence.
|
|
pub response_sink: Option<HttpResponseSinkTarget>,
|
|
}
|
|
|
|
/// Session-scoped defaults that shape HTTP execution.
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
pub struct HttpSessionModel {
|
|
/// Stable session identifier.
|
|
pub session_id: String,
|
|
/// Optional user-agent string.
|
|
pub user_agent: Option<String>,
|
|
/// Default headers applied to requests.
|
|
pub default_headers: Vec<HttpHeader>,
|
|
/// Cookies carried by the session.
|
|
pub cookies: Vec<Cookie>,
|
|
/// Optional default credential.
|
|
pub auth: Option<AuthCredential>,
|
|
/// Optional default proxy configuration.
|
|
pub proxy: Option<ProxyConfig>,
|
|
/// Optional TLS behavior for the session.
|
|
pub tls: Option<TlsConfig>,
|
|
/// Default retry strategy for the session.
|
|
pub retry: RetryStrategy,
|
|
}
|
|
|
|
/// Response-body representation used by the protocol layer.
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
pub enum ResponseBody {
|
|
/// No response payload.
|
|
Empty,
|
|
/// Inline retained payload bytes.
|
|
Inline(Vec<u8>),
|
|
/// Streamed payload metadata with optional retained artifacts.
|
|
Streamed {
|
|
/// Declared content length when known.
|
|
expected_len: Option<u64>,
|
|
/// Observed byte count written through the sink.
|
|
observed_len: Option<u64>,
|
|
/// Observed digest when computed by the sink.
|
|
observed_digest: Option<String>,
|
|
/// Optional temporary file path holding the streamed body.
|
|
temp_path: Option<PathBuf>,
|
|
},
|
|
}
|
|
|
|
/// Executable HTTP transfer task passed into downloaders.
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
pub struct HttpTransferTaskModel {
|
|
/// Stable task identifier.
|
|
pub task_id: String,
|
|
/// Request model for the task.
|
|
pub request: HttpRequestModel,
|
|
/// Response headers already associated with the task.
|
|
pub response_headers: HttpResponseHeaders,
|
|
/// Current response body state.
|
|
pub body: ResponseBody,
|
|
/// Resume metadata when resuming is in play.
|
|
pub resume_state: Option<ResumeState>,
|
|
/// Retry-attempt history.
|
|
pub retry_attempts: Vec<RetryAttempt>,
|
|
/// Optional checksum hook.
|
|
pub checksum_hook: Option<ChecksumHookModel>,
|
|
/// Maximum allowed concurrent connections.
|
|
pub max_connections: u16,
|
|
/// Retry strategy for the task.
|
|
pub retry: RetryStrategy,
|
|
}
|
|
|
|
/// Normalized HTTP response model produced by connectors and fixtures.
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
pub struct HttpResponseModel {
|
|
/// Numeric HTTP status code.
|
|
pub status: u16,
|
|
/// Human-readable reason phrase.
|
|
pub reason: String,
|
|
/// Negotiated HTTP version.
|
|
pub version: HttpVersion,
|
|
/// Response headers.
|
|
pub headers: HttpResponseHeaders,
|
|
/// Response body representation.
|
|
pub body: ResponseBody,
|
|
/// Parsed `Content-Range` metadata when present.
|
|
pub content_range: Option<ContentRangeSpec>,
|
|
/// Whether the response used partial-content semantics.
|
|
pub partial_content: bool,
|
|
/// Optional checksum metadata.
|
|
pub checksum: Option<ChecksumSpec>,
|
|
/// Original URL before redirects when one occurred.
|
|
pub redirected_from: Option<String>,
|
|
}
|