handlers.RdaddHandler adds a content handler to be used with the
webserver.
rmAllHandlers removes all currently registered handlers.
defaultBodyParsers returns the request body parsers used by R
function handlers with parse.body=TRUE.
addHandler(type, prefix, ...)
rmAllHandlers()
defaultBodyParsers()undefined (currently returns TRUE invisibly, but that is not
guaranteed for the future).
For each webserver request the content handlers are matched in sequence against the request's path and each matching handler gets a chance to provide the result for the request.
Most commonly used handlers are "static" which serves files from
the file system, "rfun" which registers an R function to be
called with the request details and "rewrite" which modifies the
request path according to specified rules.
Syntax: addHandler("static", prefix, path, index=NULL,
stop=FALSE, gzip=FALSE)
path must be an existing directory. It is expanded (see
path.expand) and converted to an absolute path when the
handler is added (on unix symbolic links are
resolved), so later changes of the working directory have no effect.
When the prefix is matched, it is removed from the request path
and the remaining path is appended to path to look up
files. If the target matches a directory and index is a string,
then index is appended to the path, unless the trailing slash is
missing in which case a re-direct is returned to add the slash (this
makes sure that relative paths in the index stay valid).
If the resulting target is a file, it is served as the request result.
Otherwise either 404 Not Found response is sent (if stop=TRUE)
or the processing is passed to the next handler.
The static handler supports conditional GET requests based on last
modified timestamp. It also supports HTTP range requests. If
gzip=TRUE and the client has requested gzip compression then the
handler checks if a file <target>.gz exists and is not older than
<target> then the compressed file is served instead. This saves
bandwidth for compressible static content.
Example:
addHandler("static", "/", path=".", index="index.html", stop=TRUE)
Serves files from the current directory (at the time of the call) at the root of URLs. It will stop and not evaluate any further handlers even if the file is not found.
This handler calls an R function with the same API as the internal R server and Rserve.
addHandler("rfun", prefix, FUN, parse.query=TRUE,
parse.headers=TRUE, parse.body=FALSE, fork=FALSE)
function to call for a request (see below for details)
logical, if TRUE then the query string is
parsed into a named character vector, otherwise it is just one
string (see below)
logical, if TRUE then the headers are
parsed (see below), otherwise just a raw vector
FALSE to pass the request body as-is,
TRUE to decode it with the parsers returned by
defaultBodyParsers() or a named list of parsers (see below)
logical, if TRUE then the R processing will be
delegated to forked workers, one per each I/O thread (not
available on Windows). Otherwise the R code is evaluated in the
current session.
The function FUN should have the following signature:
function(path, query, body, headers, ...)
string, path of the request
query string part of the request. If
parse.query=TRUE (the default) then the query string is
parsed into a named character vector, so, e.g., the query string
"a=1&b=foo" will be parsed into the R object
c(a="1", b="foo"). Otherwise it is just the string itself.
body part of the request or NULL if there is no
body. Unless it is decoded by a parser (see parse.body
below), it is a raw vector with the "content-type"
attribute (if specified by the client).
request headers. It is a raw vector unless
parse.headers=TRUE in which case the headers are parsed
into a named list where the header names are lowercase and the
"-" character is replaced by "." so, for example,
User-Agent is stored in the user.agent element of
the list. Note that the parsing is experimental, since the
interpretation can vary among header entries.
The server adds the following headers which are always present
unless stated otherwise: Request-Method (request.method
when parsed) is the request method name (GET, POST,
etc.), Request-Proto (request.proto) is http or
https, depending on the listener the request was received
on, and Request-Client-CN (request.client.cn) is
the common name of the client certificate. The latter is only
present if the client has presented a valid certificate, i.e.,
on HTTPS listeners with tls.client.ca set (see
webstart), and the certificate has a common name
that can be passed in a header (without control characters and
not excessively long), so handlers can use it to identify the
client. Header names starting with Request- are reserved for
the server, so such headers sent by the client are dropped.
Behind a reverse proxy, these describe the connection from the proxy,
the proxy may pass the original protocol on in another header
such as X-Forwarded-Proto.
reserved for future extensions
The result is expected to have the following form:
list(result, content.type, headers, http.code)
Only the first list element is mandatory, all others are optional.
Can be either a string or a raw vector containing the
body of the result to return to the client. As a special case, the
result can be a named character vector of length one with either
file or tempfile name in which case the result is
interpreted as a path to a file whose contents will be served.
In the case of tempfile the file will be removed once read.
string, MIME type of the result, defaults to
"text/html"
character vector (unnamed) of any additional headers
to send. Note that it may not contain Content-Type nor
Content-Length.
integer, valid HTTP code (100..999), defaults to 200L
One exception is that returning FALSE indicates that the
handler has refused to process the request and so the search should
continue to the next handler. Note that due to the relatively
expensive nature of some evaluation methods (such as worker
communication) it is recommended to consolidate R handlers instead of
relying on each to signal its unwillingness to process the request.
If the returned object has any other form (e.g. if it is a character vector), it is assumed to be an error and it will result in 500 HTTP error code.
Example: addHandler("rfun", "/api/v1/add",
function(path, query, ...)
list(as.numeric(query["a"]) + as.numeric(query["b"])))
Body parsers. A parser is a function function(body,
content.type) which receives the request body (raw vector) and the
value of the Content-Type header (including parameters such as
charset) and returns the decoded body which is then passed to
FUN. The names of the list of parsers are media types (matched
case-insensitively, parameters are ignored). A name can also start
with * to match any media type ending with the rest (e.g.,
"*+json") or end with * to match any media type starting
with the rest (e.g., "text/*"). An exact match takes precedence,
otherwise the first matching name is used. If no parser matches, the
body is passed as-is. If the parser fails, the request is answered
with 400 Bad Request and FUN is not called.
defaultBodyParsers() returns a parser for URL encoded forms
(application/x-www-form-urlencoded) which produces a named
character vector like the parsed query and parsers for JSON
(application/json and *+json) using
jsonlite::fromJSON(). The list can be
modified or extended to define the parsers of a handler, e.g.,
addHandler("rfun", "/api", FUN, parse.body=c(defaultBodyParsers(),
list("text/csv"=function(body, content.type)
read.csv(text=rawToChar(body)))))
This handler modifies the request based on simple substitution rules.
addHandler("rewrite", prefix, replacement, stop=FALSE)
The prefix can contain the ? character as a wildcard
which will match any number of characters other than /. The
matched content is then available in the form of $n variables in
the replacement where n is one of the integers 1..9.
If the request prefix is matched then it is replaced by the
replacement.
Example:
addHandler("rewrite", "/api/?/?", "/r?name=$1&par=$2", stop=TRUE)
Will match request /api/copy/this?a=1 and rewrite it to
/r?a=1&name=copy&par=this. Note that if the replacement
contains a query string, it will be appended to the request query
string.
The stop parameter only applies to subsequent rewrite requests,
because the rewrite handler is not an actual content handler, it will
still proceed to other content handlers regardless of the value of
stop, but setting stop=TRUE will make sure that no more
rewrite handlers will be consulted.