Plugin developer responsibilities
Processing Sequence
Preliminaries
This note describes the request/response processing sequence from the plugin developer's perspective. The responsibilities incumbent upon the developer are outlined for plugins following typical patterns.
Plugin Patterns
Plugins play a role in a long sequence of processing steps, comprising: built-in request modules which validate, sanitize, and authorize the request; the router module which shunts requests to plugins; the plugins themselves; and built-in response modules which compress, cache, and add standard outgoing headers.
Each built-in module and dynamic plugin is responsible for communicating to subsequent response modules and plugins whether any further processing is expected. This is implicitly conveyed through the presence or absence of a response status code and a payload type. There are five patterns that a plugin may follow:
- The chainable processing pattern is when a plugin expects subsequent processing by other plugins and response modules to be taken as usual after its own work has finished.
- The response-body processing pattern is when a plugin has set the response body, and expects subsequent processing steps to honor its content when performing their work, and expects the final status code to be
200
if nothing goes wrong. - The empty-body processing pattern is when a plugin has explicitly instructed that no payload be present in the final response body, and that the status code should be in the
201
to304
range, and expects subsequent processing steps not to changes these unless an unequivocal error occurs. - The static file processing pattern is when a resource request matches a file in the public document path. Static file processing occurs after all plugins perform their work, and only when
setStatusCode()
has not been called. - The terminal processing pattern is when a plugin sets the status code to be in the
400
to416
range, and no further work should be performed by any subsequent plugin or response module.
Chainable processing
Chainable processing occurs when a plugin examines the work order's request headers in order to perform some work or make some decision that does not involve the response body or the final status code. Examples might include:
- Adding extra headers to the response
- Capturing statistical data and holding it in memory
- Saving data to a file on the server
- Examining or changing the server's state
- Communicating with another networked service
Response-body processing
Response-body processing occurs when the plugin dynamically creates the content, uses the setOutgoingPayload()
method to set the response body, adds a header to indicate the content-type
, and uses the setStatusCode(200)
method to indicate "OK". Examples include:
- Retrieving data from a database where the response body contains rows from tables
- Inserting, updating or deleting data in a database where the response body contains metadata about the success of the operation
With this type of request, the response body should be further processed by the built-on modules to compress the payload if content-encoding
is enabled, add caching instructions if cache-control
is enabled, generate an Etag if etags
are enabled, and calculate the content-length
.
Empty-body processing
Empty-body processing occurs when the plugin successfully performs some work that does not result in a response body. In this pattern the setEmptyPayload()
method should be called by the plugin together with a setStatusCode()
value of 201
CREATED, 204
NO CONTENT, 206
PARTIAL CONTENT, 302
FOUND, 303
SEE OTHER, or 304
NOT MODIFIED. (Other values in the 200
and 300
range sets may also apply here.) Examples include:
- Uploading a file to the server (
201
) - Handling HTML <form> data without redirecting to a different page (
204
) - Retrieving a range of bytes from a resource (
206
) - Adding a
location
header to temporarily redirect the response to a different page (302
) - Adding a
location
header after a successful POST to redirect to a confirmation page (303
) - Responding to a second request for a resource by informing the user-agent that it already has a copy of it (
304
)
With this type of request, subsequent plugins are called, but with the expectation that they will conduct chainable processing only. The built-in response modules are not called because there is no payload to compress or cache.
Static file processing
Static file processing occurs when the response body is created directly from a requested resource path that matches a file in the server's public document path. This is the implied handling routine for GET
and HEAD
requests. In order for this pattern to complete as expected, any plugin that is called during its processing sequence must follow the chainable processing pattern only.
Terminal processing
Terminal processing occurs when the plugin determines that no further work should be performed on the request. In this pattern the plugin calls setStatusCode()
with a value in the 400
to 416
range. No further plugins are called, the setEmptyPayload()
method is implied, and the response modules that examine the payload are automatically bypassed.
Standard response processing
After all plugins have completed their work, the processing sequence continues with the built-in response modules.
Chainable pattern
When all plugins follow the chainable processing pattern and no status code has been set by any of them, the server sets the status code to 200
and adds these headers.
content-length
is set to 0server
is set to "rwserve"date
is set to the current time using IETF RFC-5322 format
Response-body pattern
When the pattern is response-body, and a status code has been set by the plugin, the server calls these standard modules for additional processing:
- The Etag module is called, if enabled, and an Etag is generated from the hashed value of the response body.
- If the hashed value matches the incoming request's
if-match
orif-none-match
header the status code is set to304
and the response body is set to empty. - If the incoming request does not have a
if-match
orif-none-match
header, or if the generated Etag is different, aetag
header is added to the response. - The Cache Control module is called, if enabled, and its configured instructions are added in a
cache-control
header. - The Content Encoding module is called, if enabled, to compress the payload, and a
content-encoding
header is added. content-length
is set to the length of the payloadserver
is set to "rwserve"date
is set to the current time using IETF RFC-5322 format
Empty-body pattern
When the pattern is empty-body, a status code should have been set by the plugin, so the server simply adds these headers before sending the response:
content-length
is set to 0server
is set to "rwserve"date
is set to the current time using IETF RFC-5322 format
Static file pattern
When the pattern is static file and the method is GET
the server calls these standard modules:
- The File Permission module determines whether the resource exists on the file system, is readable, and is not a directory.
- The Content Types module adds a
content-type
header based on the MIME-type mapped to the resource's filename extension. - The Etag module is called, if enabled, and an Etag is generated from the SHA1 hash of the file's modification time and file size.
- If the hashed value matches the incoming request's
if-match
orif-none-match
header the status code is set to304
and the response body is set to empty. - If the incoming request does not have a
if-match
orif-none-match
header, or if the generated Etag is different, aetag
header is added to the response. - The If Modified Since module is called and the file's modification time is compared to the request's
if-modified-since
header which may conditionally either trigger a status code of304
, or cause the addition of alast-modified
header. - The Cache Control module is called, if enabled, and its configured instructions are added in a
cache-control
header. - The Range module is called, if enabled, and a subset of the file's bytes is added to the response body when a properly specified
range
request header is present. - The Content Encoding module is called, if enabled, to compress the payload, and a
content-encoding
header is added. content-length
is set to the size of the file (or the number of bytes for a range request)server
is set to "rwserve"date
is set to the current time using IETF RFC-5322 format- If the status code was not set by any of the built-in modules, it is set to
200
.
Terminal pattern
When the pattern is terminal, a status code should have been set by the plugin. Any residual outgoing payload is discarded, and the server adds these headers before sending the response:
content-length
is set to 0server
is set to "rwserve"date
is set to the current time using IETF RFC-5322 format
Review
Key points to remember:
- Chainable processing is when no payload is set and no status code is set.
- Response-body processing is when a response body is set and the status code is set to
200
. - Empty-body processing is when an empty payload is explicitly set and the status code is set in the
201
to304
range. - Static file processing occurs after all plugins perform their work, and only when no status code has been set by a plugin.
- Terminal processing is when a plugin sets the status code to be in the
400
to416
range.