diff options
Diffstat (limited to 'http.ts')
| -rw-r--r-- | http.ts | 72 |
1 files changed, 64 insertions, 8 deletions
@@ -1,7 +1,8 @@ import { listen, Conn } from "deno"; -import { BufReader, BufState } from "./bufio.ts"; +import { BufReader, BufState, BufWriter } from "./bufio.ts"; import { TextProtoReader } from "./textproto.ts"; -import { Headers } from "./headers.ts"; +import { STATUS_TEXT } from "./http_status"; +import { assert } from "./util"; export async function* serve(addr: string) { const listener = listen("tcp", addr); @@ -14,9 +15,21 @@ export async function* serve(addr: string) { export async function* serveConn(c: Conn) { let bufr = new BufReader(c); + let bufw = new BufWriter(c); try { while (true) { - const req = await readRequest(bufr); + 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; yield req; } } finally { @@ -26,7 +39,19 @@ export async function* serveConn(c: Conn) { interface Response { status?: number; - body: string; + 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()); + } + } } class ServerRequest { @@ -34,13 +59,41 @@ class ServerRequest { method: string; proto: string; headers: Headers; + 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"); + } - respond(r: Response): Promise<void> { - throw Error("not implemented"); + 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(); } } -async function readRequest(b: BufReader): Promise<ServerRequest> { +async function readRequest(b: BufReader): Promise<[ServerRequest, BufState]> { const tp = new TextProtoReader(b); const req = new ServerRequest(); @@ -49,9 +102,12 @@ async function readRequest(b: BufReader): Promise<ServerRequest> { // First line: GET /index.html HTTP/1.0 [s, err] = await tp.readLine(); + if (err) { + return [null, err]; + } [req.method, req.url, req.proto] = s.split(" ", 3); [req.headers, err] = await tp.readMIMEHeader(); - return req; + return [req, err]; } |
