docs: document http() and Lua json in scripts

This commit is contained in:
aykhans committed 2026-09-20 23:30:16 +04:00
1 parent 529420ee5a
commit a60287b78b
2 files changed
+252

No files matched your search

+101
View File
@@ -458,6 +458,8 @@ end
> **Note:** Header, parameter, and cookie values can be a single string or a table (array) for multiple values per key (e.g. `{"val1", "val2"}`).
> **Note:** Lua scripts can send their own HTTP requests with `http` and work with JSON through the global `json` table. See [HTTP Requests in Scripts](#http-requests-in-scripts).
**YAML example:**
```yaml
@@ -523,6 +525,8 @@ function transform(req) {
> **Note:** Header, parameter, and cookie values can be a single string or an array for multiple values per key (e.g. `["val1", "val2"]`).
> **Note:** JavaScript scripts can send their own HTTP requests with `http`. See [HTTP Requests in Scripts](#http-requests-in-scripts).
**YAML example:**
```yaml
@@ -554,3 +558,100 @@ js:
```sh
SARIN_JS='function transform(req) { req.headers["X-Custom"] = "my-value"; return req; }'
```
## HTTP Requests in Scripts
Lua and JavaScript scripts can send their own HTTP requests and use the response in the main request, for example to fetch a fresh token or CSRF value from another endpoint.
**Function:**
```
http(url, opts)
```
`url` must be an absolute `http` or `https` URL. `opts` is optional.
**Options:**
| Option | Type | Default | Description |
| -------------- | --------------------------- | ------- | ------------------------------------------------------------------------------------------------------ |
| `method` | string | `GET` | HTTP method, sent as given |
| `headers` | table/object | - | Request headers, same shape as `req.headers` |
| `params` | table/object | - | Query parameters, added to any already in the URL |
| `cookies` | table/object | - | Cookies, sent as a single `Cookie` header |
| `body` | string | `""` | Request body |
| `timeout` | duration string (`"500ms"`) | `30s` | Request timeout (the `timeout` config does not apply), applied to each hop when redirects are followed |
| `insecure` | boolean | `false` | Skip TLS verification (the `insecure` config does not apply) |
| `maxRedirects` | number | `0` | How many redirects to follow, `0` follows none |
Unknown options and values of the wrong type raise an error.
**Response:**
| Field / Method | Description |
| -------------- | ------------------------------------------------------------------ |
| `status` | Status code (number) |
| `headers` | Response headers, each key holding an array of values |
| `body` | Response body (string) |
| `header(name)` | First value of a header, case-insensitive; `nil`/`null` if missing |
| `cookie(name)` | Value of a cookie from `Set-Cookie`; `nil`/`null` if missing |
| `json()` | JavaScript only: parses the body as JSON |
In Lua, call the helpers as `res:header("name")` or `res.header("name")`.
**Behavior:**
- **Runs on every request:** the requests are sent each time `transform` runs, so every main request triggers them. Script globals persist across requests within a worker, so a script can cache a value itself (e.g. `if not token then token = login() end`).
- **Same proxy:** when proxies are configured, a script's requests go through the same proxy as the main request they belong to.
- **Status codes:** non-2xx responses are returned normally; check `status` in the script.
- **Errors:** network failures and timeouts raise a script error. The main request is not sent and the error is counted in the results. Scripts can catch it with `pcall` (Lua) or `try`/`catch` (JavaScript).
- **Only inside `transform`:** `http` works anywhere while `transform` runs, including in helper functions it calls. Calling it at the top level of a script raises an error, because that code also runs during config validation and when each worker starts.
- **Dry run:** script requests are still sent in dry-run mode.
- **Not measured:** script requests are not included in the results.
**Lua JSON:**
Lua has no built-in JSON support, so Lua scripts get a global `json` table:
- `json.decode(string)`: arrays become 1-indexed tables and `null` becomes `nil` (so `null` array items leave holes).
- `json.encode(value)`: a table with keys exactly `1..n` becomes an array, any other table becomes an object, and an empty table becomes `{}`.
JavaScript scripts use the built-in `JSON` object.
**Lua example:**
```lua
function transform(req)
local res = http("https://api.example.com/login", {
method = "POST",
headers = { ["Content-Type"] = "application/json" },
body = json.encode({ user = "test", password = "secret" }),
timeout = "2s",
})
if res.status ~= 200 then
error("login failed: " .. res.status)
end
req.headers["Authorization"] = "Bearer " .. json.decode(res.body).token
return req
end
```
**JavaScript example:**
```javascript
function transform(req) {
const res = http("https://api.example.com/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ user: "test", password: "secret" }),
timeout: "2s",
});
if (res.status !== 200) {
throw new Error("login failed: " + res.status);
}
req.headers["Authorization"] = "Bearer " + res.json().token;
return req;
}
```