mirror of
https://github.com/denoland/deno
synced 2024-10-13 11:32:29 +00:00
std/http: allow response body to be string (#3705)
This commit is contained in:
parent
5fa056e53b
commit
fc077cd315
|
@ -233,6 +233,8 @@ test(async function emptyDirPermission(): Promise<void> {
|
||||||
await Deno.remove(testfolder, { recursive: true });
|
await Deno.remove(testfolder, { recursive: true });
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
// Make the test rerunnable
|
||||||
|
// Otherwise would throw error due to mkdir fail.
|
||||||
|
await Deno.remove(testfolder, { recursive: true });
|
||||||
// done
|
// done
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,11 +2,10 @@
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { serve } from "https://deno.land/std/http/server.ts";
|
import { serve } from "https://deno.land/std/http/server.ts";
|
||||||
const body = new TextEncoder().encode("Hello World\n");
|
|
||||||
const s = serve({ port: 8000 });
|
const s = serve({ port: 8000 });
|
||||||
console.log("http://localhost:8000/");
|
console.log("http://localhost:8000/");
|
||||||
for await (const req of s) {
|
for await (const req of s) {
|
||||||
req.respond({ body });
|
req.respond({ body: "Hello World\n" });
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@ import { STATUS_TEXT } from "./http_status.ts";
|
||||||
import { assert } from "../testing/asserts.ts";
|
import { assert } from "../testing/asserts.ts";
|
||||||
import { deferred, Deferred, MuxAsyncIterator } from "../util/async.ts";
|
import { deferred, Deferred, MuxAsyncIterator } from "../util/async.ts";
|
||||||
|
|
||||||
|
const encoder = new TextEncoder();
|
||||||
|
|
||||||
function bufWriter(w: Writer): BufWriter {
|
function bufWriter(w: Writer): BufWriter {
|
||||||
if (w instanceof BufWriter) {
|
if (w instanceof BufWriter) {
|
||||||
return w;
|
return w;
|
||||||
|
@ -25,6 +27,7 @@ export function setContentLength(r: Response): void {
|
||||||
|
|
||||||
if (r.body) {
|
if (r.body) {
|
||||||
if (!r.headers.has("content-length")) {
|
if (!r.headers.has("content-length")) {
|
||||||
|
// typeof r.body === "string" handled in writeResponse.
|
||||||
if (r.body instanceof Uint8Array) {
|
if (r.body instanceof Uint8Array) {
|
||||||
const bodyLength = r.body.byteLength;
|
const bodyLength = r.body.byteLength;
|
||||||
r.headers.append("Content-Length", bodyLength.toString());
|
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> {
|
async function writeChunkedBody(w: Writer, r: Reader): Promise<void> {
|
||||||
const writer = bufWriter(w);
|
const writer = bufWriter(w);
|
||||||
const encoder = new TextEncoder();
|
|
||||||
|
|
||||||
for await (const chunk of toAsyncIterator(r)) {
|
for await (const chunk of toAsyncIterator(r)) {
|
||||||
if (chunk.byteLength <= 0) continue;
|
if (chunk.byteLength <= 0) continue;
|
||||||
|
@ -64,6 +66,9 @@ export async function writeResponse(w: Writer, r: Response): Promise<void> {
|
||||||
if (!r.body) {
|
if (!r.body) {
|
||||||
r.body = new Uint8Array();
|
r.body = new Uint8Array();
|
||||||
}
|
}
|
||||||
|
if (typeof r.body === "string") {
|
||||||
|
r.body = encoder.encode(r.body);
|
||||||
|
}
|
||||||
|
|
||||||
let out = `HTTP/${protoMajor}.${protoMinor} ${statusCode} ${statusText}\r\n`;
|
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";
|
out += "\r\n";
|
||||||
|
|
||||||
const header = new TextEncoder().encode(out);
|
const header = encoder.encode(out);
|
||||||
const n = await writer.write(header);
|
const n = await writer.write(header);
|
||||||
assert(n === header.byteLength);
|
assert(n === header.byteLength);
|
||||||
|
|
||||||
|
@ -424,7 +429,7 @@ export class Server implements AsyncIterable<ServerRequest> {
|
||||||
try {
|
try {
|
||||||
await writeResponse(req!.w, {
|
await writeResponse(req!.w, {
|
||||||
status: 400,
|
status: 400,
|
||||||
body: new TextEncoder().encode(`${err.message}\r\n\r\n`)
|
body: encoder.encode(`${err.message}\r\n\r\n`)
|
||||||
});
|
});
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
// The connection is destroyed.
|
// The connection is destroyed.
|
||||||
|
@ -472,7 +477,7 @@ interface ServerConfig {
|
||||||
* Start a HTTP server
|
* Start a HTTP server
|
||||||
*
|
*
|
||||||
* import { serve } from "https://deno.land/std/http/server.ts";
|
* 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 });
|
* const s = serve({ port: 8000 });
|
||||||
* for await (const req of s) {
|
* for await (const req of s) {
|
||||||
* req.respond({ body });
|
* req.respond({ body });
|
||||||
|
@ -505,7 +510,7 @@ export type HTTPSOptions = Omit<Deno.ListenTLSOptions, "transport">;
|
||||||
/**
|
/**
|
||||||
* Create an HTTPS server with given options
|
* Create an HTTPS server with given options
|
||||||
*
|
*
|
||||||
* const body = new TextEncoder().encode("Hello HTTPS");
|
* const body = "Hello HTTPS";
|
||||||
* const options = {
|
* const options = {
|
||||||
* hostname: "localhost",
|
* hostname: "localhost",
|
||||||
* port: 443,
|
* port: 443,
|
||||||
|
@ -531,7 +536,7 @@ export function serveTLS(options: HTTPSOptions): Server {
|
||||||
/**
|
/**
|
||||||
* Create an HTTPS server with given options and request handler
|
* Create an HTTPS server with given options and request handler
|
||||||
*
|
*
|
||||||
* const body = new TextEncoder().encode("Hello HTTPS");
|
* const body = "Hello HTTPS";
|
||||||
* const options = {
|
* const options = {
|
||||||
* hostname: "localhost",
|
* hostname: "localhost",
|
||||||
* port: 443,
|
* 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 {
|
export interface Response {
|
||||||
status?: number;
|
status?: number;
|
||||||
headers?: Headers;
|
headers?: Headers;
|
||||||
body?: Uint8Array | Reader;
|
body?: Uint8Array | Reader | string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -346,6 +346,38 @@ test(async function writeUint8ArrayResponse(): Promise<void> {
|
||||||
assertEquals(eof, Deno.EOF);
|
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> {
|
test(async function writeStringReaderResponse(): Promise<void> {
|
||||||
const shortText = "Hello";
|
const shortText = "Hello";
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue