diff --git a/arangod/Actions/actions.cpp b/arangod/Actions/actions.cpp index 262b4b6c57..1fde92a2db 100644 --- a/arangod/Actions/actions.cpp +++ b/arangod/Actions/actions.cpp @@ -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> 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_DefineActionVocBase(std::string const& name, @@ -51,8 +60,7 @@ std::shared_ptr 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>* which; diff --git a/arangod/Actions/actions.h b/arangod/Actions/actions.h index b88a26d125..5a5f372a1f 100644 --- a/arangod/Actions/actions.h +++ b/arangod/Actions/actions.h @@ -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_DefineActionVocBase(std::string const& name, std::shared_ptr action); diff --git a/arangod/CMakeLists.txt b/arangod/CMakeLists.txt index 6989637fca..bdf011e4ae 100644 --- a/arangod/CMakeLists.txt +++ b/arangod/CMakeLists.txt @@ -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 diff --git a/arangod/GeneralServer/GeneralServerFeature.cpp b/arangod/GeneralServer/GeneralServerFeature.cpp index 54d94903fe..f1495aa00f 100644 --- a/arangod/GeneralServer/GeneralServerFeature.cpp +++ b/arangod/GeneralServer/GeneralServerFeature.cpp @@ -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::createNoData); + + _handlerFactory->addHandler("/_admin/aql/reload", + RestHandlerCreator::createNoData); + _handlerFactory->addHandler("/_admin/auth/reload", + RestHandlerCreator::createNoData); + + if (V8DealerFeature::DEALER && V8DealerFeature::DEALER->allowAdminExecute()) { + _handlerFactory->addHandler("/_admin/execute", + RestHandlerCreator::createNoData); + } + + _handlerFactory->addHandler("/_admin/time", + RestHandlerCreator::createNoData); + _handlerFactory->addPrefixHandler("/_api/job", RestHandlerCreator::createData, _jobManager.get()); diff --git a/arangod/GeneralServer/RequestLane.h b/arangod/GeneralServer/RequestLane.h index 23dd016023..d13a54732c 100644 --- a/arangod/GeneralServer/RequestLane.h +++ b/arangod/GeneralServer/RequestLane.h @@ -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 diff --git a/arangod/RestHandler/RestAdminExecuteHandler.cpp b/arangod/RestHandler/RestAdminExecuteHandler.cpp new file mode 100644 index 0000000000..81348bdec2 --- /dev/null +++ b/arangod/RestHandler/RestAdminExecuteHandler.cpp @@ -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 +#include +#include + +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(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 current = isolate->GetCurrentContext()->Global(); + v8::TryCatch tryCatch(isolate); + + // get built-in Function constructor (see ECMA-262 5th edition 15.3.2) + v8::Local ctor = v8::Local::Cast( + current->Get(TRI_V8_ASCII_STRING(isolate, "Function"))); + v8::Handle args[1] = {TRI_V8_PAIR_STRING(isolate, body, bodySize)}; + v8::Local function = ctor->NewInstance(TRI_IGETC, 1, args).FromMaybe(v8::Local()); + v8::Handle action = v8::Local::Cast(function); + + v8::Handle 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 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::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(_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 buffer; + VPackBuilder builder(buffer); + builder.add(VPackValuePair(reinterpret_cast(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(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; +} diff --git a/arangod/RestHandler/RestAdminExecuteHandler.h b/arangod/RestHandler/RestAdminExecuteHandler.h new file mode 100644 index 0000000000..9e4b41e10c --- /dev/null +++ b/arangod/RestHandler/RestAdminExecuteHandler.h @@ -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 diff --git a/arangod/RestHandler/RestAqlReloadHandler.cpp b/arangod/RestHandler/RestAqlReloadHandler.cpp new file mode 100644 index 0000000000..58860230f7 --- /dev/null +++ b/arangod/RestHandler/RestAqlReloadHandler.cpp @@ -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 +#include +#include + +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(rest::ResponseCode::OK))); + result.close(); + + generateResult(rest::ResponseCode::OK, result.slice()); + return RestStatus::DONE; +} diff --git a/arangod/RestHandler/RestAqlReloadHandler.h b/arangod/RestHandler/RestAqlReloadHandler.h new file mode 100644 index 0000000000..c0fabe3f08 --- /dev/null +++ b/arangod/RestHandler/RestAqlReloadHandler.h @@ -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 diff --git a/arangod/RestHandler/RestAuthReloadHandler.cpp b/arangod/RestHandler/RestAuthReloadHandler.cpp new file mode 100644 index 0000000000..c0f84faf2c --- /dev/null +++ b/arangod/RestHandler/RestAuthReloadHandler.cpp @@ -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 +#include +#include + +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(rest::ResponseCode::OK))); + result.close(); + + generateResult(rest::ResponseCode::OK, result.slice()); + return RestStatus::DONE; +} diff --git a/arangod/RestHandler/RestAuthReloadHandler.h b/arangod/RestHandler/RestAuthReloadHandler.h new file mode 100644 index 0000000000..6fa139ee1a --- /dev/null +++ b/arangod/RestHandler/RestAuthReloadHandler.h @@ -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 diff --git a/arangod/RestHandler/RestTimeHandler.cpp b/arangod/RestHandler/RestTimeHandler.cpp new file mode 100644 index 0000000000..5a5ea4f469 --- /dev/null +++ b/arangod/RestHandler/RestTimeHandler.cpp @@ -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 +#include +#include + +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(rest::ResponseCode::OK))); + result.add("time", VPackValue(TRI_microtime())); + result.close(); + + generateResult(rest::ResponseCode::OK, result.slice()); + return RestStatus::DONE; +} diff --git a/arangod/RestHandler/RestTimeHandler.h b/arangod/RestHandler/RestTimeHandler.h new file mode 100644 index 0000000000..2f88c0aa32 --- /dev/null +++ b/arangod/RestHandler/RestTimeHandler.h @@ -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 diff --git a/arangod/RestHandler/RestTransactionHandler.cpp b/arangod/RestHandler/RestTransactionHandler.cpp index fb10a3f0a9..65c0a9f042 100644 --- a/arangod/RestHandler/RestTransactionHandler.cpp +++ b/arangod/RestHandler/RestTransactionHandler.cpp @@ -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; } diff --git a/arangod/V8Server/V8DealerFeature.cpp b/arangod/V8Server/V8DealerFeature.cpp index f9f497cc30..3c4e859c8f 100644 --- a/arangod/V8Server/V8DealerFeature.cpp +++ b/arangod/V8Server/V8DealerFeature.cpp @@ -361,7 +361,6 @@ void V8DealerFeature::start() { << ", max: " << _nrMaxContexts; defineDouble("V8_CONTEXTS", static_cast(_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() { diff --git a/arangod/V8Server/V8DealerFeature.h b/arangod/V8Server/V8DealerFeature.h index 640593dbe9..ec4777ff19 100644 --- a/arangod/V8Server/V8DealerFeature.h +++ b/arangod/V8Server/V8DealerFeature.h @@ -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(); diff --git a/arangod/V8Server/v8-actions.cpp b/arangod/V8Server/v8-actions.cpp index 091e1272bd..d394ee5529 100644 --- a/arangod/V8Server/v8-actions.cpp +++ b/arangod/V8Server/v8-actions.cpp @@ -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 RequestCppToV8(v8::Isolate* isolate, - TRI_v8_global_t const* v8g, - GeneralRequest* request) { +v8::Handle TRI_RequestCppToV8(v8::Isolate* isolate, + TRI_v8_global_t const* v8g, + arangodb::GeneralRequest* request, + TRI_action_t const* action) { // setup the request v8::Handle req = v8::Object::New(isolate); @@ -505,11 +506,11 @@ static v8::Handle 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 RequestCppToV8(v8::Isolate* isolate, TRI_GET_GLOBAL_STRING(CookiesKey); req->Set(CookiesKey, cookiesObject); } + + // copy suffix, which comes from the action: + std::vector const& suffixes = request->decodedSuffixes(); + std::vector const& rawSuffixes = request->suffixes(); + + uint32_t index = 0; + char const* sep = ""; + + size_t const n = suffixes.size(); + v8::Handle suffixArray = + v8::Array::New(isolate, static_cast(n - action->_urlParts)); + v8::Handle rawSuffixArray = + v8::Array::New(isolate, static_cast(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(response); httpResponse->body().appendText(content, length); TRI_FreeString(content); - } break; + } + break; case Endpoint::TransportType::VST: { VPackBuffer 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 req = RequestCppToV8(isolate, v8g, request); - - // copy suffix, which comes from the action: - std::string path = request->prefix(); - std::vector const& suffixes = request->decodedSuffixes(); - std::vector const& rawSuffixes = request->suffixes(); - - uint32_t index = 0; - char const* sep = ""; - - size_t const n = suffixes.size(); - v8::Handle suffixArray = - v8::Array::New(isolate, static_cast(n - action->_urlParts)); - v8::Handle rawSuffixArray = - v8::Array::New(isolate, static_cast(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 req = TRI_RequestCppToV8(isolate, v8g, request, action); // create the response object v8::Handle res = v8::Object::New(isolate); diff --git a/arangod/V8Server/v8-actions.h b/arangod/V8Server/v8-actions.h index 981c69f843..2926814e5c 100644 --- a/arangod/V8Server/v8-actions.h +++ b/arangod/V8Server/v8-actions.h @@ -28,6 +28,18 @@ #include +class TRI_action_t; +struct TRI_v8_global_t; + +namespace arangodb { +class GeneralRequest; +} + +v8::Handle 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 context); void TRI_InitV8DebugUtils(v8::Isolate* isolate, v8::Handle context); diff --git a/arangod/VocBase/Methods/AqlUserFunctions.cpp b/arangod/VocBase/Methods/AqlUserFunctions.cpp index 6b50b9d62e..42926ca48e 100644 --- a/arangod/VocBase/Methods/AqlUserFunctions.cpp +++ b/arangod/VocBase/Methods/AqlUserFunctions.cpp @@ -246,7 +246,7 @@ Result arangodb::registerUserFunction(TRI_vocbase_t& vocbase, velocypack::Slice v8::Handle result; { - v8::TryCatch tryCatch(isolate);; + v8::TryCatch tryCatch(isolate); result = TRI_ExecuteJavaScriptString(isolate, isolate->GetCurrentContext(), TRI_V8_STD_STRING(isolate, testCode), diff --git a/arangod/VocBase/Methods/Tasks.cpp b/arangod/VocBase/Methods/Tasks.cpp index adc5d95411..653050b340 100644 --- a/arangod/VocBase/Methods/Tasks.cpp +++ b/arangod/VocBase/Methods/Tasks.cpp @@ -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()) { diff --git a/arangod/VocBase/Methods/Transactions.cpp b/arangod/VocBase/Methods/Transactions.cpp index 93605e1738..a28c231029 100644 --- a/arangod/VocBase/Methods/Transactions.cpp +++ b/arangod/VocBase/Methods/Transactions.cpp @@ -42,7 +42,7 @@ Result executeTransaction(v8::Isolate* isolate, basics::ReadWriteLock& lock, v8::Handle in = TRI_VPackToV8(isolate, slice); v8::Handle result; - v8::TryCatch tryCatch(isolate);; + v8::TryCatch tryCatch(isolate); v8::Handle request = v8::Object::New(isolate); v8::Handle jsPortTypeKey = @@ -276,7 +276,7 @@ Result executeTransactionJS(v8::Isolate* isolate, v8::Handle const& a v8::Local ctor = v8::Local::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")); diff --git a/arangosh/Shell/V8ClientConnection.cpp b/arangosh/Shell/V8ClientConnection.cpp index 4def364d55..6571f10e02 100644 --- a/arangosh/Shell/V8ClientConnection.cpp +++ b/arangosh/Shell/V8ClientConnection.cpp @@ -1467,7 +1467,7 @@ v8::Local 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 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)); diff --git a/js/actions/_admin/app.js b/js/actions/_admin/app.js index c815be74b7..9242575c5f 100644 --- a/js/actions/_admin/app.js +++ b/js/actions/_admin/app.js @@ -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; diff --git a/js/actions/api-configuration.js b/js/actions/api-configuration.js deleted file mode 100644 index 59f2834c40..0000000000 --- a/js/actions/api-configuration.js +++ /dev/null @@ -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); - } - } -}); diff --git a/js/actions/api-system.js b/js/actions/api-system.js index e0ed3b33cc..09a578604e 100644 --- a/js/actions/api-system.js +++ b/js/actions/api-system.js @@ -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); - } -}); diff --git a/js/apps/system/_admin/aardvark/APP/aardvark.js b/js/apps/system/_admin/aardvark/APP/aardvark.js index c4fb6edfff..45417f1988 100644 --- a/js/apps/system/_admin/aardvark/APP/aardvark.js +++ b/js/apps/system/_admin/aardvark/APP/aardvark.js @@ -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') diff --git a/js/common/bootstrap/modules/internal.js b/js/common/bootstrap/modules/internal.js index c7b890b10a..2c03ea00a9 100644 --- a/js/common/bootstrap/modules/internal.js +++ b/js/common/bootstrap/modules/internal.js @@ -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 // ////////////////////////////////////////////////////////////////////////////// diff --git a/js/server/modules/@arangodb/configuration.js b/js/common/modules/@arangodb/configuration.js similarity index 64% rename from js/server/modules/@arangodb/configuration.js rename to js/common/modules/@arangodb/configuration.js index bc5336d22d..f707b48252 100644 --- a/js/server/modules/@arangodb/configuration.js +++ b/js/common/modules/@arangodb/configuration.js @@ -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); }; diff --git a/js/server/bootstrap/modules/internal.js b/js/server/bootstrap/modules/internal.js index 359ee1d346..fa0d2a5800 100644 --- a/js/server/bootstrap/modules/internal.js +++ b/js/server/bootstrap/modules/internal.js @@ -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 diff --git a/tests/js/client/shell/shell-require-canceled.js b/tests/js/client/shell/shell-require-canceled.js index 47735e592c..da31d48a68 100644 --- a/tests/js/client/shell/shell-require-canceled.js +++ b/tests/js/client/shell/shell-require-canceled.js @@ -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); } };