shithub: mc

Download patch

ref: 3d956b3adc6dc8e32cf17e2baa0a2408295ae12f
parent: f37c8970f11e21b0b6f29c4aac10f92101d0c906
author: Ori Bernstein <ori@eigenstate.org>
date: Sat Apr 22 15:57:30 EDT 2017

Working demo server.

--- a/lib/http/parse.myr
+++ b/lib/http/parse.myr
@@ -22,7 +22,6 @@
 		.params=[][:],
 	])
 
-	std.put("parsing request\n")
 	match bio.readln(s.f)
 	| `bio.Err e:
 		err = `Econn
@@ -31,11 +30,9 @@
 		err = `Econn
 		goto error
 	| `bio.Ok ln:
-		std.put("status line: {}\n", ln)
 		match parsereqstatus(s, r, ln)
 		| `std.Ok void:
 		| `std.Err e:
-			std.put("err: {}\n", e)
 			std.slfree(ln)
 			err = e
 			-> `std.Err e
@@ -44,7 +41,6 @@
 	;;
 
 	while true
-		std.put("parsing headers\n")
 		match bio.readln(s.f)
 		| `bio.Err e:	
 			err = `Econn
@@ -53,7 +49,6 @@
 			err = `Econn
 			goto error
 		| `bio.Ok ln:
-			std.put("ln: {}\n", ln)
 			if std.strstrip(ln).len == 0
 				std.slfree(ln)
 				break
@@ -127,25 +122,27 @@
 }
 
 const parsereqstatus = {s, r, ln
-	var m, p, v
-
 	match parseword(&ln)
-	| `std.Some w:	m = w
+	| `std.Some "GET":	r.method = `Get
+	| `std.Some "HEAD":	r.method = `Head
+	| `std.Some "POST":	r.method = `Post
+	| `std.Some "DELETE":	r.method = `Delete
+	| `std.Some "TRACE":	r.method = `Trace
+	| `std.Some "OPTIONS":	r.method = `Options
+	| `std.Some _:	-> `std.Err `Eproto
 	| `std.None:	-> `std.Err `Eproto
 	;;
-	std.put("got method: {}\n", m)
 
 	match parseword(&ln)
-	| `std.Some w:	p = w
+	| `std.Some w:	r.url.path = std.sldup(w)
 	| `std.None:	-> `std.Err `Eproto
 	;;
-	std.put("got path: {}\n", p)
 
 	match parseword(&ln)
-	| `std.Some w:	v = w
+	| `std.Some "HTTP/1.1":	/* ok */
+	| `std.Some w:	std.put("warn: http version '{}'\n", w)
 	| `std.None:	-> `std.Err `Eproto
 	;;
-	std.put("got version: {}\n", v)
 
 	ln = std.strfstrip(ln)
 	-> `std.Ok void
