1
0
Fork 0

Bug fix/move a few actions from js to cpp (#8549)

This commit is contained in:
Jan 2019-03-26 10:02:21 +01:00 committed by GitHub
parent deb770caba
commit 207c978d1e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 728 additions and 286 deletions

View File

@ -23,6 +23,7 @@
#include "actions.h"
#include "Basics/Exceptions.h"
#include "Basics/ReadLocker.h"
#include "Basics/ReadWriteLock.h"
#include "Basics/StringUtils.h"
@ -40,6 +41,14 @@ static std::unordered_map<std::string, std::shared_ptr<TRI_action_t>> PrefixActi
/// @brief actions lock
static ReadWriteLock ActionsLock;
/// @brief actions of this type are executed directly. nothing to do here
TRI_action_result_t TRI_fake_action_t::execute(TRI_vocbase_t*,
arangodb::GeneralRequest*,
arangodb::GeneralResponse*,
arangodb::Mutex*, void**) {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "TRI_fake_action_t::execute must never be called");
}
/// @brief defines an action
std::shared_ptr<TRI_action_t> TRI_DefineActionVocBase(std::string const& name,
@ -51,8 +60,7 @@ std::shared_ptr<TRI_action_t> TRI_DefineActionVocBase(std::string const& name,
url = url.substr(1);
}
action->_url = url;
action->_urlParts = StringUtils::split(url, "/").size();
action->setUrl(url, StringUtils::split(url, "/").size());
std::unordered_map<std::string, std::shared_ptr<TRI_action_t>>* which;

View File

@ -58,6 +58,11 @@ class TRI_action_t {
virtual bool cancel(arangodb::Mutex* dataLock, void** data) = 0;
void setUrl(std::string const& url, size_t urlParts) {
_url = url;
_urlParts = urlParts;
}
std::string _url;
size_t _urlParts;
@ -66,6 +71,28 @@ class TRI_action_t {
bool _allowUseDatabase;
};
/// @brief fake action class used only inside /_admin/execute RestHandler
class TRI_fake_action_t final : public TRI_action_t {
public:
TRI_fake_action_t(std::string const& url, size_t urlParts)
: TRI_action_t() {
setUrl(url, urlParts);
}
void visit(void*) override {}
/// @brief actions of this type are executed directly. nothing to do here
TRI_action_result_t execute(TRI_vocbase_t*, arangodb::GeneralRequest*,
arangodb::GeneralResponse*,
arangodb::Mutex*, void**) override;
/// @brief actions of this type are not registered anywhere, and thus
/// cannot be canceled
bool cancel(arangodb::Mutex*, void**) override {
return false;
}
};
/// @brief defines an action
std::shared_ptr<TRI_action_t> TRI_DefineActionVocBase(std::string const& name,
std::shared_ptr<TRI_action_t> action);

View File

@ -442,13 +442,16 @@ SET(ARANGOD_SOURCES
Replication/common-defines.cpp
Replication/utilities.cpp
RestHandler/RestAdminDatabaseHandler.cpp
RestHandler/RestAdminExecuteHandler.cpp
RestHandler/RestAdminLogHandler.cpp
RestHandler/RestAdminRoutingHandler.cpp
RestHandler/RestAdminServerHandler.cpp
RestHandler/RestAdminStatisticsHandler.cpp
RestHandler/RestAqlFunctionsHandler.cpp
RestHandler/RestAqlReloadHandler.cpp
RestHandler/RestAqlUserFunctionsHandler.cpp
RestHandler/RestAuthHandler.cpp
RestHandler/RestAuthReloadHandler.cpp
RestHandler/RestBaseHandler.cpp
RestHandler/RestBatchHandler.cpp
RestHandler/RestCollectionHandler.cpp
@ -476,6 +479,7 @@ SET(ARANGOD_SOURCES
RestHandler/RestSimpleQueryHandler.cpp
RestHandler/RestStatusHandler.cpp
RestHandler/RestTasksHandler.cpp
RestHandler/RestTimeHandler.cpp
RestHandler/RestTransactionHandler.cpp
RestHandler/RestTtlHandler.cpp
RestHandler/RestUploadHandler.cpp

View File

@ -45,13 +45,16 @@
#include "ProgramOptions/ProgramOptions.h"
#include "ProgramOptions/Section.h"
#include "RestHandler/RestAdminDatabaseHandler.h"
#include "RestHandler/RestAdminExecuteHandler.h"
#include "RestHandler/RestAdminLogHandler.h"
#include "RestHandler/RestAdminRoutingHandler.h"
#include "RestHandler/RestAdminServerHandler.h"
#include "RestHandler/RestAdminStatisticsHandler.h"
#include "RestHandler/RestAqlFunctionsHandler.h"
#include "RestHandler/RestAqlReloadHandler.h"
#include "RestHandler/RestAqlUserFunctionsHandler.h"
#include "RestHandler/RestAuthHandler.h"
#include "RestHandler/RestAuthReloadHandler.h"
#include "RestHandler/RestBatchHandler.h"
#include "RestHandler/RestCollectionHandler.h"
#include "RestHandler/RestControlPregelHandler.h"
@ -79,6 +82,7 @@
#include "RestHandler/RestStatusHandler.h"
#include "RestHandler/RestTasksHandler.h"
#include "RestHandler/RestTestHandler.h"
#include "RestHandler/RestTimeHandler.h"
#include "RestHandler/RestTransactionHandler.h"
#include "RestHandler/RestTtlHandler.h"
#include "RestHandler/RestUploadHandler.h"
@ -95,6 +99,7 @@
#include "Ssl/SslServerFeature.h"
#include "StorageEngine/EngineSelectorFeature.h"
#include "StorageEngine/StorageEngine.h"
#include "V8Server/V8DealerFeature.h"
using namespace arangodb::rest;
using namespace arangodb::options;
@ -448,7 +453,21 @@ void GeneralServerFeature::defineHandlers() {
// And now some handlers which are registered in both /_api and /_admin
_handlerFactory->addHandler("/_admin/actions",
RestHandlerCreator<MaintenanceRestHandler>::createNoData);
_handlerFactory->addHandler("/_admin/aql/reload",
RestHandlerCreator<RestAqlReloadHandler>::createNoData);
_handlerFactory->addHandler("/_admin/auth/reload",
RestHandlerCreator<RestAuthReloadHandler>::createNoData);
if (V8DealerFeature::DEALER && V8DealerFeature::DEALER->allowAdminExecute()) {
_handlerFactory->addHandler("/_admin/execute",
RestHandlerCreator<RestAdminExecuteHandler>::createNoData);
}
_handlerFactory->addHandler("/_admin/time",
RestHandlerCreator<RestTimeHandler>::createNoData);
_handlerFactory->addPrefixHandler("/_api/job",
RestHandlerCreator<arangodb::RestJobHandler>::createData<AsyncJobManager*>,
_jobManager.get());

View File

@ -49,7 +49,7 @@ enum class RequestLane {
// which are not CLIENT_AQL or CLIENT_V8.
CLIENT_SLOW,
// Used for all requests send by the web ui
// Used for all requests sent by the web ui
CLIENT_UI,
// For requests between agents. These are basically the

View File

@ -0,0 +1,214 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 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 ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////
#include "RestAdminExecuteHandler.h"
#include "Actions/ActionFeature.h"
#include "Actions/actions.h"
#include "Basics/Exceptions.h"
#include "Basics/StaticStrings.h"
#include "Basics/StringUtils.h"
#include "Logger/Logger.h"
#include "V8/v8-globals.h"
#include "V8/v8-vpack.h"
#include "V8Server/v8-actions.h"
#include "V8Server/V8Context.h"
#include "V8Server/V8DealerFeature.h"
#include <velocypack/Builder.h>
#include <velocypack/Value.h>
#include <velocypack/velocypack-aliases.h>
using namespace arangodb;
using namespace arangodb::rest;
RestAdminExecuteHandler::RestAdminExecuteHandler(GeneralRequest* request, GeneralResponse* response)
: RestVocbaseBaseHandler(request, response) {}
RestStatus RestAdminExecuteHandler::execute() {
if (!V8DealerFeature::DEALER) {
generateError(rest::ResponseCode::BAD, TRI_ERROR_INTERNAL,
"JavaScript operations are not available");
return RestStatus::DONE;
}
TRI_ASSERT(V8DealerFeature::DEALER->allowAdminExecute());
arangodb::velocypack::StringRef bodyStr = _request->rawPayload();
char const* body = bodyStr.data();
size_t bodySize = bodyStr.size();
if (bodySize == 0) {
// nothing to execute. return an empty response
VPackBuilder result;
result.openObject(true);
result.add(StaticStrings::Error, VPackValue(false));
result.add(StaticStrings::Code, VPackValue(static_cast<int>(rest::ResponseCode::OK)));
result.close();
generateResult(rest::ResponseCode::OK, result.slice());
return RestStatus::DONE;
}
try {
LOG_TOPIC("c838e", WARN, Logger::FIXME) << "about to execute: '" << Logger::CHARS(body, bodySize) << "'";
ssize_t forceContext = -1;
bool found;
std::string const& c = _request->header("x-arango-v8-context", found);
if (found && !c.empty()) {
forceContext = basics::StringUtils::int32(c);
}
// get a V8 context
bool const allowUseDatabase = ActionFeature::ACTION->allowUseDatabase();
V8Context* context = V8DealerFeature::DEALER->enterContext(&_vocbase, allowUseDatabase, forceContext);
// note: the context might be nullptr in case of shut-down
if (context == nullptr) {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_RESOURCE_LIMIT,
"unable to acquire V8 context in time");
}
TRI_DEFER(V8DealerFeature::DEALER->exitContext(context));
{
v8::Isolate* isolate = context->_isolate;
v8::HandleScope scope(isolate);
v8::Handle<v8::Object> current = isolate->GetCurrentContext()->Global();
v8::TryCatch tryCatch(isolate);
// get built-in Function constructor (see ECMA-262 5th edition 15.3.2)
v8::Local<v8::Function> ctor = v8::Local<v8::Function>::Cast(
current->Get(TRI_V8_ASCII_STRING(isolate, "Function")));
v8::Handle<v8::Value> args[1] = {TRI_V8_PAIR_STRING(isolate, body, bodySize)};
v8::Local<v8::Object> function = ctor->NewInstance(TRI_IGETC, 1, args).FromMaybe(v8::Local<v8::Object>());
v8::Handle<v8::Function> action = v8::Local<v8::Function>::Cast(function);
v8::Handle<v8::Value> rv;
if (!action.IsEmpty()) {
action->SetName(TRI_V8_ASCII_STRING(isolate, "source"));
TRI_GET_GLOBALS();
TRI_fake_action_t adminExecuteAction("_admin/execute", 2);
v8g->_currentRequest = TRI_RequestCppToV8(isolate, v8g, _request.get(), &adminExecuteAction);
v8g->_currentResponse = v8::Object::New(isolate);
auto guard = scopeGuard([&v8g, &isolate]() {
v8g->_currentRequest = v8::Undefined(isolate);
v8g->_currentResponse = v8::Undefined(isolate);
});
v8::Handle<v8::Value> args[] = {v8::Null(isolate)};
rv = action->Call(current, 0, args);
}
if (tryCatch.HasCaught()) {
// got an error
std::string errorMessage;
auto stacktraceV8 = tryCatch.StackTrace(TRI_IGETC).FromMaybe(v8::Local<v8::Value>());
v8::String::Utf8Value tryCatchStackTrace(isolate, stacktraceV8);
if (*tryCatchStackTrace != nullptr) {
errorMessage = *tryCatchStackTrace;
} else if (!tryCatch.Message().IsEmpty()) {
v8::String::Utf8Value tryCatchMessage(isolate, tryCatch.Message()->Get());
if (*tryCatchMessage != nullptr) {
errorMessage = *tryCatchMessage;
}
}
_response->setResponseCode(rest::ResponseCode::SERVER_ERROR);
switch (_response->transportType()) {
case Endpoint::TransportType::HTTP: {
HttpResponse* httpResponse = dynamic_cast<HttpResponse*>(_response.get());
if (httpResponse == nullptr) {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "unable to cast response object");
}
_response->setContentType(rest::ContentType::TEXT);
httpResponse->body().appendText(errorMessage.data(), errorMessage.size());
break;
}
case Endpoint::TransportType::VST: {
VPackBuffer<uint8_t> buffer;
VPackBuilder builder(buffer);
builder.add(VPackValuePair(reinterpret_cast<uint8_t const*>(errorMessage.data()), errorMessage.size()));
_response->setContentType(rest::ContentType::VPACK);
_response->setPayload(std::move(buffer), true);
break;
}
}
} else {
// all good!
bool returnAsJSON = _request->parsedValue("returnAsJSON", false);
if (returnAsJSON) {
// if the result is one of the following type, we return it as is
returnAsJSON &= (rv->IsString() || rv->IsStringObject() ||
rv->IsNumber() || rv->IsNumberObject() ||
rv->IsBoolean());
}
VPackBuilder result;
bool handled = false;
int res = TRI_ERROR_FAILED;
if (returnAsJSON) {
result.openObject(true);
result.add(StaticStrings::Error, VPackValue(false));
result.add(StaticStrings::Code, VPackValue(static_cast<int>(rest::ResponseCode::OK)));
if (rv->IsObject()) {
res = TRI_V8ToVPack(isolate, result, rv, false);
handled = true;
}
result.close();
}
if (!handled) {
result.clear();
VPackBuilder temp;
res = TRI_V8ToVPack(isolate, temp, rv, false);
result.add(temp.slice());
}
if (res != TRI_ERROR_NO_ERROR) {
THROW_ARANGO_EXCEPTION(res);
}
generateResult(rest::ResponseCode::OK, result.slice());
}
}
} catch (basics::Exception const& ex) {
generateError(GeneralResponse::responseCode(ex.code()), ex.code(), ex.what());
} catch (std::exception const& ex) {
generateError(rest::ResponseCode::SERVER_ERROR, TRI_ERROR_INTERNAL, ex.what());
}
return RestStatus::DONE;
}

View File

@ -0,0 +1,41 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 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 ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGOD_REST_HANDLER_REST_ADMIN_EXECUTE_HANDLER_H
#define ARANGOD_REST_HANDLER_REST_ADMIN_EXECUTE_HANDLER_H 1
#include "RestHandler/RestVocbaseBaseHandler.h"
namespace arangodb {
class RestAdminExecuteHandler : public arangodb::RestVocbaseBaseHandler {
public:
RestAdminExecuteHandler(GeneralRequest*, GeneralResponse*);
public:
char const* name() const override final { return "RestAdminExecuteHandler"; }
RequestLane lane() const override final { return RequestLane::CLIENT_V8; }
RestStatus execute() override;
};
} // namespace arangodb
#endif

View File

@ -0,0 +1,51 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 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 ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////
#include "RestAqlReloadHandler.h"
#include "ApplicationFeatures/ApplicationServer.h"
#include "Basics/StaticStrings.h"
#include "V8Server/V8DealerFeature.h"
#include <velocypack/Builder.h>
#include <velocypack/Value.h>
#include <velocypack/velocypack-aliases.h>
using namespace arangodb;
using namespace arangodb::rest;
RestAqlReloadHandler::RestAqlReloadHandler(GeneralRequest* request, GeneralResponse* response)
: RestBaseHandler(request, response) {}
RestStatus RestAqlReloadHandler::execute() {
V8DealerFeature::DEALER->addGlobalContextMethod("reloadAql");
VPackBuilder result;
result.openObject(true);
result.add(StaticStrings::Error, VPackValue(false));
result.add(StaticStrings::Code, VPackValue(static_cast<int>(rest::ResponseCode::OK)));
result.close();
generateResult(rest::ResponseCode::OK, result.slice());
return RestStatus::DONE;
}

View File

@ -0,0 +1,41 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 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 ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGOD_REST_HANDLER_REST_AQL_RELOAD_HANDLER_H
#define ARANGOD_REST_HANDLER_REST_AQL_RELOAD_HANDLER_H 1
#include "RestHandler/RestBaseHandler.h"
namespace arangodb {
class RestAqlReloadHandler : public arangodb::RestBaseHandler {
public:
RestAqlReloadHandler(GeneralRequest*, GeneralResponse*);
public:
char const* name() const override final { return "RestAqlReloadHandler"; }
RequestLane lane() const override final { return RequestLane::CLIENT_SLOW; }
RestStatus execute() override;
};
} // namespace arangodb
#endif

View File

@ -0,0 +1,56 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 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 ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////
#include "RestAuthReloadHandler.h"
#include "ApplicationFeatures/ApplicationServer.h"
#include "Auth/UserManager.h"
#include "Basics/StaticStrings.h"
#include "GeneralServer/AuthenticationFeature.h"
#include <velocypack/Builder.h>
#include <velocypack/Value.h>
#include <velocypack/velocypack-aliases.h>
using namespace arangodb;
using namespace arangodb::rest;
RestAuthReloadHandler::RestAuthReloadHandler(GeneralRequest* request, GeneralResponse* response)
: RestBaseHandler(request, response) {}
RestStatus RestAuthReloadHandler::execute() {
auth::UserManager* um = AuthenticationFeature::instance()->userManager();
if (um != nullptr) {
um->triggerLocalReload();
um->triggerGlobalReload(); // noop except on coordinator
}
VPackBuilder result;
result.openObject(true);
result.add(StaticStrings::Error, VPackValue(false));
result.add(StaticStrings::Code, VPackValue(static_cast<int>(rest::ResponseCode::OK)));
result.close();
generateResult(rest::ResponseCode::OK, result.slice());
return RestStatus::DONE;
}

View File

@ -0,0 +1,41 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 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 ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGOD_REST_HANDLER_REST_AUTH_RELOAD_HANDLER_H
#define ARANGOD_REST_HANDLER_REST_AUTH_RELOAD_HANDLER_H 1
#include "RestHandler/RestBaseHandler.h"
namespace arangodb {
class RestAuthReloadHandler : public arangodb::RestBaseHandler {
public:
RestAuthReloadHandler(GeneralRequest*, GeneralResponse*);
public:
char const* name() const override final { return "RestAuthReloadHandler"; }
RequestLane lane() const override final { return RequestLane::CLIENT_SLOW; }
RestStatus execute() override;
};
} // namespace arangodb
#endif

View File

@ -0,0 +1,48 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 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 ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////
#include "RestTimeHandler.h"
#include "Basics/StaticStrings.h"
#include <velocypack/Builder.h>
#include <velocypack/Value.h>
#include <velocypack/velocypack-aliases.h>
using namespace arangodb;
using namespace arangodb::rest;
RestTimeHandler::RestTimeHandler(GeneralRequest* request, GeneralResponse* response)
: RestBaseHandler(request, response) {}
RestStatus RestTimeHandler::execute() {
VPackBuilder result;
result.openObject(true);
result.add(StaticStrings::Error, VPackValue(false));
result.add(StaticStrings::Code, VPackValue(static_cast<int>(rest::ResponseCode::OK)));
result.add("time", VPackValue(TRI_microtime()));
result.close();
generateResult(rest::ResponseCode::OK, result.slice());
return RestStatus::DONE;
}

View File

@ -0,0 +1,41 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 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 ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGOD_REST_HANDLER_REST_TIME_HANDLER_H
#define ARANGOD_REST_HANDLER_REST_TIME_HANDLER_H 1
#include "RestHandler/RestBaseHandler.h"
namespace arangodb {
class RestTimeHandler : public arangodb::RestBaseHandler {
public:
RestTimeHandler(GeneralRequest*, GeneralResponse*);
public:
char const* name() const override final { return "RestTimeHandler"; }
RequestLane lane() const override final { return RequestLane::CLIENT_FAST; }
RestStatus execute() override;
};
} // namespace arangodb
#endif

View File

@ -233,7 +233,7 @@ void RestTransactionHandler::executeJSTransaction() {
auto slice = _request->payload();
if (!slice.isObject()) {
generateError(
Result(TRI_ERROR_BAD_PARAMETER, "could not acquire v8 context"));
Result(TRI_ERROR_BAD_PARAMETER, "expecting object input data"));
return;
}

View File

@ -361,7 +361,6 @@ void V8DealerFeature::start() {
<< ", max: " << _nrMaxContexts;
defineDouble("V8_CONTEXTS", static_cast<double>(_nrMaxContexts));
defineBoolean("ALLOW_ADMIN_EXECUTE", _allowAdminExecute);
// setup instances
{
@ -568,22 +567,20 @@ void V8DealerFeature::unprepare() {
}
bool V8DealerFeature::addGlobalContextMethod(std::string const& method) {
auto cb = [this, &method]() -> bool {
bool result = true;
for (auto& context : _contexts) {
try {
if (!context->addGlobalContextMethod(method)) {
result = false;
}
} catch (...) {
result = false;
}
}
return result;
};
bool result = true;
CONDITION_LOCKER(guard, _contextCondition);
return cb();
for (auto& context : _contexts) {
try {
if (!context->addGlobalContextMethod(method)) {
result = false;
}
} catch (...) {
result = false;
}
}
return result;
}
void V8DealerFeature::collectGarbage() {

View File

@ -76,6 +76,8 @@ class V8DealerFeature final : public application_features::ApplicationFeature {
bool _enableJS;
public:
bool allowAdminExecute() const { return _allowAdminExecute; }
bool addGlobalContextMethod(std::string const&);
void collectGarbage();

View File

@ -105,7 +105,7 @@ class v8_action_t final : public TRI_action_t {
void** data) override {
TRI_action_result_t result;
// allow use datase execution in rest calls
// allow use database execution in rest calls
bool allowUseDatabaseInRestActions = ActionFeature::ACTION->allowUseDatabase();
if (_allowUseDatabase) {
@ -307,9 +307,10 @@ static void AddCookie(v8::Isolate* isolate, TRI_v8_global_t const* v8g,
/// @brief convert a C++ HttpRequest to a V8 request object
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Object> RequestCppToV8(v8::Isolate* isolate,
TRI_v8_global_t const* v8g,
GeneralRequest* request) {
v8::Handle<v8::Object> TRI_RequestCppToV8(v8::Isolate* isolate,
TRI_v8_global_t const* v8g,
arangodb::GeneralRequest* request,
TRI_action_t const* action) {
// setup the request
v8::Handle<v8::Object> req = v8::Object::New(isolate);
@ -505,11 +506,11 @@ static v8::Handle<v8::Object> RequestCppToV8(v8::Isolate* isolate,
req->Set(RequestTypeKey, HeadConstant);
break;
}
case rest::RequestType::GET: {
default:
TRI_GET_GLOBAL_STRING(GetConstant);
req->Set(RequestTypeKey, GetConstant);
break;
case rest::RequestType::GET:
default: {
TRI_GET_GLOBAL_STRING(GetConstant);
req->Set(RequestTypeKey, GetConstant);
break;
}
}
@ -561,6 +562,37 @@ static v8::Handle<v8::Object> RequestCppToV8(v8::Isolate* isolate,
TRI_GET_GLOBAL_STRING(CookiesKey);
req->Set(CookiesKey, cookiesObject);
}
// copy suffix, which comes from the action:
std::vector<std::string> const& suffixes = request->decodedSuffixes();
std::vector<std::string> const& rawSuffixes = request->suffixes();
uint32_t index = 0;
char const* sep = "";
size_t const n = suffixes.size();
v8::Handle<v8::Array> suffixArray =
v8::Array::New(isolate, static_cast<int>(n - action->_urlParts));
v8::Handle<v8::Array> rawSuffixArray =
v8::Array::New(isolate, static_cast<int>(n - action->_urlParts));
for (size_t s = action->_urlParts; s < n; ++s) {
suffixArray->Set(index, TRI_V8_STD_STRING(isolate, suffixes[s]));
rawSuffixArray->Set(index, TRI_V8_STD_STRING(isolate, rawSuffixes[s]));
++index;
path += sep + suffixes[s];
sep = "/";
}
TRI_GET_GLOBAL_STRING(SuffixKey);
req->Set(SuffixKey, suffixArray);
TRI_GET_GLOBAL_STRING(RawSuffixKey);
req->Set(RawSuffixKey, rawSuffixArray);
// copy full path
TRI_GET_GLOBAL_STRING(PathKey);
req->Set(PathKey, TRI_V8_STD_STRING(isolate, path));
return req;
}
@ -791,7 +823,8 @@ static void ResponseV8ToCpp(v8::Isolate* isolate, TRI_v8_global_t const* v8g,
HttpResponse* httpResponse = dynamic_cast<HttpResponse*>(response);
httpResponse->body().appendText(content, length);
TRI_FreeString(content);
} break;
}
break;
case Endpoint::TransportType::VST: {
VPackBuffer<uint8_t> buffer;
@ -800,9 +833,10 @@ static void ResponseV8ToCpp(v8::Isolate* isolate, TRI_v8_global_t const* v8g,
TRI_FreeString(content);
// create vpack from file
response->setContentType(rest::ContentType::VPACK);
response->setContentType(rest::ContentType::TEXT);
response->setPayload(std::move(buffer), true);
} break;
}
break;
default:
TRI_FreeString(content);
@ -885,39 +919,7 @@ static TRI_action_result_t ExecuteActionVocbase(TRI_vocbase_t* vocbase, v8::Isol
TRI_GET_GLOBALS();
v8::Handle<v8::Object> req = RequestCppToV8(isolate, v8g, request);
// copy suffix, which comes from the action:
std::string path = request->prefix();
std::vector<std::string> const& suffixes = request->decodedSuffixes();
std::vector<std::string> const& rawSuffixes = request->suffixes();
uint32_t index = 0;
char const* sep = "";
size_t const n = suffixes.size();
v8::Handle<v8::Array> suffixArray =
v8::Array::New(isolate, static_cast<int>(n - action->_urlParts));
v8::Handle<v8::Array> rawSuffixArray =
v8::Array::New(isolate, static_cast<int>(n - action->_urlParts));
for (size_t s = action->_urlParts; s < n; ++s) {
suffixArray->Set(index, TRI_V8_STD_STRING(isolate, suffixes[s]));
rawSuffixArray->Set(index, TRI_V8_STD_STRING(isolate, rawSuffixes[s]));
++index;
path += sep + suffixes[s];
sep = "/";
}
TRI_GET_GLOBAL_STRING(SuffixKey);
req->Set(SuffixKey, suffixArray);
TRI_GET_GLOBAL_STRING(RawSuffixKey);
req->Set(RawSuffixKey, rawSuffixArray);
// copy full path
TRI_GET_GLOBAL_STRING(PathKey);
req->Set(PathKey, TRI_V8_STD_STRING(isolate, path));
v8::Handle<v8::Object> req = TRI_RequestCppToV8(isolate, v8g, request, action);
// create the response object
v8::Handle<v8::Object> res = v8::Object::New(isolate);

View File

@ -28,6 +28,18 @@
#include <v8.h>
class TRI_action_t;
struct TRI_v8_global_t;
namespace arangodb {
class GeneralRequest;
}
v8::Handle<v8::Object> TRI_RequestCppToV8(v8::Isolate* isolate,
TRI_v8_global_t const* v8g,
arangodb::GeneralRequest* request,
TRI_action_t const* action);
void TRI_InitV8Actions(v8::Isolate* isolate, v8::Handle<v8::Context> context);
void TRI_InitV8DebugUtils(v8::Isolate* isolate, v8::Handle<v8::Context> context);

View File

@ -246,7 +246,7 @@ Result arangodb::registerUserFunction(TRI_vocbase_t& vocbase, velocypack::Slice
v8::Handle<v8::Value> result;
{
v8::TryCatch tryCatch(isolate);;
v8::TryCatch tryCatch(isolate);
result = TRI_ExecuteJavaScriptString(isolate, isolate->GetCurrentContext(),
TRI_V8_STD_STRING(isolate, testCode),

View File

@ -412,7 +412,7 @@ void Task::work(ExecContext const* exec) {
// call the function within a try/catch
try {
v8::TryCatch tryCatch(isolate);;
v8::TryCatch tryCatch(isolate);
action->Call(current, 1, &fArgs);
if (tryCatch.HasCaught()) {
if (tryCatch.CanContinue()) {

View File

@ -42,7 +42,7 @@ Result executeTransaction(v8::Isolate* isolate, basics::ReadWriteLock& lock,
v8::Handle<v8::Value> in = TRI_VPackToV8(isolate, slice);
v8::Handle<v8::Value> result;
v8::TryCatch tryCatch(isolate);;
v8::TryCatch tryCatch(isolate);
v8::Handle<v8::Object> request = v8::Object::New(isolate);
v8::Handle<v8::Value> jsPortTypeKey =
@ -276,7 +276,7 @@ Result executeTransactionJS(v8::Isolate* isolate, v8::Handle<v8::Value> const& a
v8::Local<v8::Function> ctor = v8::Local<v8::Function>::Cast(
current->Get(TRI_V8_ASCII_STRING(isolate, "Function")));
// Invoke Function constructor to create function with the given body and no
// Invoke Function constructor to create function with the given body and the
// arguments
std::string body = TRI_ObjectToString(isolate,
TRI_GetProperty(context, isolate, object, "action"));

View File

@ -1467,7 +1467,7 @@ v8::Local<v8::Value> V8ClientConnection::requestData(
int res = TRI_V8ToVPack(isolate, builder, body, false);
if (res != TRI_ERROR_NO_ERROR) {
LOG_TOPIC("46ae2", ERR, Logger::V8)
<< "error converting request body " << TRI_errno_string(res);
<< "error converting request body: " << TRI_errno_string(res);
return v8::Null(isolate);
}
req->addVPack(std::move(buffer));
@ -1526,7 +1526,7 @@ v8::Local<v8::Value> V8ClientConnection::requestDataRaw(
int res = TRI_V8ToVPack(isolate, builder, body, false);
if (res != TRI_ERROR_NO_ERROR) {
LOG_TOPIC("10318", ERR, Logger::V8)
<< "error converting request body " << TRI_errno_string(res);
<< "error converting request body: " << TRI_errno_string(res);
return v8::Null(isolate);
}
req->addVPack(std::move(buffer));

View File

@ -29,7 +29,6 @@
// //////////////////////////////////////////////////////////////////////////////
const internal = require('internal');
const console = require('console');
const actions = require('@arangodb/actions');
// //////////////////////////////////////////////////////////////////////////////
@ -47,48 +46,3 @@ actions.defineHttp({
res.body = JSON.stringify(req);
}
});
// //////////////////////////////////////////////////////////////////////////////
// / @brief was docuBlock JSF_get_admin_time
// //////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url: '_admin/time',
prefix: false,
callback: function (req, res) {
actions.resultOk(req, res, actions.HTTP_OK, { time: internal.time() });
}
});
// //////////////////////////////////////////////////////////////////////////////
// / @brief was docuBlock JSF_post_admin_execute
// //////////////////////////////////////////////////////////////////////////////
if (global.ALLOW_ADMIN_EXECUTE) {
actions.defineHttp({
url: '_admin/execute',
prefix: false,
callback: function (req, res) {
/* jshint evil: true */
var body = req.requestBody;
var result;
console.warn("about to execute: '%s'", body);
if (body !== '') {
result = eval('(function() {' + body + '}());');
}
if (req.parameters.hasOwnProperty('returnAsJSON') &&
req.parameters.returnAsJSON === 'true') {
actions.resultOk(req, res, actions.HTTP_OK, result);
} else {
actions.resultOk(req, res, actions.HTTP_OK, JSON.stringify(result));
}
}
});
}
delete global.ALLOW_ADMIN_EXECUTE;

View File

@ -1,69 +0,0 @@
/* jshint strict: false */
// //////////////////////////////////////////////////////////////////////////////
// / @brief global configuration
// /
// / @file
// /
// / DISCLAIMER
// /
// / Copyright 2014 ArangoDB 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 ArangoDB GmbH, Cologne, Germany
// /
// / @author Jan Steemann
// / @author Copyright 2014, triAGENS GmbH, Cologne, Germany
// //////////////////////////////////////////////////////////////////////////////
var actions = require('@arangodb/actions');
var configuration = require('@arangodb/configuration');
// //////////////////////////////////////////////////////////////////////////////
// / @brief _admin/configuration/versions
// //////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url: '_admin/configuration/notifications/versions',
prefix: false,
callback: function (req, res) {
var json;
try {
switch (req.requestType) {
case actions.GET:
actions.resultOk(req, res, actions.HTTP_OK, configuration.notifications.versions());
break;
case actions.PUT:
json = actions.getJsonBody(req, res, actions.HTTP_BAD);
if (json === undefined) {
return;
}
configuration.notifications.setVersions(json);
actions.resultOk(req, res, actions.HTTP_OK, {});
break;
default:
actions.resultUnsupported(req, res);
}
} catch (err) {
actions.resultException(req, res, err, undefined, false);
}
}
});

View File

@ -29,8 +29,6 @@
// //////////////////////////////////////////////////////////////////////////////
var actions = require('@arangodb/actions');
var internal = require('internal');
var users = require('@arangodb/users');
// //////////////////////////////////////////////////////////////////////////////
// / @brief main routing action
@ -72,31 +70,3 @@ actions.defineHttp({
}
}
});
// //////////////////////////////////////////////////////////////////////////////
// / @brief reloads the server authentication information
// //////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url: '_admin/auth/reload',
prefix: false,
callback: function (req, res) {
users.reload();
actions.resultOk(req, res, actions.HTTP_OK);
}
});
// //////////////////////////////////////////////////////////////////////////////
// / @brief reloads the AQL user functions
// //////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url: '_admin/aql/reload',
prefix: false,
callback: function (req, res) {
internal.reloadAqlFunctions();
actions.resultOk(req, res, actions.HTTP_OK);
}
});

View File

@ -389,7 +389,10 @@ authRouter.post('/job', function (req, res) {
`);
authRouter.delete('/job', function (req, res) {
db._frontend.removeByExample({model: 'job'}, false);
let frontend = db._collection('_frontend');
if (frontend) {
frontend.removeByExample({model: 'job'}, false);
}
res.json(true);
})
.summary('Delete all jobs')
@ -398,7 +401,10 @@ authRouter.delete('/job', function (req, res) {
`);
authRouter.delete('/job/:id', function (req, res) {
db._frontend.removeByExample({id: req.pathParams.id}, false);
let frontend = db._collection('_frontend');
if (frontend) {
frontend.removeByExample({id: req.pathParams.id}, false);
}
res.json(true);
})
.summary('Delete a job id')

View File

@ -273,24 +273,6 @@ global.DEFINE_MODULE('internal', (function () {
delete global.SYS_EXECUTE;
}
// //////////////////////////////////////////////////////////////////////////////
// / @brief getCurrentRequest
// //////////////////////////////////////////////////////////////////////////////
if (global.SYS_GET_CURRENT_REQUEST) {
exports.getCurrentRequest = global.SYS_GET_CURRENT_REQUEST;
delete global.SYS_GET_CURRENT_REQUEST;
}
// //////////////////////////////////////////////////////////////////////////////
// / @brief getCurrentResponse
// //////////////////////////////////////////////////////////////////////////////
if (global.SYS_GET_CURRENT_RESPONSE) {
exports.getCurrentResponse = global.SYS_GET_CURRENT_RESPONSE;
delete global.SYS_GET_CURRENT_RESPONSE;
}
// //////////////////////////////////////////////////////////////////////////////
// / @brief extend
// //////////////////////////////////////////////////////////////////////////////

View File

@ -23,17 +23,11 @@
// / @author Dr. Frank Celler, Lucas Dohmen
// //////////////////////////////////////////////////////////////////////////////
var db = require('@arangodb').db;
var internal = require('internal');
var shallowCopy = require('@arangodb/util').shallowCopy;
let db = require('@arangodb').db;
let internal = require('internal');
// //////////////////////////////////////////////////////////////////////////////
// / @brief the frontend collection
// //////////////////////////////////////////////////////////////////////////////
function getFrontendCollection () {
return db._collection('_frontend');
}
const cn = '_frontend';
const key = 'notifications';
// //////////////////////////////////////////////////////////////////////////////
// / @brief the notifications configuration
@ -46,36 +40,28 @@ exports.notifications = {};
// //////////////////////////////////////////////////////////////////////////////
exports.notifications.versions = function () {
var n = 'notifications';
var v = 'versions';
var d;
let frontend = getFrontendCollection();
if (!frontend) {
// collection not (yet) available
return { versions: {} };
}
let doc = {};
try {
d = frontend.document(n);
} catch (err) {
let frontend = internal.db._collection(cn);
if (frontend) {
try {
d = frontend.save({ _key: n });
} catch (err2) {
d = {};
doc = frontend.document(key);
} catch (err) {
try {
doc = frontend.insert({ _key: key });
} catch (err) {}
}
}
d = shallowCopy(d);
if (!d.hasOwnProperty(v)) {
d.versions = {};
if (!doc.hasOwnProperty('versions')) {
doc.versions = {};
}
if (internal.hasOwnProperty('frontendVersionCheck') &&
!internal.frontendVersionCheck) {
doc.enableVersionNotification = false;
}
if (!internal.frontendVersionCheck) {
d.enableVersionNotification = false;
}
return d;
return doc;
};
// //////////////////////////////////////////////////////////////////////////////
@ -83,19 +69,18 @@ exports.notifications.versions = function () {
// //////////////////////////////////////////////////////////////////////////////
exports.notifications.setVersions = function (data) {
const n = 'notifications';
let frontend = getFrontendCollection();
let frontend = internal.db._collection(cn);
if (!frontend) {
// collection not (yet) available
return;
}
try {
frontend.document(n);
// assume document is there already
frontend.update(key, data);
} catch (err) {
frontend.save({ _key: n });
// probably not, so try to insert it
data._key = key;
frontend.insert(data);
}
frontend.update(n, data);
};

View File

@ -238,11 +238,29 @@
if (global.SYS_EXECUTE_GLOBAL_CONTEXT_FUNCTION) {
exports.executeGlobalContextFunction = global.SYS_EXECUTE_GLOBAL_CONTEXT_FUNCTION;
}else {
} else {
exports.executeGlobalContextFunction = function () {
// nothing to do. we're probably in --no-server mode
};
}
// //////////////////////////////////////////////////////////////////////////////
// / @brief getCurrentRequest
// //////////////////////////////////////////////////////////////////////////////
if (global.SYS_GET_CURRENT_REQUEST) {
exports.getCurrentRequest = global.SYS_GET_CURRENT_REQUEST;
delete global.SYS_GET_CURRENT_REQUEST;
}
// //////////////////////////////////////////////////////////////////////////////
// / @brief getCurrentResponse
// //////////////////////////////////////////////////////////////////////////////
if (global.SYS_GET_CURRENT_RESPONSE) {
exports.getCurrentResponse = global.SYS_GET_CURRENT_RESPONSE;
delete global.SYS_GET_CURRENT_RESPONSE;
}
// //////////////////////////////////////////////////////////////////////////////
// / @brief reloads the AQL user functions

View File

@ -74,15 +74,7 @@ function RequireCanceledTestSuite() {
'x-arango-v8-context': 0
});
var d;
try {
d = VPACK_TO_V8(c.body);
} catch (err) {
require("internal").print(c.body);
throw err;
}
var d = VPACK_TO_V8(c.body);
assertEqual(2, d.length);
}
};