diff options
author | Marcos Casagrande <marcoscvp90@gmail.com> | 2022-09-26 20:27:50 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-26 20:27:50 +0200 |
commit | c7dd842f84268985e8701c67a9ea2607c13c9ae1 (patch) | |
tree | 88b55ac6880a539b3f6f8342c388eff6d5cc79ce /cli/tests/unit/fetch_test.ts | |
parent | 1628dba6db3f9cd5d9730a95f5c06573f66361ca (diff) |
perf(ext/fetch): use content-length in InnerBody.consume (#15925)
This fast path prevents repeated allocations when receiving a fetch body with a known size.
Co-authored-by: Luca Casonato <hello@lcas.dev>
Diffstat (limited to 'cli/tests/unit/fetch_test.ts')
-rw-r--r-- | cli/tests/unit/fetch_test.ts | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/cli/tests/unit/fetch_test.ts b/cli/tests/unit/fetch_test.ts index b3e097cae..5375457bc 100644 --- a/cli/tests/unit/fetch_test.ts +++ b/cli/tests/unit/fetch_test.ts @@ -1639,3 +1639,137 @@ Deno.test(async function staticResponseJson() { const res = await resp.json(); assertEquals(res, data); }); + +function invalidServer(addr: string, body: Uint8Array): Deno.Listener { + const [hostname, port] = addr.split(":"); + const listener = Deno.listen({ + hostname, + port: Number(port), + }) as Deno.Listener; + + (async () => { + for await (const conn of listener) { + const p1 = conn.read(new Uint8Array(2 ** 14)); + const p2 = conn.write(body); + + await Promise.all([p1, p2]); + conn.close(); + } + })(); + + return listener; +} + +Deno.test( + { permissions: { net: true } }, + async function fetchWithInvalidContentLengthAndTransferEncoding(): Promise< + void + > { + const addr = "127.0.0.1:4516"; + const data = "a".repeat(10 << 10); + + const body = new TextEncoder().encode( + `HTTP/1.1 200 OK\r\nContent-Length: ${ + Math.round(data.length * 2) + }\r\nTransfer-Encoding: chunked\r\n\r\n${ + data.length.toString(16) + }\r\n${data}\r\n0\r\n\r\n`, + ); + + // if transfer-encoding is sent, content-length is ignored + // even if it has an invalid value (content-length > totalLength) + const listener = invalidServer(addr, body); + const response = await fetch(`http://${addr}/`); + + const res = await response.arrayBuffer(); + const buf = new TextEncoder().encode(data); + assertEquals(res.byteLength, buf.byteLength); + assertEquals(new Uint8Array(res), buf); + + listener.close(); + }, +); + +Deno.test( + { permissions: { net: true } }, + async function fetchWithInvalidContentLength(): Promise< + void + > { + const addr = "127.0.0.1:4517"; + const data = "a".repeat(10 << 10); + + const body = new TextEncoder().encode( + `HTTP/1.1 200 OK\r\nContent-Length: ${ + Math.round(data.length / 2) + }\r\nContent-Length: ${data.length}\r\n\r\n${data}`, + ); + + // It should fail if multiple content-length headers with different values are sent + const listener = invalidServer(addr, body); + await assertRejects( + async () => { + await fetch(`http://${addr}/`); + }, + TypeError, + "invalid content-length parsed", + ); + + listener.close(); + }, +); + +Deno.test( + { permissions: { net: true } }, + async function fetchWithInvalidContentLength(): Promise< + void + > { + const addr = "127.0.0.1:4518"; + const data = "a".repeat(10 << 10); + + const contentLength = data.length / 2; + const body = new TextEncoder().encode( + `HTTP/1.1 200 OK\r\nContent-Length: ${contentLength}\r\n\r\n${data}`, + ); + + const listener = invalidServer(addr, body); + const response = await fetch(`http://${addr}/`); + + // If content-length < totalLength, a maximum of content-length bytes + // should be returned. + const res = await response.arrayBuffer(); + const buf = new TextEncoder().encode(data); + assertEquals(res.byteLength, contentLength); + assertEquals(new Uint8Array(res), buf.subarray(contentLength)); + + listener.close(); + }, +); + +Deno.test( + { permissions: { net: true } }, + async function fetchWithInvalidContentLength(): Promise< + void + > { + const addr = "127.0.0.1:4519"; + const data = "a".repeat(10 << 10); + + const contentLength = data.length * 2; + const body = new TextEncoder().encode( + `HTTP/1.1 200 OK\r\nContent-Length: ${contentLength}\r\n\r\n${data}`, + ); + + const listener = invalidServer(addr, body); + const response = await fetch(`http://${addr}/`); + // If content-length > totalLength, a maximum of content-length bytes + // should be returned. + await assertRejects( + async () => { + await response.arrayBuffer(); + }, + Error, + "end of file before message length reached", + ); + + listener.close(); + }, +); |