Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,15 +105,15 @@ x-rendering-proxy-version: 1

#### Protocol schema (v1)

**Request header** `X-Rendering-Proxy` — JSON object:
**Request header** `X-Rendering-Proxy` — a single JSON object header value:

| field | type | default | description |
| --- | --- | --- | --- |
| `waitUntil` | `"load"` \| `"domcontentloaded"` \| `"networkidle"` \| `"commit"` | `"load"` | Playwright lifecycle event to wait for. Unknown values fall back to `"load"` with a server-side warning. |
| `evaluates` | `string[]` | `[]` | JavaScript snippets to evaluate before capturing the DOM. |
| `timeout` | `number` (ms) | none | Navigation timeout in milliseconds. |

Requests with a non-object `X-Rendering-Proxy` JSON payload or with fields of the wrong type are rejected with `400 Bad Request`.
Requests with a repeated `X-Rendering-Proxy` header, a non-object JSON payload, or fields of the wrong type are rejected with `400 Bad Request`.

**Response header** `X-Rendering-Proxy` — JSON array of `EvaluateResult`:

Expand Down
11 changes: 10 additions & 1 deletion src/server/request_options.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,16 @@ describe('parseRenderingProxyHeader', () => {
})
})

it('throws for syntactically invalid JSON in a non-empty header', async () => {
it('rejects repeated x-rendering-proxy header values', async () => {
expect(() =>
parseRenderingProxyHeader([
'{"evaluates":["1 + 1"]}',
'{"waitUntil":"load"}',
]),
).toThrow(TypeError)
})

it('throws SyntaxError for syntactically invalid JSON in a non-empty header', async () => {
// Callers (e.g. the HTTP server) must catch and return 400 Bad Request
expect(() => parseRenderingProxyHeader('{')).toThrow(SyntaxError)
expect(() => parseRenderingProxyHeader('[unclosed')).toThrow(SyntaxError)
Expand Down
14 changes: 13 additions & 1 deletion src/server/request_options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,26 @@ type RequestOptionInput = {
timeout?: unknown
}

function normalizeHeaderArray(headerValue: string[]): string {
if (headerValue.length === 0) {
return ''
}
if (headerValue.length === 1) {
return headerValue[0] ?? ''
}
throw new TypeError(
'X-Rendering-Proxy must be provided as a single header value',
)
}

export function parseRenderingProxyHeader(
headerValue: undefined | string | string[],
): RequestOption {
if (typeof headerValue === 'string') {
return parseOptions(headerValue)
}
if (Array.isArray(headerValue)) {
return parseOptions(headerValue.join(''))
return parseOptions(normalizeHeaderArray(headerValue))
}
return parseOptions('')
}
Expand Down
Loading