diff options
author | Kevin (Kun) "Kassimo" Qian <kevinkassimo@gmail.com> | 2020-01-17 15:44:35 -0800 |
---|---|---|
committer | Ry Dahl <ry@tinyclouds.org> | 2020-01-17 18:44:35 -0500 |
commit | fc077cd315f3d2ea508f2aac39bc65d4ac6a5747 (patch) | |
tree | 6a37b08aee4dbd425ba6cdf58b6604e99c389b24 /std/http | |
parent | 5fa056e53be6d17ab746629ea0eaa89fe817141b (diff) |
std/http: allow response body to be string (#3705)
Diffstat (limited to 'std/http')
-rw-r--r-- | std/http/README.md | 3 | ||||
-rw-r--r-- | std/http/server.ts | 24 | ||||
-rw-r--r-- | std/http/server_test.ts | 32 |
3 files changed, 50 insertions, 9 deletions
diff --git a/std/http/README.md b/std/http/README.md index 459c8e286..993b46cb8 100644 --- a/std/http/README.md +++ b/std/http/README.md @@ -2,11 +2,10 @@ ```typescript import { serve } from "https://deno.land/std/http/server.ts"; -const body = new TextEncoder().encode("Hello World\n"); const s = serve({ port: 8000 }); console.log("http://localhost:8000/"); for await (const req of s) { - req.respond({ body }); + req.respond({ body: "Hello World\n" }); } ``` diff --git a/std/http/server.ts b/std/http/server.ts index 0966d450a..9884cd845 100644 --- a/std/http/server.ts +++ b/std/http/server.ts @@ -10,6 +10,8 @@ import { STATUS_TEXT } from "./http_status.ts"; import { assert } from "../testing/asserts.ts"; import { deferred, Deferred, MuxAsyncIterator } from "../util/async.ts"; +const encoder = new TextEncoder(); + function bufWriter(w: Writer): BufWriter { if (w instanceof BufWriter) { return w; @@ -25,6 +27,7 @@ export function setContentLength(r: Response): void { if (r.body) { if (!r.headers.has("content-length")) { + // typeof r.body === "string" handled in writeResponse. if (r.body instanceof Uint8Array) { const bodyLength = r.body.byteLength; r.headers.append("Content-Length", bodyLength.toString()); @@ -37,7 +40,6 @@ export function setContentLength(r: Response): void { async function writeChunkedBody(w: Writer, r: Reader): Promise<void> { const writer = bufWriter(w); - const encoder = new TextEncoder(); for await (const chunk of toAsyncIterator(r)) { if (chunk.byteLength <= 0) continue; @@ -64,6 +66,9 @@ export async function writeResponse(w: Writer, r: Response): Promise<void> { if (!r.body) { r.body = new Uint8Array(); } + if (typeof r.body === "string") { + r.body = encoder.encode(r.body); + } let out = `HTTP/${protoMajor}.${protoMinor} ${statusCode} ${statusText}\r\n`; @@ -75,7 +80,7 @@ export async function writeResponse(w: Writer, r: Response): Promise<void> { } out += "\r\n"; - const header = new TextEncoder().encode(out); + const header = encoder.encode(out); const n = await writer.write(header); assert(n === header.byteLength); @@ -424,7 +429,7 @@ export class Server implements AsyncIterable<ServerRequest> { try { await writeResponse(req!.w, { status: 400, - body: new TextEncoder().encode(`${err.message}\r\n\r\n`) + body: encoder.encode(`${err.message}\r\n\r\n`) }); } catch (_) { // The connection is destroyed. @@ -472,7 +477,7 @@ interface ServerConfig { * Start a HTTP server * * import { serve } from "https://deno.land/std/http/server.ts"; - * const body = new TextEncoder().encode("Hello World\n"); + * const body = "Hello World\n"; * const s = serve({ port: 8000 }); * for await (const req of s) { * req.respond({ body }); @@ -505,7 +510,7 @@ export type HTTPSOptions = Omit<Deno.ListenTLSOptions, "transport">; /** * Create an HTTPS server with given options * - * const body = new TextEncoder().encode("Hello HTTPS"); + * const body = "Hello HTTPS"; * const options = { * hostname: "localhost", * port: 443, @@ -531,7 +536,7 @@ export function serveTLS(options: HTTPSOptions): Server { /** * Create an HTTPS server with given options and request handler * - * const body = new TextEncoder().encode("Hello HTTPS"); + * const body = "Hello HTTPS"; * const options = { * hostname: "localhost", * port: 443, @@ -556,8 +561,13 @@ export async function listenAndServeTLS( } } +/** + * Interface of HTTP server response. + * If body is a Reader, response would be chunked. + * If body is a string, it would be UTF-8 encoded by default. + */ export interface Response { status?: number; headers?: Headers; - body?: Uint8Array | Reader; + body?: Uint8Array | Reader | string; } diff --git a/std/http/server_test.ts b/std/http/server_test.ts index 5dbbe526c..5fe06f357 100644 --- a/std/http/server_test.ts +++ b/std/http/server_test.ts @@ -346,6 +346,38 @@ test(async function writeUint8ArrayResponse(): Promise<void> { assertEquals(eof, Deno.EOF); }); +test(async function writeStringResponse(): Promise<void> { + const body = "Hello"; + + const res: Response = { body }; + + const buf = new Deno.Buffer(); + await writeResponse(buf, res); + + const decoder = new TextDecoder("utf-8"); + const reader = new BufReader(buf); + + let r: ReadLineResult; + r = assertNotEOF(await reader.readLine()); + assertEquals(decoder.decode(r.line), "HTTP/1.1 200 OK"); + assertEquals(r.more, false); + + r = assertNotEOF(await reader.readLine()); + assertEquals(decoder.decode(r.line), `content-length: ${body.length}`); + assertEquals(r.more, false); + + r = assertNotEOF(await reader.readLine()); + assertEquals(r.line.byteLength, 0); + assertEquals(r.more, false); + + r = assertNotEOF(await reader.readLine()); + assertEquals(decoder.decode(r.line), body); + assertEquals(r.more, false); + + const eof = await reader.readLine(); + assertEquals(eof, Deno.EOF); +}); + test(async function writeStringReaderResponse(): Promise<void> { const shortText = "Hello"; |