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.

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.

Rewriter-rules

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>

Comments

  • In the second XML snippet, there is an extra ":" character after each "dispatch" element. I assume those are typos?
    • Also, in the first XML snippet, the "matches" attribute lacks the closing double-quote character.