HTTP, TLS and network¶
HTTP versions¶
HTTPS speaks HTTP/2 when the server offers it (ALPN), as browsers and k6 do, and
HTTP/1.1 otherwise; plain HTTP stays HTTP/1.1. httpVersion: '1.1' or '2' (or
--http-version, K9_HTTP_VERSION) forces one; '2' over plain HTTP is h2c with
prior knowledge. Each VU keeps its own connection per host, so on HTTP/2 a VU's
concurrent requests are streams on one connection, each with its own timings
(sending until the body is handed over, waiting until the stream's response
headers). httpVersion: '3' speaks HTTP/3 over QUIC (HTTPS only, UDP on the URL's
port), with the same sharing and per-stream timings; the whole QUIC handshake counts
as http_req_connecting, since it includes TLS. HTTP/3 is experimental (the h3
crate is pre-1.0), and auto doesn't switch to it from Alt-Svc yet. The proto
tag (HTTP/1.1, HTTP/2.0, HTTP/3.0) and Python's res.proto say which was used.
TLS¶
k6's TLS options work in plans and in scripts' options:
options:
tlsAuth: # client certificates (mutual TLS), by domain
- { domains: [api.example.com, '*.internal.example.com'], cert: client.pem, key: client-key.pem }
tlsVersion: { min: tls1.2, max: tls1.3 } # or just tls1.2
tlsCipherSuites: [TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_AES_128_GCM_SHA256]
cert and key are PEM text or files (relative to the plan or script); an entry
without domains applies to every host. The certificate goes with HTTP, WebSocket
and gRPC connections (not HTTP/3 yet). rustls speaks TLS 1.2 and 1.3 only, so
tls1.0/tls1.1 are rejected, as are encrypted keys (password). HTTPS samples
get k6's tls_version tag, and Python responses have res.tls_version and
res.tls_cipher_suite.
Network options¶
So do k6's network options:
options:
hosts: { api.example.com: 10.0.0.5, 'web.example.com:443': '10.0.0.6:8443', '*.test.local': 127.0.0.1 }
dns: { ttl: 5m, select: random, policy: preferIPv4 } # or 'ttl=1m,select=roundRobin'
blockHostnames: ['*.ads.example.com']
blacklistIPs: [10.0.0.0/8]
localIPs: 192.168.1.10-192.168.1.20 # VU n sends from the n-th, wrapping around
noConnectionReuse: false # true: a new connection per request
noVUConnectionReuse: false # true: a VU's connections close between iterations
dns.ttl caps how long lookups are cached (0: not at all, inf: forever);
select picks the address to try first, the others following if it doesn't
answer. Blocked hosts and IPs fail the request before it connects (Python's
res.error_code is blocked). The CLI has --dns, --block-hostnames,
--blacklist-ip, --local-ips, --no-connection-reuse and
--no-vu-connection-reuse, and the environment K9_DNS, K9_BLOCK_HOSTNAMES,
K9_BLACKLIST_IPS, K9_LOCAL_IPS, K9_NO_CONNECTION_REUSE and
K9_NO_VU_CONNECTION_REUSE. localIPs doesn't apply to HTTP/3 yet.
localIPs must be addresses of this machine's interfaces. To try it on
loopback, Linux and Windows answer on all of 127.0.0.0/8; macOS only on
127.0.0.1 until you add others (sudo ifconfig lo0 alias 127.0.0.2 up).