1
0
Fork 0

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

This commit is contained in:
Jan Steemann 2014-01-06 13:18:12 +01:00
commit 7fcabc2cbf
3 changed files with 202 additions and 350 deletions

View File

@ -52,19 +52,6 @@ namespace triagens {
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief parameter type
////////////////////////////////////////////////////////////////////////////////
typedef enum {
TRI_ACT_STRING,
TRI_ACT_NUMBER,
TRI_ACT_COLLECTION,
TRI_ACT_COLLECTION_NAME,
TRI_ACT_COLLECTION_ID
}
TRI_action_parameter_type_e;
////////////////////////////////////////////////////////////////////////////////
/// @brief action descriptor
////////////////////////////////////////////////////////////////////////////////
@ -72,7 +59,7 @@ TRI_action_parameter_type_e;
class TRI_action_t {
public:
TRI_action_t (std::set<std::string> const& context)
: _type(), _url(), _isPrefix(false), _urlParts(0), _parameters(), _contexts(context) {
: _type(), _url(), _isPrefix(false), _urlParts(0), _contexts(context) {
}
virtual ~TRI_action_t () {}
@ -84,7 +71,6 @@ class TRI_action_t {
bool _isPrefix;
size_t _urlParts;
std::map<std::string, TRI_action_parameter_type_e> _parameters;
std::set<std::string> _contexts;
};

View File

@ -203,69 +203,6 @@ class v8_action_t : public TRI_action_t {
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief parses the action options "parameters" field of type string
////////////////////////////////////////////////////////////////////////////////
static void ParseActionOptionsParameter (TRI_v8_global_t* v8g,
TRI_action_t* action,
string const& key,
string const& parameter) {
TRI_action_parameter_type_e p;
if (parameter == "collection") {
p = TRI_ACT_COLLECTION;
}
else if (parameter == "collection-name") {
p = TRI_ACT_COLLECTION_NAME;
}
else if (parameter == "collection-identifier") {
p = TRI_ACT_COLLECTION_ID;
}
else if (parameter == "number") {
p = TRI_ACT_NUMBER;
}
else if (parameter == "string") {
p = TRI_ACT_STRING;
}
else {
LOG_ERROR("unknown parameter type '%s', falling back to string", parameter.c_str());
p = TRI_ACT_STRING;
}
action->_parameters[key] = p;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief parses the action options "parameters" field
////////////////////////////////////////////////////////////////////////////////
static void ParseActionOptionsParameter (TRI_v8_global_t* v8g,
TRI_action_t* action,
string const& key,
v8::Handle<v8::Value> parameter) {
if (parameter->IsString() || parameter->IsStringObject()) {
ParseActionOptionsParameter(v8g, action, key, TRI_ObjectToString(parameter));
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief parses the action options "parameters" field
////////////////////////////////////////////////////////////////////////////////
static void ParseActionOptionsParameters (TRI_v8_global_t* v8g,
TRI_action_t* action,
v8::Handle<v8::Object> parameters) {
v8::Handle<v8::Array> keys = parameters->GetOwnPropertyNames();
uint32_t len = keys->Length();
for (uint32_t i = 0; i < len; ++i) {
v8::Handle<v8::Value> key = keys->Get(i);
ParseActionOptionsParameter(v8g, action, TRI_ObjectToString(key), parameters->Get(key));
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief parses the action options
////////////////////////////////////////////////////////////////////////////////
@ -274,15 +211,6 @@ static void ParseActionOptions (TRI_v8_global_t* v8g,
TRI_action_t* action,
v8::Handle<v8::Object> options) {
// check "parameters" field
if (options->Has(v8g->ParametersKey)) {
v8::Handle<v8::Value> parameters = options->Get(v8g->ParametersKey);
if (parameters->IsObject()) {
ParseActionOptionsParameters(v8g, action, parameters->ToObject());
}
}
// check the "prefix" field
if (options->Has(v8g->PrefixKey)) {
action->_isPrefix = TRI_ObjectToBoolean(options->Get(v8g->PrefixKey));
@ -296,7 +224,7 @@ static void ParseActionOptions (TRI_v8_global_t* v8g,
/// @brief add cookie
////////////////////////////////////////////////////////////////////////////////
static void AddCookie (TRI_v8_global_t* v8g,
static void AddCookie (TRI_v8_global_t const* v8g,
HttpResponse* response,
v8::Handle<v8::Object> data) {
@ -349,21 +277,12 @@ static void AddCookie (TRI_v8_global_t* v8g,
}
////////////////////////////////////////////////////////////////////////////////
/// @brief executes an action
/// @brief convert a C++ HttpRequest to a V8 request object
////////////////////////////////////////////////////////////////////////////////
static HttpResponse* ExecuteActionVocbase (TRI_vocbase_t* vocbase,
v8::Isolate* isolate,
TRI_action_t const* action,
v8::Handle<v8::Function> callback,
HttpRequest* request) {
TRI_v8_global_t* v8g;
static v8::Handle<v8::Object> RequestCppToV8 ( TRI_v8_global_t const* v8g,
HttpRequest* request) {
v8::HandleScope scope;
v8::TryCatch tryCatch;
v8g = (TRI_v8_global_t*) isolate->GetData();
// setup the request
v8::Handle<v8::Object> req = v8::Object::New();
@ -440,25 +359,6 @@ static HttpResponse* ExecuteActionVocbase (TRI_vocbase_t* vocbase,
req->Set(v8g->PrefixKey, v8::String::New(path.c_str(), path.size()));
// copy suffix
v8::Handle<v8::Array> suffixArray = v8::Array::New();
vector<string> const& suffix = request->suffix();
uint32_t index = 0;
char const* sep = "";
for (size_t s = action->_urlParts; s < suffix.size(); ++s) {
suffixArray->Set(index++, v8::String::New(suffix[s].c_str(), suffix[s].size()));
path += sep + suffix[s];
sep = "/";
}
req->Set(v8g->SuffixKey, suffixArray);
// copy full path
req->Set(v8g->PathKey, v8::String::New(path.c_str(), path.size()));
// copy header fields
v8::Handle<v8::Object> headerFields = v8::Object::New();
@ -466,8 +366,10 @@ static HttpResponse* ExecuteActionVocbase (TRI_vocbase_t* vocbase,
map<string, string>::const_iterator iter = headers.begin();
for (; iter != headers.end(); ++iter) {
headerFields->Set(v8::String::New(iter->first.c_str(), iter->first.size()),
v8::String::New(iter->second.c_str(), iter->second.size()));
headerFields->Set(v8::String::New(iter->first.c_str(),
iter->first.size()),
v8::String::New(iter->second.c_str(),
iter->second.size()));
}
req->Set(v8g->HeadersKey, headerFields);
@ -476,17 +378,20 @@ static HttpResponse* ExecuteActionVocbase (TRI_vocbase_t* vocbase,
switch (request->requestType()) {
case HttpRequest::HTTP_REQUEST_POST:
req->Set(v8g->RequestTypeKey, v8g->PostConstant);
req->Set(v8g->RequestBodyKey, v8::String::New(request->body(), request->bodySize()));
req->Set(v8g->RequestBodyKey, v8::String::New(request->body(),
request->bodySize()));
break;
case HttpRequest::HTTP_REQUEST_PUT:
req->Set(v8g->RequestTypeKey, v8g->PutConstant);
req->Set(v8g->RequestBodyKey, v8::String::New(request->body(), request->bodySize()));
req->Set(v8g->RequestBodyKey, v8::String::New(request->body(),
request->bodySize()));
break;
case HttpRequest::HTTP_REQUEST_PATCH:
req->Set(v8g->RequestTypeKey, v8g->PatchConstant);
req->Set(v8g->RequestBodyKey, v8::String::New(request->body(), request->bodySize()));
req->Set(v8g->RequestBodyKey, v8::String::New(request->body(),
request->bodySize()));
break;
case HttpRequest::HTTP_REQUEST_OPTIONS:
@ -511,101 +416,20 @@ static HttpResponse* ExecuteActionVocbase (TRI_vocbase_t* vocbase,
v8::Handle<v8::Object> valuesObject = v8::Object::New();
map<string, string> values = request->values();
for (map<string, string>::iterator i = values.begin(); i != values.end(); ++i) {
for (map<string, string>::iterator i = values.begin();
i != values.end(); ++i) {
string const& k = i->first;
string const& v = i->second;
map<string, TRI_action_parameter_type_e>::const_iterator p = action->_parameters.find(k);
if (p == action->_parameters.end()) {
valuesObject->Set(v8::String::New(k.c_str(), k.size()),
v8::String::New(v.c_str(), v.size()));
}
else {
TRI_action_parameter_type_e const& ap = p->second;
switch (ap) {
case TRI_ACT_COLLECTION: {
if (! v.empty()) {
char ch = v[0];
TRI_vocbase_col_t const* collection = 0;
if ('0' < ch && ch <= '9') {
collection = TRI_LookupCollectionByIdVocBase(vocbase, TRI_UInt64String(v.c_str()));
}
else {
collection = TRI_LookupCollectionByNameVocBase(vocbase, v.c_str());
}
if (collection != 0) {
v8::Handle<v8::Value> c = TRI_WrapCollection(collection);
if (c.IsEmpty()) {
// TODO: raise exception here
}
else {
valuesObject->Set(v8::String::New(k.c_str(), k.size()), c);
}
}
}
break;
}
case TRI_ACT_COLLECTION_NAME: {
TRI_vocbase_col_t const* collection = TRI_LookupCollectionByNameVocBase(vocbase, v.c_str());
if (collection != 0) {
v8::Handle<v8::Value> c = TRI_WrapCollection(collection);
if (c.IsEmpty()) {
// TODO: raise exception here
}
else {
valuesObject->Set(v8::String::New(k.c_str(), k.size()), c);
}
}
break;
}
case TRI_ACT_COLLECTION_ID: {
TRI_vocbase_col_t const* collection = TRI_LookupCollectionByIdVocBase(
vocbase,
TRI_UInt64String(v.c_str()));
if (collection != 0) {
v8::Handle<v8::Value> c = TRI_WrapCollection(collection);
if (c.IsEmpty()) {
// TODO: raise exception here
}
else {
valuesObject->Set(v8::String::New(k.c_str(), k.size()), c);
}
}
break;
}
case TRI_ACT_NUMBER:
valuesObject->Set(v8::String::New(k.c_str(), k.size()),
v8::Number::New(TRI_DoubleString(v.c_str())));
break;
case TRI_ACT_STRING: {
valuesObject->Set(v8::String::New(k.c_str(), k.size()),
v8::String::New(v.c_str()));
break;
}
}
}
valuesObject->Set(v8::String::New(k.c_str(), k.size()),
v8::String::New(v.c_str(), v.size()));
}
// copy request array parameter (a[]=1&a[]=2&...)
map<string, vector<char const*>* > arrayValues = request->arrayValues();
for (map<string, vector<char const*>* >::iterator i = arrayValues.begin(); i != arrayValues.end(); ++i) {
for (map<string, vector<char const*>* >::iterator i = arrayValues.begin();
i != arrayValues.end(); ++i) {
string const& k = i->first;
vector<char const*>* v = i->second;
@ -627,17 +451,193 @@ static HttpResponse* ExecuteActionVocbase (TRI_vocbase_t* vocbase,
iter = cookies.begin();
for (; iter != cookies.end(); ++iter) {
cookiesObject->Set(v8::String::New(iter->first.c_str(), iter->first.size()),
v8::String::New(iter->second.c_str(), iter->second.size()));
cookiesObject->Set(v8::String::New(iter->first.c_str(),
iter->first.size()),
v8::String::New(iter->second.c_str(),
iter->second.size()));
}
req->Set(v8g->CookiesKey, cookiesObject);
// determine API compatibility version
int32_t compatibility = request->compatibility();
req->Set(v8g->CompatibilityKey, v8::Integer::New(compatibility));
return scope.Close(req);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief convert a C++ HttpRequest to a V8 request object
////////////////////////////////////////////////////////////////////////////////
static HttpResponse* ResponseV8ToCpp( TRI_v8_global_t const* v8g,
v8::Handle<v8::Object> res) {
HttpResponse::HttpResponseCode code = HttpResponse::OK;
if (res->Has(v8g->ResponseCodeKey)) {
// Windows has issues with converting from a double to an enumeration type
code = (HttpResponse::HttpResponseCode)
((int) (TRI_ObjectToDouble(res->Get(v8g->ResponseCodeKey))));
}
HttpResponse* response = new HttpResponse(code);
if (res->Has(v8g->ContentTypeKey)) {
response->setContentType(
TRI_ObjectToString(res->Get(v8g->ContentTypeKey)));
}
// .........................................................................
// body
// .........................................................................
if (res->Has(v8g->BodyKey)) {
// check if we should apply result transformations
// transformations turn the result from one type into another
// a Javascript action can request transformations by
// putting a list of transformations into the res.transformations
// array, e.g. res.transformations = [ "base64encode" ]
v8::Handle<v8::Value> val = res->Get(v8g->TransformationsKey);
if (val->IsArray()) {
string out(TRI_ObjectToString(res->Get(v8g->BodyKey)));
v8::Handle<v8::Array> transformations = val.As<v8::Array>();
for (uint32_t i = 0; i < transformations->Length(); i++) {
v8::Handle<v8::Value> transformator
= transformations->Get(v8::Integer::New(i));
string name = TRI_ObjectToString(transformator);
// check available transformations
if (name == "base64encode") {
// base64-encode the result
out = StringUtils::encodeBase64(out);
// set the correct content-encoding header
response->setHeader("content-encoding", "base64");
}
else if (name == "base64decode") {
// base64-decode the result
out = StringUtils::decodeBase64(out);
// set the correct content-encoding header
response->setHeader("content-encoding", "binary");
}
}
response->body().appendText(out);
}
else {
response->body().appendText(TRI_ObjectToString(res->Get(v8g->BodyKey)));
}
}
// .........................................................................
// body from file
// .........................................................................
else if (res->Has(v8g->BodyFromFileKey)) {
TRI_Utf8ValueNFC filename(TRI_UNKNOWN_MEM_ZONE,
res->Get(v8g->BodyFromFileKey));
size_t length;
char* content = TRI_SlurpFile(TRI_UNKNOWN_MEM_ZONE, *filename, &length);
if (content != 0) {
response->body().appendText(content, length);
TRI_FreeString(TRI_UNKNOWN_MEM_ZONE, content);
}
else {
string msg = string("cannot read file '") + *filename + "': " +
TRI_last_error();
response->body().appendText(msg.c_str(), msg.size());
response->setResponseCode(HttpResponse::SERVER_ERROR);
}
}
// .........................................................................
// headers
// .........................................................................
if (res->Has(v8g->HeadersKey)) {
v8::Handle<v8::Value> val = res->Get(v8g->HeadersKey);
v8::Handle<v8::Object> v8Headers = val.As<v8::Object>();
if (v8Headers->IsObject()) {
v8::Handle<v8::Array> props = v8Headers->GetPropertyNames();
for (uint32_t i = 0; i < props->Length(); i++) {
v8::Handle<v8::Value> key = props->Get(v8::Integer::New(i));
response->setHeader(TRI_ObjectToString(key),
TRI_ObjectToString(v8Headers->Get(key)));
}
}
}
// .........................................................................
// cookies
// .........................................................................
if (res->Has(v8g->CookiesKey)) {
v8::Handle<v8::Value> val = res->Get(v8g->CookiesKey);
v8::Handle<v8::Object> v8Cookies = val.As<v8::Object>();
if (v8Cookies->IsArray()) {
v8::Handle<v8::Array> v8Array = v8Cookies.As<v8::Array>();
for (uint32_t i = 0; i < v8Array->Length(); i++) {
v8::Handle<v8::Value> v8Cookie = v8Array->Get(i);
if (v8Cookie->IsObject()) {
AddCookie(v8g, response, v8Cookie.As<v8::Object>());
}
}
}
else if (v8Cookies->IsObject()) {
// one cookie
AddCookie(v8g, response, v8Cookies);
}
}
return response;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief executes an action
////////////////////////////////////////////////////////////////////////////////
static HttpResponse* ExecuteActionVocbase (TRI_vocbase_t* vocbase,
v8::Isolate* isolate,
TRI_action_t const* action,
v8::Handle<v8::Function> callback,
HttpRequest* request) {
TRI_v8_global_t const* v8g;
v8::HandleScope scope;
v8::TryCatch tryCatch;
v8g = (TRI_v8_global_t const*) isolate->GetData();
v8::Handle<v8::Object> req = RequestCppToV8(v8g, request);
// copy suffix, which comes from the action:
string path = request->prefix();
v8::Handle<v8::Array> suffixArray = v8::Array::New();
vector<string> const& suffix = request->suffix();
uint32_t index = 0;
char const* sep = "";
for (size_t s = action->_urlParts; s < suffix.size(); ++s) {
suffixArray->Set(index++, v8::String::New(suffix[s].c_str(),
suffix[s].size()));
path += sep + suffix[s];
sep = "/";
}
req->Set(v8g->SuffixKey, suffixArray);
// copy full path
req->Set(v8g->PathKey, v8::String::New(path.c_str(), path.size()));
// execute the callback
v8::Handle<v8::Object> res = v8::Object::New();
v8::Handle<v8::Value> args[2] = { req, res };
@ -654,124 +654,8 @@ static HttpResponse* ExecuteActionVocbase (TRI_vocbase_t* vocbase,
}
else {
HttpResponse::HttpResponseCode code = HttpResponse::OK;
HttpResponse* response = ResponseV8ToCpp( v8g, res );
if (res->Has(v8g->ResponseCodeKey)) {
// Windows has issues with converting from a double to an enumeration type
code = (HttpResponse::HttpResponseCode) ((int) (TRI_ObjectToDouble(res->Get(v8g->ResponseCodeKey))));
}
HttpResponse* response = new HttpResponse(code);
if (res->Has(v8g->ContentTypeKey)) {
response->setContentType(TRI_ObjectToString(res->Get(v8g->ContentTypeKey)));
}
// .............................................................................
// body
// .............................................................................
if (res->Has(v8g->BodyKey)) {
// check if we should apply result transformations
// transformations turn the result from one type into another
// a Javascript action can request transformations by
// putting a list of transformations into the res.transformations
// array, e.g. res.transformations = [ "base64encode" ]
v8::Handle<v8::Value> val = res->Get(v8g->TransformationsKey);
if (val->IsArray()) {
string out(TRI_ObjectToString(res->Get(v8g->BodyKey)));
v8::Handle<v8::Array> transformations = val.As<v8::Array>();
for (uint32_t i = 0; i < transformations->Length(); i++) {
v8::Handle<v8::Value> transformator = transformations->Get(v8::Integer::New(i));
string name = TRI_ObjectToString(transformator);
// check available transformations
if (name == "base64encode") {
// base64-encode the result
out = StringUtils::encodeBase64(out);
// set the correct content-encoding header
response->setHeader("content-encoding", "base64");
}
else if (name == "base64decode") {
// base64-decode the result
out = StringUtils::decodeBase64(out);
// set the correct content-encoding header
response->setHeader("content-encoding", "binary");
}
}
response->body().appendText(out);
}
else {
response->body().appendText(TRI_ObjectToString(res->Get(v8g->BodyKey)));
}
}
// .............................................................................
// body from file
// .............................................................................
else if (res->Has(v8g->BodyFromFileKey)) {
TRI_Utf8ValueNFC filename(TRI_UNKNOWN_MEM_ZONE, res->Get(v8g->BodyFromFileKey));
size_t length;
char* content = TRI_SlurpFile(TRI_UNKNOWN_MEM_ZONE, *filename, &length);
if (content != 0) {
response->body().appendText(content, length);
TRI_FreeString(TRI_UNKNOWN_MEM_ZONE, content);
}
else {
string msg = string("cannot read file '") + *filename + "': " + TRI_last_error();
response->body().appendText(msg.c_str(), msg.size());
response->setResponseCode(HttpResponse::SERVER_ERROR);
}
}
// .............................................................................
// headers
// .............................................................................
if (res->Has(v8g->HeadersKey)) {
v8::Handle<v8::Value> val = res->Get(v8g->HeadersKey);
v8::Handle<v8::Object> v8Headers = val.As<v8::Object>();
if (v8Headers->IsObject()) {
v8::Handle<v8::Array> props = v8Headers->GetPropertyNames();
for (uint32_t i = 0; i < props->Length(); i++) {
v8::Handle<v8::Value> key = props->Get(v8::Integer::New(i));
response->setHeader(TRI_ObjectToString(key), TRI_ObjectToString(v8Headers->Get(key)));
}
}
}
// .............................................................................
// cookies
// .............................................................................
if (res->Has(v8g->CookiesKey)) {
v8::Handle<v8::Value> val = res->Get(v8g->CookiesKey);
v8::Handle<v8::Object> v8Cookies = val.As<v8::Object>();
if (v8Cookies->IsArray()) {
v8::Handle<v8::Array> v8Array = v8Cookies.As<v8::Array>();
for (uint32_t i = 0; i < v8Array->Length(); i++) {
v8::Handle<v8::Value> v8Cookie = v8Array->Get(i);
if (v8Cookie->IsObject()) {
AddCookie(v8g, response, v8Cookie.As<v8::Object>());
}
}
}
else if (v8Cookies->IsObject()) {
// one cookie
AddCookie(v8g, response, v8Cookies);
}
}
return response;
}
}

View File

@ -932,17 +932,6 @@ function flattenRouting (routes, path, urlParameters, depth, prefix) {
///
/// You can use the functions @FN{ResultOk} and @FN{ResultError} to easily
/// generate a response.
///
/// @FA{options.parameters}
///
/// Normally the parameters are passed to the callback as strings. You can
/// use the @FA{options}, to force a converstion of the parameter to
///
/// - @c "collection"
/// - @c "collection-identifier"
/// - @c "collection-name"
/// - @c "number"
/// - @c "string"
////////////////////////////////////////////////////////////////////////////////
function defineHttp (options) {
@ -951,7 +940,6 @@ function defineHttp (options) {
var url = options.url;
var context = options.context;
var callback = options.callback;
var parameters = options.parameters;
var prefix = true;
if (typeof context === "undefined") {
@ -968,7 +956,6 @@ function defineHttp (options) {
}
var parameter = {
parameters : parameters,
prefix : prefix
};
@ -1994,11 +1981,6 @@ exports.redirectRequest = redirectRequest;
exports.pathHandler = pathHandler;
// some useful constants
exports.COLLECTION = "collection";
exports.COLLECTION_IDENTIFIER = "collection-identifier";
exports.COLLECTION_NAME = "collection-name";
exports.NUMBER = "number";
exports.DELETE = "DELETE";
exports.GET = "GET";
exports.HEAD = "HEAD";