1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-12 18:42:18 -05:00
denoland-deno/http.ts

114 lines
2.5 KiB
TypeScript
Raw Normal View History

2018-11-08 15:03:45 -05:00
import { listen, Conn } from "deno";
2018-11-09 17:23:01 -05:00
import { BufReader, BufState, BufWriter } from "./bufio.ts";
2018-11-07 13:16:07 -05:00
import { TextProtoReader } from "./textproto.ts";
2018-11-09 17:23:01 -05:00
import { STATUS_TEXT } from "./http_status";
import { assert } from "./util";
2018-11-07 13:16:07 -05:00
2018-11-08 15:03:45 -05:00
export async function* serve(addr: string) {
const listener = listen("tcp", addr);
while (true) {
const c = await listener.accept();
yield* serveConn(c);
2018-11-07 13:16:07 -05:00
}
2018-11-08 15:03:45 -05:00
listener.close();
}
2018-11-07 13:16:07 -05:00
2018-11-08 15:03:45 -05:00
export async function* serveConn(c: Conn) {
let bufr = new BufReader(c);
2018-11-09 17:23:01 -05:00
let bufw = new BufWriter(c);
2018-11-08 15:03:45 -05:00
try {
while (true) {
2018-11-09 17:23:01 -05:00
const [req, err] = await readRequest(bufr);
if (err == "EOF") {
break;
}
if (err == "ShortWrite") {
console.log("ShortWrite error");
break;
}
if (err) {
throw err;
}
req.w = bufw;
2018-11-08 15:03:45 -05:00
yield req;
}
} finally {
c.close();
2018-11-07 13:16:07 -05:00
}
}
2018-11-08 15:03:45 -05:00
interface Response {
status?: number;
2018-11-09 17:23:01 -05:00
headers?: Headers;
body?: Uint8Array;
}
function setContentLength(r: Response): void {
if (r.body) {
if (!r.headers) {
r.headers = new Headers();
}
if (!r.headers.has("content-length")) {
r.headers.append("Content-Length", r.body.byteLength.toString());
}
}
2018-11-08 15:03:45 -05:00
}
2018-11-07 13:16:07 -05:00
2018-11-08 15:03:45 -05:00
class ServerRequest {
url: string;
method: string;
proto: string;
2018-11-08 18:15:26 -05:00
headers: Headers;
2018-11-09 17:23:01 -05:00
w: BufWriter;
async respond(r: Response): Promise<void> {
const protoMajor = 1;
const protoMinor = 1;
const statusCode = r.status || 200;
const statusText = STATUS_TEXT.get(statusCode);
if (!statusText) {
throw Error("bad status code");
}
2018-11-07 13:16:07 -05:00
2018-11-09 17:23:01 -05:00
let out = `HTTP/${protoMajor}.${protoMinor} ${r.status} ${statusText}\r\n`;
setContentLength(r);
if (r.headers) {
for (let [key, value] of r.headers) {
out += `${key}: ${value}\r\n`;
}
}
out += "\r\n";
const header = new TextEncoder().encode(out);
let n = await this.w.write(header);
assert(header.byteLength == n);
if (r.body) {
n = await this.w.write(r.body);
assert(r.body.byteLength == n);
}
await this.w.flush();
2018-11-07 01:08:51 -05:00
}
2018-11-07 13:16:07 -05:00
}
2018-11-07 01:08:51 -05:00
2018-11-09 17:23:01 -05:00
async function readRequest(b: BufReader): Promise<[ServerRequest, BufState]> {
2018-11-07 13:16:07 -05:00
const tp = new TextProtoReader(b);
const req = new ServerRequest();
2018-11-07 01:08:51 -05:00
2018-11-08 15:03:45 -05:00
let s: string;
let err: BufState;
2018-11-08 18:15:26 -05:00
// First line: GET /index.html HTTP/1.0
2018-11-08 15:03:45 -05:00
[s, err] = await tp.readLine();
2018-11-09 17:23:01 -05:00
if (err) {
return [null, err];
}
2018-11-08 18:15:26 -05:00
[req.method, req.url, req.proto] = s.split(" ", 3);
2018-11-07 13:16:07 -05:00
2018-11-08 18:15:26 -05:00
[req.headers, err] = await tp.readMIMEHeader();
2018-11-08 15:03:45 -05:00
2018-11-09 17:23:01 -05:00
return [req, err];
2018-11-07 01:08:51 -05:00
}