summaryrefslogtreecommitdiff
path: root/http.ts
diff options
context:
space:
mode:
Diffstat (limited to 'http.ts')
-rw-r--r--http.ts72
1 files changed, 64 insertions, 8 deletions
diff --git a/http.ts b/http.ts
index 0266501ae..4a4f0ccd9 100644
--- a/http.ts
+++ b/http.ts
@@ -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];
}