Chapter 1: How the Internet Works
Understanding the internet's fundamental protocols is essential for system design. This chapter covers the full stack from physical layer to application protocols, with real-world performance numbers, architectural trade-offs, and interview-ready explanations.
1.1 The OSI Model & TCP/IP Model
Why Layered Architecture?
The internet uses a layered architecture where each layer provides services to the layer above and consumes services from the layer below. This design principle enables:
- Separation of concerns: Physical transmission details are hidden from application developers
- Interoperability: Different implementations can work together as long as they follow layer contracts
- Evolution: Layers can be upgraded independently (e.g., IPv4 β IPv6 without changing HTTP)
- Fault isolation: Problems at one layer don't cascade to all layers
Alternative considered and rejected: A monolithic design where each application handles its own physical transmission, error correction, routing, etc. This would require every app to reinvent the wheel and make protocol evolution impossible.
The Two Models
The OSI (Open Systems Interconnection) model is a theoretical 7-layer reference model. The TCP/IP model is the practical 4-layer implementation the internet actually uses.
(HTTP, FTP, SMTP)"] A6["6. Presentation
(TLS, encoding)"] A5["5. Session
(connections)"] A4["4. Transport
(TCP, UDP)"] A3["3. Network
(IP, routing)"] A2["2. Data Link
(Ethernet, WiFi)"] A1["1. Physical
(cables, signals)"] end subgraph "TCP/IP Model (4 Layers)" B4["4. Application
(HTTP, DNS, SSH)"] B3["3. Transport
(TCP, UDP)"] B2["2. Internet
(IP, ICMP)"] B1["1. Link
(Ethernet, WiFi)"] end A7 --> B4 A6 --> B4 A5 --> B4 A4 --> B3 A3 --> B2 A2 --> B1 A1 --> B1
| OSI Layer | TCP/IP Layer | Function | Examples | Real-World Impact |
|---|---|---|---|---|
| 7. Application | Application | End-user protocols and data representation | HTTP, DNS, SMTP, FTP, SSH | What you code against |
| 6. Presentation | Data encoding, encryption, compression | TLS/SSL, JPEG, MPEG, ASCII | TLS negotiation adds ~1 RTT | |
| 5. Session | Connection management, sessions | NetBIOS, RPC, session cookies | Often merged into application | |
| 4. Transport | Transport | End-to-end reliability, flow control | TCP, UDP, SCTP | TCP handshake = 1 RTT (~50-200ms) |
| 3. Network | Internet | Routing, addressing, packet forwarding | IPv4, IPv6, ICMP, routing protocols | Routing adds ~10-50ms per hop |
| 2. Data Link | Link | Node-to-node data transfer, MAC addressing | Ethernet, WiFi (802.11), PPP | WiFi latency ~2-5ms, Ethernet ~0.1ms |
| 1. Physical | Raw bit transmission over physical medium | Cables, fiber, radio waves, voltage levels | Speed of light in fiber: ~200km/ms |
What Happens at Each Layer
When you send an HTTP request, data flows down the stack on the sender side and up the stack on the receiver side:
Encapsulation: Each layer adds its own header (and sometimes trailer) to the data from the layer above. This is like putting a letter in an envelope, then putting that envelope in a package, then putting that package on a truck. Each layer only reads its own header.
When asked "What happens when you type google.com?" candidates who start with "DNS lookup" miss the point. Strong answers mention the full stack: Application (HTTP), Transport (TCP handshake), Network (IP routing), Link (ARP, MAC addresses), and Physical (signals on wire). Bonus points for mentioning encapsulation and which headers are added at each layer.
1.2 DNS (Domain Name System)
What is DNS?
DNS is the internet's phone book. It translates human-readable domain names (google.com) into IP addresses (142.250.185.46). Without DNS, you'd need to memorize IP addresses for every website.
Typical DNS lookup time: 20-120ms (cached: <1ms, uncached: 50-200ms)
DNS Hierarchy
DNS is a distributed hierarchical system with three levels:
(13 worldwide, . root)"] TLD_com[".com TLD Server"] TLD_org[".org TLD Server"] TLD_net[".net TLD Server"] Auth_google["google.com
Authoritative Server"] Auth_example["example.org
Authoritative Server"] Root --> TLD_com Root --> TLD_org Root --> TLD_net TLD_com --> Auth_google TLD_org --> Auth_example style Root fill:#ff6b6b,color:#1a1a2e style TLD_com fill:#4ecdc4,color:#1a1a2e style TLD_org fill:#4ecdc4,color:#1a1a2e style TLD_net fill:#4ecdc4,color:#1a1a2e style Auth_google fill:#95e1d3,color:#1a1a2e style Auth_example fill:#95e1d3,color:#1a1a2e
- Root servers: 13 root server clusters (a.root-servers.net to m.root-servers.net) that know where TLD servers are
- TLD (Top-Level Domain) servers: Manage .com, .org, .net, etc. Operated by registries like Verisign
- Authoritative name servers: The final authority for a domain, usually managed by hosting providers or domain owners
Recursive vs Iterative Resolution
When you type "www.google.com", your computer doesn't query all these servers. Your ISP's DNS resolver does the work:
Recursive query: Client asks resolver to do all the work and return final answer
Iterative query: Resolver asks each server "Who should I ask next?" and follows the chain
DNS Record Types
| Record Type | Purpose | Example | Use Case |
|---|---|---|---|
A |
Maps domain to IPv4 address | example.com β 93.184.216.34 | Most common, points to web server |
AAAA |
Maps domain to IPv6 address | example.com β 2606:2800:220:1:: | IPv6 support |
CNAME |
Alias to another domain | www.example.com β example.com | Subdomains, CDN routing |
MX |
Mail server for domain | example.com β mail.example.com (priority 10) | Email routing |
NS |
Authoritative name server | example.com β ns1.hostingprovider.com | DNS delegation |
TXT |
Arbitrary text data | "v=spf1 include:_spf.google.com ~all" | SPF, DKIM, domain verification |
SRV |
Service location | _sip._tcp.example.com β sipserver:5060 | Service discovery (SIP, XMPP) |
PTR |
Reverse DNS (IP β domain) | 34.216.184.93.in-addr.arpa β example.com | Email validation, logging |
CAA |
Certificate authority authorization | example.com β letsencrypt.org | Restrict which CAs can issue certs |
DNS Caching & TTL
DNS responses include a TTL (Time To Live) value that tells resolvers how long to cache the result:
- Low TTL (60-300s): Fast updates, more DNS queries, higher load
- High TTL (3600-86400s): Fewer queries, slower updates, better performance
Caching happens at multiple levels: browser cache β OS cache β ISP resolver cache β authoritative server
Advanced DNS Techniques
DNS Load Balancing
Return multiple A records with different IPs, rotated on each query (round-robin DNS):
example.com. 300 IN A 93.184.216.34
example.com. 300 IN A 93.184.216.35
example.com. 300 IN A 93.184.216.36
Limitation: Doesn't account for server health or load. Use dedicated load balancers for production.
GeoDNS
Return different IPs based on client location. Example: US clients get us-east-1 server, EU clients get eu-west-1 server. Reduces latency by ~50-200ms.
DNS Failover
Health check primary server; if down, return secondary IP. TTL must be low (60-300s) for fast failover.
DNS-over-HTTPS (DoH) & DNS-over-TLS (DoT)
Encrypt DNS queries to prevent ISP snooping and man-in-the-middle attacks. DoH uses HTTPS (port 443), DoT uses TLS (port 853). Supported by Chrome, Firefox, Cloudflare (1.1.1.1), Google (8.8.8.8).
What Happens When You Type "google.com"?
(root β TLD β auth) DNS-->>User: 142.250.185.46 (fresh) end end Note over User,TCP: TCP 3-way handshake User->>Server: SYN Server-->>User: SYN-ACK User->>Server: ACK Note over User,Server: TLS handshake (1-2 RTT) User->>Server: ClientHello Server-->>User: ServerHello, Certificate User->>Server: Key Exchange, Finished Note over User,Server: HTTP request User->>Server: GET / HTTP/1.1 Server-->>User: 200 OK (HTML) Note over User: Browser renders page
DNS is on the critical path: The first time a user visits your site, DNS lookup adds 20-120ms. Use low TTLs for flexibility (but more queries) or high TTLs for performance (but slower updates). CDNs like Cloudflare offer 1.1.1.1 resolver with <10ms lookups globally.
Strong candidates know DNS caching is multi-level (browser, OS, ISP) and can explain why TTL matters for blue-green deployments. Bonus points for mentioning DNS prefetching (<link rel="dns-prefetch">) to hide DNS latency.
1.3 TCP (Transmission Control Protocol)
What is TCP?
TCP is a reliable, ordered, connection-oriented transport protocol. It guarantees that data arrives in the correct order without errors, retransmitting lost packets as needed. Used by HTTP, HTTPS, SSH, email protocols.
TCP handshake cost: 1 RTT (~50-200ms for intercontinental connections, ~1-20ms within region)
TCP 3-Way Handshake (Connection Establishment)
Before sending data, TCP establishes a connection using a 3-way handshake:
Data transfer can begin
- SYN: Client sends synchronization packet with initial sequence number (ISN)
- SYN-ACK: Server acknowledges client's ISN and sends its own ISN
- ACK: Client acknowledges server's ISN. Connection established.
Why 3 steps instead of 2? To prevent old duplicate SYNs from establishing unwanted connections. Both sides must agree on initial sequence numbers.
TCP 4-Way Connection Termination
Closing a TCP connection requires 4 messages (can be optimized to 3):
(Server can still send data) Server->>Client: FIN (seq=6000) Note over Server: State: LAST-ACK Note over Client: State: TIME-WAIT Client-->>Server: ACK (ack=6001) Note over Server: State: CLOSED Note over Client: Wait 2*MSL (60-240s)
then CLOSED
Why TIME-WAIT? Client waits 2*MSL (Maximum Segment Lifetime, typically 30-120s) to ensure the final ACK isn't lost. If server doesn't receive it, server retransmits FIN, and client can re-send ACK.
TCP Sliding Window (Flow Control)
TCP uses a sliding window to send multiple packets without waiting for individual ACKs. The window size is advertised by the receiver based on its buffer space.
bytes 1-1000] B[Sent, awaiting ACK
bytes 1001-1500] C[Ready to send
bytes 1501-2000] D[Not yet sendable
bytes 2001+] end style A fill:#95e1d3,color:#1a1a2e style B fill:#ffd93d,color:#1a1a2e style C fill:#6bcf7f,color:#1a1a2e style D fill:#ddd,color:#1a1a2e Note1["Window = 1000 bytes
(bytes 1001-2000)"] Note1 -.-> B Note1 -.-> C
As ACKs arrive, the window slides forward, allowing more data to be sent. This improves throughput by keeping the pipe full.
TCP Congestion Control
TCP adjusts its sending rate based on network congestion. Key algorithms:
Congestion Window (cwnd) States
-
Slow Start: Begin with small cwnd (typically 10 segments = 14KB). Double cwnd every RTT until reaching ssthresh (slow start threshold) or packet loss occurs.
- RTT 1: 10 segments
- RTT 2: 20 segments
- RTT 3: 40 segments (exponential growth)
- Congestion Avoidance: After ssthresh, increase cwnd by 1 segment per RTT (linear growth). Continue until packet loss.
- Fast Retransmit: If 3 duplicate ACKs received, immediately retransmit the lost packet without waiting for timeout. This indicates packet loss, not network death.
- Fast Recovery: After fast retransmit, set ssthresh = cwnd / 2, set cwnd = ssthresh, and enter congestion avoidance. This avoids slow start's performance hit.
Real numbers: For a 100ms RTT connection with 10 Mbps bandwidth, slow start takes ~4 RTTs (400ms) to ramp up. This is why TCP is slow for short-lived connections.
Nagle's Algorithm
Nagle's algorithm reduces small packet overhead by buffering small writes until either:
- Enough data accumulated to fill a full segment (MSS, typically 1460 bytes)
- All previously sent data has been acknowledged
Problem: Adds latency (up to 1 RTT) for interactive applications like SSH or gaming.
Solution: Disable Nagle with TCP_NODELAY socket option. HTTP/2 and gRPC do this by default.
Head-of-Line Blocking
TCP delivers data in order. If packet 5 is lost, packets 6, 7, 8 must wait for packet 5 to be retransmitted, even if they arrived successfully. This is head-of-line blocking.
until 3 arrives Sender->>Network: Packet 3 (retransmitted) Network->>Receiver: Packet 3 Note over Receiver: Now deliver 3, 4, 5
in order
Impact: On lossy networks (1% loss), TCP throughput can drop by 50%. HTTP/2 multiplexing over a single TCP connection amplifies this problem. HTTP/3 solves it by using QUIC over UDP with per-stream ordering.
TCP guarantees reliability but adds latency: 3-way handshake (1 RTT), slow start (3-5 RTTs to full speed), head-of-line blocking (1 RTT per loss). For low-latency applications, consider UDP + custom reliability (QUIC) or HTTP/3.
Candidates who mention "TCP is reliable" without explaining the cost (handshake, congestion control, HOL blocking) miss nuance. Strong answers quantify latency (1 RTT handshake, 200ms for US-Europe) and explain when TCP's guarantees aren't worth the cost (real-time video, gaming).
1.4 UDP (User Datagram Protocol) & QUIC
What is UDP?
UDP is a connectionless, unreliable transport protocol. It sends packets (datagrams) without handshakes, acknowledgments, or retransmissions. Minimal overhead, but no guarantees.
Latency: No connection setup. First packet can be sent immediately (0 RTT).
TCP vs UDP Comparison
| Feature | TCP | UDP |
|---|---|---|
| Connection | Connection-oriented (3-way handshake) | Connectionless (no handshake) |
| Reliability | Guaranteed delivery, retransmission | Best effort, no guarantees |
| Ordering | In-order delivery guaranteed | Packets may arrive out of order |
| Error Checking | Checksum + retransmission | Checksum only (optional) |
| Flow Control | Sliding window | None |
| Congestion Control | Yes (slow start, AIMD) | None (app must handle) |
| Overhead | 20+ bytes header + state tracking | 8 bytes header, stateless |
| Speed | Slower (handshake, retransmissions) | Faster (no handshake, no retransmit) |
| Use Cases | HTTP, HTTPS, email, file transfer | DNS, video streaming, gaming, VoIP |
When to Use UDP
UDP is ideal when:
- Low latency matters more than reliability: Gaming (lost frame is OK, stale frame is not), live video streaming
- Small request-response: DNS (single packet query + response, faster than TCP handshake)
- Real-time communication: VoIP (Zoom, Skype), video conferencing (dropped packet = brief glitch, not worth delaying)
- Broadcast/multicast: IPTV, service discovery
- Custom reliability: When you want to build your own congestion control (QUIC, game engines)
QUIC: UDP's Evolution
QUIC (Quick UDP Internet Connections) is a modern transport protocol built on UDP. It combines UDP's low latency with TCP-like reliability, plus built-in encryption (TLS 1.3).
QUIC Advantages over TCP
-
0-RTT Connection Establishment: First request sent immediately (vs TCP's 1-RTT handshake + 1-RTT TLS = 2 RTT total)
sequenceDiagram participant Client participant Server Note over Client,Server: QUIC 0-RTT (Resumed Connection) Client->>Server: QUIC Initial + TLS ClientHello + HTTP Request Server-->>Client: QUIC Handshake + TLS ServerHello + HTTP Response Note over Client,Server: Total: 1 RTT (data sent on first packet!) Note over Client,Server: vs TCP + TLS 1.3 Client->>Server: TCP SYN Server-->>Client: TCP SYN-ACK Client->>Server: TCP ACK + TLS ClientHello Server-->>Client: TLS ServerHello Client->>Server: HTTP Request Server-->>Client: HTTP Response Note over Client,Server: Total: 2-3 RTT
- No Head-of-Line Blocking: QUIC supports multiple independent streams over a single connection. Lost packet in stream 1 doesn't block stream 2.
- Connection Migration: Connection identified by ID (not 4-tuple of IP:port). Switch from WiFi to cellular without reconnecting.
- Improved Congestion Control: Congestion control in userspace (not kernel), easier to update algorithms.
- Built-in Encryption: All QUIC packets are encrypted (TLS 1.3 mandatory). No plaintext metadata.
QUIC Adoption
- HTTP/3 uses QUIC (replacing TCP)
- Google (YouTube, Search, Gmail), Facebook, Cloudflare use QUIC
- ~25% of internet traffic uses QUIC (2024 estimate)
- Supported by Chrome, Firefox, Edge, Safari (partial)
UDP sacrifices reliability for speed. TCP's 3-way handshake + TLS = 2 RTT (100-400ms for intercontinental) before sending data. UDP + QUIC = 0-1 RTT. For real-time apps, this matters more than perfect delivery.
Weak answers: "UDP is faster because it's unreliable." Strong answers: "UDP avoids TCP's 1-RTT handshake and head-of-line blocking. QUIC layers reliability on UDP while keeping 0-RTT connection setup and per-stream ordering. This is why YouTube uses QUICβlost packet in one video chunk doesn't block the next chunk."
1.5 IP (Internet Protocol): IPv4 & IPv6
What is IP?
IP is the network layer protocol responsible for addressing and routing packets across networks. It's connectionless and best-effort (no guarantees). TCP/UDP sit on top of IP.
IPv4 vs IPv6
| Feature | IPv4 | IPv6 |
|---|---|---|
| Address Size | 32 bits (4 bytes) | 128 bits (16 bytes) |
| Format | Dotted decimal: 192.168.1.1 | Hex colon: 2001:0db8::1 |
| Address Space | 4.3 billion (~4.3Γ10βΉ) | 340 undecillion (~3.4Γ10Β³βΈ) |
| Header Size | 20-60 bytes (variable) | 40 bytes (fixed) |
| Fragmentation | Routers can fragment packets | Only sender fragments (Path MTU Discovery) |
| Checksum | Header checksum required | No checksum (relies on upper layers) |
| NAT | Required (address exhaustion) | Not needed (enough addresses) |
| Configuration | DHCP or manual | SLAAC (auto-config) or DHCPv6 |
| Broadcast | Supported | Replaced by multicast |
| Adoption | ~97% of internet traffic (2024) | ~40% and growing |
IPv4 Address Classes (Historical)
Originally, IPv4 addresses were divided into classes:
- Class A: 1.0.0.0 - 126.255.255.255 (8-bit network, 24-bit host = 16M hosts per network)
- Class B: 128.0.0.0 - 191.255.255.255 (16-bit network, 16-bit host = 65K hosts)
- Class C: 192.0.0.0 - 223.255.255.255 (24-bit network, 8-bit host = 254 hosts)
Obsolete: Replaced by CIDR (Classless Inter-Domain Routing) in 1993. Now use /prefix notation: 10.0.0.0/8 means first 8 bits are network, last 24 bits are host.
Subnetting Basics
CIDR notation: 192.168.1.0/24 means first 24 bits are network, last 8 bits are host.
- /24 = 256 addresses (254 usable, 2 reserved: network address + broadcast)
- /16 = 65,536 addresses
- /8 = 16,777,216 addresses
Example: Split 10.0.0.0/16 into 4 subnets:
- 10.0.0.0/18 (10.0.0.0 - 10.0.63.255)
- 10.0.64.0/18 (10.0.64.0 - 10.0.127.255)
- 10.0.128.0/18 (10.0.128.0 - 10.0.191.255)
- 10.0.192.0/18 (10.0.192.0 - 10.0.255.255)
NAT (Network Address Translation)
NAT allows multiple devices on a private network (e.g., 192.168.1.x) to share a single public IP. The router translates private IPs to its public IP for outgoing traffic.
192.168.1.10:5000"] Phone["Phone
192.168.1.11:5001"] end Router["NAT Router
Private: 192.168.1.1
Public: 203.0.113.5"] Internet["Internet
Server: 93.184.216.34:80"] Laptop -->|SRC: 192.168.1.10:5000
DST: 93.184.216.34:80| Router Phone -->|SRC: 192.168.1.11:5001
DST: 93.184.216.34:80| Router Router -->|SRC: 203.0.113.5:6000
DST: 93.184.216.34:80| Internet Router -->|SRC: 203.0.113.5:6001
DST: 93.184.216.34:80| Internet style Router fill:#ff6b6b,color:#1a1a2e
NAT Translation Table:
| Private IP:Port | Public IP:Port | Destination |
|---|---|---|
| 192.168.1.10:5000 | 203.0.113.5:6000 | 93.184.216.34:80 |
| 192.168.1.11:5001 | 203.0.113.5:6001 | 93.184.216.34:80 |
Problem with NAT: Breaks end-to-end connectivity. Inbound connections can't reach private IPs without port forwarding or NAT traversal (STUN, TURN).
Unicast vs Multicast vs Anycast
duplicated by routers| M_R1[Receiver 1] M_Sender -->|Same packet| M_R2[Receiver 2] M_Sender -->|Same packet| M_R3[Receiver 3] end subgraph "Anycast (1-to-nearest)" A_Sender[Sender] -->|Routed to
nearest instance| A_Server1[Server 1
US-East] A_Sender -.->|Same IP, but
not chosen| A_Server2[Server 2
EU-West] end style U_Receiver fill:#95e1d3,color:#1a1a2e style M_R1 fill:#95e1d3,color:#1a1a2e style M_R2 fill:#95e1d3,color:#1a1a2e style M_R3 fill:#95e1d3,color:#1a1a2e style A_Server1 fill:#95e1d3,color:#1a1a2e style A_Server2 fill:#ddd,color:#1a1a2e
- Unicast: One sender, one receiver. Standard IP addressing (most traffic).
- Multicast: One sender, multiple receivers in a group. Used for IPTV, video conferencing, stock tickers. IPv4: 224.0.0.0/4, IPv6: ff00::/8.
- Anycast: Multiple servers share the same IP. Routers send traffic to the nearest server (by BGP routing). Used by DNS root servers (13 IPs, 1000+ physical servers), CDNs (Cloudflare 1.1.1.1).
Private IP Ranges (RFC 1918)
These ranges are not routable on the public internet:
- 10.0.0.0/8 (10.0.0.0 - 10.255.255.255) β Large enterprises, AWS VPCs
- 172.16.0.0/12 (172.16.0.0 - 172.31.255.255) β Medium networks, Docker default
- 192.168.0.0/16 (192.168.0.0 - 192.168.255.255) β Home routers, small offices
IPv4 exhaustion is real. IANA allocated the last /8 blocks in 2011. NAT is a workaround, not a solution. IPv6 adoption is growing (~40% of Google traffic in 2024), but IPv4 will coexist for decades. Dual-stack (IPv4 + IPv6) is the pragmatic approach.
Strong candidates know why IPv6 is better (no NAT, larger address space, simpler header) but can explain why adoption is slow (legacy systems, NAT works "well enough"). Bonus points for mentioning anycast (Cloudflare 1.1.1.1 uses it) or IPv6-only mobile networks (T-Mobile, Verizon use 464XLAT).
1.6 HTTP/1.1
What is HTTP?
HTTP (Hypertext Transfer Protocol) is the application-layer protocol for the web. It defines how clients (browsers) and servers exchange requests and responses. HTTP/1.1 (RFC 2616, 1999) is the foundation of the modern web.
Request-Response Model
HTTP is a stateless, text-based protocol. Every interaction is a request-response pair:
Request (Client β Server):
GET /api/users/123 HTTP/1.1
Host: api.example.com
User-Agent: Mozilla/5.0
Accept: application/json
Authorization: Bearer eyJhbGc...
Response (Server β Client):
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 87
Cache-Control: max-age=3600
{"id":123,"name":"Alice","email":"alice@example.com"}
HTTP Methods
| Method | Purpose | Safe? | Idempotent? | Cacheable? |
|---|---|---|---|---|
GET |
Retrieve resource | Yes | Yes | Yes |
POST |
Create resource, submit data | No | No | Rarely |
PUT |
Replace resource (full update) | No | Yes | No |
PATCH |
Partial update | No | No* | No |
DELETE |
Delete resource | No | Yes | No |
HEAD |
GET without body (headers only) | Yes | Yes | Yes |
OPTIONS |
Query supported methods (CORS) | Yes | Yes | No |
CONNECT |
Establish tunnel (HTTPS proxy) | No | No | No |
TRACE |
Echo request (debugging) | Yes | Yes | No |
Safe: Does not modify server state (read-only)
Idempotent: Multiple identical requests have same effect as one
*PATCH: Can be idempotent depending on implementation
HTTP Status Codes
| Code | Meaning | Use Case |
|---|---|---|
| 1xx Informational | ||
| 100 | Continue | Client should continue with request body |
| 101 | Switching Protocols | WebSocket upgrade |
| 2xx Success | ||
| 200 | OK | Standard success |
| 201 | Created | Resource created (POST) |
| 202 | Accepted | Async processing started |
| 204 | No Content | Success, no response body (DELETE) |
| 3xx Redirection | ||
| 301 | Moved Permanently | URL changed forever (SEO signals) |
| 302 | Found | Temporary redirect (common misuse of 301) |
| 304 | Not Modified | Cache is still valid (ETag match) |
| 307 | Temporary Redirect | Like 302, but preserves method |
| 308 | Permanent Redirect | Like 301, but preserves method |
| 4xx Client Error | ||
| 400 | Bad Request | Invalid syntax or parameters |
| 401 | Unauthorized | Authentication required |
| 403 | Forbidden | Authenticated but not authorized |
| 404 | Not Found | Resource doesn't exist |
| 409 | Conflict | State conflict (version mismatch) |
| 429 | Too Many Requests | Rate limit exceeded |
| 5xx Server Error | ||
| 500 | Internal Server Error | Generic server failure |
| 502 | Bad Gateway | Upstream server error (proxy/LB) |
| 503 | Service Unavailable | Overloaded or maintenance |
| 504 | Gateway Timeout | Upstream server timeout |
Important HTTP Headers
Request Headers
Host: Target domain (required in HTTP/1.1)User-Agent: Client software (browser, bot)Accept: Content types client can handle (application/json, text/html)Authorization: Credentials (Bearer token, Basic auth)Cookie: Session stateIf-None-Match: ETag for conditional requestsRange: Partial content request (byte-range downloads)
Response Headers
Content-Type: MIME type (application/json, text/html)Content-Length: Body size in bytesCache-Control: Caching policy (max-age=3600, no-cache)ETag: Resource version hash (for conditional requests)Set-Cookie: Set client cookieLocation: Redirect URLServer: Server software (nginx, Apache)
HTTP/1.1 Features
Persistent Connections (Keep-Alive)
HTTP/1.0 opened a new TCP connection for each request. HTTP/1.1 defaults to persistent connections (Connection: keep-alive), reusing the same TCP connection for multiple requests.
Benefit: Avoids TCP handshake overhead (1 RTT saved per request after the first)
Default timeout: 5-15 seconds idle before server closes connection
HTTP Pipelining (Failed Experiment)
Pipelining allows sending multiple requests without waiting for responses (similar to TCP sliding window). Example: Send GET /a, GET /b, GET /c, then receive all responses in order.
Problem: Head-of-line blocking. If /a takes 5 seconds, /b and /c must wait, even if they're ready in 100ms.
Reality: Disabled in all major browsers due to buggy proxies and servers. HTTP/2 multiplexing solved this properly.
Connection Limits per Domain
Browsers limit concurrent connections per domain to prevent overwhelming servers:
- HTTP/1.1: 6 connections per domain (Chrome, Firefox)
- Workaround: Domain sharding (static1.example.com, static2.example.com) to get 6 connections Γ N domains
- HTTP/2: 1 connection per domain, unlimited streams (domain sharding is anti-pattern)
HTTP/1.1 bottlenecks: 6 connections per domain, head-of-line blocking (pipelining failure), text-based headers (overhead). For modern apps loading 100+ resources, HTTP/1.1 adds ~500-1000ms latency. HTTP/2 fixes this with multiplexing and binary framing.
Candidates who say "HTTP is stateless" are correct but surface-level. Strong answers explain the trade-off: stateless design enables horizontal scaling (any server can handle any request) but requires cookies/tokens for session management. Bonus points for mentioning idempotency (PUT/DELETE are idempotent, POST is not) and why it matters for retry logic.
1.7 HTTP/2
What is HTTP/2?
HTTP/2 (RFC 7540, 2015) is a major revision designed to solve HTTP/1.1's performance bottlenecks. It maintains HTTP semantics (methods, status codes, headers) but completely changes the transport layer using a binary framing layer.
Adoption: ~50% of websites support HTTP/2 (2024). All modern browsers support it over TLS.
Binary Framing Layer
HTTP/1.1 is text-based (human-readable but inefficient). HTTP/2 encodes messages into binary frames, making parsing faster and less error-prone.
Host: example.com
Accept: */*
"] end subgraph "HTTP/2 (Binary Frames)" Frame1[HEADERS Frame
Stream 1
:method: GET
:path: /api] Frame2[DATA Frame
Stream 1
Payload bytes] Frame3[HEADERS Frame
Stream 3
:method: POST] end Text -.-> |"Encoded into"| Frame1 Frame1 --> Frame2 Frame2 --> Frame3 style Text fill:#ffd93d,color:#1a1a2e style Frame1 fill:#95e1d3,color:#1a1a2e style Frame2 fill:#95e1d3,color:#1a1a2e style Frame3 fill:#95e1d3,color:#1a1a2e
Frame structure: Each frame has a 9-byte header (length, type, flags, stream ID) followed by a payload.
Multiplexing: Multiple Streams Over One Connection
HTTP/2's killer feature: send multiple request-response pairs concurrently over a single TCP connection without head-of-line blocking at the HTTP layer.
(no head-of-line blocking)
Key concepts:
- Stream: Independent bidirectional message flow (one request-response pair)
- Stream ID: Odd numbers = client-initiated, even numbers = server-initiated (server push)
- Concurrency: 100+ streams can be active simultaneously on one connection
- No more 6-connection limit: Only 1 connection needed per origin
Performance impact: Reduces page load time by 10-30% compared to HTTP/1.1, especially on high-latency connections.
Server Push
Server can proactively send resources to the client before they're requested. Example: Browser requests /index.html, server pushes /style.css and /script.js immediately.
in 1 RTT instead of 2-3
Reality: Server push is tricky. If the client already has the resource cached, push wastes bandwidth. Chrome deprecated support in 2022. HTTP/3 has early hints (103 status) instead.
Header Compression (HPACK)
HTTP headers are repetitive (User-Agent, Cookie, Authorization sent on every request). HTTP/2 uses HPACK compression to reduce overhead.
How HPACK works:
- Static table: Common headers pre-defined (61 entries like :method GET = index 2)
- Dynamic table: Recently used headers stored in a shared table (LRU cache)
- Huffman encoding: Compress header values
Example:
Request 1 (full headers):
:method: GET
:path: /api/users
user-agent: Mozilla/5.0
cookie: session=abc123...
Request 2 (compressed):
:path: /api/orders (only path changes, rest references dynamic table)
Dynamic table index: 4, 5, 6 (method, user-agent, cookie)
Compression ratio: 80-95% reduction in header size. Critical for mobile networks where RTT is high (100-300ms).
Stream Prioritization
Clients can assign priorities to streams (dependencies + weights). Example: HTML (high priority) β CSS (medium) β images (low).
HTML
Weight: 256] -->|Depends on| Root[Root Stream] CSS[Stream 3
CSS
Weight: 220] -->|Depends on| HTML JS[Stream 5
JS
Weight: 220] -->|Depends on| HTML Img1[Stream 7
Image
Weight: 16] -->|Depends on| HTML Img2[Stream 9
Image
Weight: 16] -->|Depends on| HTML style HTML fill:#ff6b6b,color:#1a1a2e style CSS fill:#4ecdc4,color:#1a1a2e style JS fill:#4ecdc4,color:#1a1a2e style Img1 fill:#95e1d3,color:#1a1a2e style Img2 fill:#95e1d3,color:#1a1a2e
Reality: Many servers ignore priorities. CDNs (Cloudflare, Fastly) implement it, but origin servers often don't.
Flow Control
Each stream and the connection have flow control windows (similar to TCP). Receiver advertises how much data it can accept (WINDOW_UPDATE frames).
Purpose: Prevent fast sender from overwhelming slow receiver. Important for proxies handling many connections.
HTTP/1.1 vs HTTP/2 Comparison
| Feature | HTTP/1.1 | HTTP/2 |
|---|---|---|
| Encoding | Text-based | Binary frames |
| Multiplexing | No (6 connections per domain) | Yes (1 connection, unlimited streams) |
| Header Compression | None | HPACK (80-95% reduction) |
| Server Push | No | Yes (PUSH_PROMISE) |
| Prioritization | No | Yes (stream dependencies + weights) |
| Connections per Domain | 6 (browser limit) | 1 |
| Head-of-Line Blocking | HTTP layer (pipelining) | Only TCP layer |
| TLS Requirement | Optional | De facto required (browsers only support over TLS) |
| Page Load Time | Baseline | 10-30% faster |
Why HTTP/2 Was Needed
HTTP/1.1 problems that HTTP/2 solves:
- Head-of-line blocking: HTTP/1.1 pipelining failed. HTTP/2 multiplexing succeeds.
- Connection overhead: Opening 6 TCP connections per domain = 6 handshakes (6 RTT). HTTP/2 uses 1 connection.
- Header overhead: Repetitive headers on every request. HPACK reduces bandwidth by 80-95%.
- Resource loading: Modern pages load 100+ resources. HTTP/1.1 serializes them (even with 6 connections). HTTP/2 parallelizes on 1 connection.
Real numbers: Page with 100 resources, 50ms RTT:
- HTTP/1.1: ~17 rounds (100 resources Γ· 6 connections) Γ 50ms = ~850ms
- HTTP/2: ~1 round (all multiplexed) Γ 50ms = ~50ms (17x faster)
HTTP/2 eliminates HTTP-layer head-of-line blocking via multiplexing, but TCP-layer HOL blocking remains. If a TCP packet is lost, all streams on that connection stall. HTTP/3 solves this by moving to QUIC (UDP-based).
Strong candidates explain that HTTP/2 multiplexing only solves HTTP-layer HOL blocking, not TCP-layer. On lossy networks (1% packet loss), HTTP/2 can be slower than HTTP/1.1 with 6 connections because 1 lost packet blocks all streams. This is why HTTP/3 was created despite HTTP/2 being recent.
1.8 HTTP/3 & QUIC
What is HTTP/3?
HTTP/3 (RFC 9114, 2022) is the latest version of HTTP, built on QUIC instead of TCP. It solves HTTP/2's remaining problem: TCP head-of-line blocking.
Adoption: ~30% of websites (Google, Facebook, Cloudflare, Shopify). Supported by Chrome, Firefox, Edge, Safari.
Why HTTP/3? The TCP Problem
HTTP/2 multiplexes streams over a single TCP connection. If one TCP packet is lost, the entire connection stalls (all streams) until the packet is retransmitted. This is TCP head-of-line blocking.
until Stream 1 packet 2 arrives
(TCP guarantees in-order delivery) Browser->>Network: Retransmit Stream 1 packet 2 Network->>Server: Stream 1 packet 2 Note over Server: Now all streams unblocked
Impact: On networks with 1% packet loss, HTTP/2 throughput drops 20-50% compared to HTTP/1.1 with multiple connections.
QUIC Architecture
QUIC (Quick UDP Internet Connections) is a transport protocol built on UDP. It reimplements TCP's reliability, congestion control, and flow control in userspace, while adding stream multiplexing and built-in encryption.
includes TLS 1.3] H3_UDP[UDP] H3_IP[IP] end H2_App --> H2_TLS H2_TLS --> H2_TCP H2_TCP --> H2_IP H3_App --> H3_QUIC H3_QUIC --> H3_UDP H3_UDP --> H3_IP style H2_TCP fill:#ff6b6b,color:#1a1a2e style H3_QUIC fill:#4ecdc4,color:#1a1a2e style H3_UDP fill:#95e1d3,color:#1a1a2e
Key insight: QUIC moves reliability and encryption from kernel (TCP + TLS) to userspace (QUIC library). This enables faster iteration and per-stream ordering.
0-RTT Connection Establishment
HTTP/2 over TCP + TLS 1.3 requires 2 RTT minimum (1 for TCP, 1 for TLS). QUIC supports 0-RTT resumption for previously seen servers.
(using cached session ticket) Server-->>Client: Encrypted HTTP Response Note over Client,Server: Data sent immediately!
No round trips before request rect rgb(255, 200, 200) Note over Client,Server: Compare: TCP + TLS 1.3 (2-RTT minimum) Client->>Server: TCP SYN Server-->>Client: TCP SYN-ACK Client->>Server: TCP ACK + TLS ClientHello Server-->>Client: TLS ServerHello Client->>Server: HTTP Request Server-->>Client: HTTP Response end
Latency savings:
- US-Europe (100ms RTT): 200ms saved per request
- Mobile (200ms RTT): 400ms saved per request
Security note: 0-RTT data is not forward-secure and vulnerable to replay attacks. Only safe for idempotent requests (GET, not POST).
Independent Stream Multiplexing (No HOL Blocking)
QUIC provides per-stream ordering, not global ordering. Lost packet in stream 1 only blocks stream 1, not streams 2, 3, 4.
Only Stream 1 waits for retransmission Server-->>Client: Stream 2 response Server-->>Client: Stream 3 response Client->>Network: Retransmit Stream 1 packet 2 Network->>Server: Stream 1 packet 2 Server-->>Client: Stream 1 response
Performance impact: On 1% lossy network, HTTP/3 is 30-50% faster than HTTP/2.
Connection Migration
TCP connections are identified by 4-tuple (source IP, source port, dest IP, dest port). Changing networks (WiFi β cellular) breaks the connection.
QUIC connections are identified by a Connection ID (independent of IP/port). Connection survives network changes.
Switch to cellular Phone->>Cellular: QUIC packet (conn_id=abc123, src=10.20.30.40) Cellular->>Server: QUIC packet Note over Server: Same conn_id!
Connection continues seamlessly Server-->>Cellular: Response Cellular-->>Phone: Response Note over Phone,Server: No reconnection, no handshake
Download continues without interruption
Use case: Mobile apps downloading large files. User walks out of WiFi range, switches to cellular. Download continues without restarting.
HTTP/2 vs HTTP/3 Comparison
| Feature | HTTP/2 | HTTP/3 |
|---|---|---|
| Transport Protocol | TCP | QUIC (over UDP) |
| Connection Setup | 2-3 RTT (TCP + TLS) | 1 RTT (first connection), 0 RTT (resumed) |
| Head-of-Line Blocking | TCP layer (all streams blocked) | None (per-stream ordering) |
| Connection Migration | No (IP:port change = new connection) | Yes (connection ID survives network change) |
| Encryption | TLS 1.2 or 1.3 (separate layer) | TLS 1.3 integrated (all packets encrypted) |
| Congestion Control | TCP kernel (slow to update) | QUIC userspace (fast iteration) |
| Packet Loss (1%) | 20-50% throughput drop | Minimal impact |
| Adoption | ~50% of sites | ~30% of sites (growing) |
Why HTTP/3 Exists Despite HTTP/2 Being Recent
HTTP/2 was standardized in 2015. Why replace it 7 years later?
- TCP HOL blocking is unfixable: TCP is a kernel protocol with in-order delivery baked in. Can't change without breaking the internet.
- Mobile networks are lossy: 1-2% packet loss is common on cellular. HTTP/2 performance degrades badly on lossy networks.
- TLS handshake is slow: 1-2 RTT adds 50-400ms on every connection. 0-RTT is a game-changer for mobile.
- Connection migration needed: Users switch networks constantly (WiFi β cellular). TCP can't handle it.
- Innovation velocity: TCP is in the kernel, updated every ~5 years. QUIC is userspace, updated every ~6 months.
Google's motivation: YouTube and Search make millions of requests/second. Saving 1 RTT per request = billions of RTT saved = faster load times = more engagement.
HTTP/3 trades TCP's ubiquity for QUIC's performance. On clean networks, HTTP/2 and HTTP/3 are similar. On lossy networks (mobile, congested WiFi), HTTP/3 is 30-50% faster. The 0-RTT handshake alone saves 100-400ms on mobile.
Candidates who mention "HTTP/3 uses UDP" without explaining why are surface-level. Strong answers: "HTTP/3 uses QUIC over UDP to eliminate TCP head-of-line blocking. Lost packet in stream 1 doesn't block stream 2. This matters on mobile networks with 1-2% loss. Also, 0-RTT connection resumption saves 100-400ms per request on mobile."
1.9 TLS/SSL (Transport Layer Security)
What is TLS?
TLS (Transport Layer Security) encrypts data between client and server, providing confidentiality, integrity, and authentication. It sits between the application layer (HTTP) and transport layer (TCP).
SSL (Secure Sockets Layer) is the deprecated predecessor. SSL 3.0 was replaced by TLS 1.0 in 1999. Today "SSL" colloquially refers to TLS.
TLS Versions
- TLS 1.0 (1999): Deprecated (insecure)
- TLS 1.1 (2006): Deprecated (insecure)
- TLS 1.2 (2008): Widely used (74% of connections in 2024), secure if configured properly
- TLS 1.3 (2018): Modern standard (26% of connections, growing), faster and more secure
TLS 1.2 Handshake (2-RTT)
TLS 1.2 requires 2 round trips to establish a secure connection (after TCP handshake):
(supported cipher suites, random nonce) Server-->>Client: ServerHello
(chosen cipher, random nonce)
+ Certificate
(server's public key + CA signature)
+ ServerHelloDone end rect rgb(230, 255, 230) Note over Client,Server: RTT 2 Client->>Server: ClientKeyExchange
(pre-master secret, encrypted with server's public key)
+ ChangeCipherSpec
+ Finished Note over Client: Derive session keys
from pre-master + nonces Note over Server: Decrypt pre-master secret
Derive same session keys Server-->>Client: ChangeCipherSpec + Finished end Note over Client,Server: Secure channel established
Total: 3 RTT (TCP + TLS) Client->>Server: HTTP Request (encrypted) Server-->>Client: HTTP Response (encrypted)
Key steps:
- ClientHello: Client announces supported TLS versions, cipher suites, compression methods
- ServerHello: Server picks TLS version and cipher suite, sends certificate
- Certificate validation: Client verifies server's certificate against trusted CAs
- Key exchange: Client generates pre-master secret, encrypts with server's public key
- Session keys: Both derive symmetric encryption keys from pre-master + random nonces
- Finished: Both send encrypted "Finished" messages to confirm handshake
Total latency: 3 RTT (1 TCP + 2 TLS) = 150-600ms for intercontinental connections
TLS 1.3 Handshake (1-RTT)
TLS 1.3 reduces handshake to 1 RTT by combining key exchange with ClientHello:
+ KeyShare (DH public key)
+ SupportedGroups
+ SignatureAlgorithms Note over Client: Speculatively send
key exchange parameters Server-->>Client: ServerHello
+ KeyShare (DH public key)
+ Certificate
+ CertificateVerify
+ Finished Note over Server: Derive session keys
from DH key exchange end Client->>Server: Finished Note over Client: Derive session keys Note over Client,Server: Secure channel established
Total: 2 RTT (TCP + TLS) Client->>Server: HTTP Request (encrypted) Server-->>Client: HTTP Response (encrypted)
Key improvements:
- 1-RTT handshake: Client speculatively sends key share in first message
- Fewer cipher suites: Removed weak algorithms (RC4, MD5, SHA-1, RSA key exchange)
- Forward secrecy mandatory: Ephemeral Diffie-Hellman (DHE/ECDHE) required
- Encrypted handshake: More of the handshake is encrypted (hides server certificate from eavesdroppers)
- 0-RTT resumption: For repeated connections, send encrypted data in first packet (like QUIC)
Latency savings: 50-200ms per connection (1 RTT saved)
Certificate Chain Validation
TLS uses a chain of trust from website certificate β intermediate CA β root CA. Client trusts the root CA (pre-installed in OS/browser).
DigiCert Global Root] Intermediate[Intermediate CA
DigiCert SHA2 Secure Server CA] Leaf[Website Certificate
*.example.com] Browser[Browser
Trusts Root CA] Root -->|Signs| Intermediate Intermediate -->|Signs| Leaf Browser -.->|Pre-installed trust| Root Leaf -->|1. Verify signature| Intermediate Intermediate -->|2. Verify signature| Root Root -->|3. Trusted?| Browser style Root fill:#ff6b6b,color:#1a1a2e style Intermediate fill:#4ecdc4,color:#1a1a2e style Leaf fill:#95e1d3,color:#1a1a2e style Browser fill:#ffd93d,color:#1a1a2e
Validation steps:
- Client receives server certificate (leaf) and intermediate CA certificate
- Verify leaf certificate signature using intermediate CA's public key
- Verify intermediate CA certificate signature using root CA's public key
- Check root CA is in trusted store (browser/OS)
- Verify certificate is not expired and domain matches
- Check Certificate Revocation List (CRL) or OCSP (Online Certificate Status Protocol)
Public Key Infrastructure (PKI)
Certificate Authorities (CAs) are trusted organizations that issue certificates. Browsers/OS ship with ~100-200 trusted root CAs.
Major CAs: DigiCert, Let's Encrypt, GlobalSign, Sectigo
Let's Encrypt: Free, automated CA. Issues 300M+ certificates. Uses ACME protocol (Automatic Certificate Management Environment) for domain validation.
Cipher Suites Explained
A cipher suite defines algorithms for key exchange, authentication, encryption, and MAC (Message Authentication Code).
Example (TLS 1.2): TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- ECDHE: Elliptic Curve Diffie-Hellman Ephemeral (key exchange, forward secrecy)
- RSA: RSA signature (authentication)
- AES_128_GCM: AES encryption in Galois/Counter Mode (128-bit key, authenticated encryption)
- SHA256: Hash function for HMAC
Example (TLS 1.3): TLS_AES_256_GCM_SHA384 (simplified, key exchange implicit)
Perfect Forward Secrecy (PFS)
Perfect Forward Secrecy ensures that if the server's private key is compromised, past sessions remain secure. Achieved by using ephemeral keys (generated per session).
How it works (Diffie-Hellman):
- Client and server generate temporary key pairs (discarded after session)
- Exchange public keys
- Both compute shared secret using their private key + other's public key
- Derive session keys from shared secret
- Discard temporary private keys after session ends
Without PFS: Attacker records encrypted traffic, steals server's private key years later, decrypts all past sessions.
With PFS: Server's private key only used for authentication (signing), not encryption. Past sessions remain secure.
Certificate Pinning
Certificate pinning hardcodes expected certificate or public key in the application. Prevents man-in-the-middle attacks using rogue CAs.
Use case: Mobile apps connecting to specific API. Pin the expected certificate fingerprint.
Risk: If certificate expires or rotates, app breaks. Must be updated.
Alternative: HTTP Public Key Pinning (HPKP, deprecated) or Certificate Transparency logs.
Mutual TLS (mTLS)
Standard TLS: client verifies server's certificate. Mutual TLS: server also verifies client's certificate.
Client not authenticated Note over Client,Server: Mutual TLS (mTLS) Client->>Server: ClientHello Server-->>Client: ServerHello + Certificate
+ CertificateRequest Note over Client: Verify server certificate Client->>Server: Certificate + Key exchange Note over Server: Verify client certificate Note over Client,Server: Both authenticated
Use case:
- Service-to-service communication: Microservices authenticate each other (zero-trust architecture)
- API authentication: Client certificate instead of API keys
- Enterprise VPNs: User certificate for authentication
Adoption: Common in service meshes (Istio, Linkerd, Consul Connect).
TLS 1.2 vs TLS 1.3 Comparison
| Feature | TLS 1.2 | TLS 1.3 |
|---|---|---|
| Handshake RTT | 2 RTT | 1 RTT (0-RTT resumption) |
| Cipher Suites | 37 options (many weak) | 5 options (all strong) |
| Forward Secrecy | Optional (DHE/ECDHE) | Mandatory (always ephemeral keys) |
| RSA Key Exchange | Supported | Removed (no PFS) |
| Handshake Encryption | Minimal (most plaintext) | Extensive (certificate encrypted) |
| Weak Algorithms | RC4, 3DES, MD5, SHA-1 allowed | All removed |
| Session Resumption | Session IDs or tickets | PSK (Pre-Shared Key) mode |
| Latency (intercontinental) | 200-400ms | 100-200ms (1 RTT saved) |
TLS 1.3 is faster and more secure. The 1-RTT handshake saves 100-200ms per connection. Removing weak cipher suites eliminates configuration mistakes. Forward secrecy is mandatory, protecting past sessions if server is compromised. Adopt TLS 1.3 unless supporting legacy clients (IE 10, Android 4.x).
Weak answers: "TLS encrypts traffic." Strong answers: "TLS provides confidentiality (encryption), integrity (MAC), and authentication (certificates). TLS 1.3 reduces handshake from 2 RTT to 1 RTT, saving 100-200ms. Perfect forward secrecy (ephemeral keys) ensures past sessions remain secure even if server key is compromised. This is why TLS 1.3 mandates ECDHE."
1.10 WebSockets
What are WebSockets?
WebSockets (RFC 6455, 2011) provide full-duplex, bidirectional communication over a single TCP connection. Unlike HTTP's request-response model, WebSockets allow server and client to send messages independently at any time.
Use cases: Real-time chat, live notifications, multiplayer games, collaborative editing, live dashboards, stock tickers
HTTP Upgrade Handshake
WebSockets start as HTTP, then upgrade to the WebSocket protocol using the Upgrade header:
GET /chat HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZQ==
Sec-WebSocket-Version: 13 end rect rgb(230, 255, 230) Server-->>Browser: HTTP Response
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= end Note over Browser,Server: Protocol switched to WebSocket
Full-duplex communication begins Browser->>Server: WebSocket frame: "Hello" Server-->>Browser: WebSocket frame: "Hi there!" Server->>Browser: WebSocket frame: "New message" Browser->>Server: WebSocket frame: "Got it" Note over Browser,Server: Both sides can send anytime
No request-response pattern
Key headers:
Upgrade: websocket- Request protocol upgradeConnection: Upgrade- Connection should be upgradedSec-WebSocket-Key- Random base64 value (prevents caching proxies from reusing connection)Sec-WebSocket-Accept- SHA-1 hash of key + magic string (proves server understands WebSocket)
Full-Duplex Communication
Unlike HTTP (client initiates, server responds), WebSockets are full-duplex: both sides can send messages independently.
bidirectional messages| WS_Server end style H_Client fill:#ffd93d,color:#1a1a2e style H_Server fill:#ff6b6b,color:#1a1a2e style WS_Client fill:#95e1d3,color:#1a1a2e style WS_Server fill:#4ecdc4,color:#1a1a2e
Benefit: Server can push data without client polling. Eliminates latency of request-response cycle.
WebSocket Frame Format
After the upgrade, all data is sent as frames (binary protocol, not text like HTTP):
WebSocket Frame Structure:
βββββββββββ¬ββββββββββ¬ββββββββββ¬ββββββββββββββ¬ββββββββββββββ¬βββββββββββββββ
β FIN β RSV1-3 β Opcode β Mask β Payload β Payload β
β (1 bit)β (3 bits)β (4 bits)β (1 bit) β Length β Data β
βββββββββββ΄ββββββββββ΄ββββββββββ΄ββββββββββββββ΄ββββββββββββββ΄βββββββββββββββ
Opcode values:
0x0 - Continuation frame (multi-frame message)
0x1 - Text frame (UTF-8)
0x2 - Binary frame
0x8 - Close connection
0x9 - Ping (heartbeat)
0xA - Pong (heartbeat response)
Masking:
- Client β Server: Always masked (XOR with random key)
- Server β Client: Never masked
- Prevents proxy cache poisoning attacks
Why masking? Prevents malicious JS from crafting frames that look like HTTP requests to trick caching proxies.
When to Use WebSockets
Use WebSockets when:
- Real-time bidirectional communication: Chat apps, multiplayer games, collaborative editing (Google Docs)
- High-frequency updates: Live sports scores, stock tickers, monitoring dashboards
- Low latency critical: Gaming (10-50ms updates), financial trading, remote desktop
- Server-initiated messages: Notifications, alerts, live updates
When not to use WebSockets:
- Simple request-response: Standard HTTP is simpler and better supported
- Infrequent updates: Polling or SSE is sufficient (don't maintain persistent connection)
- Large file uploads: HTTP handles resumption better
- RESTful APIs: HTTP is the standard (cacheable, stateless)
WebSocket vs Alternatives
| Feature | WebSocket | SSE | Long Polling | HTTP/2 Streams |
|---|---|---|---|---|
| Direction | Bidirectional | Server β Client only | Client β Server (polling) | Bidirectional |
| Protocol | WebSocket (upgraded HTTP) | HTTP (text/event-stream) | HTTP | HTTP/2 |
| Connection | Persistent (1 TCP) | Persistent (1 TCP) | Short-lived (many TCP) | Persistent (1 TCP) |
| Overhead | Low (2-byte frames) | Medium (HTTP headers per message) | High (full HTTP per poll) | Low (binary frames) |
| Browser Support | Universal (IE 10+) | Universal (IE/Edge via polyfill) | Universal | Universal (IE 11+) |
| Firewall/Proxy | Can be blocked | Works everywhere (HTTP) | Works everywhere | Works everywhere |
| Reconnection | Manual | Automatic (EventSource) | Manual | Manual |
| Latency | 1-10ms | 1-10ms | 100-1000ms+ (poll interval) | 1-10ms |
| Use Case | Chat, gaming, collaborative | Notifications, feeds, logs | Legacy browser support | Modern apps (gRPC) |
WebSockets are for real-time bidirectional communication. Use when server needs to push updates frequently (>1/sec) or client and server exchange messages back and forth (chat, gaming). For server-to-client only (notifications, stock tickers), SSE is simpler. For rare updates (<1/min), polling is fine.
Weak answers: "WebSockets are for real-time." Strong answers: "WebSockets provide full-duplex communication over a single persistent TCP connection. They start with HTTP upgrade (101 Switching Protocols) then use binary framing. Best for bidirectional real-time (chat, gaming). For server-to-client only, SSE is simpler. Downsides: stateful (harder to scale), can be blocked by proxies, no HTTP caching."
1.11 Server-Sent Events (SSE)
What is SSE?
Server-Sent Events (SSE) is a standard for one-way streaming from server to client over HTTP. The server holds the connection open and sends events as they occur.
Use cases: Live notifications, news feeds, stock tickers, server logs, progress updates, social media feeds
How SSE Works
SSE uses standard HTTP with Content-Type: text/event-stream. Server keeps connection open and sends events in text format:
Accept: text/event-stream Server-->>Browser: HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive Note over Server,Browser: Connection held open Server->>Browser: data: First event
Note over Browser: Fires 'message' event Server->>Browser: event: user-joined
data: {"name":"Alice"}
id: 1
Note over Browser: Fires 'user-joined' event Server->>Browser: data: Another event
id: 2
Note over Browser: Connection drops
(network issue) Browser->>Server: GET /events HTTP/1.1
Last-Event-ID: 2 Note over Server: Resume from event 2 Server-->>Browser: data: Resumed event
id: 3
Event Format
Events are text-based, newline-delimited:
Simple event:
data: This is a simple message
Multi-line event:
data: First line
data: Second line
data: Third line
Named event with ID:
event: userJoined
data: {"userId": 123, "name": "Alice"}
id: 1
Comment (ignored by client):
: This is a comment
Retry interval (milliseconds):
retry: 10000
Fields:
data- Event payload (text or JSON)event- Event type (default: "message")id- Event ID for reconnectionretry- Reconnection delay in milliseconds
EventSource API (Browser)
JavaScript code:
// Create connection
const eventSource = new EventSource('/events');
// Listen for messages (default event type)
eventSource.onmessage = (event) => {
console.log('New message:', event.data);
};
// Listen for custom event types
eventSource.addEventListener('userJoined', (event) => {
const user = JSON.parse(event.data);
console.log('User joined:', user.name);
});
// Handle errors
eventSource.onerror = (error) => {
console.error('SSE error:', error);
// EventSource auto-reconnects
};
// Close connection
eventSource.close();
Automatic Reconnection with Last-Event-ID
If the connection drops, EventSource automatically reconnects and sends the Last-Event-ID header. Server can resume from that point.
id: 1
Server-->>Browser: data: Event 2
id: 2
Server-->>Browser: data: Event 3
id: 3
Note over Browser,Server: Connection lost (timeout, network issue) Note over Browser: Wait retry interval (default: 3s) Browser->>Server: GET /events
Last-Event-ID: 3 Note over Server: Server sees last received event
Can skip already-sent events Server-->>Browser: data: Event 4
id: 4
Server-->>Browser: data: Event 5
id: 5
Note over Browser,Server: Connection resumed seamlessly
Server-side implementation:
// Node.js + Express example
app.get('/events', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
const lastEventId = req.headers['last-event-id'];
// Resume from lastEventId if provided
let eventId = parseInt(lastEventId || '0');
const sendEvent = (data) => {
eventId++;
res.write(`id: ${eventId}\n`);
res.write(`data: ${JSON.stringify(data)}\n\n`);
};
// Send event every 5 seconds
const interval = setInterval(() => {
sendEvent({ message: 'Hello', timestamp: Date.now() });
}, 5000);
// Clean up on disconnect
req.on('close', () => {
clearInterval(interval);
});
});
When to Prefer SSE Over WebSockets
Use SSE when:
- Server-to-client only: Notifications, feeds, logs, monitoring (no need for client-to-server messages)
- Simplicity: SSE is standard HTTP (easier debugging, caching, proxies)
- Automatic reconnection: Built into EventSource (WebSockets require manual reconnection logic)
- HTTP/2 multiplexing: Multiple SSE streams share one connection (no 6-connection limit)
- Progressive enhancement: Falls back gracefully (polyfills for old browsers)
SSE limitations:
- Unidirectional: Server β Client only (client must use separate HTTP requests to send data)
- Text only: Data must be UTF-8 text (JSON, XML, plain text). Binary requires base64 encoding.
- Browser connection limit: 6 SSE connections per domain (HTTP/1.1). Use HTTP/2 for multiplexing.
SSE Sequence Diagram
Connection held open loop Every second Database->>Server: New price data Server->>Browser: data: {"symbol":"AAPL","price":175.23}
id: 123
Browser->>User: Update UI (stock price) end Note over Browser: User switches tab
(browser may throttle) Note over Server,Browser: 5 minutes idle Server->>Browser: : keepalive comment
Note over Server: Prevent timeout/proxy closing connection Note over Browser: Network disconnects Browser->>Server: GET /stock-prices
Last-Event-ID: 123 Server-->>Browser: Resume from event 123
SSE is the simplest way to stream server-to-client. Use for live feeds, notifications, logs. Built-in reconnection with Last-Event-ID eliminates boilerplate. For bidirectional communication (chat, gaming), use WebSockets instead. SSE is just HTTP, so it works through proxies, supports HTTP/2 multiplexing, and is easier to debug.
Strong candidates compare SSE vs WebSockets: "SSE is server-to-client streaming over HTTP (text/event-stream). Simpler than WebSockets (standard HTTP, automatic reconnection with Last-Event-ID). Best for notifications, feeds, logs. Limitations: unidirectional (client must use separate requests to send data) and text-only. For bidirectional real-time, use WebSockets."
1.12 gRPC
What is gRPC?
gRPC (gRPC Remote Procedure Call) is a high-performance, open-source RPC framework developed by Google. It uses HTTP/2 for transport, Protocol Buffers for serialization, and supports 4 types of streaming.
Use cases: Microservices communication, mobile backends, real-time services, IoT, APIs with strict performance requirements
gRPC Architecture
generated code] end subgraph "gRPC Stack" HTTP2[HTTP/2 Transport] Protobuf[Protocol Buffers
Serialization] end subgraph "Server Application" ServerCode[Service Implementation] ServerStub[gRPC Server
generated code] end ClientCode -->|Method call| ClientStub ClientStub -->|Serialize| Protobuf Protobuf -->|Binary frames| HTTP2 HTTP2 -->|Network| HTTP2 HTTP2 -->|Binary frames| Protobuf Protobuf -->|Deserialize| ServerStub ServerStub -->|Invoke| ServerCode style HTTP2 fill:#4ecdc4,color:#1a1a2e style Protobuf fill:#95e1d3,color:#1a1a2e style ClientStub fill:#ffd93d,color:#1a1a2e style ServerStub fill:#ffd93d,color:#1a1a2e
Key components:
- Protocol Buffers (protobuf): Binary serialization format (smaller and faster than JSON)
- HTTP/2: Multiplexing, streaming, header compression
- Code generation: Client stubs and server skeletons generated from .proto files
- Service definitions: Strongly typed contracts (like WSDL for SOAP)
Protocol Buffers (Protobuf)
Protobuf is a language-neutral, platform-neutral binary serialization format. It's 3-10x smaller and 20-100x faster than JSON.
Example .proto file:
syntax = "proto3";
package ecommerce;
service ProductService {
rpc GetProduct (ProductRequest) returns (ProductResponse);
rpc ListProducts (ListProductsRequest) returns (stream ProductResponse);
rpc CreateProduct (stream ProductRequest) returns (ProductSummary);
rpc UpdateProducts (stream ProductRequest) returns (stream ProductResponse);
}
message ProductRequest {
int32 product_id = 1;
}
message ProductResponse {
int32 product_id = 1;
string name = 2;
double price = 3;
repeated string tags = 4;
}
message ListProductsRequest {
int32 page_size = 1;
string page_token = 2;
}
message ProductSummary {
int32 total_created = 1;
}
Code generation:
# Generate Go code
protoc --go_out=. --go-grpc_out=. product.proto
# Generate Python code
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. product.proto
# Generate Java code
protoc --java_out=. --grpc-java_out=. product.proto
Protobuf vs JSON:
| Feature | JSON | Protobuf |
|---|---|---|
| Encoding | Text (UTF-8) | Binary |
| Size | Baseline (100%) | 30-50% smaller |
| Speed | Baseline | 20-100x faster |
| Schema | No schema (runtime validation) | Strict schema (.proto file) |
| Readability | Human-readable | Binary (not readable) |
| Versioning | Manual (breaking changes risky) | Built-in (field numbers, optional) |
| Browser Support | Native | Requires library + gRPC-Web |
Four Streaming Modes
gRPC supports four communication patterns:
1. Unary RPC (Request-Response)
Standard request-response, like REST:
rpc GetProduct (ProductRequest) returns (ProductResponse);
2. Server Streaming
Client sends one request, server sends stream of responses:
rpc ListProducts (ListProductsRequest) returns (stream ProductResponse);
Use case: Large result sets, live updates, log streaming
3. Client Streaming
Client sends stream of requests, server sends one response:
rpc CreateProduct (stream ProductRequest) returns (ProductSummary);
Use case: Batch uploads, telemetry, file uploads
4. Bidirectional Streaming
Both client and server send streams independently:
rpc UpdateProducts (stream ProductRequest) returns (stream ProductResponse);
Use case: Chat applications, real-time collaboration, game servers
gRPC vs REST vs GraphQL
| Feature | REST | gRPC | GraphQL |
|---|---|---|---|
| Protocol | HTTP/1.1, HTTP/2 | HTTP/2 (required) | HTTP/1.1, HTTP/2 |
| Serialization | JSON, XML | Protocol Buffers (binary) | JSON |
| Schema | Optional (OpenAPI/Swagger) | Required (.proto files) | Required (GraphQL schema) |
| Payload Size | Baseline (JSON) | 30-50% smaller | Similar to JSON (or larger) |
| Speed | Baseline | 5-10x faster (binary, HTTP/2) | Similar to REST (or slower) |
| Streaming | Chunked encoding (limited) | 4 modes (unary, server, client, bidirectional) | Subscriptions (WebSocket) |
| Browser Support | Native | Via gRPC-Web (proxy required) | Native |
| Caching | HTTP caching (GET requests) | No (POST-based) | No (POST-based) |
| Code Generation | Optional | Automatic (from .proto) | Optional |
| Human Readability | High (JSON/XML) | Low (binary) | High (JSON) |
| Tooling | curl, Postman, browsers | grpcurl, BloomRPC, specialized | GraphiQL, Playground |
| Best For | Public APIs, CRUD, web apps | Microservices, high-performance, streaming | Flexible queries, mobile apps, aggregation |
When to Use gRPC
Use gRPC when:
- Microservices: Internal service-to-service communication (high throughput, low latency)
- Real-time streaming: Live data feeds, bidirectional communication
- Polyglot systems: Services in different languages (protobuf supports 10+ languages)
- Mobile backends: Bandwidth-constrained, battery-sensitive (smaller payloads)
- Performance critical: Trading systems, gaming, IoT (5-10x faster than JSON)
Don't use gRPC for:
- Public APIs: REST is standard, more accessible (curl, Postman, browsers)
- Browser clients: Requires gRPC-Web + proxy (Envoy). WebSockets simpler for bidirectional.
- Simple CRUD: REST is simpler, more tooling, HTTP caching
- Human debugging: Binary format not readable (use logging, monitoring)
Service Definition Example
Complete example with all 4 streaming modes:
syntax = "proto3";
package chat;
service ChatService {
// Unary: Login
rpc Login (LoginRequest) returns (LoginResponse);
// Server streaming: Receive messages
rpc StreamMessages (StreamRequest) returns (stream Message);
// Client streaming: Send multiple messages
rpc SendMessages (stream Message) returns (SendSummary);
// Bidirectional streaming: Live chat
rpc Chat (stream Message) returns (stream Message);
}
message LoginRequest {
string username = 1;
string password = 2;
}
message LoginResponse {
string token = 1;
string user_id = 2;
}
message StreamRequest {
string user_id = 1;
int64 since_timestamp = 2;
}
message Message {
string message_id = 1;
string user_id = 2;
string content = 3;
int64 timestamp = 4;
}
message SendSummary {
int32 messages_sent = 1;
}
gRPC is for high-performance service-to-service communication. Protocol Buffers are 3-10x smaller and 20-100x faster than JSON. HTTP/2 multiplexing + streaming makes it ideal for microservices. Use for internal APIs, not public (REST is more accessible). For browsers, consider REST or GraphQL unless performance is critical (then use gRPC-Web).
Strong candidates explain the trade-offs: "gRPC uses HTTP/2 + Protobuf for 5-10x faster serialization and smaller payloads (30-50% vs JSON). Best for microservices (internal, high throughput). Four streaming modes: unary (REST-like), server streaming (large results), client streaming (uploads), bidirectional (chat). Downsides: binary format (hard to debug), requires HTTP/2, poor browser support (needs gRPC-Web proxy). Use REST for public APIs."