Commit Diff


commit - 4ea63b457e8a1e2ee9e96e354fa90da2c7aa88e7
commit + ed8cff624698690721a3e0489c3ce3dd96e1657a
blob - 5dbdc740fb3a5ef07ae666039271cdd4501ccb2d
blob + c7ac521478186bb7bea8b5f7b1d11cc26867a89c
--- http/http.ha
+++ http/http.ha
@@ -25,7 +25,6 @@ use bufio;
 use encoding::utf8;
 use errors;
 use fmt;
-use fnmatch;
 use io;
 use log;
 use net;
@@ -76,28 +75,15 @@ type connection = struct {
 	mux: *mux,
 };
 
-export type route = struct {
-	pattern: str,
-	routefn: routefn,
-};
-
-export type mux = []route;
-
-let global: mux = [];
-
-export fn handle(pattern: str, routefn: routefn) void = {
-	append(global, route {
-		pattern = pattern,
-		routefn = routefn,
-	});
-};
-
 // XXX generic listen would be very handy!
 // something like: http::listen("localhost:8080") or maybe even
 // http::listen("unix:/run/foo.sock")
 
-export fn listen_sock(f: io::file) void = {
-	ev::add(f, ev::READ, &acceptconn, &global);
+export fn listen_sock(f: io::file, mux: nullable *mux) void = {
+	ev::add(f, ev::READ, &acceptconn, match(mux) {
+		case null => yield &global;
+		case => yield mux;
+	});
 };
 
 fn acceptconn(f: io::file, ev: ev::event, data: nullable *opaque) void = {
@@ -229,16 +215,9 @@ fn handle_request(conn: *connection) (void | io::error
 		return;
 	};
 
-	let path = conn.request.path;
-	log::printfln("< GET {}", path);
+	log::printfln("< GET {}", conn.request.path);
 
-	for (let i = 0z; i < len(conn.mux); i += 1) {
-		if (fnmatch::fnmatch(conn.mux[i].pattern, path)) {
-			conn.routefn = conn.mux[i].routefn;
-			break;
-		};
-	};
-
+	conn.routefn = mux_match(conn.mux, &conn.request, &route_notfound);
 	conn.request_done = true;
 };
 
blob - /dev/null
blob + 32f7f9b4e954a55b4fbc576137132c67b363086e (mode 644)
--- /dev/null
+++ http/mux.ha
@@ -0,0 +1,56 @@
+// This is free and unencumbered software released into the public domain.
+//
+// Anyone is free to copy, modify, publish, use, compile, sell, or
+// distribute this software, either in source code form or as a compiled
+// binary, for any purpose, commercial or non-commercial, and by any
+// means.
+//
+// In jurisdictions that recognize copyright laws, the author or authors
+// of this software dedicate any and all copyright interest in the
+// software to the public domain. We make this dedication for the benefit
+// of the public at large and to the detriment of our heirs and
+// successors. We intend this dedication to be an overt act of
+// relinquishment in perpetuity of all present and future rights to this
+// software under copyright law.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+
+use fnmatch;
+
+export type route = struct {
+	pattern: str,
+	routefn: routefn,
+};
+
+export type mux = []route;
+
+let global: mux = [];
+
+export fn newmux() mux = [];
+
+export fn handle(pattern: str, routefn: routefn) void = {
+	handle_mux(&global, pattern, routefn);
+};
+
+export fn handle_mux(mux: *mux, pattern: str, routefn: routefn) void = {
+	append(mux, route {
+		pattern = pattern,
+		routefn = routefn,
+	});
+};
+
+export fn mux_match(mux: *mux, req: *request, default: routefn) routefn = {
+	for (let i = 0z; i < len(mux); i += 1) {
+		if (fnmatch::fnmatch(mux[i].pattern, req.path)) {
+			return mux[i].routefn;
+		};
+	};
+
+	return default;
+};