nautilus_network/http/mod.rs
1// -------------------------------------------------------------------------------------------------
2// Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3// https://nautechsystems.io
4//
5// Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6// You may not use this file except in compliance with the License.
7// You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! Asynchronous HTTP requests with rate limiting, connection reuse, and bounded responses.
17//!
18//! # Architecture
19//!
20//! [`HttpClient`] applies quota policy before delegating requests to [`InnerHttpClient`]. The inner
21//! client owns one reusable Hyper client, preserving its connection pool across requests and clones.
22//!
23//! # Rate limiting and requests
24//!
25//! Requests can await default and per-key quotas from one or more shared
26//! [`RateLimiter`](crate::ratelimiter::RateLimiter) instances. Sharing a limiter across clients
27//! enforces one process-wide budget for scopes such as an IP address or account. The client accepts
28//! default and per-request headers, repeated query values, raw bodies, and client-level and
29//! per-request timeouts.
30//!
31//! # Proxy routing
32//!
33//! By default the client honors ambient proxy configuration: with `use_system_proxy` left at its
34//! default of `true` and no explicit `proxy_url`, requests are routed through the proxy named by
35//! `HTTP_PROXY`, `HTTPS_PROXY`, or `ALL_PROXY` (lowercase variants included), except destinations
36//! matched by `NO_PROXY`.
37//!
38//! This default is a deliberate trust decision on the process environment: an actor who controls
39//! it chooses the proxy that observes all plaintext HTTP traffic and the CONNECT tunnels that
40//! carry HTTPS.
41//!
42//! An optional explicit `proxy_url` applies to both HTTP and HTTPS traffic and always takes
43//! precedence over ambient lookup. Passing `use_system_proxy(false)` disables ambient lookup, so
44//! requests route directly only when `proxy_url` is unset.
45//!
46//! HTTP status errors remain [`HttpResponse`] values for adapter-specific handling. The transport
47//! retries requests canceled before transmission on reused connections, and allows two retries for
48//! remote HTTP/2 `GOAWAY(NO_ERROR)` or `REFUSED_STREAM` errors. Other transport failures and HTTP
49//! status codes do not trigger retries. Adapters can apply [`crate::retry::RetryManager`] when the
50//! operation and venue error are safe to retry.
51//!
52//! # Connection and response policy
53//!
54//! Production clients built through [`HttpClient::builder`] enable `TCP_NODELAY`, pooled idle
55//! connections, and HTTP/2 keepalive while idle.
56//!
57//! HTTP/2 connections use fixed flow-control windows of 16 MiB per stream and 32 MiB per
58//! connection, larger than Hyper's fixed defaults of 2 MiB and 5 MiB. Setting
59//! `NAUTILUS_HTTP2_ADAPTIVE_WINDOW=true` before building a client enables Hyper's adaptive windows
60//! instead, which start at 65,535 bytes and grow toward 16 MiB through PING probes and SETTINGS
61//! updates. Cloudflare-fronted endpoints can reset large response bodies mid-transfer under
62//! adaptive windows. The value `false` keeps fixed windows, and any other value fails the build.
63//!
64//! Buffered requests advertise gzip unless default or per-request headers set `Accept-Encoding`.
65//! Gzip responses are decoded before return; unsupported encodings and corrupt bodies are errors.
66//! The request deadline includes gzip decoding. Responses whose method or status forbids content
67//! preserve their encoding metadata. Decoded responses omit `Content-Encoding` and `Content-Length`,
68//! even when selected through `header_keys`.
69//!
70//! Buffered responses reject wire bodies larger than 100 MiB, including chunked bodies without a
71//! declared length. Decoded bodies have a separate 100 MiB default limit, configurable through
72//! `max_decompressed_bytes`. [`HttpClient::get_stream`] returns raw body chunks without decoding,
73//! adding `Accept-Encoding`, or applying a total size limit. Request URLs in transport errors and
74//! response-stream diagnostics are limited to their origin (scheme, host, and port). Setting `redact_url(true)` on the
75//! builder omits the origin too. This policy controls the URL context added by this client;
76//! diagnostic messages from lower layers are unchanged. The client logs request metadata only, never URLs.
77//!
78//! Hyper owns the lifecycle of individual pooled connections, so this client exposes no socket
79//! state sink or explicit reconnect operation. Callers observe connection failure through each
80//! request result and retain the client to preserve its pool.
81
82pub mod client;
83pub mod error;
84pub mod types;
85
86#[cfg(not(all(feature = "simulation", madsim)))]
87mod connector;
88#[cfg(all(feature = "simulation", madsim))]
89mod simulation;
90#[cfg(not(all(feature = "simulation", madsim)))]
91mod transport;
92
93mod stream;
94
95#[cfg(all(test, not(all(feature = "simulation", madsim))))]
96mod tests;
97
98// Re-exports
99pub use client::{HttpClient, HttpRedirectPolicy, InnerHttpClient};
100pub use error::HttpClientError;
101pub use http::{
102 Method, StatusCode,
103 header::{RETRY_AFTER, USER_AGENT},
104};
105use nautilus_core::consts::NAUTILUS_USER_AGENT;
106pub use stream::HttpResponseStream;
107pub use types::{HttpMethod, HttpResponse, HttpStatus, parse_retry_after};
108pub use url::Url;
109
110/// Returns the standard headers every NautilusTrader HTTP and WebSocket client sends.
111///
112/// Carries the NautilusTrader [`USER_AGENT`] with the compile-time version.
113#[must_use]
114pub fn create_standard_nautilus_headers() -> Vec<(String, String)> {
115 vec![(USER_AGENT.to_string(), NAUTILUS_USER_AGENT.to_string())]
116}