Server Protocol
This page presents the classes and functions of the BaseX Clients, and the underlying protocol, which is utilized for communicating with the database server. A detailed example demonstrates how a concrete byte exchange can look like.
Workflow
- All clients are based on the client/server architecture. Hence, a BaseX database server must be started first.
- Each client provides a session class or script with methods to connect to and communicate with the database server. A socket connection will be established by the constructor, which expects a host, port, username and password as arguments.
- The
execute()
method is called to launch a database command. It returns the result or throws an exception with the received error message. - The
query()
method creates a query instance. Variables and the context item can be bound to that instance, and the result can either be requested viaexecute()
, or in an iterative manner with themore()
andnext()
functions. If an error occurs, an exception will be thrown. - The
create()
,add()
,put()
andputbinary()
methods pass on input streams to the corresponding database commands. The input can be a UTF-8 encoded XML document, a binary resource, or any other data (such as JSON or CSV) that can be successfully converted to a resource by the server. - To speed up execution, an output stream can be specified by some clients; this way, all results will be directed to that output stream.
- Most clients are accompanied by some example files, which demonstrate how database commands can be executed or how queries can be evaluated.
Transfer Protocol
All Clients use the following client/server protocol to communicate with the server.
The description of the protocol is helpful if you want to implement your own client.
Conventions
\xx
: single byte.{...}
: utf8 strings or raw data, suffixed with a\00
byte. To avoid confusion with this end-of-string byte, all transferred\00
and\FF
bytes are prefixed by an additional\FF
byte.
Authentication
Digest
Digest authentication is used since Version 8.0:
- Client connects to server socket
- Server sends a realm and nonce, separated by a colon:
{realm:nonce}
- Client sends the username and a hash value. The hash is composed of the md5 hash of:
- the md5 hash of the username, realm, and password (all separated by a colon), and
- the nonce:
{username} {md5(md5(username:realm:password) + nonce)}
- Server replies with
\00
(success) or\01
(error)
CRAM-MD5
CRAM-MD5 was discarded because unsalted md5 hashes can easily be uncovered using rainbow tables. However, most client bindings still provide support for the outdated handshaking, as it only slightly differs from the new protocol:
- Client connects to server socket
- Server sends a nonce (timestamp):
{nonce}
- Client sends the username and a hash value. The hash is composed of the md5 hash of:
- the md5 of the password and
- the nonce:
{username} {md5(md5(password) + nonce)}
- Server replies with
\00
(success) or\01
(error)
It is possible to support both digest
and cram-md5
authentication in clients: If the first server response contains no colon, cram-md5
should be chosen.
Command Protocol
The following byte sequences are sent and received from the client (please note that a specific client may not support all of the presented commands):
Command | Client Request | Server Response | Description |
---|---|---|---|
COMMAND | {command} |
{result} {info} \00 |
Executes a database command. |
QUERY | \00 {query} |
{id} \00 |
Creates a new query instance and returns its id. |
CREATE | \08 {name} {input} |
{info} \00 |
Creates a new database with the specified input (may be empty). |
ADD | \09 {path} {input} |
{info} \00 |
Adds a new document to the opened database. |
PUT | \0C {path} {input} |
{info} \00 |
Puts (adds or replaces) an XML document resource in the opened database. |
PUTBINARY | \0D {path} {input} |
{info} \00 |
Puts (adds or replaces) a binary resource in the opened database. |
↯ error | – | { partial result } {error} \01 |
Error feedback. |
Query Command Protocol
Queries are referenced via an id
, which has been returned by the QUERY
command (see above).
Query Command | Client Request | Server Response | Description |
---|---|---|---|
CLOSE | \02 {id} |
\00 \00 |
Closes and unregisters the query with the specified id. |
BIND | \03 {id} {name} {value} {type} |
\00 \00 |
Binds a value to a variable. The type will be ignored if the string is empty. |
RESULTS | \04 {id} |
\xx {item} ... \xx {item} \00 |
Returns all resulting items as strings, prefixed by a single byte (\xx ) that represents the Type ID. This command is called by the more() function of a client implementation. |
EXECUTE | \05 {id} |
{result} \00 |
Executes the query and returns the result as a single string. |
INFO | \06 {id} |
{result} \00 |
Returns a string with query compilation and profiling info. |
OPTIONS | \07 {id} |
{result} \00 |
Returns a string with all query serialization parameters, which can e.g. be assigned to the SERIALIZER option. |
CONTEXT | \0E {id} {value} {type} |
\00 \00 |
Binds a value to the context. The type will be ignored if the string is empty. |
UPDATING | \1E {id} |
{result} \00 |
Returns true if the query contains updating expressions; false otherwise. |
FULL | \1F {id} |
XDM {item} ... XDM {item} \00 |
Returns all resulting items as strings, prefixed by the XDM Metadata. This command is e. g. used by the XQJ API. |
As can be seen in the table, all results end with a single \00
byte, which indicates that the process was successful. If an error occurs, an additional byte \01
is sent, which is then followed by the error
message string.
Binding Sequences
Also, sequences can be bound to variables and the context:
empty-sequence()
must be supplied as type if an empty sequence is to be bound.- Multiple items are supplied via the
{value}
argument and separated with\01
bytes. - Item types are specified by appending
\02
and the type in its string representation to an item. If no item type is specified, the general type is used.
Some examples for the {value}
argument:
- the two integers
123
and789
are encoded as123
,\01
,789
and\00
(xs:integer
may be specified via the{type}
argument). - the two items
xs:integer(123)
andxs:string('ABC')
are encoded as123
,\02
,xs:integer
,\01
,ABC
,\02
,xs:string
and\00
.
Example
In the following example, a client registers a new session and executes the INFO
database command. Next, it creates a new query instance for the XQuery expression 1, 2+'3'
. The query is then evaluated, and the server returns the result of the first subexpression 1
and an error for the second sub expression. Finally, the query instance and client session are closed.
Operation | Bytes sent/received |
---|---|
Client connects to the database server socket | |
Server sends realm and timestamp BaseX:1369578179679 |
◄ 42 61 73 65 58 3A 31 33 36 39 35 37 38 31 37 39 36 37 39 00 |
Client sends username jack |
6A 61 63 6B 00 ► |
Client sends hash: md5(md5("jack:BaseX:topsecret") + 1369578179679) = ca664a31f8deda9b71ea3e79347f6666 |
63 61 36 ... 00 ► |
Server replies with success code | ◄ 00 |
Client sends the INFO command |
49 4E 46 4F 00 ► |
Server responds with the result General Information... |
◄ 47 65 6e 65 ... 00 |
Server additionally sends an (empty) info string | ◄ 00 |
Client creates a new query instance for the XQuery 1, 2+'3' |
00 31 2C 20 32 2B 27 33 27 00 ► |
Server returns query id "1" and a success code | ◄ 31 00 00 |
Client requests the query results via the RESULTS protocol command and its query id | 04 31 00 ► |
Server returns the first result (1 , type xs:integer) |
◄ 52 31 00 |
Server sends a single \00 byte instead of a new result, which indicates that no more results can be expected |
◄ 00 |
Server sends the error code \01 and the error message (Stopped at... ) |
◄ 01 53 74 6f ... 00 |
Client closes the query instance | 02 31 00 ► |
Server sends a response (which is equal to an empty info string) and success code | ◄ 00 00 |
Client closes the socket connection |
Constructors and Functions
Most language bindings provide the following constructors and functions:
Client Sessions | |
---|---|
Create a new session | Session(String host, int port, String name, String password) |
Execute a command | String execute(String command) |
Create a new query instance | Query query(String query) |
Create a database with an initial document | void create(String name, InputStream input) |
Add a document | void add(String path, InputStream input) |
Add or replace a document | void put(String path, InputStream input) |
Add or replace a binary resource | void putBinary(String path, InputStream input) |
Return process information | String info() |
Close the session | void close() |
Query Instances | |
Create new query instance | Query(Session session, String query) |
Bind a variable | void bind(String name, String value, String type) |
Bind the context item | void context(String value, String type) |
Execute the query | String execute() |
Check if a query returns more items | boolean more() |
Return the next item | String next() |
Return query information | String info() |
Return serialization parameters | String options() |
Check if the query is updating | boolean updating() |
Close the query | void close() |
XDM Metadata
In most cases, the XDM metadata is identical to the Type ID. For the three types document-node()
, attribute()
, and xs:QName
, the ID is followed by an additional {URI}
string.
Type IDs
The following table lists the type IDs that are returned by the server. Currently, all node kinds are of type xs:untypedAtomic
:
Type ID | Node Kind/Item Type | Type |
---|---|---|
7 | Function item | function |
8 | node() |
node |
9 | text() |
node |
10 | processing-instruction() |
node |
11 | element() |
node |
12 | document-node() |
node |
13 | document-node(element()) |
node |
14 | attribute() |
node |
15 | comment() |
node |
32 | item() |
atomic value |
33 | xs:untyped |
atomic value |
34 | xs:anyType |
atomic value |
35 | xs:anySimpleType |
atomic value |
36 | xs:anyAtomicType |
atomic value |
37 | xs:untypedAtomic |
atomic value |
38 | xs:string |
atomic value |
39 | xs:normalizedString |
atomic value |
40 | xs:token |
atomic value |
41 | xs:language |
atomic value |
42 | xs:NMTOKEN |
atomic value |
43 | xs:Name |
atomic value |
44 | xs:NCName |
atomic value |
45 | xs:ID |
atomic value |
46 | xs:IDREF |
atomic value |
47 | xs:ENTITY |
atomic value |
48 | xs:float |
atomic value |
49 | xs:double |
atomic value |
50 | xs:decimal |
atomic value |
51 | xs:precisionDecimal |
atomic value |
52 | xs:integer |
atomic value |
53 | xs:nonPositiveInteger |
atomic value |
54 | xs:negativeInteger |
atomic value |
55 | xs:long |
atomic value |
56 | xs:int |
atomic value |
57 | xs:short |
atomic value |
58 | xs:byte |
atomic value |
59 | xs:nonNegativeInteger |
atomic value |
60 | xs:unsignedLong |
atomic value |
61 | xs:unsignedInt |
atomic value |
62 | xs:unsignedShort |
atomic value |
63 | xs:unsignedByte |
atomic value |
64 | xs:positiveInteger |
atomic value |
65 | xs:duration |
atomic value |
66 | xs:yearMonthDuration |
atomic value |
67 | xs:dayTimeDuration |
atomic value |
68 | xs:dateTime |
atomic value |
69 | xs:dateTimeStamp |
atomic value |
70 | xs:date |
atomic value |
71 | xs:time |
atomic value |
72 | xs:gYearMonth |
atomic value |
73 | xs:gYear |
atomic value |
74 | xs:gMonthDay |
atomic value |
75 | xs:gDay |
atomic value |
76 | xs:gMonth |
atomic value |
77 | xs:boolean |
atomic value |
78 | basex:binary |
atomic value |
79 | xs:base64Binary |
atomic value |
80 | xs:hexBinary |
atomic value |
81 | xs:anyURI |
atomic value |
82 | xs:QName |
atomic value |
83 | xs:NOTATION |
atomic value |
Changelog
Version 8.2- Removed:
WATCH
andUNWATCH
command
- Updated: cram-md5 replaced with digest authentication
- Updated:
BIND
command: support more than one item
- Added: Query Commands CONTEXT, UPDATING and FULL
- Added: Client function
context(String value, String type)