Shunting the request/response cycle through custom handlers

Router

Preliminaries

This note describes how the server is configured to route dynamic resource requests.

The server can handle both static and dynamic resource requests.

A static resource request is defined as a request to receive, save, or delete the contents of a file of unvarying content. By contrast, a dynamic request is defined as a request to receive, save, or delete data of varying content, which is not serialized in a single file.

Sometimes static files are easy to recognize: images, audio, video, fonts, etc. are all examples. Other times static files are known to be static only to the webmaster: HTML documents, CSS style sheets, and JavaScript scripts outwardly appear to be static, but in fact may be generated on-the-fly by the server.

Some types of resource requests can't be fulfilled with static files. HTTP POST requests, for example, must be handled in an application specific way. HTTP GET requests that retrieve values from a database, are another example. These are common examples of dynamic requests.

When a static request is made to the server, standard HTTP protocol rules apply. The request's resource path and method determine what to process and how to process it: the resource path points to a file, and the GET, PUT or DELETE method is applied in a well-regulated way.

When a dynamic request is made to the server, HTTP protocol guidelines still dictate the rules-of-the-road, but no code exists on the server to actually carry out the request. This is where the router fits in.

The router shunts dynamic requests to plugin modules.

Normally, incoming requests work their way through a sequence of request handlers which check the validity of the request, then work their way through a sequence of response handlers to format the payload and its metadata into HTTP compliant responses. When a dynamic request is received, the router intercepts the processing cycle midway — between the request handlers and response handlers — and shunts the processing to the configured plugin handler.

The plugin handler is provided with pointers to the data structures that contain the request headers, payload, and response headers. What it does with them and how it does it, is application specific.

Configuration

The server's plugins section contains a router subsection which comprises a collection of entries, where each entry has a path-pattern, a list of applicable methods, and a plugin name.

Unlike most other configuration sections, all defined path patterns are scanned, in top-to-bottom order, allowing multiple plugins to chain their handling of requests. Refer to the separate note regarding Path Patterns for a description of how patterns are matched.

The list of applicable methods is a comma-separated list of HTTP methods which will be honored by the router.

The plugin name is a reference to a user-defined plugin name. Read more about declaring and configuring plugins in the separate note about Plugins.

During processing, the entries in the router section are scanned from top to bottom, and each matching entry triggers the use of the declared plugin. If the incoming request's path and method do not match any resource-pattern/method combination, the router returns control to the normal request/response cycle and the request is handled as a static file.

Placement

The router configuration section may appear in either the server/plugins section or a host/plugins section: merging is not supported. If values are placed in the host/plugins section they will be used in their entirety; if not, the values in the server/plugins section, if any, will be used as a fallback.

Information Headers

When a resource-pattern/method matches a request, but the plugin module is not reachable at its declared location, a rw-router-missing-module information header is added to the response and it returns with status code 500.

EBNF

SP ::= U+20
CR ::= U+0D
ASTERISK ::= U+2A
HYPHEN ::= U+2D
QUESTION-MARK ::= U+3F
SOLIDUS ::= U+2F
GRAVE-ACCENT ::= U+60
LEFT-CURLY-BRACKET ::= U+7B
RIGHT-CURLY-BRACKET ::= U+7D
file-system-chars ::= (ALPHA | DIGIT | )*
wildcards ::= ASTERISK | QUESTION-MARK
path-pattern ::= (SOLIDUS | file-system-chars | wildcards)*
delimited-path-pattern ::= GRAVE-ACCENT path-pattern GRAVE-ACCENT
method-name ::= 'HEAD' | 'GET' | 'PUT' | 'DELETE' | 'POST' | 'PATCH' | 'OPTIONS' | 'TRACE'
methods-attribute ::= ASTERISK 'methods' EQUALS-SIGN (method-name COMMA)*
plugin-name ::= (ALPHA | DIGIT | HYPHEN)*
plugin-attribute ::= ASTERISK 'plugin' EQUALS-SIGN plugin-name CR
router-entry ::= delimited-path-pattern SP methods-attribute SP plugin-attribute CR
router-section ::= 'router' SP LEFT-CURLY-BRACKET CR
router-entry*
RIGHT-CURLY-BRACKET CR

† Legal file system characters vary by platform

Cookbook

Example 1: Routing GET requests to built-in Blue plugin
server {
plugins {
router {
`*.blue` *methods=GET,HEAD *plugin=rwserve-blue
}
}
}
Example 2: Routing GET requests to built-in Counters plugin
server {
modules {
counters on
}
plugins {
router {
`/rwserve/counters/*` *methods=GET *plugin=rwserve-counters
}
}
}
Example 3: Routing POST requests to builtin RBAC-Auth plugin
server {
modules {
rbac on
}
plugins {
router {
`/login-logout/*` *methods=POST *plugin=rwserve-rbac-auth
}
}
}
Example 4: Routing POST requests to builtin policy report handler
server {
modules {
cross-origin on
policies on
}
request {
cross-origin {
`/notifications` *origin="domain.tld" *headers=content-type *methods=POST
}
}
plugins {
router {
`/notifications` *methods=POST *plugin=rwserve-policy-reports
}
}
}
Example 5: Routing PATCH requests to custom plugin

NOTE: The custom-patch-handler is exemplary only.

server {
plugins {
router {
`/api/*` *methods=PATCH *plugin=custom-patch-handler
}
}
}

Review

Key points to remember:

  • The request/response cycle can be interrupted by the router and shunted to plugin modules for handling.
  • Plugin handlers are called in top-to-bottom order, allowing multiple plugins to chain their handling of requests.

Shunting the request/response cycle through custom handlers