Core Components¶
This page documents the core class and data models of httptap, rendered directly from the source docstrings so signatures and defaults always match the installed version.
HTTPTapAnalyzer¶
The main analyzer class that orchestrates HTTP request analysis, including redirect following and per-step metric collection.
from httptap import HTTPTapAnalyzer
from httptap.constants import HTTPMethod
analyzer = HTTPTapAnalyzer(follow_redirects=True)
steps = analyzer.analyze_url(
"https://httpbin.io",
headers={"Accept": "application/json"},
)
HTTPTapAnalyzer ¶
HTTPTapAnalyzer(
*,
follow_redirects: bool = False,
timeout: float = DEFAULT_TIMEOUT_SECONDS,
http2: bool = True,
verify_ssl: bool = True,
ca_bundle_path: str | None = None,
max_redirects: int = 10,
request_executor: RequestExecutor | None = None,
proxy: ProxyTypes | None = None,
noproxy: bool = False,
dns_resolver: DNSResolver | None = None,
tls_inspector: TLSInspector | None = None,
timing_collector_factory: type[TimingCollector]
| None = None,
)
Orchestrates HTTP request analysis with redirect following.
This class manages the high-level flow of analyzing HTTP requests, including following redirect chains and collecting metrics at each step.
Attributes:
-
follow_redirects–Whether to follow HTTP redirects.
-
timeout–Request timeout in seconds.
-
http2–Whether to enable HTTP/2 support.
-
max_redirects–Maximum number of redirects to follow.
Parameters:
-
follow_redirects(bool, default:False) –Whether to follow 3xx redirects.
-
timeout(float, default:DEFAULT_TIMEOUT_SECONDS) –Request timeout in seconds.
-
http2(bool, default:True) –Enable HTTP/2 support.
-
verify_ssl(bool, default:True) –Whether to verify TLS certificates.
-
ca_bundle_path(str | None, default:None) –Path to custom CA certificate bundle (PEM format). Only used when verify_ssl is True. If None, uses system CA bundle.
-
max_redirects(int, default:10) –Maximum number of redirects to follow.
-
request_executor(RequestExecutor | None, default:None) –Object responsible for performing HTTP requests. Must implement the RequestExecutor protocol. Defaults to the built-in httpx implementation.
-
proxy(ProxyTypes | None, default:None) –Optional proxy URL (http/https/socks5/socks5h) applied to all requests in the analysis chain.
-
noproxy(bool, default:False) –When True, ignore proxy environment variables and connect directly. Triggered by --proxy "".
-
dns_resolver(DNSResolver | None, default:None) –Custom DNS resolver implementation. If None, make_request will use its default (SystemDNSResolver).
-
tls_inspector(TLSInspector | None, default:None) –Custom TLS inspector implementation. If None, make_request will use its default (SocketTLSInspector).
-
timing_collector_factory(type[TimingCollector] | None, default:None) –Factory class for creating timing collectors. If None, make_request will use its default (PerfCounterTimingCollector). Note: This should be a class, not an instance, as a new collector is created for each request.
Methods:
-
analyze_url–Analyze URL with optional redirect following.
Source code in httptap/analyzer.py
analyze_url ¶
analyze_url(
url: str,
*,
method: HTTPMethod = GET,
content: bytes | None = None,
headers: Mapping[str, str] | None = None,
) -> list[StepMetrics]
Analyze URL with optional redirect following.
Performs HTTP request(s) and collects comprehensive metrics. If follow_redirects is enabled and server returns 3xx with Location, continues following redirects up to max_redirects.
Parameters:
-
url(str) –Initial URL to analyze. Must be valid HTTP/HTTPS URL.
-
method(HTTPMethod, default:GET) –HTTP method to use (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS).
-
content(bytes | None, default:None) –Optional request body as bytes.
-
headers(Mapping[str, str] | None, default:None) –Optional mapping of request headers applied to every step.
Returns:
-
list[StepMetrics]–List of StepMetrics, one per request in the chain. Each step contains
-
list[StepMetrics]–timing, network, and response information. Returns at least one step
-
list[StepMetrics]–even if request fails.
Examples:
Basic usage without redirects: >>> analyzer = HTTPTapAnalyzer() >>> steps = analyzer.analyze_url("https://example.com") >>> print(f"Total time: {steps[0].timing.total_ms}ms") Total time: 234.5ms
Following redirect chain: >>> analyzer = HTTPTapAnalyzer(follow_redirects=True) >>> steps = analyzer.analyze_url("http://example.com") >>> for i, step in enumerate(steps, 1): ... print(f"Step {i}: {step.response.status}") Step 1: 301 Step 2: 200
Source code in httptap/analyzer.py
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | |
Data models¶
All models are @dataclass(slots=True) and expose to_dict() for JSON export.
StepMetrics dataclass ¶
StepMetrics(
url: str = "",
step_number: int = 1,
timing: TimingMetrics = TimingMetrics(),
network: NetworkInfo = NetworkInfo(),
response: ResponseInfo = ResponseInfo(),
error: str | None = None,
note: str | None = None,
proxied_via: str | None = None,
request_method: str | None = None,
request_headers: dict[str, str] = dict(),
request_body_bytes: int = 0,
)
Complete metrics for a single HTTP request step.
Represents all collected data for one request in the chain, including timing, network, response information, and any errors.
Attributes:
-
url(str) –The URL that was requested.
-
step_number(int) –Step number in redirect chain (1-indexed).
-
timing(TimingMetrics) –Timing metrics.
-
network(NetworkInfo) –Network and security information.
-
response(ResponseInfo) –HTTP response information.
-
error(str | None) –Error message if request failed.
-
note(str | None) –Additional notes or context.
-
proxied_via(str | None) –Proxy URL used for this request, if any.
-
request_method(str | None) –HTTP method used (GET, POST, PUT, etc.).
-
request_headers(dict[str, str]) –Request headers (sanitized).
-
request_body_bytes(int) –Size of request body in bytes.
Methods:
-
to_dict–Convert step metrics to dictionary for JSON export.
has_error property ¶
Check if this step encountered an error.
Returns:
-
bool–True if error occurred, False otherwise.
is_redirect property ¶
Check if this step is a redirect response.
Returns:
-
bool–True if status is 3xx and Location header present.
to_dict ¶
Convert step metrics to dictionary for JSON export.
Returns:
-
dict[str, Any]–Dictionary containing all step information organized by category.
Source code in httptap/models.py
TimingMetrics dataclass ¶
TimingMetrics(
dns_ms: float = 0.0,
connect_ms: float = 0.0,
tls_ms: float = 0.0,
ttfb_ms: float = 0.0,
total_ms: float = 0.0,
wait_ms: float = 0.0,
xfer_ms: float = 0.0,
is_estimated: bool = False,
)
Timing metrics for HTTP request phases.
All timing values are in milliseconds.
Attributes:
-
dns_ms(float) –DNS resolution time.
-
connect_ms(float) –TCP connection establishment time.
-
tls_ms(float) –TLS handshake time (0 for HTTP).
-
ttfb_ms(float) –Time to first byte (headers received).
-
total_ms(float) –Total request time from start to finish.
-
wait_ms(float) –Server processing time (derived metric).
-
xfer_ms(float) –Response body transfer time (derived metric).
-
is_estimated(bool) –Whether connect/TLS timing was estimated vs measured.
Methods:
-
calculate_derived–Calculate derived timing metrics.
-
to_dict–Convert timing metrics to dictionary.
calculate_derived ¶
Calculate derived timing metrics.
This method computes timing values that are derived from the raw measurements. It should be called after all raw timing values (dns_ms, connect_ms, tls_ms, ttfb_ms, total_ms) are populated.
Computes
wait_ms: Time server spent processing the request before sending the first byte of the response. Calculated as: max(0, ttfb_ms - (dns_ms + connect_ms + tls_ms))
xfer_ms: Time spent transferring the response body after headers were received. Calculated as: max(0, total_ms - ttfb_ms)
Note
Both values are clamped to 0 to handle edge cases where timing measurements may have slight inconsistencies due to measurement precision or system clock adjustments.
Examples:
>>> timing = TimingMetrics(
... dns_ms=10.0,
... connect_ms=20.0,
... tls_ms=50.0,
... ttfb_ms=100.0,
... total_ms=150.0
... )
>>> timing.calculate_derived()
>>> print(f"Wait: {timing.wait_ms}ms, Transfer: {timing.xfer_ms}ms")
Wait: 20.0ms, Transfer: 50.0ms
Source code in httptap/models.py
to_dict ¶
Convert timing metrics to dictionary.
Returns:
-
dict[str, float | bool]–Dictionary with all timing metrics.
Source code in httptap/models.py
NetworkInfo dataclass ¶
NetworkInfo(
ip: str | None = None,
ip_family: str | None = None,
http_version: str | None = None,
tls_version: str | None = None,
tls_cipher: str | None = None,
cert_cn: str | None = None,
cert_days_left: int | None = None,
cert_sans: list[str] = list(),
cert_issuer: str | None = None,
cert_serial: str | None = None,
cert_not_before: datetime | None = None,
cert_not_after: datetime | None = None,
tls_verified: bool | None = None,
tls_custom_ca: bool | None = None,
proxy_url: str | None = None,
proxy_source: str | None = None,
)
Network and security information for a connection.
Attributes:
-
ip(str | None) –Resolved IP address.
-
ip_family(str | None) –Address family label (e.g., 'IPv4' or 'IPv6').
-
http_version(str | None) –HTTP protocol version negotiated (e.g., 'HTTP/2.0').
-
tls_version(str | None) –TLS protocol version (e.g., 'TLSv1.3').
-
tls_cipher(str | None) –TLS cipher suite used.
-
cert_cn(str | None) –Certificate Common Name.
-
cert_days_left(int | None) –Days until certificate expiration.
-
cert_sans(list[str]) –Subject Alternative Names (DNS entries) from the leaf certificate.
-
cert_issuer(str | None) –Issuer Common Name of the leaf certificate.
-
cert_serial(str | None) –Certificate serial number (hex string).
-
cert_not_before(datetime | None) –Start of the certificate validity window.
-
cert_not_after(datetime | None) –End of the certificate validity window.
-
tls_verified(bool | None) –Whether TLS certificate verification was enforced.
-
tls_custom_ca(bool | None) –True when a custom CA bundle was configured.
-
proxy_url(str | None) –Effective proxy URL used for this request, or None.
-
proxy_source(str | None) –Origin of the proxy setting (see PROXY_SOURCE_* constants). None when no proxy is configured.
Methods:
-
to_dict–Convert network info to dictionary.
to_dict ¶
Convert network info to dictionary.
Returns:
-
dict[str, Any]–Dictionary with all network information.
Source code in httptap/models.py
ResponseInfo dataclass ¶
ResponseInfo(
status: int | None = None,
bytes: int = 0,
content_type: str | None = None,
server: str | None = None,
date: datetime | None = None,
location: str | None = None,
headers: dict[str, str] = dict(),
)
HTTP response information.
Attributes:
-
status(int | None) –HTTP status code.
-
bytes(int) –Response body size in bytes.
-
content_type(str | None) –Content-Type header value.
-
server(str | None) –Server header value.
-
date(datetime | None) –Date header parsed as datetime.
-
location(str | None) –Location header for redirects.
-
headers(dict[str, str]) –Sanitized response headers (secrets masked).
Methods:
-
to_dict–Convert response info to dictionary.
to_dict ¶
Convert response info to dictionary.
Returns:
-
dict[str, Any]–Dictionary with all response information.
Source code in httptap/models.py
Utility functions¶
validate_url ¶
Validate URL format.
Requires an http/https scheme and a non-empty host. A scheme alone is not enough: https:///path and https://?query parse to an empty host and would fail at connection time with an opaque error, so they are rejected here where the message can be actionable.
Parameters:
-
url(str) –URL string to validate.
Returns:
-
bool–True if URL is valid HTTP/HTTPS URL, False otherwise.
Examples:
>>> validate_url("https://example.com")
True
>>> validate_url("ftp://example.com")
False
>>> validate_url("https://")
False
>>> validate_url("https:///path")
False
Source code in httptap/utils.py
sanitize_headers ¶
Sanitize HTTP headers by masking sensitive values.
Parameters:
-
headers(Mapping[str, str]) –Dictionary of HTTP headers.
Returns:
-
dict[str, str]–New dictionary with sensitive values masked.
Examples:
Source code in httptap/utils.py
parse_http_date ¶
Parse HTTP date header to datetime.
Supports RFC 7231 HTTP-date format.
Parameters:
-
date_str(str) –Date string from HTTP Date header.
Returns:
-
datetime | None–Parsed datetime in UTC or None if parsing fails.
Examples:
>>> parse_http_date("Mon, 22 Oct 2025 12:00:00 GMT")
datetime.datetime(2025, 10, 22, 12, 0, tzinfo=UTC)
Source code in httptap/utils.py
create_ssl_context ¶
Return an SSL context honoring the requested verification policy.
Parameters:
-
verify_ssl(bool) –Whether to enforce certificate validation and modern security defaults.
-
ca_bundle_path(str | None, default:None) –Path to custom CA certificate bundle file (PEM format). Only used when verify_ssl is True. If None, uses system CA bundle.
Returns:
-
SSLContext–Configured
ssl.SSLContextinstance.
Source code in httptap/utils.py
Constants¶
Selected values from httptap.constants (see the module source for the full set):
Timeouts and limits¶
from httptap.constants import (
DEFAULT_TIMEOUT_SECONDS, # 20.0 seconds
TLS_PROBE_MAX_TIMEOUT_SECONDS, # 5.0 seconds
HTTP_DEFAULT_PORT, # 80
HTTPS_DEFAULT_PORT, # 443
)
Exit codes¶
from httptap.constants import (
EXIT_CODE_OK, # 0 - Success (os.EX_OK)
EXIT_CODE_USAGE, # 64 - Invalid arguments (os.EX_USAGE)
EXIT_CODE_SOFTWARE, # 70 - Internal error (os.EX_SOFTWARE)
EXIT_CODE_TEMPFAIL, # 75 - Network/TLS error (os.EX_TEMPFAIL)
)
Example: complete usage¶
from httptap import HTTPTapAnalyzer
analyzer = HTTPTapAnalyzer(follow_redirects=True, timeout=30.0, http2=True)
steps = analyzer.analyze_url(
"https://httpbin.io/bearer",
headers={
"Authorization": "Bearer token123",
"Accept": "application/json",
"User-Agent": "MyApp/1.0",
},
)
for step in steps:
print(f"Step {step.step_number}: {step.url}")
print(f" Status: {step.response.status}")
print(f" DNS: {step.timing.dns_ms:.2f}ms")
print(f" Connect: {step.timing.connect_ms:.2f}ms")
print(f" TLS: {step.timing.tls_ms:.2f}ms")
print(f" TTFB: {step.timing.ttfb_ms:.2f}ms")
print(f" Total: {step.timing.total_ms:.2f}ms")
if step.network.ip:
print(f" IP: {step.network.ip} ({step.network.ip_family})")
if step.network.cert_cn:
print(f" Certificate: {step.network.cert_cn} (expires in {step.network.cert_days_left} days)")
What's Next?¶
-
Implement custom DNS, TLS, timing, and more
-
Patterns for monitoring, testing, batch analysis
-
Extend httptap and contribute back