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