Sikau

Computer networks · Day 10 · about 40 min

HTTP on the wire

Requests and responses are just text: parse them and build them.

It's just text

Under every fetch() is plain text over a TCP connection: a request line, headers, a blank line, then the body. Lines end in \r\n (CRLF). Once you can read and write it yourself, HTTP has no secrets.

Parsing and building

const REASONS = { 200: "OK", 201: "Created", 301: "Moved Permanently", 302: "Found", 400: "Bad Request", 404: "Not Found", 500: "Internal Server Error" };

function parseRequest(raw) {
  const [head, ...rest] = raw.split("\r\n\r\n");
  const [requestLine, ...headerLines] = head.split("\r\n");
  const [method, path, version] = requestLine.split(" ");
  const headers = {};
  for (const line of headerLines) {
    const i = line.indexOf(":");
    headers[line.slice(0, i).trim().toLowerCase()] = line.slice(i + 1).trim();
  }
  return { method, path, version, headers, body: rest.join("\r\n\r\n") };
}

function buildResponse(status, headers, body = "") {
  const all = { ...headers, "Content-Length": String(new TextEncoder().encode(body).length) };
  const lines = Object.entries(all).map(([k, v]) => `${k}: ${v}`);
  return [`HTTP/1.1 ${status} ${REASONS[status] ?? "Unknown"}`, ...lines, "", body].join("\r\n");
}

function parseResponse(raw) {
  const [head, ...rest] = raw.split("\r\n\r\n");
  const [statusLine, ...headerLines] = head.split("\r\n");
  const headers = {};
  for (const line of headerLines) {
    const i = line.indexOf(":");
    headers[line.slice(0, i).trim().toLowerCase()] = line.slice(i + 1).trim();
  }
  return { status: Number(statusLine.split(" ")[1]), headers, body: rest.join("\r\n\r\n") };
}

The rest of this lesson

  • Anatomy of a requestexplain
  • Bytes, not charactersexplain
  • A raw requestfill
  • Content-Lengthpredict
  • Parse and buildwrite code
  • Badge quizquiz
  • What you learnedrecap

Continue this lesson free — run real code in your browser

Continue with Google

See all 12 lessons of Computer networks