Static Resource Delivery

Middlewares in the valum-0.3/Valum.Static namespace ensure delivery of static resources.

using Valum.Static;

As of convention, all middleware use the path context key to resolve the resource to be served. This can easily be specified using a rule parameter with the path type.

For more flexibility, one can compute the path value and pass the control with next. The following example obtains the key from the HTTP query:

app.get ("/static", sequence ((req, res, next, ctx) => {
    ctx["path"] = req.lookup_query ("path") ?? "index.html";
    return next ();
}, serve_from_file (File.new_for_uri ("resource://"))));

If a HEAD request is performed, the payload will be omitted.

File backend

The valum-0.3/Valum.Static.serve_from_file middleware will serve resources relative to a gio-2.0/GLib.File instance.

app.get ("/static/<path:path>", serve_from_file (File.new_for_path ("static")));

To deliver from the global resources, use the resource:// scheme.

app.get ("/static/<path:path>", serve_from_file (File.new_for_uri ("resource://static")));

Before being served, each file is forwarded to make it possible to modify headers more specifically or raise a last-minute error.

Once done, invoke the next continuation to send over the content.

app.get ("/static/<path:path>", serve_from_file (File.new_for_path ("static"),
                                                 ServeFlags.NONE,
                                                 (req, res, next, ctx, file) => {
    var user = ctx["user"] as User;
    if (!user.can_access (file)) {
        throw new ClientError.FORBIDDEN ("You cannot access this file.")
    }
    return next ();
}));

Helpers

Two helpers are provided for File-based delivery: valum-0.3/Valum.Static.serve_from_path and valum-0.3/Valum.Static.serve_from_uri.

app.get ("/static/<path:path>", serve_from_path ("static/<path:path>"));

app.get ("/static/<path:path>", serve_from_uri ("static/<path:path>"));

Resource backend

The valum-0.3/Valum.Static.serve_from_resource middleware is provided to serve a resource bundle (see gio-2.0/GLib.Resource) from a given prefix. Note that the prefix must be a valid path, starting and ending with a slash / character.

app.get ("/static/<path:path>", serve_from_resource (Resource.load ("resource"),
                                                     "/static/"));

Compression

To compress static resources, it is best to negotiate a compression encoding with a Content Negotiation middleware: body stream and headers will be set properly if the encoding is supported.

Using the identity encoding provide a fallback in case the user agent does not want compression and prevent a 406 Not Acceptable from being raised.

app.get ("/static/<path:path>", sequence (accept_encoding ("gzip, deflate, identity"),
                                          serve_from_path ("static")));

Content type detection

The middlewares will detect the content type based on the file name and a lookup on its content.

Content type detection, based on the file name and a small data lookup, is performed with GLib.ContentType.

Deal with missing resources

If a resource is not available (eg. the file does not exist), the control will be forwarded to the next route.

One can use that behaviour to implement a cascading failover with the Sequence middleware.

app.get ("/static/<path:path", sequence (serve_from_path ("~/.local/app/static"),
                                         serve_from_path ("/usr/share/app/static")));

To generate a 404 Not Found, just raise a valum-0.3/Valum.ClientError.NOT_FOUND as described in Redirection and Error.

app.use (basic ());

app.get ("/static/<path:path>", sequence (serve_from_uri ("resource://"),
                                          (req, res, next, ctx) => {
    throw new ClientError.NOT_FOUND ("The static resource '%s' were not found.",
                                     ctx["path"]);
}));

Options

Options are provided as flags from the valum-0.3/Valum.Static.ServeFlags enumeration.

ETag

If the valum-0.3/Valum.Static.ServeFlags.ENABLE_ETAG is specified, a checksum of the resource will be generated in the ETag header.

If set and available, it will have precedence over valadoc:valum-0.3/Valum.Static.ServeFlags.ENABLE_LAST_MODIFIED described below.

Last-Modified

Unlike ETag, this caching feature is time-based and will indicate the last modification on the resource. This is only available for some File backend and will fallback to ETag if enabled as well.

Specify the valum-0.3/Valum.Static.ServeFlags.ENABLE_LAST_MODIFIED to enable this feature.

X-Sendfile

If the application run behind a HTTP server which have access to the resources, it might be preferable to let it serve them directly with valum-0.3/Valum.Static.ServeFlags.X_SENDFILE.

app.get ("/static/<path:path>", serve_from_path ("static", ServeFlags.X_SENDFILE));

If files are not locally available, they will be served directly.

Public caching

The valum-0.3/Valum.Static.ServeFlags.ENABLE_CACHE_CONTROL_PUBLIC let intermediate HTTP servers cache the payload by attaching a Cache-Control: public header to the response.

Expose missing permissions

The valum-0.3/Valum.Static.ServeFlags.FORBID_ON_MISSING_RIGHTS will trigger a 403 Forbidden if rights are missing to read a file. This is not a default as it may expose information about the existence of certain files.