From 59f78f38e769c44a48be250ab7fff1b9a30ec683 Mon Sep 17 00:00:00 2001 From: germondai Date: Mon, 6 Jul 2026 01:12:30 +0200 Subject: [PATCH] docs: document method/body support and header sanitisation --- CHANGELOG.md | 39 ++++++++++++++++++++ apps/docs/api-reference/flaresolvr-compat.md | 2 +- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb7ed27..1fe23f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,45 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Initial release with 4-tier execution engine +- Native `method` + `body` support across all four scraper tiers — the + `FlareSolverrRequest.cmd=request.post` body is now actually delivered upstream + instead of being silently dropped +- Header sanitisation at the API + orchestrator boundary: caller-supplied + `Host`, `Cookie`, `Authorization`, `X-Forwarded-*`, `Sec-*`, `User-Agent`, + `Content-Length`, and similar reserved headers are dropped before being + forwarded to Node fetch / Playwright +- `ScrapeRequest.method` accepts the full standard verb set: `GET`, `POST`, + `PUT`, `PATCH`, `DELETE`, `HEAD`, `OPTIONS`, `TRACE`, `QUERY` (RFC 9341). + `CONNECT` is intentionally excluded (tunneling verb, inappropriate for a + proxy) +- POST / `*` request bodies are forwarded **uncapped** — operators who want a + byte ceiling should impose it at their ingress / fronting proxy +- Body-bearing requests require a `Content-Type` header; the tier functions no + longer auto-inject `application/x-www-form-urlencoded`, which previously + mislabelled JSON / XML bodies +- `ScrapeRequest` field renamed from `postData` → `body` for REST-idiomatic + naming. (`FlareSolverrRequest.postData` is unchanged because it's the + upstream wire contract.) + +### Security +- Reserved-name header denylist prevents callers from spoofing `cf_clearance` + cookies, overriding the per-tier `User-Agent`, or rewriting routing signals + (`X-Forwarded-For`, `Host`) during a POST bypass flow + +### Limitations +- The Playwright `page.route(url, …)` interceptor only handles the first + top-frame GET to that exact URL. Server redirects to a different URL, XHR + sub-resources, and chained `POST→POST` form flows do not have the + `postData` override applied +- No idempotency-key support; transient network failures and pool churn can + re-fire a POST (separate ticket) + +### Tests +- `packages/tiers/tests/sanitize.test.ts` — header sanitiser, method + allowlist, postData size cap, Content-Type enforcement +- `packages/tiers/tests/runTier1Post.test.ts` — tier1 GET/POST round-trip and + User-Agent non-override +- Run via `bun --cwd packages/tiers test` - Persistent browser pool with real Google Chrome - Session caching via Redis - FlareSolverr v2-compatible `/v1` endpoint diff --git a/apps/docs/api-reference/flaresolvr-compat.md b/apps/docs/api-reference/flaresolvr-compat.md index 41898ca..cd2689d 100644 --- a/apps/docs/api-reference/flaresolvr-compat.md +++ b/apps/docs/api-reference/flaresolvr-compat.md @@ -28,7 +28,7 @@ interface FlareSolverrRequest { | `cmd` | string | No | `"request.get"` or `"request.post"` (default `"request.get"`) | | `url` | string | Yes | The URL to scrape | | `maxTimeout` | number | No | Max wait in ms (default 60000) | -| `postData` | string | No | POST body (only for `request.post`) | +| `postData` | string | No | POST body (only for `request.post`). On TRAWL's native `/scrape` endpoint this field is named `body`; the `/v1` adapter maps `postData` → `body` internally so the FlareSolverr wire contract stays unchanged for existing callers. | | `headers` | object | No | Custom headers forwarded to the target across all tiers — see [Custom Headers](/api-reference/custom-headers) | ## Response