diff --git a/README.md b/README.md index aadf76b88..cde78af97 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ app.get ("/", (req, res) => { return res.extend_utf8 ("Hello world!"); }); -Server.new_with_application ("http", app.handle).run ({"app", "--forks=4"}); +Server.@new ("http", handler: app).run ({"app", "--forks=4"}); ``` diff --git a/docs/application.rst b/docs/application.rst index 4f5457027..2923e5fda 100644 --- a/docs/application.rst +++ b/docs/application.rst @@ -53,21 +53,11 @@ will be served with :doc:`vsgi/server/http`. :: - Server.new_with_application ("http", app.handle).run ({"app", "--port", "3003"}); + Server.new ("http", handler: app).run ({"app", "--port", "3003"}); :doc:`vsgi/server/index` takes a server implementation and an ``ApplicationCallback``, which is respected by the ``handle`` function. -Minimal application can be defined using a simple lambda function taking -a :doc:`vsgi/request` and :doc:`vsgi/response`. - -:: - - Server.new_with_application ("http", (req, res) => { - res.status = 200; - return res.expand_utf8 ("Hello world!"); - }).run ({"app", "--port", "3003"}); - Usually, you would only pass the CLI arguments to ``run``, so that your runtime can be parametrized easily, but in this case we just want our application to run with fixed parameters. Options are documented per implementation. @@ -79,6 +69,6 @@ run with fixed parameters. Options are documented per implementation. // assume some route declarations... - Server.new_with_application ("http", app.handle).run (args); + Server.new ("http", handler: app).run (args); } diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 6192d563e..65efb65c3 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -24,7 +24,7 @@ the latest changes in the framework. return res.expand_utf8 ("Hello world!"); }); - Server.new_with_application ("http", app.handle).run ({"app", "--port", "3003"}); + Server.new ("http", handler: app.handle).run ({"app", "--port", "3003"}); Typically, the ``run`` function contains CLI argument to make runtime the parametrizable. diff --git a/docs/recipes/persistence.rst b/docs/recipes/persistence.rst index bd1b62499..e47671db5 100644 --- a/docs/recipes/persistence.rst +++ b/docs/recipes/persistence.rst @@ -59,4 +59,4 @@ maintained in nemequ/vala-extra-vapis GitHub repository. return res.expand (value, null); }); - Server.new_with_application ("http", app.handle).run (); + Server.new ("http", handler: app).run (); diff --git a/docs/recipes/scripting.rst b/docs/recipes/scripting.rst index 8cae51bfb..7303005f7 100644 --- a/docs/recipes/scripting.rst +++ b/docs/recipes/scripting.rst @@ -40,7 +40,7 @@ Lua return res.expand_utf8 (lua.do_file ("scripts/hello.lua")); }); - Server.new_with_application ("http", app.handle).run (); + Server.new ("http", handler: app.handle).run (); The sample Lua script contains: diff --git a/docs/vsgi/authentication.rst b/docs/vsgi/authentication.rst index 5e9767327..55c964344 100644 --- a/docs/vsgi/authentication.rst +++ b/docs/vsgi/authentication.rst @@ -13,27 +13,21 @@ pattern is highlighted in the following example: :: - using VSGI; + var authentication = BasicAuthentication ("realm"); - Server.new_for_application ("http", (req, res) => { - var authentication = BasicAuthentication ("realm"); + var authorization_header = req.headers.get_one ("Authorization"); - var authorization_header = req.headers.get_one ("Authorization"); - - if (authorization_header != null) { - if (authentication.parse_authorization_header (authorization_header, - out authorization)) { - var user = User.from_username (authorization.username); - if (authorization.challenge (user.password)) { - return res.expand_utf8 ("Authentication successful!"); - } + if (authorization_header != null) { + if (authentication.parse_authorization_header (authorization_header, + out authorization)) { + var user = User.from_username (authorization.username); + if (authorization.challenge (user.password)) { + return res.expand_utf8 ("Authentication successful!"); } } + } - res.headers.replace ("WWW-Authenticate", authentication.to_authenticate_header ()); - - return res.end (); - }).run (); + res.headers.replace ("WWW-Authenticate", authentication.to_authenticate_header ()); Basic ----- diff --git a/docs/vsgi/connection.rst b/docs/vsgi/connection.rst index cfdb02e6e..939cf6f99 100644 --- a/docs/vsgi/connection.rst +++ b/docs/vsgi/connection.rst @@ -20,15 +20,10 @@ require the status to be part of the response headers. .. code:: - using VSGI; - - Server.new_with_application ("http", (req, res) => { - var message = req.connection.output_stream; - message.write_all ("200 Success HTTP/1.1\r\n".data. null); - message.write_all ("Connection: close\r\n"); - message.write_all ("Content-Type: text/plain\r\n"); - message.write_all ("\r\n".data); - message.write_all ("Hello world!".data); - return true; - }); + var message = req.connection.output_stream; + message.write_all ("200 Success HTTP/1.1\r\n".data. null); + message.write_all ("Connection: close\r\n"); + message.write_all ("Content-Type: text/plain\r\n"); + message.write_all ("\r\n".data); + message.write_all ("Hello world!".data); diff --git a/docs/vsgi/converters.rst b/docs/vsgi/converters.rst index 6061f4947..db1fbfc1d 100644 --- a/docs/vsgi/converters.rst +++ b/docs/vsgi/converters.rst @@ -20,11 +20,8 @@ using the ``convert`` method. :: - Server.new_with_application ("http", (req, res) => { - res.headers.append ("Content-Encoding", "gzip"); - res.convert (new ZlibCompressor (ZlibCompressorFormat.GZIP)); - return res.expand_utf8 ("Hello world!"); - }); + res.headers.append ("Content-Encoding", "gzip"); + res.convert (new ZlibCompressor (ZlibCompressorFormat.GZIP)); .. warning:: diff --git a/docs/vsgi/index.rst b/docs/vsgi/index.rst index 2775bcba4..761a7a901 100644 --- a/docs/vsgi/index.rst +++ b/docs/vsgi/index.rst @@ -21,25 +21,33 @@ library. VSGI produces process-based applications that are able to communicate with various HTTP servers using standardized protocols. -Entry point ------------ +Handler +------- -The entry point of a VSGI application is type-compatible with the -``ApplicationCallback`` delegate. It is a function of two arguments: -a :doc:`request` and a :doc:`response` that return a boolean indicating if the -request has been or will be processed. +The entry point of any VSGI application implement the ``Handler`` abstract +class. It provides a function of two arguments: a :doc:`request` and +a :doc:`response` that return a boolean indicating if the request has been or +will be processed. It may also raise an error. :: using VSGI; - Server.new_with_application ("http", (req, res) => { - // process the request and produce the response... - return true; - }).run (); + public class App : Handler { -If an application indicate that the request has not been processed, it's up to -the server implementation to decide what will happen. + public override handle (Request req, Response res) throws Error { + // process the request and produce the response... + return true; + } + } + + Server.new ("http", handler: new App ()).run (); + +If a handler indicate that the request has not been processed, it's up to the +server implementation to decide what will happen. + +From now on, examples will consist of ``Handler.handle`` content to remain +more concise. Error handling ~~~~~~~~~~~~~~ @@ -51,9 +59,7 @@ which will in turn teardown the connection appropriately. :: - Server.new_with_application ("http", (req, res) => { - throw new IOError.FAILED ("some I/O failed"); - }); + throw new IOError.FAILED ("some I/O failed"); Asynchronous processing ~~~~~~~~~~~~~~~~~~~~~~~ @@ -89,3 +95,42 @@ done as the following example demonstrates: var written = res.body.write_async.end (result); }); +Dynamic loading +~~~~~~~~~~~~~~~ + +.. versionadded:: 0.3 + +It could be handy to dynamically load handlers the same way +:doc:`server/index` are. + +Fortunately, this can be performed with the ``HandlerModule`` by providing +a directory and name for the shared library containing a dynamically loadable +application. + +:: + + var module = var new HandlerModule ("", ""); + + Server.new ("http", handler: Object.new (module.handler_type)).run (); + +The only required definition is a ``handler_init`` symbol that return the type +of some ``Handler``. In this case, the library should be located in ``/lib.so``, +although the actual name is system-dependant. + +:: + + [ModuleInit] + public Type handler_init (TypeModule type_module) { + return typeof (App); + } + + public class App : Handler { + + public bool handle (Request req, Response res) { + return res.expand_utf8 ("Hello world!"); + } + } + +Eventually, this will be used to provide a utility to run arbitrary +applications with support for live-reloading. + diff --git a/docs/vsgi/request.rst b/docs/vsgi/request.rst index 328971206..bac8aad54 100644 --- a/docs/vsgi/request.rst +++ b/docs/vsgi/request.rst @@ -49,10 +49,7 @@ and can be accessed from the ``headers`` property. :: - Server.new_with_application ("http", (req) => { - var accept = req.headers.get_one ("Accept"); - return true; - }); + var accept = req.headers.get_one ("Accept"); libsoup-2.4 provides a very extensive set of utilities to process the information contained in headers. @@ -129,10 +126,7 @@ freeing a file resource. :: - Server.new_with_application ("http", (req, res) => { - var payload = req.flatten (); - return true; - }); + var payload = req.flatten (); Form ~~~~ @@ -142,10 +136,7 @@ format, which is submitted by web browsers. :: - Server.new_with_application ("http", (req, res) => { - var data = Soup.Form.decode (req.flatten_utf8 (out bytes_read)); - return true; - }); + var data = Soup.Form.decode (req.flatten_utf8 (out bytes_read)); Multipart body ~~~~~~~~~~~~~~ diff --git a/docs/vsgi/response.rst b/docs/vsgi/response.rst index f1528dfe4..da8b4b94d 100644 --- a/docs/vsgi/response.rst +++ b/docs/vsgi/response.rst @@ -19,10 +19,7 @@ implementation to call it at a proper moment. :: - Server.new_with_application ("http", (req, res) => { - res.status = Soup.Status.MALFORMED; - return true; - }); + res.status = Soup.Status.MALFORMED; Reason phrase ------------- @@ -36,11 +33,8 @@ status line if ``write_head`` or ``write_head_async`` is invoked. :: - Server.new_with_application ("http", (req, res) => { - res.status = Soup.Status.OK; - res.reason_phrase = "Everything Went Well" - return true; - }); + res.status = Soup.Status.OK; + res.reason_phrase = "Everything Went Well" To obtain final status line sent to the user agent, use the ``wrote_status_line`` signal. @@ -61,11 +55,7 @@ from the ``headers`` property. :: - Server.new_with_application ("http", (req, res) => { - res.status = Soup.Status.OK; - res.headers.set_content_type ("text/plain", null); - return res.body.write_all ("Hello world!".data, null); - }); + res.headers.set_content_type ("text/plain", null); Headers can be written in the response synchronously by invoking ``write_head`` or asynchronously with ``write_head_async``. @@ -134,9 +124,7 @@ stream and close it properly. :: - Server.new_with_application ("http", (req, res) => { - res.expand_utf8 ("Hello world!"); - }); + res.expand_utf8 ("Hello world!"); Filtering ~~~~~~~~~ @@ -212,12 +200,8 @@ provided: :: - Server.new_with_application ("http", (req, res, next) => { - res.status = Soup.Status.NO_CONTENT; - return res.end () && next (); - }).then ((req, res) => { - // perform blocking operation here... - }); + res.status = Soup.Status.NO_CONTENT; + res.end (); To produce a message before closing, favour ``extend`` utilities. diff --git a/docs/vsgi/server/cgi.rst b/docs/vsgi/server/cgi.rst index bbfdcd0d4..7afd84868 100644 --- a/docs/vsgi/server/cgi.rst +++ b/docs/vsgi/server/cgi.rst @@ -30,13 +30,18 @@ necessary. :: - Server.new_with_application ("cgi", (req, res) => { - Timeout.add (5000, () => { - res.expand_utf8 ("Hello world!"); - return Source.REMOVE; - }); - return true; - }).run (); + public class App : Handler { + + public override bool handle (Request req, Response res) { + Timeout.add (5000, () => { + res.expand_utf8 ("Hello world!"); + return Source.REMOVE; + }); + return true; + } + } + + Server.new ("cgi", handler: new App ()).run (); lighttpd -------- diff --git a/docs/vsgi/server/http.rst b/docs/vsgi/server/http.rst index fb56a36e1..ddd1d860d 100644 --- a/docs/vsgi/server/http.rst +++ b/docs/vsgi/server/http.rst @@ -8,9 +8,7 @@ test your application or spawn workers in production. using Valum; - Server.new_with_application ("http", (req, res) => { - return res.expand_utf8 ("Hello world!"); - }).run ({"app", "--port", "3003"}); + var https_server = Server.new ("http", https: true); Parameters ---------- diff --git a/docs/vsgi/server/index.rst b/docs/vsgi/server/index.rst index a0b203cb4..533d275a9 100644 --- a/docs/vsgi/server/index.rst +++ b/docs/vsgi/server/index.rst @@ -28,15 +28,6 @@ GObject-style arguments as well. return res.expand_utf8 ("Hello world!"); }); -For typical case, use ``Server.new_with_application`` to initialize the -instance with an application identifier and callback: - -:: - - var cgi_server = Server.new_with_application ("cgi", (req, res) => { - return res.expand_utf8 ("Hello world!"); - }); - Custom implementation --------------------- @@ -134,9 +125,7 @@ to start serving incoming requests: using GLib; using VSGI; - var server = Server.new_with_application ("http", (req, res) => { - return res.expand_utf8 ("Hello world!"); - }); + var server = Server.new ("http"); server.listen (new InetSocketAddress (new InetAddress (SocketFamily.IPV4), 3003)); @@ -185,10 +174,7 @@ is a shorthand to create and run an application. using VSGI; public int main (string[] args) { - var server = Server.new_with_application ("http", (req, res) => { - return res.expand_utf8 ("Hello world!"); - }); - + var server = Server.new ("http"); return new Application (server).run (args); } diff --git a/examples/api-interaction/app.vala b/examples/api-interaction/app.vala index 1a52deee7..35b661824 100644 --- a/examples/api-interaction/app.vala +++ b/examples/api-interaction/app.vala @@ -61,4 +61,4 @@ app.get ("/", (req, res, next, ctx) => { return true; }); -Server.new_with_application ("http", app.handle).run (); +Server.@new ("http", handler: app).run (); diff --git a/examples/app/app.vala b/examples/app/app.vala index 9ca87331e..74a0de627 100644 --- a/examples/app/app.vala +++ b/examples/app/app.vala @@ -334,4 +334,4 @@ app.get ("/auth", authenticate (new BasicAuthentication (""), (a) => { return res.expand_utf8 ("Hello %s!".printf (username)); })); -Server.new_with_application ("http", app.handle).run (); +Server.@new ("http", handler: app).run (); diff --git a/examples/cgi/app.vala b/examples/cgi/app.vala index 573452baf..26f425cde 100644 --- a/examples/cgi/app.vala +++ b/examples/cgi/app.vala @@ -24,4 +24,4 @@ app.get ("/", (req, res) => { return res.expand_utf8 ("Hello world!"); }); -Server.new_with_application ("cgi", app.handle).run (); +Server.@new ("cgi", handler: app).run (); diff --git a/examples/fastcgi/app.vala b/examples/fastcgi/app.vala index 158d1ac8a..a08ef8ed5 100644 --- a/examples/fastcgi/app.vala +++ b/examples/fastcgi/app.vala @@ -26,5 +26,5 @@ public static int main (string[] args) { return res.expand_utf8 ("Hello world!"); }); - return Server.new_with_application ("fastcgi", app.handle).run (args); + return Server.@new ("fastcgi", handler: app).run (args); } diff --git a/examples/https/app.vala b/examples/https/app.vala index 82bc1024d..b653c1dc0 100644 --- a/examples/https/app.vala +++ b/examples/https/app.vala @@ -18,5 +18,5 @@ public int main (string[] args) { return 1; } - return Server.new_with_application ("http", app.handle, https: true, tls_certificate: tls_certificate).run (args); + return Server.@new ("http", handler: app, https: true, tls_certificate: tls_certificate).run (args); } diff --git a/examples/json/app.vala b/examples/json/app.vala index 46978bb7b..3cc22163b 100644 --- a/examples/json/app.vala +++ b/examples/json/app.vala @@ -45,4 +45,4 @@ app.get ("/", (req, res) => { return generator.to_stream (res.body); }); -Server.new_with_application ("http", app.handle).run (); +Server.@new ("http", handler: app).run (); diff --git a/examples/lua/app.vala b/examples/lua/app.vala index 7ed928f61..f673ae165 100644 --- a/examples/lua/app.vala +++ b/examples/lua/app.vala @@ -32,4 +32,4 @@ app.get ("/", (req, res) => { return res.expand_utf8 (vm.to_string (-1)); }); -Server.new_with_application ("http", app.handle).run (); +Server.@new ("http", handler: app).run (); diff --git a/examples/markdown/app.vala b/examples/markdown/app.vala index 9de7b61b0..76e909c9e 100644 --- a/examples/markdown/app.vala +++ b/examples/markdown/app.vala @@ -29,4 +29,4 @@ app.get ("/", (req, res) => { return res.expand_utf8 (markdown); }); -Server.new_with_application ("http", app.handle).run (); +Server.@new ("http", handler: app).run (); diff --git a/examples/memcached/app.vala b/examples/memcached/app.vala index e7fa4d9da..dbe98e206 100644 --- a/examples/memcached/app.vala +++ b/examples/memcached/app.vala @@ -69,4 +69,4 @@ app.delete ("/", (req, res, next, context) => { }); -Server.new_with_application ("http", app.handle).run (); +Server.@new ("http", handler: app).run (); diff --git a/examples/modular-app/app.vala b/examples/modular-app/app.vala index 60920f41c..69701ba3f 100644 --- a/examples/modular-app/app.vala +++ b/examples/modular-app/app.vala @@ -36,4 +36,4 @@ app.get ("/", (req, res) => { app.rule (Method.ANY, "/user/*", new UserRouter ().handle); app.rule (Method.ANY, "/admin/*", new AdminRouter ().handle); -Server.new_with_application ("http", app.handle).run (); +Server.@new ("http", handler: app).run (); diff --git a/examples/scgi/app.vala b/examples/scgi/app.vala index 8d98c8c05..634b7e8ac 100644 --- a/examples/scgi/app.vala +++ b/examples/scgi/app.vala @@ -25,5 +25,5 @@ public int main (string[] args) { return res.expand_utf8 ("Hello world!"); }); - return Server.new_with_application ("scgi", app.handle).run (args); + return Server.@new ("scgi", handler: app).run (args); } diff --git a/examples/template-glib/app.vala b/examples/template-glib/app.vala index 1b252ceb8..d59d4cdcf 100644 --- a/examples/template-glib/app.vala +++ b/examples/template-glib/app.vala @@ -17,5 +17,5 @@ app.get ("/", (req, res) => { return home.expand (res.body, scope); }); -Server.new_with_application ("http", "org.valum.example.TemplateGLib", app.handle).run (); +Server.new ("http", handler: app).run (); diff --git a/examples/vsgi/app.vala b/examples/vsgi/app.vala index 5495cd2b0..eabb981f5 100644 --- a/examples/vsgi/app.vala +++ b/examples/vsgi/app.vala @@ -17,8 +17,13 @@ using VSGI; -public int main (string[] args) { - return Server.new_with_application ("http", (req, res) => { +public class App : Handler { + + public override bool handle (Request req, Response res) throws Error { return res.expand_utf8 ("Hello world!"); - }).run (args); + } +} + +public int main (string[] args) { + return Server.@new ("http", handler: new App ()).run (args); } diff --git a/meson.build b/meson.build index be2fe556d..ce21ab558 100644 --- a/meson.build +++ b/meson.build @@ -15,7 +15,7 @@ add_global_arguments(['-Wall', language: 'c') add_global_arguments(['--enable-experimental', - '--enable-deprecated'], + '--enable-deprecated', '--vapi-comments'], language: 'vala') endif diff --git a/src/valum/valum-router.vala b/src/valum/valum-router.vala index 8f373dbbe..9dc86e82e 100644 --- a/src/valum/valum-router.vala +++ b/src/valum/valum-router.vala @@ -24,7 +24,7 @@ namespace Valum { * Dispatches incoming requests to the appropriate registered handler. */ [Version (since = "0.1")] - public class Router : Object { + public class Router : Handler { /** * Global routing context. @@ -385,12 +385,9 @@ namespace Valum { * If the request method is {@link VSGI.Request.OPTIONS}, a success * message will be produced with the 'Allow' header set accordingly. No * error will be thrown. - * - * Parameters and return values are complying with {@link VSGI.ApplicationCallback} - * and meant to be used as such. */ [Version (since = "0.1")] - public bool handle (Request req, Response res) throws Error { + public override bool handle (Request req, Response res) throws Error { return perform_routing (this.routes.get_begin_iter (), req, res, () => { if (req.method == Request.TRACE) { var head = new StringBuilder (); diff --git a/src/vsgi/meson.build b/src/vsgi/meson.build index 644412eea..2ce4df252 100644 --- a/src/vsgi/meson.build +++ b/src/vsgi/meson.build @@ -9,6 +9,8 @@ vsgi_sources = files( 'vsgi-cgi.vala', 'vsgi-connection.vala', 'vsgi-cookie-utils.vala', + 'vsgi-handler-module.vala', + 'vsgi-handler.vala', 'vsgi-mock.vala', 'vsgi-request.vala', 'vsgi-response.vala', diff --git a/src/vsgi/vsgi-handler-module.vala b/src/vsgi/vsgi-handler-module.vala new file mode 100644 index 000000000..a5b4c3687 --- /dev/null +++ b/src/vsgi/vsgi-handler-module.vala @@ -0,0 +1,96 @@ +/* + * This file is part of Valum. + * + * Valum is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Valum is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Valum. If not, see . + */ + +using GLib; + +/** + * Load custom {@link VSGI.Handler} implementations. + */ +[Version (since = "0.3")] +public class VSGI.HandlerModule : TypeModule { + + /** + * The directory from which the shared library will be searched, or 'null' + * to search in standard locations. + */ + [Version (since = "0.3")] + public string? directory { construct; get; } + + /** + * The name of the server implementation. + */ + [Version (since = "0.3")] + public string name { construct; get; } + + /** + * Path from which the module is loaded. + */ + [Version (since = "0.3")] + public string path { construct; get; } + + /** + * Once loaded, this contain the type of the {@link VSGI.Handler} provided + * by this. + */ + [Version (since = "0.3")] + public Type handler_type { get; private set; } + + private Module? module; + + [Version (since = "0.3")] + public HandlerModule (string? directory, string name) { + Object (directory: directory, name: name); + } + + construct { + path = Module.build_path (directory, name); + } + + public override bool load () { + module = Module.open (path, ModuleFlags.BIND_LAZY); + + if (module == null) { + critical (Module.error ()); + return false; + } + + void* func; + if (!module.symbol ("handler_init", out func)) { + critical (Module.error ()); + return false; + } + + if (func == null) { + critical ("No registration function was found in '%s'.", path); + return false; + } + + handler_type = ((HandlerInitFunc) func) (this); + + if (!handler_type.is_a (typeof (Handler))) { + critical ("The registration function must return a type derived from '%s'", + typeof (Handler).name ()); + return false; + } + + return true; + } + + public override void unload () { + module = null; + } +} diff --git a/src/vsgi/vsgi-handler.vala b/src/vsgi/vsgi-handler.vala new file mode 100644 index 000000000..147d23739 --- /dev/null +++ b/src/vsgi/vsgi-handler.vala @@ -0,0 +1,40 @@ +/* + * This file is part of Valum. + * + * Valum is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Valum is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Valum. If not, see . + */ + +using GLib; + +[Version (since = "0.3")] +public abstract class VSGI.Handler : Object { + + /** + * Process a pair of {@link VSGI.Request} and {@link VSGI.Response}. + * + * It is passed to a {@link VSGI.Server} in order to receive request to + * process. + * + * @throws Error unrecoverable error condition can be raised and will be + * handled by the implementation + * + * @param req a resource being requested + * @param res the response to that request + * + * @return 'true' if the request has been or will eventually be handled, + * otherwise 'false' + */ + [Version (since = "0.3")] + public abstract bool handle (Request req, Response res) throws Error; +} diff --git a/src/vsgi/vsgi-server.vala b/src/vsgi/vsgi-server.vala index ccd365be2..161d79c5f 100644 --- a/src/vsgi/vsgi-server.vala +++ b/src/vsgi/vsgi-server.vala @@ -20,8 +20,7 @@ using GLib; namespace VSGI { /** - * Server that feeds a {@link VSGI.ApplicationCallback} with incoming - * requests. + * Server that feeds a {@link VSGI.Handler} with incoming requests. * * Once you have initialized a Server instance, start it by calling * {@link GLib.Application.run} with the command-line arguments or a set of @@ -80,33 +79,10 @@ namespace VSGI { } /** - * Instantiate a new {@link VSGI.Server} with an initial application - * callback. - * - * @param name name of the server implementation to load - * @param callback initial application callback - * @param list arguments to pass to {@link GLib.Object.new} - * - * @return the server instance of loaded successfully, otherwise 'null' - * and a warning will be emitted - */ - [Version (since = "0.3")] - public static Server? new_valist_with_application (string name, owned ApplicationCallback callback, va_list list) { - var server = @new_valist (name, list); - if (server != null) { - server.set_application_callback ((owned) callback); - } - return server; - } - - /** - * Instantiate a new {@link VSGI.Server} with an initial application - * callback and varidic arguments. + * Handler processing incoming connections. */ [Version (since = "0.3")] - public static Server? new_with_application (string name, owned ApplicationCallback callback, ...) { - return new_valist_with_application (name, callback, va_list ()); - } + public Handler handler { get; construct set; } /** * URIs this server is listening on. @@ -114,16 +90,6 @@ namespace VSGI { [Version (since = "0.3")] public abstract SList uris { owned get; } - private ApplicationCallback? _application = null; - - /** - * Assign the callback used when {@link VSGI.Server.dispatch} is called. - */ - [Version (since = "0.3")] - public void set_application_callback (owned ApplicationCallback application) { - _application = (owned) application; - } - /** * Prepare the server for listening on the provided socket address. * @@ -194,11 +160,7 @@ namespace VSGI { */ [Version (since = "0.3")] protected bool dispatch (Request req, Response res) throws Error { - if (unlikely (_application == null)) { - error ("Use 'set_application_callback' to assign this an application."); - } else { - return _application (req, res); - } + return handler.handle (req, res); } /** diff --git a/src/vsgi/vsgi.vala b/src/vsgi/vsgi.vala index a7bbe128b..87a83a36c 100644 --- a/src/vsgi/vsgi.vala +++ b/src/vsgi/vsgi.vala @@ -26,24 +26,9 @@ using GLib; [CCode (gir_namespace = "VSGI", gir_version = "0.3")] namespace VSGI { - /** - * Process a pair of {@link VSGI.Request} and {@link VSGI.Response}. - * - * This delegate describe the signature of a compliant VSGI application. It - * is passed to a {@link VSGI.Server} in order to receive request to - * process. - * - * @throws Error unrecoverable error condition can be raised and will be - * handled by the implementation - * - * @param req a resource being requested - * @param res the response to that request - * - * @return 'true' if the request has been or will eventually be handled, - * otherwise 'false' - */ - [Version (since = "0.2")] - public delegate bool ApplicationCallback (Request req, Response res) throws Error; + [Version (since = "0.3")] + [CCode (has_target = false)] + public delegate Type HandlerInitFunc (TypeModule type_module); [Version (since = "0.3")] [CCode (has_target = false)]