5 min read #networking #HTTP
On this page

HTTP/1.1

The core mechanisms of HTTP/1.1—persistent connections, pipelining (theoretically good but practically poor), chunked encoding, and cache negotiation—have carried web traffic for two decades. Head-of-line blocking and connection limits directly spurred the multiplexing of HTTP/2.

Overview

HTTP/1.1 (1997–2014) defined the foundation of the web: the request-response model, status codes, cache control, and persistent connections. Although HTTP/2 and HTTP/3 have significantly surpassed it in performance, HTTP/1.1 remains the baseline that all HTTP implementations must be compatible with—every HTTP/2 connection begins with an HTTP/1.1 Upgrade. Understanding its message format, chunked transfer, CORS cross-origin, and cache semantics is fundamental to web development.

Message Format

HTTP-message = start-line *(header-field CRLF) CRLF [ message-body ]

Request:
  GET /api/v1/query?q=up HTTP/1.1
  Host: grafana.example.com
  Accept: application/json
  Accept-Encoding: gzip, br

Response:
  HTTP/1.1 200 OK
  Content-Type: application/json
  Content-Length: 42
  Cache-Control: max-age=3600

  {"status":"success"}

Status Code:
  1xx: Informational (100 Continue, 101 Switching Protocols)
  2xx: Success (200 OK, 201 Created, 204 No Content, 206 Partial Content)
  3xx: Redirection (301 Moved Permanently, 302 Found, 304 Not Modified, 307/308 redirect with method preserved)
  4xx: Client Error (400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 429 Too Many Requests)
  5xx: Server Error (500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable, 504 Gateway Timeout)

Persistent Connections

HTTP/1.0: Per request → new TCP connection → 3-way handshake overhead HTTP/1.1: Connection: keep-alive (default) — reuse the same TCP connection to send multiple requests

Pipelining (HTTP/1.1): Send multiple requests without waiting for the previous response. Rarely used in practice (servers must reply in order → HOL blocking, poor proxy compatibility).

Chunked Transfer Encoding

When the size of the response body cannot be known in advance in the headers (dynamically generated, streaming data):

HTTP/1.1 200 OK
Transfer-Encoding: chunked

1a\r\n
abcdefghijklmnopqrstuvwxyz\r\n
0d\r\n
Hello, World\r\n
0\r\n
\r\n

Format: <chunk size in hex>\r\n<chunk data>\r\n
Last chunk: 0\r\n + optional trailer headers + \r\n

CORS

The browser's same-origin policy prevents pages from accessing resources from different origins. CORS allows servers to declare exceptions:

Simple Request (GET with simple headers):
  GET /api/data HTTP/1.1
  Origin: https://chat.example.com           ← browser auto-adds

  HTTP/1.1 200 OK
  Access-Control-Allow-Origin: https://chat.example.com
  Vary: Origin

Preflight (before non-simple requests):
  OPTIONS /api/data HTTP/1.1
  Origin: https://chat.example.com
  Access-Control-Request-Method: POST
  Access-Control-Request-Headers: Content-Type

  HTTP/1.1 204 No Content
  Access-Control-Allow-Origin: https://chat.example.com
  Access-Control-Allow-Methods: GET, POST, PUT
  Access-Control-Allow-Headers: Content-Type
  Access-Control-Max-Age: 86400             ← cache preflight for 24h

Credentials (cookies, HTTP auth):
  Access-Control-Allow-Credentials: true     ← cannot be used with wildcard origin "*"
  Access-Control-Allow-Origin: https://chat.example.com  ← must be a specific value

HTTP Caching

Request:
  Cache-Control: max-age=3600                 ← expect freshness for 3600s
  If-None-Match: "abc123"                     ← conditional request (ETag)
  If-Modified-Since: Tue, 01 Jan 2025 00:00:00 GMT

Response:
  Cache-Control: public, max-age=86400, immutable
    public:        CDN/intermediate proxies can cache
    private:       Only browser can cache (includes Authorization or cookie)
    max-age:       Fresh lifetime (starts from response date)
    immutable:     Resource content never changes (fingerprinted asset) → no revalidation needed
    no-cache:      Can use cache but must revalidate first (If-None-Match)
    no-store:      Do not store any cache (including private caches)
    must-revalidate: Must revalidate after expiration (even if max-stale)
  ETag: "abc123"                               ← resource version (content hash)
  Last-Modified: Tue, 01 Jan 2025 00:00:00 GMT

304 Not Modified:
  Conditional request If-None-Match matches → server returns 304 (empty body) → client continues using cache

References

  • RFC: 7230-7235, 7234
  • MDN: developer.mozilla.org/en-US/docs/Web/HTTP

Keywords: HTTP/1.1, keep-alive, chunked, CORS, preflight, cache-control, ETag, conditional request