diff options
Diffstat (limited to 'cli')
-rw-r--r-- | cli/tests/unit/http_test.ts | 503 |
1 files changed, 501 insertions, 2 deletions
diff --git a/cli/tests/unit/http_test.ts b/cli/tests/unit/http_test.ts index 5ff1475b3..68500006f 100644 --- a/cli/tests/unit/http_test.ts +++ b/cli/tests/unit/http_test.ts @@ -95,7 +95,7 @@ Deno.test( const resp = new Uint8Array(200); const readResult = await conn.read(resp); - assertEquals(readResult, 115); + assertEquals(readResult, 138); conn.close(); @@ -1165,7 +1165,7 @@ Deno.test( const resp = new Uint8Array(200); const readResult = await conn.read(resp); - assertEquals(readResult, 115); + assertEquals(readResult, 138); conn.close(); @@ -1173,6 +1173,505 @@ Deno.test( }, ); +/* Automatic Body Compression */ + +const decoder = new TextDecoder(); + +Deno.test({ + name: "http server compresses body", + permissions: { net: true }, + async fn() { + const hostname = "localhost"; + const port = 4501; + + async function server() { + const listener = Deno.listen({ hostname, port }); + const tcpConn = await listener.accept(); + const httpConn = Deno.serveHttp(tcpConn); + const e = await httpConn.nextRequest(); + assert(e); + const { request, respondWith } = e; + assertEquals(request.headers.get("Accept-Encoding"), "gzip, deflate, br"); + const response = new Response( + JSON.stringify({ hello: "deno", now: "with", compressed: "body" }), + { + headers: { "content-type": "application/json" }, + }, + ); + await respondWith(response); + httpConn.close(); + listener.close(); + } + + async function client() { + const url = `http://${hostname}:${port}/`; + const cmd = [ + "curl", + "-I", + "--request", + "GET", + "--url", + url, + "--header", + "Accept-Encoding: gzip, deflate, br", + ]; + const proc = Deno.run({ cmd, stdout: "piped", stderr: "null" }); + const status = await proc.status(); + assert(status.success); + const output = decoder.decode(await proc.output()); + assert(output.includes("vary: Accept-Encoding\r\n")); + assert(output.includes("content-encoding: gzip\r\n")); + proc.close(); + } + + await Promise.all([server(), client()]); + }, +}); + +Deno.test({ + name: "http server doesn't compress small body", + permissions: { net: true }, + async fn() { + const hostname = "localhost"; + const port = 4501; + + async function server() { + const listener = Deno.listen({ hostname, port }); + const tcpConn = await listener.accept(); + const httpConn = Deno.serveHttp(tcpConn); + const e = await httpConn.nextRequest(); + assert(e); + const { request, respondWith } = e; + assertEquals(request.headers.get("Accept-Encoding"), "gzip, deflate, br"); + const response = new Response( + JSON.stringify({ hello: "deno" }), + { + headers: { "content-type": "application/json" }, + }, + ); + await respondWith(response); + httpConn.close(); + listener.close(); + } + + async function client() { + const url = `http://${hostname}:${port}/`; + const cmd = [ + "curl", + "-I", + "--request", + "GET", + "--url", + url, + "--header", + "Accept-Encoding: gzip, deflate, br", + ]; + const proc = Deno.run({ cmd, stdout: "piped", stderr: "null" }); + const status = await proc.status(); + assert(status.success); + const output = decoder.decode(await proc.output()).toLocaleLowerCase(); + assert(output.includes("vary: accept-encoding\r\n")); + assert(!output.includes("content-encoding: ")); + proc.close(); + } + + await Promise.all([server(), client()]); + }, +}); + +Deno.test({ + name: "http server respects accept-encoding weights", + permissions: { net: true }, + async fn() { + const hostname = "localhost"; + const port = 4501; + + async function server() { + const listener = Deno.listen({ hostname, port }); + const tcpConn = await listener.accept(); + const httpConn = Deno.serveHttp(tcpConn); + const e = await httpConn.nextRequest(); + assert(e); + const { request, respondWith } = e; + assertEquals( + request.headers.get("Accept-Encoding"), + "gzip;q=0.8, br;q=1.0, *;q=0.1", + ); + const response = new Response( + JSON.stringify({ hello: "deno", now: "with", compressed: "body" }), + { + headers: { "content-type": "application/json" }, + }, + ); + await respondWith(response); + httpConn.close(); + listener.close(); + } + + async function client() { + const url = `http://${hostname}:${port}/`; + const cmd = [ + "curl", + "-I", + "--request", + "GET", + "--url", + url, + "--header", + "Accept-Encoding: gzip;q=0.8, br;q=1.0, *;q=0.1", + ]; + const proc = Deno.run({ cmd, stdout: "piped", stderr: "null" }); + const status = await proc.status(); + assert(status.success); + const output = decoder.decode(await proc.output()); + assert(output.includes("vary: Accept-Encoding\r\n")); + assert(output.includes("content-encoding: br\r\n")); + proc.close(); + } + + await Promise.all([server(), client()]); + }, +}); + +Deno.test({ + name: "http server augments vary header", + permissions: { net: true }, + async fn() { + const hostname = "localhost"; + const port = 4501; + + async function server() { + const listener = Deno.listen({ hostname, port }); + const tcpConn = await listener.accept(); + const httpConn = Deno.serveHttp(tcpConn); + const e = await httpConn.nextRequest(); + assert(e); + const { request, respondWith } = e; + assertEquals(request.headers.get("Accept-Encoding"), "gzip, deflate, br"); + const response = new Response( + JSON.stringify({ hello: "deno", now: "with", compressed: "body" }), + { + headers: { "content-type": "application/json", vary: "Accept" }, + }, + ); + await respondWith(response); + httpConn.close(); + listener.close(); + } + + async function client() { + const url = `http://${hostname}:${port}/`; + const cmd = [ + "curl", + "-I", + "--request", + "GET", + "--url", + url, + "--header", + "Accept-Encoding: gzip, deflate, br", + ]; + const proc = Deno.run({ cmd, stdout: "piped", stderr: "null" }); + const status = await proc.status(); + assert(status.success); + const output = decoder.decode(await proc.output()); + assert(output.includes("vary: Accept-Encoding, Accept\r\n")); + assert(output.includes("content-encoding: gzip\r\n")); + proc.close(); + } + + await Promise.all([server(), client()]); + }, +}); + +Deno.test({ + name: "http server weakens etag header", + permissions: { net: true }, + async fn() { + const hostname = "localhost"; + const port = 4501; + + async function server() { + const listener = Deno.listen({ hostname, port }); + const tcpConn = await listener.accept(); + const httpConn = Deno.serveHttp(tcpConn); + const e = await httpConn.nextRequest(); + assert(e); + const { request, respondWith } = e; + assertEquals(request.headers.get("Accept-Encoding"), "gzip, deflate, br"); + const response = new Response( + JSON.stringify({ hello: "deno", now: "with", compressed: "body" }), + { + headers: { + "content-type": "application/json", + etag: "33a64df551425fcc55e4d42a148795d9f25f89d4", + }, + }, + ); + await respondWith(response); + httpConn.close(); + listener.close(); + } + + async function client() { + const url = `http://${hostname}:${port}/`; + const cmd = [ + "curl", + "-I", + "--request", + "GET", + "--url", + url, + "--header", + "Accept-Encoding: gzip, deflate, br", + ]; + const proc = Deno.run({ cmd, stdout: "piped", stderr: "null" }); + const status = await proc.status(); + assert(status.success); + const output = decoder.decode(await proc.output()); + assert(output.includes("vary: Accept-Encoding\r\n")); + assert( + output.includes("etag: W/33a64df551425fcc55e4d42a148795d9f25f89d4\r\n"), + ); + assert(output.includes("content-encoding: gzip\r\n")); + proc.close(); + } + + await Promise.all([server(), client()]); + }, +}); + +Deno.test({ + name: "http server passes through weak etag header", + permissions: { net: true }, + async fn() { + const hostname = "localhost"; + const port = 4501; + + async function server() { + const listener = Deno.listen({ hostname, port }); + const tcpConn = await listener.accept(); + const httpConn = Deno.serveHttp(tcpConn); + const e = await httpConn.nextRequest(); + assert(e); + const { request, respondWith } = e; + assertEquals(request.headers.get("Accept-Encoding"), "gzip, deflate, br"); + const response = new Response( + JSON.stringify({ hello: "deno", now: "with", compressed: "body" }), + { + headers: { + "content-type": "application/json", + etag: "W/33a64df551425fcc55e4d42a148795d9f25f89d4", + }, + }, + ); + await respondWith(response); + httpConn.close(); + listener.close(); + } + + async function client() { + const url = `http://${hostname}:${port}/`; + const cmd = [ + "curl", + "-I", + "--request", + "GET", + "--url", + url, + "--header", + "Accept-Encoding: gzip, deflate, br", + ]; + const proc = Deno.run({ cmd, stdout: "piped", stderr: "null" }); + const status = await proc.status(); + assert(status.success); + const output = decoder.decode(await proc.output()); + assert(output.includes("vary: Accept-Encoding\r\n")); + assert( + output.includes("etag: W/33a64df551425fcc55e4d42a148795d9f25f89d4\r\n"), + ); + assert(output.includes("content-encoding: gzip\r\n")); + proc.close(); + } + + await Promise.all([server(), client()]); + }, +}); + +Deno.test({ + name: "http server doesn't compress body when no-transform is set", + permissions: { net: true }, + async fn() { + const hostname = "localhost"; + const port = 4501; + + async function server() { + const listener = Deno.listen({ hostname, port }); + const tcpConn = await listener.accept(); + const httpConn = Deno.serveHttp(tcpConn); + const e = await httpConn.nextRequest(); + assert(e); + const { request, respondWith } = e; + assertEquals(request.headers.get("Accept-Encoding"), "gzip, deflate, br"); + const response = new Response( + JSON.stringify({ hello: "deno", now: "with", compressed: "body" }), + { + headers: { + "content-type": "application/json", + "cache-control": "no-transform", + }, + }, + ); + await respondWith(response); + httpConn.close(); + listener.close(); + } + + async function client() { + const url = `http://${hostname}:${port}/`; + const cmd = [ + "curl", + "-I", + "--request", + "GET", + "--url", + url, + "--header", + "Accept-Encoding: gzip, deflate, br", + ]; + const proc = Deno.run({ cmd, stdout: "piped", stderr: "null" }); + const status = await proc.status(); + assert(status.success); + const output = decoder.decode(await proc.output()); + assert(output.includes("vary: Accept-Encoding\r\n")); + assert(!output.includes("content-encoding: ")); + proc.close(); + } + + await Promise.all([server(), client()]); + }, +}); + +Deno.test({ + name: "http server doesn't compress body when content-range is set", + permissions: { net: true }, + async fn() { + const hostname = "localhost"; + const port = 4501; + + async function server() { + const listener = Deno.listen({ hostname, port }); + const tcpConn = await listener.accept(); + const httpConn = Deno.serveHttp(tcpConn); + const e = await httpConn.nextRequest(); + assert(e); + const { request, respondWith } = e; + assertEquals(request.headers.get("Accept-Encoding"), "gzip, deflate, br"); + const response = new Response( + JSON.stringify({ hello: "deno", now: "with", compressed: "body" }), + { + headers: { + "content-type": "application/json", + "content-range": "bytes 200-100/67589", + }, + }, + ); + await respondWith(response); + httpConn.close(); + listener.close(); + } + + async function client() { + const url = `http://${hostname}:${port}/`; + const cmd = [ + "curl", + "-I", + "--request", + "GET", + "--url", + url, + "--header", + "Accept-Encoding: gzip, deflate, br", + ]; + const proc = Deno.run({ cmd, stdout: "piped", stderr: "null" }); + const status = await proc.status(); + assert(status.success); + const output = decoder.decode(await proc.output()); + assert(output.includes("vary: Accept-Encoding\r\n")); + assert(!output.includes("content-encoding: ")); + proc.close(); + } + + await Promise.all([server(), client()]); + }, +}); + +Deno.test({ + name: "http server doesn't compress streamed bodies", + permissions: { net: true }, + async fn() { + const hostname = "localhost"; + const port = 4501; + + async function server() { + const encoder = new TextEncoder(); + const listener = Deno.listen({ hostname, port }); + const tcpConn = await listener.accept(); + const httpConn = Deno.serveHttp(tcpConn); + const e = await httpConn.nextRequest(); + assert(e); + const { request, respondWith } = e; + assertEquals(request.headers.get("Accept-Encoding"), "gzip, deflate, br"); + const bodyInit = new ReadableStream({ + start(controller) { + controller.enqueue( + encoder.encode( + JSON.stringify({ + hello: "deno", + now: "with", + compressed: "body", + }), + ), + ); + controller.close(); + }, + }); + const response = new Response( + bodyInit, + { + headers: { "content-type": "application/json", vary: "Accept" }, + }, + ); + await respondWith(response); + httpConn.close(); + listener.close(); + } + + async function client() { + const url = `http://${hostname}:${port}/`; + const cmd = [ + "curl", + "-I", + "--request", + "GET", + "--url", + url, + "--header", + "Accept-Encoding: gzip, deflate, br", + ]; + const proc = Deno.run({ cmd, stdout: "piped", stderr: "null" }); + const status = await proc.status(); + assert(status.success); + const output = decoder.decode(await proc.output()); + assert(output.includes("vary: Accept\r\n")); + assert(!output.includes("content-encoding: ")); + proc.close(); + } + + await Promise.all([server(), client()]); + }, +}); + function chunkedBodyReader(h: Headers, r: BufReader): Deno.Reader { // Based on https://tools.ietf.org/html/rfc2616#section-19.4.6 const tp = new TextProtoReader(r); |