|
| 1 | +# HTTP Redirection: Why 308 Matters for APIs |
| 2 | + |
| 3 | +This document explains the technical details behind the HTTP redirection issue we fixed in the `ai-gateway-core` chart. |
| 4 | + |
| 5 | +## 1. The Core Issue: 301 vs. 308 |
| 6 | + |
| 7 | +When a client (like `curl`) makes a request to `http://` and receives a redirect to `https://`, the status code tells the client exactly how to behave. |
| 8 | + |
| 9 | +### HTTP 301 (Moved Permanently) |
| 10 | +* **Legacy Behavior**: Originally, the spec said the method should be preserved. In practice, however, most browsers and clients (including `curl`) **change the method to GET** and drop the request body when following a 301 redirect. |
| 11 | +* **The Symptom**: Your `POST` request became a `GET` request on the second leg, leading to "method not allowed" or missing body errors. |
| 12 | + |
| 13 | +### HTTP 308 (Permanent Redirect) |
| 14 | +* **Modern Behavior**: This code was specifically created to solve the ambiguity of 301. It **requires** the client to preserve the original HTTP method and body. |
| 15 | +* **The Result**: A `POST` remains a `POST`. This is essential for REST APIs. |
| 16 | + |
| 17 | +## 2. The Discovery |
| 18 | +We knew it was a redirection issue when your `curl -v` log showed: |
| 19 | +```text |
| 20 | +* Clear auth, redirects to port from 80 to 443 |
| 21 | +* Switch from POST to GET |
| 22 | +``` |
| 23 | +This "Switch from POST to GET" is the hallmark behavior of a client following a 301 redirect. |
| 24 | + |
| 25 | +## 3. The Implementation (Envoy Gateway) |
| 26 | + |
| 27 | +### The Constraint |
| 28 | +Envoy Gateway (EG) implements the Kubernetes Gateway API. While the spec allows `308`, the **Envoy Gateway controller (as of v1.7.0) only supports `301` and `302`** in its standard `RequestRedirect` filter. |
| 29 | + |
| 30 | +### The Workaround: EnvoyPatchPolicy |
| 31 | +Since we couldn't set `308` in the `HTTPRoute`, we had to go "under the hood" of the Envoy configuration (xDS) using an `EnvoyPatchPolicy`. |
| 32 | + |
| 33 | +1. **Inspection**: We used `kubectl port-forward` and a `config_dump` to see exactly how EG was configuring Envoy. |
| 34 | +2. **Mapping**: We found that the redirect routes were located in specific `virtual_hosts` indices (1 and 2). |
| 35 | +3. **Patching**: We applied a JSON Patch to override the generated Envoy configuration: |
| 36 | + ```yaml |
| 37 | + operation: |
| 38 | + op: add |
| 39 | + path: /virtual_hosts/1/routes/0/redirect/response_code |
| 40 | + value: "PERMANENT_REDIRECT" # This is Envoy's internal name for 308 |
| 41 | + ``` |
| 42 | + |
| 43 | +## 4. The `curl` Security Behavior |
| 44 | + |
| 45 | +Even with a 308, you noticed that the `Authorization` header was initially missing in the second request. |
| 46 | + |
| 47 | +### Why `curl` drops headers |
| 48 | +By default, `curl` is highly protective of your credentials. When it follows a redirect that changes the **origin** (even just a protocol change from `http` to `https`), it strips sensitive headers like `Authorization` to prevent them from being sent to a potentially malicious redirected destination. |
| 49 | + |
| 50 | +### The Fix: `--location-trusted` |
| 51 | +The `--location-trusted` flag tells `curl` that you trust the redirected destination and want it to reuse the original credentials and headers. |
| 52 | + |
| 53 | +## Summary Checklist for API Redirects |
| 54 | +1. **Use 308**: Always use 308 for internal HTTP -> HTTPS redirects in APIs. |
| 55 | +2. **Avoid 80**: Ideally, API clients should talk directly to 443 (HTTPS) to avoid the redirect trip entirely. |
| 56 | +3. **HSTS**: Consider enabling strict-transport-security (HSTS) headers so the client's OS remembers to use HTTPS automatically for future requests. |
0 commit comments