# HTTP Fundamentals

## 1. What HTTP Is

HTTP (HyperText Transfer Protocol) is an application-layer, request-response protocol: a client sends a **request**, a server sends back exactly one **response**. It is built on top of a reliable transport (TCP, or QUIC for HTTP/3 — see the HTTP Versions topic) and is **stateless** — the server does not, by default, remember anything about a previous request when handling the next one. Every piece of context (who you are, what's in your cart) has to be re-sent or reconstructed via mechanisms like cookies (see the Cookies and Sessions topic).

```
Client                              Server
  |------- HTTP Request ----------->|
  |<------ HTTP Response -----------|
```

## 2. Anatomy of a Request

```
GET /users/42?include=orders HTTP/1.1
Host: api.example.com
User-Agent: Mozilla/5.0
Accept: application/json
Authorization: Bearer eyJhbGciOi...

```

| Part | Example | Meaning |
|---|---|---|
| Method | `GET` | the action being requested |
| Request target | `/users/42?include=orders` | path + optional query string |
| Version | `HTTP/1.1` | protocol version in use |
| Headers | `Host: ...`, `Accept: ...` | metadata, one per line |
| Body | (empty for GET) | payload, present for POST/PUT/PATCH |

A blank line separates headers from the body — this is how the parser knows headers have ended, even before reading `Content-Length` bytes of body.

## 3. Anatomy of a Response

```
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 58
Cache-Control: max-age=60

{"id":42,"name":"Ada Lovelace","orders":[101,102]}
```

| Part | Example | Meaning |
|---|---|---|
| Version | `HTTP/1.1` | protocol version the server used |
| Status code | `200` | machine-readable outcome |
| Reason phrase | `OK` | human-readable label (advisory only) |
| Headers | `Content-Type: ...` | metadata about the body |
| Body | the JSON | actual payload |

## 4. HTTP Methods

| Method | Purpose | Safe | Idempotent | Has a body |
|---|---|---|---|---|
| `GET` | retrieve a resource | yes | yes | no (by convention) |
| `HEAD` | like GET, headers only | yes | yes | no |
| `POST` | create a resource / trigger an action | no | no | yes |
| `PUT` | replace a resource entirely | no | yes | yes |
| `PATCH` | partially update a resource | no | no* | yes |
| `DELETE` | remove a resource | no | yes | no (by convention) |
| `OPTIONS` | ask what methods/headers are allowed | yes | yes | no |

**Safe** means the method must not change server state (a GET that increments a view counter is a real-world violation of this, not an exception to it). **Idempotent** means firing the same request N times has the same effect as firing it once — `DELETE /users/42` twice still ends with user 42 gone, so it's idempotent even though it's not safe. `PATCH` is not idempotent in general because a patch like `{"balance": "+10"}` (relative, not absolute) applied twice produces a different result than applied once — though a PATCH expressed as an absolute field replacement can be idempotent in practice.

## 5. Status Code Categories

| Range | Category | Examples |
|---|---|---|
| 1xx | Informational | `100 Continue`, `101 Switching Protocols` |
| 2xx | Success | `200 OK`, `201 Created`, `204 No Content` |
| 3xx | Redirection | `301 Moved Permanently`, `304 Not Modified` |
| 4xx | Client Error | `400 Bad Request`, `401 Unauthorized`, `404 Not Found` |
| 5xx | Server Error | `500 Internal Server Error`, `503 Service Unavailable` |

The **first digit** tells a client (or a proxy that never parses the body) how to broadly react without understanding the specific code — this is deliberate: a generic HTTP client can treat any unrecognized `4xx` as "my request was wrong" and any unrecognized `5xx` as "retry might help" purely from that leading digit.

![Client sends a request across a TCP connection, server sends back a response, connection is reused for the next request](diagrams/01-request-response-cycle.svg)

## 6. URLs, the Request Target

```
https://api.example.com:443/v1/users/42?include=orders#profile
\___/   \_______________/ \_/\_____________/\_____________/\_____/
scheme        host        port     path          query      fragment
```

Only scheme, host, and path (plus query) typically reach the server — the **fragment** (`#profile`) is resolved entirely client-side and is never sent in the actual HTTP request line; a server has no way to see it.

## 7. Statelessness in Practice

Because HTTP itself has no memory, "session" behavior is always built on top of it, never inside it: a cookie is just a header value the client happens to re-send on every subsequent request, and a JWT is just a token the client re-attaches to `Authorization`. The protocol never tracks "this is the third request from the same visitor" — every request is judged solely on the headers/body present in that one request.

## Under the Hood: What Actually Crosses the Wire

### Before any HTTP bytes: the TCP handshake

For HTTP/1.1 and HTTP/2 (both run over TCP), no HTTP data can be sent until a TCP connection exists. That's a real 3-step exchange:

```
Client -> Server   SYN            (client proposes a connection)
Server -> Client   SYN-ACK        (server acknowledges, proposes back)
Client -> Server   ACK            (client acknowledges — connection is now open)
```

Only after this round trip completes does the client write the actual `GET / HTTP/1.1\r\n...` bytes onto the now-open socket. This is one full network round trip spent before a single byte of HTTP exists — the reason HTTPS adds a further TLS handshake round trip on top, and the reason connection reuse (`Connection: keep-alive`, the default in HTTP/1.1) matters: without it, every request pays this handshake cost again.

### HTTP/1.1's request format is literally text, CRLF-terminated

There is no framing layer, no length-prefixed fields — the parser reads the socket byte-by-byte looking for `\r\n` (carriage return + line feed) to end each header line, and a bare `\r\n\r\n` to mark "headers are done, body starts now." This is why a header injection vulnerability is possible if user input containing a raw `\r\n` ever gets concatenated unescaped into a header value — the parser has no other way to know where a line ends, so injected `\r\n` sequences can forge additional headers.

```
GET / HTTP/1.1\r\n
Host: example.com\r\n
\r\n
```

### Connection reuse (keep-alive)

In HTTP/1.0, a new TCP connection (and thus a new handshake) was opened per request by default — expensive. HTTP/1.1 makes persistent connections the default: the same TCP socket serves multiple sequential request/response pairs, avoiding a repeated handshake for every asset a page needs. The client and server both need `Content-Length` (or `Transfer-Encoding: chunked`) on every response specifically so the reader knows exactly where one response ends and the next one can begin on the same socket — without a known length, there'd be no way to tell "response body" apart from "start of the next response."

## Common Pitfalls

1. **Treating GET as always side-effect-free in practice** — it's a convention the spec requires, not something the protocol enforces; a poorly built API can still mutate state on GET, which breaks caching, prefetching, and browser back/forward behavior that all assume GET is safe.
2. **Confusing "idempotent" with "has no effect the second time"** — idempotent means the *end state* is the same, not that the second call does nothing; `DELETE /users/42` called twice still returns some response the second time (often `404`), it just doesn't change server state further.
3. **Assuming the fragment (`#...`) reaches the server** — it never does; it's resolved purely in the browser, which is exactly why it's used for client-side routing state.
4. **Forgetting the response needs `Content-Length` or chunked encoding** — without one of these, an HTTP/1.1 client reading a persistent connection has no reliable way to know where the response body ends.

## Quick Reference

```
Request:  METHOD /path?query HTTP/version\r\n  Headers\r\n  \r\n  [body]
Response: HTTP/version STATUS reason\r\n        Headers\r\n  \r\n  [body]

Safe + idempotent:      GET, HEAD, OPTIONS
Idempotent, not safe:   PUT, DELETE
Neither:                POST, (usually) PATCH

1xx info   2xx success   3xx redirect   4xx client error   5xx server error
```