--- a/lib/http/server.myr
+++ b/lib/http/server.myr
@@ -9,7 +9,8 @@
 pkg http =
 	const announce	: (ds : byte[:] -> std.result(server#, err))
 	const shutdown	: (srv : server# -> void)
-	const serve	: (srv : server# -> void)
+	const serve	: (srv : server#, fn : (srv : server#, s : session#, req : req# -> void) -> void)
+	const respond	: (srv : server#, sess : session#, resp : resp# -> void)
 ;;
 
 const announce = {ds
@@ -28,44 +29,27 @@
 	;;
 }
 
-const serve = {srv
+const serve = {srv, fn
 	while true
 		match waitconn(srv)
 		| `std.Ok fd:	
-			thread.spawn({;communicate(srv, fd)})
+			thread.spawn({;communicate(srv, fd, fn)})
 		| `std.Err e:	/* eh? */
 		;;
 	;;
 }
 
-const communicate = {srv, fd
+const communicate = {srv, fd, fn
 	var s
 
 	s = mksrvsession(fd)
 	while !srv.quit
 		match parsereq(s)
-		| `std.Ok req:
-			dispatch(srv, s, req)
-		| `std.Err e:
-			break
+		| `std.Ok req:	fn(srv, s, req)
+		| `std.Err e:	break
 		;;
 	;;
 	std.close(fd)
-}
-
-const dispatch = {srv, sess, req
-	var resp : resp#
-
-	resp = std.mk([
-		.status=200,
-		.hdrs = [][:],
-		.len = 0,
-		.err = `std.None,
-		.reason = "",
-		.body = "pong\n",
-		.enc = `Length
-	])
-	respond(srv, sess, resp)
 }
 
 const respond = {srv, s, resp
--- a/lib/http/session.myr
+++ b/lib/http/session.myr
@@ -8,10 +8,6 @@
 	const mksrvsession	: (fd	: std.fd -> session#)
 	const freesession	: (s : session# -> void)
 
-	//const setcookie	: (s : session#, name : byte[:], val : byte[:] -> void)
-	//const getcookie	: (s : session#, name : byte[:] -> void)
-	//const clearjar	: (s : session# -> void)
-
 	pkglocal const ioput	: (s : session#, fmt : byte[:], args : ... -> bool)
 	pkglocal const ioflush	: (s : session# -> void)
 ;;
--- a/lib/http/srvdot.myr
+++ b/lib/http/srvdot.myr
@@ -9,41 +9,45 @@
 	| `std.Err e:	std.fatal("unable to announce: {}\n", e)
 	;;
 
-	http.serve(srv)
+	http.serve(srv, route)
+}
+
+const route = {srv, sess, req
+	std.put("Reading path {}\n", req.url.path)
+	match req.url.path
+	| "/ping":	respond(srv, sess, 200, "pong")
+	| fspath:	showfile(srv, sess, req.url.path)
+	;;
+}
+
+const showfile = {srv, sess, path
+	var eb : byte[128]
+	var p
 
-	//router = http.mkrouter(srv, [
-	//	[.path="*", .render=showfile],
-	//	[.path="/foo", .render={ctx; show(ctx, "foo")}],
-	//	[.path="/foo/bar", .render={ctx; show(ctx, "foobar")}],
-	//	[.path="/foo/baz", .render={ctx; show(ctx, "foobarbaz")}],
-	//][:])
-	//
-	//http.run(router)
+	p = std.pathcat(".", path)
+	match std.slurp(p)
+	| `std.Ok buf:
+		respond(srv, sess, 200, buf)
+		std.slfree(buf)
+	| `std.Err e:
+		respond(srv, sess, 404, std.bfmt(eb[:], "error reading {}: {}\n", p, e))
+	;;
+	std.slfree(p)
 }
 
-// const showfile = {ctx
-// 	var buf : byte[32*std.KiB]
-// 	var fd
-// 
-// 	match std.open(ctx.path, std.Ordonly)
-// 	| `std.Ok f:
-// 		fd = f
-// 	| `std.Err e:
-// 		http.srvput(ctx, "unable to open path {}\n", ctx.path)
-// 		-> 404
-// 	;;
-// 
-// 	http.setchunk(ctx)
-// 	while true
-// 		match std.read(fd, buf[:])
-// 		| `std.Ok n:	http.writechunk(ctx, buf[:n])
-// 		| `std.Ok 0:	http.closechunk(ctx); break
-// 		| `std.Err e:	http.closechunk(ctx); break
-// 		;;
-// 	;;
-// 	-> 200
-// }
-// 
-// const show = {ctx, txt
-// 	http.srvput(ctx, "{}", txt)
-// }
+
+const respond = {srv, sess, status, body
+	var resp
+
+	resp = std.mk([
+		.status=status,
+		.hdrs = [][:],
+		.len = 0,
+		.err = `std.None,
+		.reason = "",
+		.body = body,
+		.enc = `http.Length
+	])
+	http.respond(srv, sess, resp)
+	std.free(resp)
+}
--- a/lib/http/types.myr
+++ b/lib/http/types.myr
@@ -82,6 +82,7 @@
 		url	: url#
 		hdrs	: (byte[:], byte[:])[:]
 		err	: std.option(err)
+		method	: method
 	;;
 
 	type resp = struct