Enhanced HTTP Server
The Enhanced HTTP server simplifies the out-of-the-box experience with MarkLogic and can improve the performance of client/server interactions. An instance of the Enhanced HTTP server will be running by default and will allow you to use the REST API, custom HTTP, XCC/XDBC (over HTTP) using a single interface.
In MarkLogic 8 our core applications and REST library are configured to take advantage of these features. In addition you may create new HTTP servers and your own declarative rewriter.
A significant feature is the ability for XCC clients to communicate on the same port as REST and HTTP clients. You can also execute requests with the same features as XCC but without needing to use the XCC library. This is enabled by rules in the rewriter as well as internal server enhancements.
- Ease of use not having to create extra ports
- Performance improvements and efficiency for apps (Custom Apps)
Rewriter Features
The XML rewriter is a simple declarative XML format which can replace the need for an XQuery rewriter for many cases. The XML rewriter has many more options for affecting the request environment then the XQuery writer. On the other hand, because it is designed for efficiency it doesn't have the expressive power of XQuery or access to the system function calls; instead a select set of match and evaluation rules are available designed to support a large set of common cases.
The XML rewriter is defined with a simple XML file that contains rules for matching request values and preparing an updated environment for the request. If all the requested updates are accepted then the request precedes with the updated environment, otherwise an error or warning is logged. The XQuery rewriter can only affect the request URI (Path and Query parameters). The XML rewriter can additionally change the database, modules database, transaction ID, and other settings that would normally require an “eval-into” in an XQuery application. In some cases (such as requests for static content) the need for using XQuery code can be eliminated entirely for that request, while still intercepting requests for dynamic content.
A significant feature is the ability for XCC clients to communicate on the same port as REST and HTTP clients. You can also execute requests with the same features as XCC but without needing to use the XCC library. This is enabled by rules in the rewriter as well as internal server enhancements.
In MarkLogic 8 our core applications and REST library will be shipped configured with an XML rewriter to take advantage of these features. In addition you may create new HTTP servers and your own rewriter.
Rewriter Overview
The XML Rewriter fills the same purpose and “slot” in the server as the XQuery rewriter. To use an XML rewriter simply use a “.xml” extension in the rewriter field for the server configuration of any HTTP server. The following diagram outlines the internal processing of a request. This is essentially unchanged from prior versions except that the rewriter can be either an XML or XQuery rewriter.
The evaluator performs an in order traversal of the tree evaluating every rule recursively. For Match rules a condition is evaluated and if true then node is descended and its children evaluated. Evaluation rules, on the other hand, can produce a rewriter modification request. The evaluation stops when either an error, a dispatch or the end of the tree is reached. A dispatch indicates a successful rewrite and all accumulated modifications are passed to the request handler for validation. An error causes a request error, and reaching the end of the tree with no dispatch causes the request to continue unchanged to the original URL.
The following is a summary of rules available.
Match Rules
Element | Description |
---|---|
rewriter | Root element of the rewriter rule tree. |
match-accept | Matches on an HTTP Accept header |
match-content-type | Matches on an HTTP Content-Type header |
match-cookie | Match on a cookie |
match-execute-privilege | Match on the users execute privileges |
match-header | Match on an HTTP Header |
match-method | Match on the HTTP Method |
match-path | Match on the request path |
match-role | Match on the users assigned roles |
match-string | Matches a string value against a regular expression |
match-query-param | Match on a uri parameter (query parameter) |
match-user | Match on a user name, id or default user |
Evaluation Rules
Element | Description |
---|---|
add-query-param | Adds a query parameter (name/value) to the query parameters |
error | Structured error generation |
set-database | Sets the Database |
set-error-handler | Sets the Error Handler |
set-eval | Sets the Evaluation mode (eval or direct) |
set-modules-database | Sets the Modules database |
set-modules-root | Sets the modules root path |
set-path | Sets the URI path |
set-query-param | Set/overwrite query param |
set-transaction | Sets the transaction |
set-transaction-mode | Sets the transaction mode |
set-var | Sets a variable in the local scope |
etrace | Trace Events |
Termination Rules
Element | Description |
---|---|
dispatch | Stop evaluation and dispatch with all rewrite commands |
error | Terminates evaluation with an error |
System (read only) variables.
Variable | Type(s) | Desc / Notes |
---|---|---|
$_cookie. | String | The value of the cookie
<name>
. . Only the text value of the cookie is returned, not the extra metadata (path, domain, expires etc.).
If the cookie does not exist evaluates as “” Cookie names matched and compared case insensitive. Future: may expose substructure of the cookie header |
$_database[.name] | String | Document database nameuser”); |
$_database.id | Integer | Document database ID |
$_defaultuser | Boolean | True if the authenticated user is the default user |
$_method | String | HTTP Method name |
$_modules-database[.name] | String | Modules database name This is empty if using the file system for modules. |
$_modules-database.id | Integer | Modules database ID The ID is 0 when using the file system for modules. |
$_modules-root | String | Modules root path |
$_path | String | The HTTP request path Not including the query string |
$_query-param. | List of String | The query parameters matching the name as a List of string. |
$_request-url | String | The original request URI including path and query parameters |
$_user[.name] | String | User Name |
$_user.id | Integer | User ID |
Some examples of simple rewriters:
Redirect a request by removing an initial prefix(/dir)
<rewriter xmlns="http://marklogic.com/xdmp/rewriter"> <match-path matches="^/dir(/.+)"> <dispatch>$1</dispatch> </match-path> </rewriter>
For GET and PUT requests only, if the a query parameter named “path” is exactly “/admin” then redirect to “/private/admin.xqy” otherwise use the value of the parameter for the redirect.
If no “path” query parameter then do not change the request
<rewriter xmlns="http://marklogic.com/xdmp/rewriter"> <match-method any-of="GET PUT"> <!-- match by name/value --> <match-query-param name="path" value="/admin"> <dispatch>/private/admin.xqy</dispatch> </match-query-param> <!-- match by name use value --> <match-query-param name="path"> <dispatch>$0</dispatch> </match-query-param> </match-method> </rewriter>
If a query parameter named "data" is present then set the database to “UserData”. If a query parameter “module” is present then set the modules database to “UserModule”. If the path starts /users/ and ends with /version(version id) then extract the next path component ($1), append it to /app and add a query parameter “version” with the version ID.
<rewriter xmlns="http://marklogic.com/xdmp/rewriter"> <match-query-param name="data"> <set-database>UserData</set-database> </match-query-param> <match-query-param name="module"> <set-modules-database>UserModule</set-modules-database> </match-query-param> <match-path match="^/users/([^/]+)/version(.+)%"> <set-path>/app/$1</set-path> <add-query-param name="version">$2</add-query-param> </match-path> <dispatch/> </rewriter>
Matching users by name and default user and setting or overwriting a query parameter.
<rewriter xmlns="http://marklogic.com/xdmp/rewriter"> <set-query-param name="default">default-user no match</set-query-param> <match-user name="admin"> <add-query-param name="user">admin matched</add-query-param> </match-user> <match-user name="infostudio-admin"> <add-query-param name="user">infostudio-admin matced</add-query-param> </match-user> <match-user default-user="true"> <set-query-param name="default">default-user matched</set-query-param> </match-user> <dispatch>/myapp.xqy</dispatch> </rewriter>
Matching cookies. This properly parses the cookie HTTP header structure so matches can be performed reliably. In this example, the SESSIONID cookie is used to conditionally set the current transaction.
<rewriter xmlns="http://marklogic.com/xdmp/rewriter"> <match-cookie name="SESSIONID"> <set-transaction>$0</set-transaction> </match-cookie> </rewriter>
User defined variables with local scoping. Set an initial value to the user variable “test”. If the patch starts with /test/ and contains atleast 2 more path components then reset the “test” variable to the first matching path, and add a query param “var1″ to the second matching path. If the role of the user also contains either “admin-builtins” or “app-builder” then rewrite to the path ‘/admin/secret.xqy’, otherwise add a query param “var2″ with the value of the “test” user variable and rewrite to “/default.xqy”
If you change the scoped attribute from true to false, (or remove it), then all the changes within that condition are discarded if the final dispatch to /admin/secret.xqy is not reached, leaving intact the initial value for the “test” variable, not adding the “var1″ query parameter and dispatching to /default.xqy
<rewriter xmlns="http://marklogic.com/xdmp/rewriter" > <set-var name="test">initial</set-var> <match-path matches="^/test/(\w+)/(\w+).*" scoped="true"> <set-var name="test">$1</set-var> <set-query-param name="var1">$2</set-query-param> <match-role any-of="admin-builtins app-builder"> <dispatch>/admin/secret.xqy</dispatch> </match-role> </match-path> <add-query-param name="var2">$test</add-query-param> <dispatch>/default.xqy</dispatch> </rewriter>