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:

  1. 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.
  2. 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.
  3. 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 to 304 range, and expects subsequent processing steps not to changes these unless an unequivocal error occurs.
  4. 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.
  5. The terminal processing pattern is when a plugin sets the status code to be in the 400 to 416 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.

  1. content-length is set to 0
  2. server is set to "rwserve"
  3. 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:

  1. 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 or if-none-match header the status code is set to 304 and the response body is set to empty.
    • If the incoming request does not have a if-match or if-none-match header, or if the generated Etag is different, a etag header is added to the response.
  2. The Cache Control module is called, if enabled, and its configured instructions are added in a cache-control header.
  3. The Content Encoding module is called, if enabled, to compress the payload, and a content-encoding header is added.
  4. content-length is set to the length of the payload
  5. server is set to "rwserve"
  6. 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:

  1. content-length is set to 0
  2. server is set to "rwserve"
  3. 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:

  1. The File Permission module determines whether the resource exists on the file system, is readable, and is not a directory.
  2. The Content Types module adds a content-type header based on the MIME-type mapped to the resource's filename extension.
  3. 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 or if-none-match header the status code is set to 304 and the response body is set to empty.
    • If the incoming request does not have a if-match or if-none-match header, or if the generated Etag is different, a etag header is added to the response.
  4. 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 of 304, or cause the addition of a last-modified header.
  5. The Cache Control module is called, if enabled, and its configured instructions are added in a cache-control header.
  6. 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.
  7. The Content Encoding module is called, if enabled, to compress the payload, and a content-encoding header is added.
  8. content-length is set to the size of the file (or the number of bytes for a range request)
  9. server is set to "rwserve"
  10. date is set to the current time using IETF RFC-5322 format
  11. 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:

  1. content-length is set to 0
  2. server is set to "rwserve"
  3. 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 to 304 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 to 416 range.

Plugin developer responsibilities