response.writeHead(403, { 'Content-Length': 0 }).end();
return;
}
+ if (request.headers['content-length'] === undefined) { // Refuse Transfer-Encoding: chunked
+ response.writeHead(411, { 'Content-Length': 0 }).end();
+ return;
+ }
if (request.headers['content-type'] !== 'application/octet-stream') {
response.writeHead(400, { 'Content-Length': 0 }).end();
return;
import { suite, test } from 'node:test';
import { deepStrictEqual, match, ok, rejects } from 'node:assert/strict';
+import { Readable } from 'node:stream';
import { request } from 'undici';
deepStrictEqual((await fetch(makePostRequest(url, { headers: { 'Sec-Fetch-Dest': 'embed' } }))).status, 403);
deepStrictEqual((await fetch(makePostRequest(url, { headers: { 'Sec-Fetch-Dest': 'empty' } }))).status, 200);
});
+ test('rejects Transfer-Encoding: chunked on POST', async (t) => {
+ const { url } = await setupServer(t);
+ // Using the lower-level `request` instead to force Transfer-Encoding
+ const { origin, searchParams } = new URL(url);
+ const options = {
+ method: 'POST',
+ headers: /** @type {Record<string,string>} */({
+ 'Content-Type': 'application/octet-stream',
+ 'Origin': origin,
+ 'Sec-Fetch-Site': 'same-origin',
+ 'Sec-Fetch-Mode': 'cors',
+ 'Sec-Fetch-Dest': 'empty',
+ 'Envpass-Challenge': searchParams.get('challenge')
+ }),
+ body: Readable.from([Uint8Array.fromHex('deadbeef000000000000000000000000000000000000000000000000cafebabe')])
+ }
+ deepStrictEqual((await request(origin, options)).statusCode, 411);
+ });
test('validates Content-Type header on POST', async (t) => {
const { url } = await setupServer(t);
deepStrictEqual((await fetch(makePostRequest(url, { headers: { 'Content-Type': null } }))).status, 400);