Blog
Mert Özen's blog posts on software development, backend, frontend, and DevOps.
What Happens When You Press Enter on a URL: End to End from DNS to Render
When you press Enter, the browser parses the URL, finds the IP with DNS, connects with TCP and TLS 1.3, sends the HTTP request and renders the response; a new connection spends at least three to four RTTs before the first byte. We read every phase line by line against our own Kestrel server with curl -v and curl -w.
IP Addresses, Subnets, Ports and NAT: localhost, 0.0.0.0 and Connectivity in Containers
An IP address finds an interface, a port finds a socket on that machine; a server bound to 127.0.0.1 can only be reached from inside that machine. RFC 1918 private addresses, subnets with CIDR, NAT, ephemeral ports, address already in use, and why a Kestrel bound to localhost in a container returns an Empty reply, with real output.
How TCP Works: 3-Way Handshake, Congestion Control and HttpClient Socket Exhaustion
TCP opens a connection with a 3-way handshake for a reliable byte stream, starts slowly with slow start and waits in TIME_WAIT on close; that's why new HttpClient per request exhausts ports. 500 TIME_WAITs for 500 requests, 6x slower with TLS, IHttpClientFactory, PooledConnectionLifetime and handler defaults, with real output.
How DNS Works: Resolvers, Record Types, TTL and Querying with dig
DNS resolves a name through a chain of stub resolver, recursive resolver, root, TLD and authoritative servers and caches every answer for its TTL. dig +trace, A/AAAA/CNAME/MX/TXT/CAA/HTTPS records, negative caching, DoH, and a blue-green experiment showing why HttpClient's open connections don't see DNS changes.
The TLS 1.3 Handshake: Certificate Chain, SNI, ALPN and Post-Quantum Key Exchange
TLS 1.3 sets up the encrypted channel in one RTT by putting the key_share in the ClientHello; ECDHE gives forward secrecy and X25519MLKEM768 adds post-quantum protection. The handshake with openssl s_client, a ClientHello growing from 285 to 1,525 bytes, certificate chain errors, SNI/ECH/ALPN, 0-RTT and .NET staying on TLS 1.2 on macOS.
Reading HTTP/1.1 Off the Wire: Message Format, Method Semantics and Keep-Alive
HTTP/1.1 is a text protocol: a start line, headers, an empty line and a body framed by Content-Length or chunked. Requests written by hand with nc and openssl s_client, a 400 for a request without Host, what the 3d in chunked means, safe/idempotent methods and a handler that only retries idempotent requests, keep-alive, and Kestrel against request smuggling.
HTTP Caching and Conditional Requests: Cache-Control, ETag and 304
An HTTP cache uses Cache-Control to decide how long a copy stays fresh, and ETag or Last-Modified to cheaply revalidate it with a 304 Not Modified when it expires. no-cache vs no-store, heuristic freshness for static files without Cache-Control, the old index.html after a deploy, and an ETag handler written because HttpClient has no cache of its own.
HTTP/2: Binary Framing, Multiplexing, HPACK and HTTP/2 in Kestrel
HTTP/2 doesn't change semantics; it splits messages into binary frames belonging to streams, interleaves them on one TCP connection and compresses headers with HPACK. Pseudo-headers and h2c with curl, one connection instead of 20 for 20 concurrent requests, Kestrel's 100-stream limit, HttpClient's default 1.1, and 103 Early Hints instead of Server Push.
HTTP/3 and QUIC: Secure Transport over UDP, Alt-Svc and HTTP/3 in .NET
HTTP/3 uses QUIC, which runs over UDP instead of TCP: TLS 1.3 built in, ordering per stream, one RTT less on a new connection. Discovery via Alt-Svc and the DNS HTTPS record, QuicConnection.IsSupported=false on macOS, Kestrel HTTP/3 working with libmsquic in a Linux container, why HTTP/3 isn't faster on loopback, and the full RTT it saves at 50 ms RTT, with real measurements.
Where Does a Slow Request Come From: Diagnosing the Network with curl -w, DevTools Timing and Wireshark
A slow request's time splits into DNS, TCP, TLS, server (TTFB) and download phases, and every phase has a recognizable signature. Five cases with curl -w under a 50 ms RTT via netem (no keep-alive, an IPv6 attempt, TLS 1.2, a slow server, a large response), .NET's System.Net metrics, dotnet-counters and a TLS key log file for Wireshark.