commit ed8cff624698690721a3e0489c3ce3dd96e1657a from: Omar Polo date: Thu Dec 21 23:11:54 2023 UTC http: move mux to its own file; allow to specify the mux per listen 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; +};