1
0
Fork 0

Merge branch '1.4' of github.com:triAGENS/ArangoDB into 1.4

This commit is contained in:
Frank Celler 2013-11-06 16:44:52 +01:00
commit 62cc9cf84b
15 changed files with 424 additions and 21 deletions

View File

@ -82,6 +82,10 @@ Managing Databases using HTTP {#HttpDatabaseHttp}
@anchor HttpDatabaseCurrent
@copydetails JSF_get_api_database_current
@CLEARPAGE
@anchor HttpDatabaseUser
@copydetails JSF_get_api_database_user
@CLEARPAGE
@anchor HttpDatabaseList
@copydetails JSF_get_api_database_list

View File

@ -7,6 +7,7 @@ TOC {#HttpDatabaseTOC}
- @ref HttpDatabaseManagement
- @ref HttpDatabaseHttp
- @ref HttpDatabaseCurrent "GET /_api/database/current"
- @ref HttpDatabaseUser "GET /_api/database/user"
- @ref HttpDatabaseList "GET /_api/database"
- @ref HttpDatabaseCreate "POST /_api/database"
- @ref HttpDatabaseDelete "DELETE /_api/database/database-name"

View File

@ -22,6 +22,19 @@ describe ArangoDB do
result.should include("_system")
end
################################################################################
## retrieving the list of databases for the current user
################################################################################
it "retrieves the list of user-specific databases" do
doc = ArangoDB.log_get("#{prefix}-list-user", api + "/user")
doc.code.should eq(200)
result = doc.parsed_response["result"]
result.should include("_system")
end
################################################################################
## checking information about current database
################################################################################

View File

@ -284,6 +284,7 @@ SHELL_COMMON = \
@top_srcdir@/js/common/tests/shell-require.js \
@top_srcdir@/js/common/tests/shell-aqlfunctions.js \
@top_srcdir@/js/common/tests/shell-attributes.js \
@top_srcdir@/js/common/tests/shell-base64.js \
@top_srcdir@/js/common/tests/shell-collection.js \
@top_srcdir@/js/common/tests/shell-collection-volatile.js \
@top_srcdir@/js/common/tests/shell-crypto.js \

View File

@ -249,6 +249,8 @@ bool RestEdgeHandler::createDocument () {
if (res != TRI_ERROR_NO_ERROR) {
FREE_STRING(TRI_CORE_MEM_ZONE, edge._fromKey);
FREE_STRING(TRI_CORE_MEM_ZONE, edge._toKey);
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
if (res == TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND) {
generateError(HttpResponse::NOT_FOUND, res, wrongPart + " does not point to a valid collection");

View File

@ -7866,7 +7866,8 @@ static v8::Handle<v8::Value> JS_UseDatabase (v8::Arguments const& argv) {
static v8::Handle<v8::Value> JS_ListDatabases (v8::Arguments const& argv) {
v8::HandleScope scope;
if (argv.Length() != 0) {
const uint32_t argc = argv.Length();
if (argc != 0 && argc != 2) {
TRI_V8_EXCEPTION_USAGE(scope, "db._listDatabases()");
}
@ -7876,7 +7877,8 @@ static v8::Handle<v8::Value> JS_ListDatabases (v8::Arguments const& argv) {
TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
}
if (! TRI_IsSystemVocBase(vocbase)) {
if (argc == 0 &&
! TRI_IsSystemVocBase(vocbase)) {
TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_USE_SYSTEM_DATABASE);
}
@ -7884,7 +7886,19 @@ static v8::Handle<v8::Value> JS_ListDatabases (v8::Arguments const& argv) {
TRI_vector_string_t names;
TRI_InitVectorString(&names, TRI_UNKNOWN_MEM_ZONE);
int res = TRI_GetDatabaseNamesServer((TRI_server_t*) v8g->_server, &names);
int res;
if (argc == 0) {
// return all databases
res = TRI_GetDatabaseNamesServer((TRI_server_t*) v8g->_server, &names);
}
else {
// return all databases for a specific user
string username = TRI_ObjectToString(argv[0]);
string password = TRI_ObjectToString(argv[1]);
res = TRI_GetUserDatabasesServer((TRI_server_t*) v8g->_server, username.c_str(), password.c_str(), &names);
}
if (res != TRI_ERROR_NO_ERROR) {
TRI_DestroyVectorString(&names);
@ -8005,6 +8019,9 @@ static v8::Handle<v8::Value> JS_CreateDatabase (v8::Arguments const& argv) {
// version check failed
// TODO: report an error
}
// populate the authentication cache. otherwise no one can access the new database
TRI_ReloadAuthInfo(database);
// finally decrease the reference-counter
TRI_ReleaseVocBase(database);

View File

@ -567,7 +567,7 @@ bool TRI_CheckAuthenticationAuthInfo (TRI_vocbase_t* vocbase,
TRI_ReadUnlockReadWriteLock(&vocbase->_authInfoLock);
if (res) {
if (res && hash != NULL) {
// insert item into the cache
TRI_vocbase_auth_cache_t* cached;

View File

@ -43,6 +43,7 @@
#include "BasicsC/random.h"
#include "BasicsC/tri-strings.h"
#include "Ahuacatl/ahuacatl-statementlist.h"
#include "VocBase/auth.h"
#include "VocBase/vocbase.h"
// -----------------------------------------------------------------------------
@ -474,9 +475,39 @@ static int WriteShutdownInfo (TRI_server_t* server) {
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the current tick value, without using a lock
/// @brief check if a user can see a database
////////////////////////////////////////////////////////////////////////////////
static bool CanUseDatabase (TRI_vocbase_t* vocbase,
char const* username,
char const* password) {
if (! vocbase->_settings.requireAuthentication) {
// authentication is turned off
return true;
}
return TRI_CheckAuthenticationAuthInfo(vocbase, NULL, username, password);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief comparator for database names
////////////////////////////////////////////////////////////////////////////////
static int DatabaseNameComparator (const void* lhs, const void* rhs) {
const char* l = *((char**) lhs);
const char* r = *((char**) rhs);
return strcmp(l, r);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief sort a list of database names
////////////////////////////////////////////////////////////////////////////////
static void SortDatabaseNames (TRI_vector_string_t* names) {
qsort(names->_buffer, names->_length, sizeof(char*), &DatabaseNameComparator);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief extract the numeric part from a filename
////////////////////////////////////////////////////////////////////////////////
@ -498,7 +529,7 @@ static uint64_t GetNumericFilenamePart (const char* filename) {
/// the filename. this is used to sort database filenames on startup
////////////////////////////////////////////////////////////////////////////////
static int NameComparator (const void* lhs, const void* rhs) {
static int DatabaseIdComparator (const void* lhs, const void* rhs) {
const char* l = *((char**) lhs);
const char* r = *((char**) rhs);
@ -600,7 +631,7 @@ static int OpenDatabases (TRI_server_t* server) {
// open databases in defined order
if (n > 1) {
qsort(files._buffer, n, sizeof(char**), &NameComparator);
qsort(files._buffer, n, sizeof(char**), &DatabaseIdComparator);
}
for (i = 0; i < n; ++i) {
@ -914,7 +945,7 @@ static int GetDatabases (TRI_server_t* server,
regfree(&re);
// sort by id
qsort(databases->_buffer, databases->_length, sizeof(char*), &NameComparator);
qsort(databases->_buffer, databases->_length, sizeof(char*), &DatabaseIdComparator);
return res;
}
@ -2178,6 +2209,58 @@ void TRI_ReleaseDatabaseServer (TRI_server_t* server,
TRI_ReleaseVocBase(vocbase);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return the list of all databases a user can see
////////////////////////////////////////////////////////////////////////////////
int TRI_GetUserDatabasesServer (TRI_server_t* server,
char const* username,
char const* password,
TRI_vector_string_t* names) {
size_t i, n;
int res;
res = TRI_ERROR_NO_ERROR;
TRI_ReadLockReadWriteLock(&server->_databasesLock);
n = server->_databases._nrAlloc;
for (i = 0; i < n; ++i) {
TRI_vocbase_t* vocbase = server->_databases._table[i];
if (vocbase != NULL) {
char* copy;
assert(vocbase->_name != NULL);
if (! CanUseDatabase(vocbase, username, password)) {
// user cannot see database
continue;
}
copy = TRI_DuplicateStringZ(names->_memoryZone, vocbase->_name);
if (copy == NULL) {
res = TRI_ERROR_OUT_OF_MEMORY;
break;
}
if (TRI_PushBackVectorString(names, copy) != TRI_ERROR_NO_ERROR) {
// insertion failed.
TRI_Free(names->_memoryZone, copy);
res = TRI_ERROR_OUT_OF_MEMORY;
break;
}
}
}
TRI_ReadUnlockReadWriteLock(&server->_databasesLock);
SortDatabaseNames(names);
return res;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return the list of all database names
////////////////////////////////////////////////////////////////////////////////
@ -2217,6 +2300,8 @@ int TRI_GetDatabaseNamesServer (TRI_server_t* server,
}
}
TRI_ReadUnlockReadWriteLock(&server->_databasesLock);
SortDatabaseNames(names);
return res;
}

View File

@ -207,6 +207,15 @@ struct TRI_vocbase_s* TRI_UseDatabaseServer (TRI_server_t*,
void TRI_ReleaseDatabaseServer (TRI_server_t*,
struct TRI_vocbase_s*);
////////////////////////////////////////////////////////////////////////////////
/// @brief return the list of all databases a user can see
////////////////////////////////////////////////////////////////////////////////
int TRI_GetUserDatabasesServer (TRI_server_t*,
char const*,
char const*,
TRI_vector_string_t*);
////////////////////////////////////////////////////////////////////////////////
/// @brief return the list of all database names
////////////////////////////////////////////////////////////////////////////////

View File

@ -1374,6 +1374,8 @@ TRI_vocbase_t* TRI_OpenVocBase (TRI_server_t* server,
}
TRI_ReloadAuthInfo(vocbase);
// .............................................................................
// vocbase is now active
// .............................................................................

View File

@ -49,7 +49,7 @@ var API = "_api/database";
/// @RESTHEADER{GET /_api/database,retrieves a list of all existing databases}
///
/// @RESTDESCRIPTION
/// Retrieves a list of all existing databases
/// Retrieves the list of all existing databases
///
/// Note: retrieving the list of databases is only possible from within the `_system` database.
///
@ -64,9 +64,6 @@ var API = "_api/database";
/// @RESTRETURNCODE{403}
/// is returned if the request was not executed in the `_system` database.
///
/// @RESTRETURNCODE{404}
/// is returned if the database could not be found.
///
/// @EXAMPLES
///
/// @EXAMPLE_ARANGOSH_RUN{RestDatabaseGet}
@ -79,6 +76,36 @@ var API = "_api/database";
/// @END_EXAMPLE_ARANGOSH_RUN
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @fn JSF_get_api_database_user
/// @brief retrieves a list of all databases the current user can access
///
/// @RESTHEADER{GET /_api/database/user,retrieves a list of all databases the current user can access}
///
/// @RESTDESCRIPTION
/// Retrieves the list of all databases the current user can access without
/// specifying a different username or password.
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{200}
/// is returned if the list of database was compiled successfully.
///
/// @RESTRETURNCODE{400}
/// is returned if the request is invalid.
///
/// @EXAMPLES
///
/// @EXAMPLE_ARANGOSH_RUN{RestDatabaseGetUser}
/// var url = "/_api/database/user";
/// var response = logCurlRequest('GET', url);
///
/// assert(response.code === 200);
///
/// logJsonResponse(response);
/// @END_EXAMPLE_ARANGOSH_RUN
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @fn JSF_get_api_database_current
/// @brief retrieves information about the current database
@ -127,7 +154,7 @@ function get_api_database (req, res) {
return;
}
if (req.suffix.length === 1 && req.suffix[0] !== 'current') {
if (req.suffix.length > 1) {
actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER);
return;
}
@ -138,13 +165,36 @@ function get_api_database (req, res) {
result = arangodb.db._listDatabases();
}
else {
// information about the current database
result = {
name: arangodb.db._name(),
id: arangodb.db._id(),
path: arangodb.db._path(),
isSystem: arangodb.db._isSystem()
};
if (req.suffix[0] === 'user') {
// return all databases for current user
var username = '', password = '';
if (req.headers.hasOwnProperty('authorization')) {
var header = req.headers.authorization.replace(/^Basic\s+/i, '');
var decoded = require("internal").base64Decode(header);
var pos = decoded.indexOf(':');
if (pos >= 0) {
username = decoded.substr(0, pos);
password = decoded.substr(pos + 1, decoded.length - pos - 1);
}
}
result = arangodb.db._listDatabases(username, password);
}
else if (req.suffix[0] === 'current') {
// information about the current database
result = {
name: arangodb.db._name(),
id: arangodb.db._id(),
path: arangodb.db._path(),
isSystem: arangodb.db._isSystem()
};
}
else {
actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER);
return;
}
}
actions.resultOk(req, res, actions.HTTP_OK, { result : result });

View File

@ -5,6 +5,7 @@
REPLICATION_LOGGER_CONFIGURE, REPLICATION_APPLIER_CONFIGURE, REPLICATION_APPLIER_START,
REPLICATION_APPLIER_STOP, REPLICATION_APPLIER_FORGET, REPLICATION_APPLIER_STATE,
REPLICATION_SYNCHRONISE, REPLICATION_SERVER_ID, CONFIGURE_ENDPOINT, REMOVE_ENDPOINT, LIST_ENDPOINTS,
SYS_BASE64DECODE, SYS_BASE64ENCODE,
SYS_DEBUG_CAN_USE_FAILAT, SYS_DEBUG_SET_FAILAT, SYS_DEBUG_REMOVE_FAILAT, SYS_DEBUG_CLEAR_FAILAT,
SYS_DOWNLOAD, SYS_EXECUTE, SYS_LOAD, SYS_LOG_LEVEL, SYS_MD5, SYS_OUTPUT, SYS_PROCESS_STATISTICS,
SYS_RAND, SYS_SERVER_STATISTICS, SYS_SPRINTF, SYS_TIME, SYS_START_PAGER, SYS_STOP_PAGER,
@ -356,6 +357,24 @@
delete LIST_ENDPOINTS;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief base64Decode
////////////////////////////////////////////////////////////////////////////////
if (typeof SYS_BASE64DECODE !== "undefined") {
exports.base64Decode = SYS_BASE64DECODE;
delete SYS_BASE64DECODE;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief base64Encode
////////////////////////////////////////////////////////////////////////////////
if (typeof SYS_BASE64ENCODE !== "undefined") {
exports.base64Encode = SYS_BASE64ENCODE;
delete SYS_BASE64ENCODE;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief debugSetFailAt
////////////////////////////////////////////////////////////////////////////////

View File

@ -5,6 +5,7 @@
REPLICATION_LOGGER_CONFIGURE, REPLICATION_APPLIER_CONFIGURE, REPLICATION_APPLIER_START,
REPLICATION_APPLIER_STOP, REPLICATION_APPLIER_FORGET, REPLICATION_APPLIER_STATE,
REPLICATION_SYNCHRONISE, REPLICATION_SERVER_ID, CONFIGURE_ENDPOINT, REMOVE_ENDPOINT, LIST_ENDPOINTS,
SYS_BASE64DECODE, SYS_BASE64ENCODE,
SYS_DEBUG_CAN_USE_FAILAT, SYS_DEBUG_SET_FAILAT, SYS_DEBUG_REMOVE_FAILAT, SYS_DEBUG_CLEAR_FAILAT,
SYS_DOWNLOAD, SYS_EXECUTE, SYS_LOAD, SYS_LOG_LEVEL, SYS_MD5, SYS_OUTPUT, SYS_PROCESS_STATISTICS,
SYS_RAND, SYS_SERVER_STATISTICS, SYS_SPRINTF, SYS_TIME, SYS_START_PAGER, SYS_STOP_PAGER,
@ -356,6 +357,24 @@
delete LIST_ENDPOINTS;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief base64Decode
////////////////////////////////////////////////////////////////////////////////
if (typeof SYS_BASE64DECODE !== "undefined") {
exports.base64Decode = SYS_BASE64DECODE;
delete SYS_BASE64DECODE;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief base64Encode
////////////////////////////////////////////////////////////////////////////////
if (typeof SYS_BASE64ENCODE !== "undefined") {
exports.base64Encode = SYS_BASE64ENCODE;
delete SYS_BASE64ENCODE;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief debugSetFailAt
////////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,123 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief test the base64 functions
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2012 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var jsunity = require("jsunity");
var internal = require("internal");
// -----------------------------------------------------------------------------
// --SECTION-- base64 functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief test suite
////////////////////////////////////////////////////////////////////////////////
function Base64Suite () {
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief test encode
////////////////////////////////////////////////////////////////////////////////
testBase64Encode : function () {
var data = [
["",""],
[" ","IA=="],
[" ","ICA="],
["\nnew line\n","Cm5ldyBsaW5lCg=="],
["abc","YWJj"],
["ABC","QUJD"],
["abC","YWJD"],
[" aBC","IGFCQw=="],
["123","MTIz"],
["abcdef123456","YWJjZGVmMTIzNDU2"],
["the Quick brown fox jumped over the lazy dog","dGhlIFF1aWNrIGJyb3duIGZveCBqdW1wZWQgb3ZlciB0aGUgbGF6eSBkb2c="],
["This is a long string that contains a lot of characters. It should work without any particular problems, too.","VGhpcyBpcyBhIGxvbmcgc3RyaW5nIHRoYXQgY29udGFpbnMgYSBsb3Qgb2YgY2hhcmFjdGVycy4gSXQgc2hvdWxkIHdvcmsgd2l0aG91dCBhbnkgcGFydGljdWxhciBwcm9ibGVtcywgdG9vLg=="],
[1,"MQ=="],
[2,"Mg=="],
[-1,"LTE="],
[100,"MTAw"],
[1000,"MTAwMA=="],
[99,"OTk="]
];
data.forEach(function (value) {
assertEqual(value[1], internal.base64Encode(value[0]));
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test decode
////////////////////////////////////////////////////////////////////////////////
testBase64Decode : function () {
var data = [
["",""],
[" ","IA=="],
[" ","ICA="],
["\nnew line\n","Cm5ldyBsaW5lCg=="],
["abc","YWJj"],
["ABC","QUJD"],
["abC","YWJD"],
[" aBC","IGFCQw=="],
["123","MTIz"],
["abcdef123456","YWJjZGVmMTIzNDU2"],
["the Quick brown fox jumped over the lazy dog","dGhlIFF1aWNrIGJyb3duIGZveCBqdW1wZWQgb3ZlciB0aGUgbGF6eSBkb2c="],
["This is a long string that contains a lot of characters. It should work without any particular problems, too.","VGhpcyBpcyBhIGxvbmcgc3RyaW5nIHRoYXQgY29udGFpbnMgYSBsb3Qgb2YgY2hhcmFjdGVycy4gSXQgc2hvdWxkIHdvcmsgd2l0aG91dCBhbnkgcGFydGljdWxhciBwcm9ibGVtcywgdG9vLg=="],
["1","MQ=="],
["2","Mg=="],
["-1","LTE="],
["100","MTAw"],
["1000","MTAwMA=="],
["99","OTk="]
];
data.forEach(function (value) {
assertEqual(value[0], internal.base64Decode(value[1]));
});
}
};
}
// -----------------------------------------------------------------------------
// --SECTION-- main
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief executes the test suite
////////////////////////////////////////////////////////////////////////////////
jsunity.run(Base64Suite);
return jsunity.done();
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:

View File

@ -283,6 +283,62 @@ static void FillDistribution (v8::Handle<v8::Object> list,
// --SECTION-- JS functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief decode a base64-encoded string
///
/// @FUN{internal.base64Decode(@FA{value})}
///
/// Base64-decodes the string @FA{value}.
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> JS_Base64Decode (v8::Arguments const& argv) {
v8::HandleScope scope;
if (argv.Length() != 1) {
TRI_V8_EXCEPTION_USAGE(scope, "base64Decode(<value>)");
}
string base64;
try {
string value = TRI_ObjectToString(argv[0]);
base64 = StringUtils::decodeBase64(value);
}
catch (...) {
TRI_V8_EXCEPTION_MESSAGE(scope, TRI_errno(), TRI_last_error());
}
return scope.Close(v8::String::New(base64.c_str(), base64.size()));
}
////////////////////////////////////////////////////////////////////////////////
/// @brief base64-encode a string
///
/// @FUN{internal.base64Encode(@FA{value})}
///
/// Base64-encodes the string @FA{value}.
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> JS_Base64Encode (v8::Arguments const& argv) {
v8::HandleScope scope;
if (argv.Length() != 1) {
TRI_V8_EXCEPTION_USAGE(scope, "base64Encode(<value>)");
}
string base64;
try {
string value = TRI_ObjectToString(argv[0]);
base64 = StringUtils::encodeBase64(value);
}
catch (...) {
TRI_V8_EXCEPTION_MESSAGE(scope, TRI_errno(), TRI_last_error());
}
return scope.Close(v8::String::New(base64.c_str(), base64.size()));
}
////////////////////////////////////////////////////////////////////////////////
/// @brief parse a Javascript snippet, but do not execute it
///
@ -1709,7 +1765,7 @@ static v8::Handle<v8::Value> JS_Read64 (v8::Arguments const& argv) {
TRI_V8_EXCEPTION_MESSAGE(scope, TRI_errno(), TRI_last_error());
}
return scope.Close(v8::String::New(base64.c_str()));
return scope.Close(v8::String::New(base64.c_str(), base64.size()));
}
////////////////////////////////////////////////////////////////////////////////
@ -2700,6 +2756,8 @@ void TRI_InitV8Utils (v8::Handle<v8::Context> context,
TRI_AddGlobalFunctionVocbase(context, "FS_UNZIP_FILE", JS_UnzipFile);
TRI_AddGlobalFunctionVocbase(context, "FS_ZIP_FILE", JS_ZipFile);
TRI_AddGlobalFunctionVocbase(context, "SYS_BASE64DECODE", JS_Base64Decode);
TRI_AddGlobalFunctionVocbase(context, "SYS_BASE64ENCODE", JS_Base64Encode);
TRI_AddGlobalFunctionVocbase(context, "SYS_DOWNLOAD", JS_Download);
TRI_AddGlobalFunctionVocbase(context, "SYS_EXECUTE", JS_Execute);
TRI_AddGlobalFunctionVocbase(context, "SYS_GETLINE", JS_Getline);