Networking & Protocols
HTTP headers, caching, and CORS
The HTTP version determines how bytes travel. The headers determine what happens to them — whether they’re cached, who can read them cross-origin, how long cookies live, and whether the browser enforces HTTPS forever. Getting headers wrong is the most common source of production security bugs.
Methods and idempotency
HTTP defines verbs (methods) for what the client wants: GET (read), POST (create or generic non-idempotent), PUT (idempotent replace), DELETE (idempotent remove), PATCH (partial update), HEAD (metadata-only GET), OPTIONS (capabilities check), CONNECT (tunnel for proxies).
Idempotency (RFC 9110 § 9.2.2): a method is idempotent if running it multiple times produces the same result as running it once. GET, HEAD, PUT, DELETE, and OPTIONS MUST be safe to retry automatically after timeout because the result is the same regardless of repetition. POST and PATCH are not idempotent — auto-retrying them can create duplicate orders, duplicate payments, or duplicate records.
The practical implication: HTTP clients (browsers, load balancers, CDN edge nodes) may retry idempotent methods transparently on network error. POST /orders should never be auto-retried without an Idempotency-Key header or application-level deduplication.
Status codes
Status codes follow RFC 9110:
- 1xx informational:
100 Continue(client can send body),101 Switching Protocols(WebSocket upgrade),103 Early Hints(preload critical resources before 200 arrives). - 2xx success:
200 OK,201 Created(POST that created a resource),204 No Content(DELETE success),206 Partial Content(range request fulfilled). - 3xx redirect:
301 Moved Permanently(cached by browsers forever),302/307 Temporary Redirect(not cached),304 Not Modified(cache validation hit — empty body). - 4xx client error:
400 Bad Request,401 Unauthorized(requires authentication),403 Forbidden(authenticated but not allowed),404 Not Found,409 Conflict,422 Unprocessable Entity(validation error),429 Too Many Requests. - 5xx server error:
500 Internal Server Error,502 Bad Gateway,503 Service Unavailable,504 Gateway Timeout.
Common mistake: returning 200 OK with { "error": "not found" } in the JSON body. This bypasses HTTP’s machinery — CDNs cache the 200, retry logic doesn’t trigger, browser console doesn’t show an error. Use the correct status code.
Caching: Cache-Control and ETags
The browser, CDN edges, and reverse proxies all cache responses. Cache-Control is the directive:
max-age=3600— cache for 3600 seconds; no revalidation needed until stale.no-cache— store the response, but revalidate with the origin before serving (sendsIf-None-Match). Good for data that changes frequently but can be served from cache if still fresh.no-store— do not store at all — not in browser cache, not at CDN. Use for highly sensitive data (banking statements, account pages, auth tokens).private— only the browser may cache this; CDN/proxy must not. Use for user-specific data.public— any cache may store this. CDNs need this (or noCache-Control) to cache at all.stale-while-revalidate=60— serve the stale copy immediately, revalidate in background.
ETags enable conditional requests: the server sends ETag: "v2" with a response. When the browser re-requests the resource, it includes If-None-Match: "v2". If the ETag still matches, the server returns 304 Not Modified with an empty body — saving bandwidth. If-Modified-Since is the date-based equivalent; ETags are preferred because they are more precise.
Order common cache-related headers in their typical lifecycle:
- 1 Response carries ETag and Cache-Control: max-age=3600
- 2 Browser caches the response for 3600 seconds
- 3 After 3600s the cache entry becomes stale
- 4 Next request: browser sends If-None-Match with the stored ETag
- 5 Server returns 304 Not Modified (empty body) if ETag still matches
- 6 Or 200 OK with new body + new ETag if content changed
CORS — Cross-Origin Resource Sharing
Browsers enforce the same-origin policy: a script on a.example.com cannot read responses from b.example.com by default. CORS opts in:
- Server replies with
Access-Control-Allow-Origin: https://a.example.comto permit access from that origin. - Wildcard
*permits any origin but cannot be combined with credentials — the browser refuses to send cookies or Authorization headers to a wildcard origin. - Preflight requests (OPTIONS): for non-simple methods (PUT, DELETE, custom headers), the browser first sends an OPTIONS request to check if the server allows the cross-origin access. On success, the real request proceeds.
Access-Control-Allow-Credentials: trueplus a non-wildcard explicit origin lets cross-origin requests carry cookies and Auth headers.
Misconfigured CORS pitfall: Access-Control-Allow-Origin: * with Access-Control-Allow-Credentials: true is a security hole. The browser prevents this combination — but some proxy configurations or server frameworks allow it via bugs, enabling confused-deputy attacks where a malicious cross-origin page reads authenticated user data.
Cookies: security flags
Cookies persist client state across requests. Server sets via:
Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Strict; Max-Age=3600; Path=/HttpOnly— blocks JavaScript from reading the cookie (document.cookiecannot see it). This is the primary XSS mitigation for session tokens.Secure— only send on HTTPS. A session cookie withoutSecuremay be sent on HTTP fallback connections.SameSite=Strict— never send on cross-site requests (including top-level navigations).SameSite=Lax— send on safe cross-site navigations (following a link) but not on POST cross-site.SameSite=None; Secure— send on all cross-site requests (for legitimate third-party embedded content — requiresSecure).
Modern browsers default to SameSite=Lax if the directive is absent — this breaks many legacy third-party cookie flows. The shift is intentional: browsers are tightening privacy defaults.
Session token security: rotate tokens on privilege escalation (login), use HttpOnly + Secure, and add CSRF protection (SameSite + a separate CSRF token) for state-changing requests.
Security headers
Common response headers that harden the browser’s behaviour:
Strict-Transport-Security(HSTS): tells browsers to always use HTTPS for this domain, formax-ageseconds, and optionallyincludeSubDomains. Browsers remember this and refuse HTTP connections without even contacting the server.Content-Security-Policy(CSP): tells browsers which sources are allowed to load scripts, styles, fonts, frames.script-src 'self'blocks inline scripts and external scripts not from the same origin — a powerful XSS mitigation.X-Content-Type-Options: nosniff— prevents browsers from MIME-sniffing responses away from the declared Content-Type.Referrer-Policy: strict-origin-when-cross-origin— limits how much URL information leaks in theRefererheader on cross-origin requests.
Content negotiation and range requests
Content negotiation: clients tell the server what they prefer via Accept headers. Accept: application/json, text/html;q=0.9 means JSON preferred, HTML acceptable. Accept-Encoding: br, gzip lists supported compressions. The Vary response header tells caches which request headers affect the response — without Vary: Accept-Encoding, a cache may serve a gzip-compressed body to a client that can’t decompress it.
Range requests: Range: bytes=500-999 asks for a byte range; server replies with 206 Partial Content. Used for HTTP-based video streaming (browsers fetch the file in chunks as the user watches) and resume-after-disconnect. Servers must return Accept-Ranges: bytes to advertise support.
Which HTTP method is required to be idempotent per RFC 9110?
What does Cache-Control: no-store mean to a browser and CDN?
Trace a cross-origin API call from a browser application.
- 01When should you set Cache-Control: no-store vs no-cache?
- 02Why is CORS not a security boundary for APIs?
- 03What does SameSite=Lax do and why is it the browser default?
HTTP methods define the intended operation — idempotent methods (GET, HEAD, PUT, DELETE) may be auto-retried; non-idempotent (POST, PATCH) must not be without idempotency keys. Status codes are semantic signals that HTTP infrastructure (CDNs, retry logic, browser UI) relies on — using 200 for errors breaks the machinery. Cache-Control directives (max-age, no-cache, no-store, private) control where and how long responses are stored; ETags enable cheap revalidation via 304 Not Modified. CORS is a browser-enforced same-origin policy opt-in — not a server-side access-control mechanism. Cookies need HttpOnly (blocks XSS), Secure (HTTPS-only), and SameSite=Lax or Strict (CSRF mitigation). HSTS and CSP harden the browser’s security posture at the header level.