diff options
| author | Yusuke Sakurai <kerokerokerop@gmail.com> | 2019-02-16 01:03:57 +0900 |
|---|---|---|
| committer | Ryan Dahl <ry@tinyclouds.org> | 2019-02-15 11:03:57 -0500 |
| commit | 57f4e6a86448263c9f1c75934e829e048c76f572 (patch) | |
| tree | b4e46dcb4a43fec2694e289702fba2cd5e475c50 /http/server_test.ts | |
| parent | 34ece9f2ede9c63af2678feb15ef5290a74c8d2f (diff) | |
Redesign of http server module (denoland/deno_std#188)
Original: https://github.com/denoland/deno_std/commit/8569f15207bdc12c2c8ca81e9d020955be54918b
Diffstat (limited to 'http/server_test.ts')
| -rw-r--r-- | http/server_test.ts | 399 |
1 files changed, 233 insertions, 166 deletions
diff --git a/http/server_test.ts b/http/server_test.ts index 099547d0c..f8aca487c 100644 --- a/http/server_test.ts +++ b/http/server_test.ts @@ -5,19 +5,26 @@ // Ported from // https://github.com/golang/go/blob/master/src/net/http/responsewrite_test.go -import { Buffer } from "deno"; -import { assertEqual, test } from "../testing/mod.ts"; -import { Response, ServerRequest } from "./server.ts"; -import { BufReader, BufWriter } from "../io/bufio.ts"; +import { Buffer, copy, Reader } from "deno"; +import { assert, assertEqual, test } from "../testing/mod.ts"; +import { + createResponder, + createServer, + readRequest, + readResponse, + ServerResponse, + writeResponse +} from "./server.ts"; +import { encode } from "../strings/strings.ts"; +import { StringReader } from "../io/readers.ts"; +import { StringWriter } from "../io/writers.ts"; +import { defer } from "../util/deferred.ts"; interface ResponseTest { - response: Response; + response: ServerResponse; raw: string; } -const enc = new TextEncoder(); -const dec = new TextDecoder(); - const responseTests: ResponseTest[] = [ // Default response { @@ -28,7 +35,7 @@ const responseTests: ResponseTest[] = [ { response: { status: 200, - body: new Buffer(new TextEncoder().encode("abcdef")) + body: new Buffer(encode("abcdef")) }, raw: @@ -38,181 +45,241 @@ const responseTests: ResponseTest[] = [ } ]; -test(async function responseWrite() { - for (const testCase of responseTests) { +test(async function httpWriteResponse() { + for (const { raw, response } of responseTests) { const buf = new Buffer(); - const bufw = new BufWriter(buf); - const request = new ServerRequest(); - request.w = bufw; - - await request.respond(testCase.response); - assertEqual(buf.toString(), testCase.raw); + await writeResponse(buf, response); + assertEqual(buf.toString(), raw); } }); -test(async function requestBodyWithContentLength() { - { - const req = new ServerRequest(); - req.headers = new Headers(); - req.headers.set("content-length", "5"); - const buf = new Buffer(enc.encode("Hello")); - req.r = new BufReader(buf); - const body = dec.decode(await req.body()); - assertEqual(body, "Hello"); - } +test(async function httpReadRequest() { + const body = "0123456789"; + const lines = [ + "GET /index.html?deno=land HTTP/1.1", + "Host: deno.land", + "Content-Type: text/plain", + `Content-Length: ${body.length}`, + "\r\n" + ]; + let msg = lines.join("\r\n"); + msg += body; + const req = await readRequest(new StringReader(`${msg}`)); + assert.equal(req.url, "/index.html?deno=land"); + assert.equal(req.method, "GET"); + assert.equal(req.proto, "HTTP/1.1"); + assert.equal(req.headers.get("host"), "deno.land"); + assert.equal(req.headers.get("content-type"), "text/plain"); + assert.equal(req.headers.get("content-length"), `${body.length}`); + const w = new StringWriter(); + await copy(w, req.body); + assert.equal(w.toString(), body); +}); - // Larger than internal buf - { - const longText = "1234\n".repeat(1000); - const req = new ServerRequest(); - req.headers = new Headers(); - req.headers.set("Content-Length", "5000"); - const buf = new Buffer(enc.encode(longText)); - req.r = new BufReader(buf); - const body = dec.decode(await req.body()); - assertEqual(body, longText); - } +test(async function httpReadRequestChunkedBody() { + const lines = [ + "GET /index.html?deno=land HTTP/1.1", + "Host: deno.land", + "Content-Type: text/plain", + `Transfer-Encoding: chunked`, + "\r\n" + ]; + const hd = lines.join("\r\n"); + const buf = new Buffer(); + await buf.write(encode(hd)); + await buf.write(encode("4\r\ndeno\r\n")); + await buf.write(encode("5\r\n.land\r\n")); + await buf.write(encode("0\r\n\r\n")); + const req = await readRequest(buf); + assert.equal(req.url, "/index.html?deno=land"); + assert.equal(req.method, "GET"); + assert.equal(req.proto, "HTTP/1.1"); + assert.equal(req.headers.get("host"), "deno.land"); + assert.equal(req.headers.get("content-type"), "text/plain"); + assert.equal(req.headers.get("transfer-encoding"), `chunked`); + const dest = new Buffer(); + await copy(dest, req.body); + assert.equal(dest.toString(), "deno.land"); }); -test(async function requestBodyWithTransferEncoding() { - { - const shortText = "Hello"; - const req = new ServerRequest(); - req.headers = new Headers(); - req.headers.set("transfer-encoding", "chunked"); - let chunksData = ""; - let chunkOffset = 0; - const maxChunkSize = 70; - while (chunkOffset < shortText.length) { - const chunkSize = Math.min(maxChunkSize, shortText.length - chunkOffset); - chunksData += `${chunkSize.toString(16)}\r\n${shortText.substr( - chunkOffset, - chunkSize - )}\r\n`; - chunkOffset += chunkSize; +test(async function httpServer() { + const server = createServer(); + server.handle("/index", async (req, res) => { + await res.respond({ + status: 200, + body: encode("ok") + }); + }); + server.handle(new RegExp("/foo/(?<id>.+)"), async (req, res) => { + const { id } = req.match.groups; + await res.respond({ + status: 200, + headers: new Headers({ + "content-type": "application/json" + }), + body: encode(JSON.stringify({ id })) + }); + }); + server.handle("/no-response", async (req, res) => {}); + const cancel = defer<void>(); + try { + server.listen("127.0.0.1:8080", cancel); + { + const res1 = await fetch("http://127.0.0.1:8080/index"); + const text = await res1.body.text(); + assert.equal(res1.status, 200); + assert.equal(text, "ok"); } - chunksData += "0\r\n\r\n"; - const buf = new Buffer(enc.encode(chunksData)); - req.r = new BufReader(buf); - const body = dec.decode(await req.body()); - assertEqual(body, shortText); - } - - // Larger than internal buf - { - const longText = "1234\n".repeat(1000); - const req = new ServerRequest(); - req.headers = new Headers(); - req.headers.set("transfer-encoding", "chunked"); - let chunksData = ""; - let chunkOffset = 0; - const maxChunkSize = 70; - while (chunkOffset < longText.length) { - const chunkSize = Math.min(maxChunkSize, longText.length - chunkOffset); - chunksData += `${chunkSize.toString(16)}\r\n${longText.substr( - chunkOffset, - chunkSize - )}\r\n`; - chunkOffset += chunkSize; + { + const res2 = await fetch("http://127.0.0.1:8080/foo/123"); + const json = await res2.body.json(); + assert.equal(res2.status, 200); + assert.equal(res2.headers.get("content-type"), "application/json"); + assert.equal(json["id"], "123"); + } + { + const res = await fetch("http://127.0.0.1:8080/no-response"); + assert.equal(res.status, 500); + const text = await res.body.text(); + assert.assert(!!text.match("Not Responded")); + } + { + const res = await fetch("http://127.0.0.1:8080/not-found"); + const text = await res.body.text(); + assert.equal(res.status, 404); + assert.assert(!!text.match("Not Found")); } - chunksData += "0\r\n\r\n"; - const buf = new Buffer(enc.encode(chunksData)); - req.r = new BufReader(buf); - const body = dec.decode(await req.body()); - assertEqual(body, longText); + } finally { + cancel.resolve(); } }); -test(async function requestBodyStreamWithContentLength() { - { - const shortText = "Hello"; - const req = new ServerRequest(); - req.headers = new Headers(); - req.headers.set("content-length", "" + shortText.length); - const buf = new Buffer(enc.encode(shortText)); - req.r = new BufReader(buf); - const it = await req.bodyStream(); - let offset = 0; - for await (const chunk of it) { - const s = dec.decode(chunk); - assertEqual(shortText.substr(offset, s.length), s); - offset += s.length; - } - } +test(async function httpServerResponder() { + const w = new Buffer(); + const res = createResponder(w); + assert.assert(!res.isResponded); + await res.respond({ + status: 200, + headers: new Headers({ + "content-type": "text/plain" + }), + body: encode("ok") + }); + assert.assert(res.isResponded); + const resp = await readResponse(w); + assert.equal(resp.status, 200); + assert.equal(resp.headers.get("content-type"), "text/plain"); + const sw = new StringWriter(); + await copy(sw, resp.body as Reader); + assert.equal(sw.toString(), "ok"); +}); - // Larger than internal buf - { - const longText = "1234\n".repeat(1000); - const req = new ServerRequest(); - req.headers = new Headers(); - req.headers.set("Content-Length", "5000"); - const buf = new Buffer(enc.encode(longText)); - req.r = new BufReader(buf); - const it = await req.bodyStream(); - let offset = 0; - for await (const chunk of it) { - const s = dec.decode(chunk); - assertEqual(longText.substr(offset, s.length), s); - offset += s.length; +test(async function httpServerResponderRespondJson() { + const w = new Buffer(); + const res = createResponder(w); + const json = { + id: 1, + deno: { + is: "land" } - } + }; + assert.assert(!res.isResponded); + await res.respondJson( + json, + new Headers({ + deno: "land" + }) + ); + assert.assert(res.isResponded); + const resp = await readResponse(w); + assert.equal(resp.status, 200); + assert.equal(resp.headers.get("content-type"), "application/json"); + const sw = new StringWriter(); + await copy(sw, resp.body as Reader); + const resJson = JSON.parse(sw.toString()); + assert.equal(resJson, json); + assert.equal(resp.headers.get("deno"), "land"); +}); + +test(async function httpServerResponderRespondText() { + const w = new Buffer(); + const res = createResponder(w); + assert.assert(!res.isResponded); + await res.respondText( + "deno.land", + new Headers({ + deno: "land" + }) + ); + assert.assert(res.isResponded); + const resp = await readResponse(w); + assert.equal(resp.status, 200); + assert.equal(resp.headers.get("content-type"), "text/plain"); + const sw = new StringWriter(); + await copy(sw, resp.body as Reader); + assert.equal(sw.toString(), "deno.land"); + assert.equal(resp.headers.get("deno"), "land"); }); -test(async function requestBodyStreamWithTransferEncoding() { +test(async function httpServerResponderShouldThrow() { + const w = new Buffer(); { - const shortText = "Hello"; - const req = new ServerRequest(); - req.headers = new Headers(); - req.headers.set("transfer-encoding", "chunked"); - let chunksData = ""; - let chunkOffset = 0; - const maxChunkSize = 70; - while (chunkOffset < shortText.length) { - const chunkSize = Math.min(maxChunkSize, shortText.length - chunkOffset); - chunksData += `${chunkSize.toString(16)}\r\n${shortText.substr( - chunkOffset, - chunkSize - )}\r\n`; - chunkOffset += chunkSize; - } - chunksData += "0\r\n\r\n"; - const buf = new Buffer(enc.encode(chunksData)); - req.r = new BufReader(buf); - const it = await req.bodyStream(); - let offset = 0; - for await (const chunk of it) { - const s = dec.decode(chunk); - assertEqual(shortText.substr(offset, s.length), s); - offset += s.length; - } + const res = createResponder(w); + await res.respond({ + body: null + }); + await assert.throwsAsync( + async () => res.respond({ body: null }), + Error, + "responded" + ); + await assert.throwsAsync( + async () => res.respondJson({}), + Error, + "responded" + ); + await assert.throwsAsync( + async () => res.respondText(""), + Error, + "responded" + ); } - - // Larger than internal buf { - const longText = "1234\n".repeat(1000); - const req = new ServerRequest(); - req.headers = new Headers(); - req.headers.set("transfer-encoding", "chunked"); - let chunksData = ""; - let chunkOffset = 0; - const maxChunkSize = 70; - while (chunkOffset < longText.length) { - const chunkSize = Math.min(maxChunkSize, longText.length - chunkOffset); - chunksData += `${chunkSize.toString(16)}\r\n${longText.substr( - chunkOffset, - chunkSize - )}\r\n`; - chunkOffset += chunkSize; - } - chunksData += "0\r\n\r\n"; - const buf = new Buffer(enc.encode(chunksData)); - req.r = new BufReader(buf); - const it = await req.bodyStream(); - let offset = 0; - for await (const chunk of it) { - const s = dec.decode(chunk); - assertEqual(longText.substr(offset, s.length), s); - offset += s.length; - } + const res = createResponder(w); + await res.respondText(""); + await assert.throwsAsync( + async () => res.respond({ body: null }), + Error, + "responded" + ); + await assert.throwsAsync( + async () => res.respondJson({}), + Error, + "responded" + ); + await assert.throwsAsync( + async () => res.respondText(""), + Error, + "responded" + ); + } + { + const res = createResponder(w); + await res.respondJson({}); + await assert.throwsAsync( + async () => res.respond({ body: null }), + Error, + "responded" + ); + await assert.throwsAsync( + async () => res.respondJson({}), + Error, + "responded" + ); + await assert.throwsAsync( + async () => res.respondText(""), + Error, + "responded" + ); } }); |
