bool Node::handle<SET>(VPackSlice const& slice) { Slice val = slice.get("new"); if (val.isObject()) { if (val.hasKey("op")) { // No longer a keyword but a regular key "op" if (_children.find("op") == _children.end()) { _children["op"] = std::make_shared<Node>("op", this); } *(_children["op"]) = val.get("op"); } else { // Deeper down this->applies(val); } } else { *this = val; } if (slice.hasKey("ttl")) { VPackSlice ttl_v = slice.get("ttl"); if (ttl_v.isNumber()) { long ttl = 1000l * ((ttl_v.isDouble()) ? static_cast<long>(slice.get("ttl").getDouble()) : static_cast<long>(slice.get("ttl").getInt())); addTimeToLive(ttl); } else { LOG_TOPIC(WARN, Logger::AGENCY) << "Non-number value assigned to ttl: " << ttl_v.toJson(); } } return true; }
TraverserExpression::TraverserExpression(VPackSlice const& slice) { isEdgeAccess = slice.get("isEdgeAccess").getBool(); comparisonType = static_cast<aql::AstNodeType>( slice.get("comparisonType").getNumber<uint32_t>()); auto registerNode = [&](aql::AstNode const* node) -> void { _nodeRegister.emplace_back(node); }; auto registerString = [&](std::string const& str) -> char const* { auto copy = std::make_unique<std::string>(str.c_str(), str.size()); _stringRegister.emplace_back(copy.get()); auto p = copy.release(); TRI_ASSERT(p != nullptr); TRI_ASSERT(p->c_str() != nullptr); return p->c_str(); // should never change its position, even if vector // grows/shrinks }; VPackSlice compareToSlice = slice.get("compareTo"); VPackBuilder* builder = new VPackBuilder; try { builder->add(compareToSlice); } catch (...) { delete builder; throw; } compareTo.reset(builder); // If this fails everything before does not leak varAccess = new aql::AstNode(registerNode, registerString, slice.get("varAccess")); }
void RestVocbaseBaseHandler::generate20x( arangodb::OperationResult const& result, std::string const& collectionName, TRI_col_type_e type, VPackOptions const* options) { VPackSlice slice = result.slice(); if (slice.isNone()) { // will happen if silent == true slice = VelocyPackHelper::EmptyObjectValue(); } else { TRI_ASSERT(slice.isObject() || slice.isArray()); if (slice.isObject()) { _response->setHeaderNC( StaticStrings::Etag, "\"" + slice.get(StaticStrings::RevString).copyString() + "\""); // pre 1.4 location headers withdrawn for >= 3.0 std::string escapedHandle(assembleDocumentId( collectionName, slice.get(StaticStrings::KeyString).copyString(), true)); _response->setHeaderNC(StaticStrings::Location, std::string("/_db/" + _request->databaseName() + DOCUMENT_PATH + "/" + escapedHandle)); } } writeResult(slice, *options); }
void RestVocbaseBaseHandler::generatePreconditionFailed( VPackSlice const& slice) { createResponse(GeneralResponse::ResponseCode::PRECONDITION_FAILED); if (slice.isObject()) { // single document case std::string const rev = VelocyPackHelper::getStringValue(slice, StaticStrings::RevString, ""); _response->setHeaderNC(StaticStrings::Etag, "\"" + rev + "\""); } VPackBuilder builder; { VPackObjectBuilder guard(&builder); builder.add("error", VPackValue(true)); builder.add("code", VPackValue(static_cast<int32_t>( GeneralResponse::ResponseCode::PRECONDITION_FAILED))); builder.add("errorNum", VPackValue(TRI_ERROR_ARANGO_CONFLICT)); builder.add("errorMessage", VPackValue("precondition failed")); if (slice.isObject()) { builder.add(StaticStrings::IdString, slice.get(StaticStrings::IdString)); builder.add(StaticStrings::KeyString, slice.get(StaticStrings::KeyString)); builder.add(StaticStrings::RevString, slice.get(StaticStrings::RevString)); } else { builder.add("result", slice); } } auto transactionContext(StandaloneTransactionContext::Create(_vocbase)); writeResult(builder.slice(), *(transactionContext->getVPackOptionsForDump())); }
/// @brief remaining int64_t RemoteBlock::remaining() { DEBUG_BEGIN_BLOCK(); // For every call we simply forward via HTTP std::unique_ptr<ClusterCommResult> res = sendRequest( rest::RequestType::GET, "/_api/aql/remaining/", std::string()); throwExceptionAfterBadSyncRequest(res.get(), false); // If we get here, then res->result is the response which will be // a serialized AqlItemBlock: StringBuffer const& responseBodyBuf(res->result->getBody()); std::shared_ptr<VPackBuilder> builder = VPackParser::fromJson(responseBodyBuf.c_str(), responseBodyBuf.length()); VPackSlice slice = builder->slice(); if (!slice.hasKey("error") || slice.get("error").getBoolean()) { THROW_ARANGO_EXCEPTION(TRI_ERROR_CLUSTER_AQL_COMMUNICATION); } int64_t remaining = 0; if (slice.hasKey("remaining")) { remaining = slice.get("remaining").getNumericValue<int64_t>(); } return remaining; // cppcheck-suppress style DEBUG_END_BLOCK(); }
/// Log transactions (follower) arangodb::consensus::index_t State::log(query_t const& transactions, size_t ndups) { VPackSlice slices = transactions->slice(); TRI_ASSERT(slices.isArray()); size_t nqs = slices.length(); TRI_ASSERT(nqs > ndups); MUTEX_LOCKER(mutexLocker, _logLock); // log entries must stay in order for (size_t i = ndups; i < nqs; ++i) { VPackSlice slice = slices[i]; try { auto idx = slice.get("index").getUInt(); auto trm = slice.get("term").getUInt(); auto buf = std::make_shared<Buffer<uint8_t>>(); buf->append((char const*)slice.get("query").begin(), slice.get("query").byteSize()); // to RAM _log.push_back(log_t(idx, trm, buf)); // to disk persist(idx, trm, slice.get("query")); } catch (std::exception const& e) { LOG_TOPIC(ERR, Logger::AGENCY) << e.what() << " " << __FILE__ << __LINE__; } } TRI_ASSERT(!_log.empty()); return _log.back().index; }
AuthJwtResult AuthInfo::validateJwtBody(std::string const& body) { std::shared_ptr<VPackBuilder> bodyBuilder = parseJson(StringUtils::decodeBase64(body), "jwt body"); AuthJwtResult authResult; if (bodyBuilder.get() == nullptr) { return authResult; } VPackSlice const bodySlice = bodyBuilder->slice(); if (!bodySlice.isObject()) { return authResult; } VPackSlice const issSlice = bodySlice.get("iss"); if (!issSlice.isString()) { return authResult; } if (issSlice.copyString() != "arangodb") { return authResult; } if (bodySlice.hasKey("preferred_username")) { VPackSlice const usernameSlice = bodySlice.get("preferred_username"); if (!usernameSlice.isString()) { return authResult; } authResult._username = usernameSlice.copyString(); } else if (bodySlice.hasKey("server_id")) { // mop: hmm...nothing to do here :D // authResult._username = "******"; } else { return authResult; } // mop: optional exp (cluster currently uses non expiring jwts) if (bodySlice.hasKey("exp")) { VPackSlice const expSlice = bodySlice.get("exp"); if (!expSlice.isNumber()) { return authResult; } std::chrono::system_clock::time_point expires( std::chrono::seconds(expSlice.getNumber<uint64_t>())); std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); if (now >= expires) { return authResult; } authResult._expires = true; authResult._expireTime = expires; } authResult._authorized = true; return authResult; }
arangodb::traverser::TraverserOptions::LookupInfo::LookupInfo( arangodb::aql::Query* query, VPackSlice const& info, VPackSlice const& shards) { TRI_ASSERT(shards.isArray()); idxHandles.reserve(shards.length()); conditionNeedUpdate = arangodb::basics::VelocyPackHelper::getBooleanValue( info, "condNeedUpdate", false); conditionMemberToUpdate = arangodb::basics::VelocyPackHelper::getNumericValue<size_t>( info, "condMemberToUpdate", 0); VPackSlice read = info.get("handle"); if (!read.isObject()) { THROW_ARANGO_EXCEPTION_MESSAGE( TRI_ERROR_BAD_PARAMETER, "Each lookup requires handle to be an object"); } read = read.get("id"); if (!read.isString()) { THROW_ARANGO_EXCEPTION_MESSAGE( TRI_ERROR_BAD_PARAMETER, "Each handle requires id to be a string"); } std::string idxId = read.copyString(); auto trx = query->trx(); for (auto const& it : VPackArrayIterator(shards)) { if (!it.isString()) { THROW_ARANGO_EXCEPTION_MESSAGE( TRI_ERROR_BAD_PARAMETER, "Shards have to be a list of strings"); } idxHandles.emplace_back(trx->getIndexByIdentifier(it.copyString(), idxId)); } read = info.get("expression"); if (!read.isObject()) { THROW_ARANGO_EXCEPTION_MESSAGE( TRI_ERROR_BAD_PARAMETER, "Each lookup requires expression to be an object"); } expression = new aql::Expression(query->ast(), read); read = info.get("condition"); if (!read.isObject()) { THROW_ARANGO_EXCEPTION_MESSAGE( TRI_ERROR_BAD_PARAMETER, "Each lookup requires condition to be an object"); } indexCondition = new aql::AstNode(query->ast(), read); }
/// @brief shutdown, will be called exactly once for the whole query int RemoteBlock::shutdown(int errorCode) { DEBUG_BEGIN_BLOCK(); if (!_isResponsibleForInitializeCursor) { // do nothing... return TRI_ERROR_NO_ERROR; } // For every call we simply forward via HTTP std::unique_ptr<ClusterCommResult> res = sendRequest(rest::RequestType::PUT, "/_api/aql/shutdown/", std::string("{\"code\":" + std::to_string(errorCode) + "}")); if (throwExceptionAfterBadSyncRequest(res.get(), true)) { // artificially ignore error in case query was not found during shutdown return TRI_ERROR_NO_ERROR; } StringBuffer const& responseBodyBuf(res->result->getBody()); std::shared_ptr<VPackBuilder> builder = VPackParser::fromJson(responseBodyBuf.c_str(), responseBodyBuf.length()); VPackSlice slice = builder->slice(); // read "warnings" attribute if present and add it to our query if (slice.isObject()) { VPackSlice warnings = slice.get("warnings"); if (warnings.isArray()) { auto query = _engine->getQuery(); for (auto const& it : VPackArrayIterator(warnings)) { if (it.isObject()) { VPackSlice code = it.get("code"); VPackSlice message = it.get("message"); if (code.isNumber() && message.isString()) { query->registerWarning(code.getNumericValue<int>(), message.copyString().c_str()); } } } } } if (slice.hasKey("code")) { return slice.get("code").getNumericValue<int>(); } return TRI_ERROR_INTERNAL; // cppcheck-suppress style DEBUG_END_BLOCK(); }
bool Node::handle<OBSERVE>(VPackSlice const& slice) { if (!slice.hasKey("url")) return false; if (!slice.get("url").isString()) return false; std::string url(slice.get("url").copyString()), uri(this->uri()); // check if such entry exists if (!observedBy(url)) { store().observerTable().emplace( std::pair<std::string, std::string>(url, uri)); store().observedTable().emplace( std::pair<std::string, std::string>(uri, url)); return true; } return false; }
/// @brief initialize int RemoteBlock::initialize() { DEBUG_BEGIN_BLOCK(); if (!_isResponsibleForInitializeCursor) { // do nothing... return TRI_ERROR_NO_ERROR; } std::unique_ptr<ClusterCommResult> res = sendRequest(rest::RequestType::PUT, "/_api/aql/initialize/", "{}"); throwExceptionAfterBadSyncRequest(res.get(), false); // If we get here, then res->result is the response which will be // a serialized AqlItemBlock: StringBuffer const& responseBodyBuf(res->result->getBody()); std::shared_ptr<VPackBuilder> builder = VPackParser::fromJson(responseBodyBuf.c_str(), responseBodyBuf.length()); VPackSlice slice = builder->slice(); if (slice.hasKey("code")) { return slice.get("code").getNumericValue<int>(); } return TRI_ERROR_INTERNAL; // cppcheck-suppress style DEBUG_END_BLOCK(); }
uint64_t VelocyPackHelper::hashByAttributes( VPackSlice slice, std::vector<std::string> const& attributes, bool docComplete, int& error, std::string const& key) { uint64_t hash = TRI_FnvHashBlockInitial(); error = TRI_ERROR_NO_ERROR; slice = slice.resolveExternal(); if (slice.isObject()) { for (auto const& attr : attributes) { VPackSlice sub = slice.get(attr).resolveExternal(); if (sub.isNone()) { if (attr == StaticStrings::KeyString && !key.empty()) { VPackBuilder temporaryBuilder; temporaryBuilder.add(VPackValue(key)); hash = temporaryBuilder.slice().normalizedHash(hash); continue; } if (!docComplete) { error = TRI_ERROR_CLUSTER_NOT_ALL_SHARDING_ATTRIBUTES_GIVEN; } // Null is equal to None/not present sub = VPackSlice::nullSlice(); } hash = sub.normalizedHash(hash); } } return hash; }
bool AuthInfo::validateJwtHeader(std::string const& header) { std::shared_ptr<VPackBuilder> headerBuilder = parseJson(StringUtils::decodeBase64(header), "jwt header"); if (headerBuilder.get() == nullptr) { return false; } VPackSlice const headerSlice = headerBuilder->slice(); if (!headerSlice.isObject()) { return false; } VPackSlice const algSlice = headerSlice.get("alg"); VPackSlice const typSlice = headerSlice.get("typ"); if (!algSlice.isString()) { return false; } if (!typSlice.isString()) { return false; } if (algSlice.copyString() != "HS256") { return false; } std::string typ = typSlice.copyString(); if (typ != "JWT") { return false; } return true; }
ShortestPathOptions::ShortestPathOptions(VPackSlice const& slice) { VPackSlice obj = slice.get("shortestpathFlags"); weightAttribute = ""; if (obj.hasKey("weightAttribute")) { VPackSlice v = obj.get("weightAttribute"); if (v.isString()) { weightAttribute = v.copyString(); } } defaultWeight = 1; if (obj.hasKey("defaultWeight")) { VPackSlice v = obj.get("defaultWeight"); if (v.isNumber()) { defaultWeight = v.getNumericValue<double>(); } } }
static bool SortCollections(VPackSlice const& l, VPackSlice const& r) { VPackSlice const left = l.get("parameters"); VPackSlice const right = r.get("parameters"); int leftType = arangodb::basics::VelocyPackHelper::getNumericValue<int>(left, "type", 0); int rightType = arangodb::basics::VelocyPackHelper::getNumericValue<int>( right, "type", 0); if (leftType != rightType) { return leftType < rightType; } std::string leftName = arangodb::basics::VelocyPackHelper::getStringValue(left, "name", ""); std::string rightName = arangodb::basics::VelocyPackHelper::getStringValue(right, "name", ""); return strcasecmp(leftName.c_str(), rightName.c_str()) < 0; }
arangodb::traverser::TraverserOptions::TraverserOptions( arangodb::Transaction* trx, VPackSlice const& slice) : _trx(trx), _baseVertexExpression(nullptr), _tmpVar(nullptr), _ctx(new aql::FixedVarExpressionContext()), _isCoordinator(arangodb::ServerState::instance()->isCoordinator()), minDepth(1), maxDepth(1), useBreadthFirst(false), uniqueVertices(UniquenessLevel::NONE), uniqueEdges(UniquenessLevel::PATH) { VPackSlice obj = slice.get("traversalFlags"); TRI_ASSERT(obj.isObject()); minDepth = VPackHelper::getNumericValue<uint64_t>(obj, "minDepth", 1); maxDepth = VPackHelper::getNumericValue<uint64_t>(obj, "maxDepth", 1); TRI_ASSERT(minDepth <= maxDepth); useBreadthFirst = VPackHelper::getBooleanValue(obj, "bfs", false); std::string tmp = VPackHelper::getStringValue(obj, "uniqueVertices", ""); if (tmp == "path") { uniqueVertices = arangodb::traverser::TraverserOptions::UniquenessLevel::PATH; } else if (tmp == "global") { if (!useBreadthFirst) { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, "uniqueVertices: 'global' is only " "supported, with bfs: true due to " "unpredictable results."); } uniqueVertices = arangodb::traverser::TraverserOptions::UniquenessLevel::GLOBAL; } else { uniqueVertices = arangodb::traverser::TraverserOptions::UniquenessLevel::NONE; } tmp = VPackHelper::getStringValue(obj, "uniqueEdges", ""); if (tmp == "none") { uniqueEdges = arangodb::traverser::TraverserOptions::UniquenessLevel::NONE; } else if (tmp == "global") { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, "uniqueEdges: 'global' is not supported, " "due to unpredictable results. Use 'path' " "or 'none' instead"); uniqueEdges = arangodb::traverser::TraverserOptions::UniquenessLevel::GLOBAL; } else { uniqueEdges = arangodb::traverser::TraverserOptions::UniquenessLevel::PATH; } }
HttpHandler::status_t RestAuthHandler::execute() { auto const type = _request->requestType(); if (type != GeneralRequest::RequestType::POST) { generateError(GeneralResponse::ResponseCode::METHOD_NOT_ALLOWED, TRI_ERROR_HTTP_METHOD_NOT_ALLOWED); return status_t(HANDLER_DONE); } VPackOptions options = VPackOptions::Defaults; options.checkAttributeUniqueness = true; bool parseSuccess; std::shared_ptr<VPackBuilder> parsedBody = parseVelocyPackBody(&options, parseSuccess); if (!parseSuccess) { return badRequest(); } VPackSlice slice = parsedBody->slice(); if (!slice.isObject()) { return badRequest(); } VPackSlice usernameSlice = slice.get("username"); VPackSlice passwordSlice = slice.get("password"); if (!usernameSlice.isString() || !passwordSlice.isString()) { return badRequest(); } std::string const username = usernameSlice.copyString(); std::string const password = passwordSlice.copyString(); AuthResult auth = RestServerFeature::AUTH_INFO.checkPassword(username, password); if (auth._authorized) { VPackBuilder resultBuilder; { VPackObjectBuilder b(&resultBuilder); std::string jwt = generateJwt(username, password); resultBuilder.add("jwt", VPackValue(jwt)); resultBuilder.add("must_change_password", VPackValue(auth._mustChange)); } generateDocument(resultBuilder.slice(), true, &VPackOptions::Defaults); return status_t(HANDLER_DONE); } else { // mop: rfc 2616 10.4.2 (if credentials wrong 401) generateError(GeneralResponse::ResponseCode::UNAUTHORIZED, TRI_ERROR_HTTP_UNAUTHORIZED, "Wrong credentials"); return status_t(HANDLER_DONE); } }
/// @brief initializeCursor, could be called multiple times int RemoteBlock::initializeCursor(AqlItemBlock* items, size_t pos) { DEBUG_BEGIN_BLOCK(); // For every call we simply forward via HTTP if (!_isResponsibleForInitializeCursor) { // do nothing... return TRI_ERROR_NO_ERROR; } VPackBuilder builder; builder.openObject(); if (items == nullptr) { // first call, items is still a nullptr builder.add("exhausted", VPackValue(true)); builder.add("error", VPackValue(false)); } else { builder.add("exhausted", VPackValue(false)); builder.add("error", VPackValue(false)); builder.add("pos", VPackValue(pos)); builder.add(VPackValue("items")); builder.openObject(); items->toVelocyPack(_engine->getQuery()->trx(), builder); builder.close(); } builder.close(); std::string bodyString(builder.slice().toJson()); std::unique_ptr<ClusterCommResult> res = sendRequest( rest::RequestType::PUT, "/_api/aql/initializeCursor/", bodyString); throwExceptionAfterBadSyncRequest(res.get(), false); // If we get here, then res->result is the response which will be // a serialized AqlItemBlock: StringBuffer const& responseBodyBuf(res->result->getBody()); { std::shared_ptr<VPackBuilder> builder = VPackParser::fromJson( responseBodyBuf.c_str(), responseBodyBuf.length()); VPackSlice slice = builder->slice(); if (slice.hasKey("code")) { return slice.get("code").getNumericValue<int>(); } return TRI_ERROR_INTERNAL; } // cppcheck-suppress style DEBUG_END_BLOCK(); }
int Syncer::createIndex(VPackSlice const& slice) { VPackSlice const indexSlice = slice.get("index"); if (!indexSlice.isObject()) { return TRI_ERROR_REPLICATION_INVALID_RESPONSE; } TRI_voc_cid_t cid = getCid(slice); std::string cnameString = getCName(slice); // TODO // Backwards compatibility. old check to nullptr, new is empty string // Other api does not know yet. char const* cname = nullptr; if (!cnameString.empty()) { cname = cnameString.c_str(); } try { CollectionGuard guard(_vocbase, cid, cname); if (guard.collection() == nullptr) { return TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND; } TRI_document_collection_t* document = guard.collection()->_collection; SingleCollectionTransaction trx(StandaloneTransactionContext::Create(_vocbase), guard.collection()->_cid, TRI_TRANSACTION_WRITE); int res = trx.begin(); if (res != TRI_ERROR_NO_ERROR) { return res; } arangodb::Index* idx = nullptr; res = TRI_FromVelocyPackIndexDocumentCollection(&trx, document, indexSlice, &idx); if (res == TRI_ERROR_NO_ERROR) { res = TRI_SaveIndex(document, idx, true); } res = trx.finish(res); return res; } catch (arangodb::basics::Exception const& ex) { return ex.code(); } catch (...) { return TRI_ERROR_INTERNAL; } }
bool VelocyPackHelper::getBooleanValue(VPackSlice const& slice, char const* name, bool defaultValue) { TRI_ASSERT(slice.isObject()); if (!slice.hasKey(name)) { return defaultValue; } VPackSlice const& sub = slice.get(name); if (sub.isBoolean()) { return sub.getBool(); } return defaultValue; }
/// @brief skipSome size_t RemoteBlock::skipSome(size_t atLeast, size_t atMost) { DEBUG_BEGIN_BLOCK(); // For every call we simply forward via HTTP VPackBuilder builder; builder.openObject(); builder.add("atLeast", VPackValue(atLeast)); builder.add("atMost", VPackValue(atMost)); builder.close(); std::string bodyString(builder.slice().toJson()); std::unique_ptr<ClusterCommResult> res = sendRequest(rest::RequestType::PUT, "/_api/aql/skipSome/", bodyString); throwExceptionAfterBadSyncRequest(res.get(), false); // If we get here, then res->result is the response which will be // a serialized AqlItemBlock: StringBuffer const& responseBodyBuf(res->result->getBody()); { std::shared_ptr<VPackBuilder> builder = VPackParser::fromJson( responseBodyBuf.c_str(), responseBodyBuf.length()); VPackSlice slice = builder->slice(); if (!slice.hasKey("error") || slice.get("error").getBoolean()) { THROW_ARANGO_EXCEPTION(TRI_ERROR_CLUSTER_AQL_COMMUNICATION); } size_t skipped = 0; if (slice.hasKey("skipped")) { skipped = slice.get("skipped").getNumericValue<size_t>(); } return skipped; } // cppcheck-suppress style DEBUG_END_BLOCK(); }
bool Node::handle<UNOBSERVE>(VPackSlice const& slice) { if (!slice.hasKey("url")) return false; if (!slice.get("url").isString()) return false; std::string url(slice.get("url").copyString()), uri(this->uri()); // delete in both cases a single entry (ensured above) // breaking the iterators is fine then auto ret = store().observerTable().equal_range(url); for (auto it = ret.first; it != ret.second; ++it) { if (it->second == uri) { store().observerTable().erase(it); break; } } ret = store().observedTable().equal_range(uri); for (auto it = ret.first; it != ret.second; ++it) { if (it->second == url) { store().observedTable().erase(it); return true; } } return false; }
std::string VelocyPackHelper::checkAndGetStringValue(VPackSlice const& slice, std::string const& name) { TRI_ASSERT(slice.isObject()); if (!slice.hasKey(name)) { std::string msg = "The attribute '" + name + "' was not found."; THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, msg); } VPackSlice const sub = slice.get(name); if (!sub.isString()) { std::string msg = "The attribute '" + name + "' is not a string."; THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, msg); } return sub.copyString(); }
std::string VelocyPackHelper::getStringValue(VPackSlice slice, std::string const& name, std::string const& defaultValue) { if (slice.isExternal()) { slice = VPackSlice(slice.getExternal()); } TRI_ASSERT(slice.isObject()); if (!slice.hasKey(name)) { return defaultValue; } VPackSlice const sub = slice.get(name); if (!sub.isString()) { return defaultValue; } return sub.copyString(); }
bool Node::handle<PREPEND>(VPackSlice const& slice) { if (!slice.hasKey("new")) { LOG_TOPIC(WARN, Logger::AGENCY) << "Operator prepend without new value: " << slice.toJson(); return false; } Builder tmp; tmp.openArray(); tmp.add(slice.get("new")); if (this->slice().isArray()) { for (auto const& old : VPackArrayIterator(this->slice())) tmp.add(old); } tmp.close(); *this = tmp.slice(); return true; }
TRI_voc_cid_t Syncer::getCid(VPackSlice const& slice) const { if (!slice.isObject()) { return 0; } VPackSlice id = slice.get("cid"); if (id.isString()) { // string cid, e.g. "9988488" return StringUtils::uint64(id.copyString()); } else if (id.isNumber()) { // numeric cid, e.g. 9988488 return id.getNumericValue<TRI_voc_cid_t>(); } return 0; }
/// @brief getSome AqlItemBlock* RemoteBlock::getSome(size_t atLeast, size_t atMost) { DEBUG_BEGIN_BLOCK(); // For every call we simply forward via HTTP traceGetSomeBegin(); VPackBuilder builder; builder.openObject(); builder.add("atLeast", VPackValue(atLeast)); builder.add("atMost", VPackValue(atMost)); builder.close(); std::string bodyString(builder.slice().toJson()); std::unique_ptr<ClusterCommResult> res = sendRequest(rest::RequestType::PUT, "/_api/aql/getSome/", bodyString); throwExceptionAfterBadSyncRequest(res.get(), false); // If we get here, then res->result is the response which will be // a serialized AqlItemBlock: std::shared_ptr<VPackBuilder> responseBodyBuilder = res->result->getBodyVelocyPack(); VPackSlice responseBody = responseBodyBuilder->slice(); ExecutionStats newStats(responseBody.get("stats")); _engine->_stats.addDelta(_deltaStats, newStats); _deltaStats = newStats; if (VelocyPackHelper::getBooleanValue(responseBody, "exhausted", true)) { traceGetSomeEnd(nullptr); return nullptr; } auto r = new arangodb::aql::AqlItemBlock(responseBody); traceGetSomeEnd(r); return r; // cppcheck-suppress style DEBUG_END_BLOCK(); }
bool Node::applieOp(VPackSlice const& slice) { std::string oper = slice.get("op").copyString(); if (oper == "delete") { if (_parent == nullptr) { // root node _children.clear(); _value.clear(); return true; } else { return _parent->removeChild(_node_name); } } else if (oper == "set") { // "op":"set" return handle<SET>(slice); } else if (oper == "increment") { // "op":"increment" return handle<INCREMENT>(slice); } else if (oper == "decrement") { // "op":"decrement" return handle<DECREMENT>(slice); } else if (oper == "push") { // "op":"push" return handle<PUSH>(slice); } else if (oper == "pop") { // "op":"pop" return handle<POP>(slice); } else if (oper == "prepend") { // "op":"prepend" return handle<PREPEND>(slice); } else if (oper == "shift") { // "op":"shift" return handle<SHIFT>(slice); } else if (oper == "observe") { // "op":"observe" return handle<OBSERVE>(slice); } else if (oper == "unobserve") { // "op":"unobserve" return handle<UNOBSERVE>(slice); } else { // "op" might not be a key word after all LOG_TOPIC(WARN, Logger::AGENCY) << "Keyword 'op' without known operation. Handling as regular key."; } return false; }
static AuthEntry CreateAuthEntry(VPackSlice const& slice) { if (slice.isNone() || !slice.isObject()) { return AuthEntry(); } // extract "user" attribute VPackSlice const userSlice = slice.get("user"); if (!userSlice.isString()) { LOG(DEBUG) << "cannot extract username"; return AuthEntry(); } VPackSlice const authDataSlice = slice.get("authData"); if (!authDataSlice.isObject()) { LOG(DEBUG) << "cannot extract authData"; return AuthEntry(); } VPackSlice const simpleSlice = authDataSlice.get("simple"); if (!simpleSlice.isObject()) { LOG(DEBUG) << "cannot extract simple"; return AuthEntry(); } VPackSlice const methodSlice = simpleSlice.get("method"); VPackSlice const saltSlice = simpleSlice.get("salt"); VPackSlice const hashSlice = simpleSlice.get("hash"); if (!methodSlice.isString() || !saltSlice.isString() || !hashSlice.isString()) { LOG(DEBUG) << "cannot extract password internals"; return AuthEntry(); } // extract "active" attribute bool active; VPackSlice const activeSlice = authDataSlice.get("active"); if (!activeSlice.isBoolean()) { LOG(DEBUG) << "cannot extract active flag"; return AuthEntry(); } active = activeSlice.getBool(); // extract "changePassword" attribute bool mustChange = VelocyPackHelper::getBooleanValue(authDataSlice, "changePassword", false); // extract "databases" attribute VPackSlice const databasesSlice = slice.get("databases"); std::unordered_map<std::string, AuthLevel> databases; AuthLevel allDatabases = AuthLevel::NONE; if (databasesSlice.isObject()) { for (auto const& obj : VPackObjectIterator(databasesSlice)) { std::string const key = obj.key.copyString(); ValueLength length; char const* value = obj.value.getString(length); if (TRI_CaseEqualString(value, "rw", 2)) { if (key == "*") { allDatabases = AuthLevel::RW; } else { databases.emplace(key, AuthLevel::RW); } } else if (TRI_CaseEqualString(value, "ro", 2)) { if (key == "*") { allDatabases = AuthLevel::RO; } else { databases.emplace(key, AuthLevel::RO); } } } } // build authentication entry return AuthEntry(userSlice.copyString(), methodSlice.copyString(), saltSlice.copyString(), hashSlice.copyString(), databases, allDatabases, active, mustChange); }
int RestoreFeature::processInputDirectory(std::string& errorMsg) { // create a lookup table for collections std::map<std::string, bool> restrictList; for (size_t i = 0; i < _collections.size(); ++i) { restrictList.insert(std::pair<std::string, bool>(_collections[i], true)); } try { std::vector<std::string> const files = FileUtils::listFiles(_inputDirectory); std::string const suffix = std::string(".structure.json"); std::vector<std::shared_ptr<VPackBuilder>> collectionBuilders; std::vector<VPackSlice> collections; // Step 1 determine all collections to process { // loop over all files in InputDirectory, and look for all structure.json // files for (std::string const& file : files) { size_t const nameLength = file.size(); if (nameLength <= suffix.size() || file.substr(file.size() - suffix.size()) != suffix) { // some other file continue; } // found a structure.json file std::string name = file.substr(0, file.size() - suffix.size()); if (!_includeSystemCollections && name[0] == '_') { continue; } std::string const fqn = _inputDirectory + TRI_DIR_SEPARATOR_STR + file; std::shared_ptr<VPackBuilder> fileContentBuilder = arangodb::basics::VelocyPackHelper::velocyPackFromFile(fqn); VPackSlice const fileContent = fileContentBuilder->slice(); if (!fileContent.isObject()) { errorMsg = "could not read collection structure file '" + fqn + "'"; return TRI_ERROR_INTERNAL; } VPackSlice const parameters = fileContent.get("parameters"); VPackSlice const indexes = fileContent.get("indexes"); if (!parameters.isObject() || !indexes.isArray()) { errorMsg = "could not read collection structure file '" + fqn + "'"; return TRI_ERROR_INTERNAL; } std::string const cname = arangodb::basics::VelocyPackHelper::getStringValue(parameters, "name", ""); bool overwriteName = false; if (cname != name && name != (cname + "_" + arangodb::rest::SslInterface::sslMD5(cname))) { // file has a different name than found in structure file if (_importStructure) { // we cannot go on if there is a mismatch errorMsg = "collection name mismatch in collection structure file '" + fqn + "' (offending value: '" + cname + "')"; return TRI_ERROR_INTERNAL; } else { // we can patch the name in our array and go on std::cout << "ignoring collection name mismatch in collection " "structure file '" + fqn + "' (offending value: '" + cname + "')" << std::endl; overwriteName = true; } } if (!restrictList.empty() && restrictList.find(cname) == restrictList.end()) { // collection name not in list continue; } if (overwriteName) { // TODO MAX // Situation: // Ich habe ein Json-Object von Datei (teile des Inhalts im Zweifel // unbekannt) // Es gibt ein Sub-Json-Object "parameters" mit einem Attribute "name" // der gesetzt ist. // Ich muss nur diesen namen überschreiben, der Rest soll identisch // bleiben. } else { collectionBuilders.emplace_back(fileContentBuilder); collections.emplace_back(fileContent); } } } std::sort(collections.begin(), collections.end(), SortCollections); StringBuffer buffer(TRI_UNKNOWN_MEM_ZONE); // step2: run the actual import for (VPackSlice const& collection : collections) { VPackSlice const parameters = collection.get("parameters"); VPackSlice const indexes = collection.get("indexes"); std::string const cname = arangodb::basics::VelocyPackHelper::getStringValue(parameters, "name", ""); int type = arangodb::basics::VelocyPackHelper::getNumericValue<int>( parameters, "type", 2); std::string const collectionType(type == 2 ? "document" : "edge"); if (_importStructure) { // re-create collection if (_progress) { if (_overwrite) { std::cout << "# Re-creating " << collectionType << " collection '" << cname << "'..." << std::endl; } else { std::cout << "# Creating " << collectionType << " collection '" << cname << "'..." << std::endl; } } int res = sendRestoreCollection(collection, cname, errorMsg); if (res != TRI_ERROR_NO_ERROR) { if (_force) { std::cerr << errorMsg << std::endl; continue; } return TRI_ERROR_INTERNAL; } } _stats._totalCollections++; if (_importData) { // import data. check if we have a datafile std::string datafile = _inputDirectory + TRI_DIR_SEPARATOR_STR + cname + "_" + arangodb::rest::SslInterface::sslMD5(cname) + ".data.json"; if (!TRI_ExistsFile(datafile.c_str())) { datafile = _inputDirectory + TRI_DIR_SEPARATOR_STR + cname + ".data.json"; } if (TRI_ExistsFile(datafile.c_str())) { // found a datafile if (_progress) { std::cout << "# Loading data into " << collectionType << " collection '" << cname << "'..." << std::endl; } int fd = TRI_OPEN(datafile.c_str(), O_RDONLY | TRI_O_CLOEXEC); if (fd < 0) { errorMsg = "cannot open collection data file '" + datafile + "'"; return TRI_ERROR_INTERNAL; } buffer.clear(); while (true) { if (buffer.reserve(16384) != TRI_ERROR_NO_ERROR) { TRI_CLOSE(fd); errorMsg = "out of memory"; return TRI_ERROR_OUT_OF_MEMORY; } ssize_t numRead = TRI_READ(fd, buffer.end(), 16384); if (numRead < 0) { // error while reading int res = TRI_errno(); TRI_CLOSE(fd); errorMsg = std::string(TRI_errno_string(res)); return res; } // read something buffer.increaseLength(numRead); _stats._totalRead += (uint64_t)numRead; if (buffer.length() < _chunkSize && numRead > 0) { // still continue reading continue; } // do we have a buffer? if (buffer.length() > 0) { // look for the last \n in the buffer char* found = (char*)memrchr((const void*)buffer.begin(), '\n', buffer.length()); size_t length; if (found == nullptr) { // no \n found... if (numRead == 0) { // we're at the end. send the complete buffer anyway length = buffer.length(); } else { // read more continue; } } else { // found a \n somewhere length = found - buffer.begin(); } TRI_ASSERT(length > 0); _stats._totalBatches++; int res = sendRestoreData(cname, buffer.begin(), length, errorMsg); if (res != TRI_ERROR_NO_ERROR) { TRI_CLOSE(fd); if (errorMsg.empty()) { errorMsg = std::string(TRI_errno_string(res)); } else { errorMsg = std::string(TRI_errno_string(res)) + ": " + errorMsg; } if (_force) { std::cerr << errorMsg << std::endl; continue; } return res; } buffer.erase_front(length); } if (numRead == 0) { // EOF break; } } TRI_CLOSE(fd); } } if (_importStructure) { // re-create indexes if (indexes.length() > 0) { // we actually have indexes if (_progress) { std::cout << "# Creating indexes for collection '" << cname << "'..." << std::endl; } int res = sendRestoreIndexes(collection, errorMsg); if (res != TRI_ERROR_NO_ERROR) { if (_force) { std::cerr << errorMsg << std::endl; continue; } return TRI_ERROR_INTERNAL; } } } } } catch (...) { errorMsg = "out of memory"; return TRI_ERROR_OUT_OF_MEMORY; } return TRI_ERROR_NO_ERROR; }