DNS and HTTP: the application layer

At the top of the stack, programs talk in application protocols. Two of them are behind every web page you open.

DNS: names to addresses

People remember example.com; packets need 93.184.216.34. The Domain Name System is a distributed database of names, spread over millions of servers:

  1. Your computer asks a resolver (usually run by your ISP, or a public one like 1.1.1.1).
  2. If the resolver does not know the answer, it asks a root server: "who handles .com?"
  3. The .com TLD server answers: "ask the servers for example.com".
  4. Those authoritative servers give the address.

Every answer has a TTL (time to live), and the resolver caches it that long, so most questions never reach the root at all.

authoritative = {"example.com": ("93.184.216.34", 300), "codebase.dev": ("76.76.21.21", 60)}
cache = {}                          # name -> (address, expires at)

def resolve(name, now):
    if name in cache and cache[name][1] > now:
        return cache[name][0] + " (cached)"
    address, ttl = authoritative[name]       # root -> TLD -> authoritative
    cache[name] = (address, now + ttl)
    return address + " (asked the servers)"

for now, name in [(0, "example.com"), (10, "example.com"), (100, "codebase.dev"), (200, "codebase.dev")]:
    print("t =", now, name, "->", resolve(name, now))
Open in compiler
RecordHoldsExample
Aan IPv4 addressexample.com → 93.184.216.34
AAAAan IPv6 addressexample.com → 2606:2800:220:1::
CNAMEanother name (an alias)www.example.com → example.com
MXthe mail server for a domainexample.com → mail.example.com

DNS mostly uses UDP port 53: one small question, one small answer.

HTTP: what browsers and servers say

HTTP is text (in versions 1.x): a request line, header lines, a blank line, and an optional body. The server answers with a status line, headers, a blank line and the page.

request = "GET /about.html HTTP/1.1\r\nHost: example.com\r\nAccept: text/html\r\nCookie: theme=dark\r\n\r\n"

head, body = request.split("\r\n\r\n", 1)
lines = head.split("\r\n")
method, path, version = lines[0].split(" ")
headers = {}
for line in lines[1:]:
    name, value = line.split(": ", 1)
    headers[name] = value

print("method:", method, " path:", path, " version:", version)
print("headers:", headers)
print("body:", repr(body))
Open in compiler
StatusMeaning
200 OKhere it is
301 / 302it moved: see the Location header
404 Not Foundno such page
500the server had an error

Methods say what to do: GET reads, POST sends data (a form), PUT and DELETE change and remove. HTTP is stateless: each request stands alone, so websites use cookies (a header the browser sends back every time) to remember who you are.

HTTPS is HTTP inside TLS on port 443: the connection is encrypted, and the server proves who it is with a certificate. Today almost every site uses it. HTTP/2 and HTTP/3 keep the same requests and answers but send them in binary, many at once on one connection (HTTP/3 over UDP).

Common mistakes

  • Thinking DNS goes to the root server for every lookup: caching answers most questions near you.
  • Forgetting the blank line between headers and body in a raw HTTP message.
  • Thinking HTTPS hides which site you visit. It hides the pages and data, but the site's name and IP address are still visible to the network.

Quick check

1. Which DNS record gives the IPv4 address of a name?
2. What does an HTTP 404 status mean?
3. Why do websites need cookies?
4. What ends a DNS answer's life in a cache?
My notes

Write down what you want to remember from this lesson. Notes are saved on this device as you type, and appear on your dashboard.