diff --git a/lib/remote/objectqueryhandler.cpp b/lib/remote/objectqueryhandler.cpp index d14182af5..24b3d712e 100644 --- a/lib/remote/objectqueryhandler.cpp +++ b/lib/remote/objectqueryhandler.cpp @@ -1,6 +1,8 @@ /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ #include "remote/objectqueryhandler.hpp" +#include "base/generator.hpp" +#include "base/json.hpp" #include "remote/httputility.hpp" #include "remote/filterutility.hpp" #include "base/serializer.hpp" @@ -9,6 +11,7 @@ #include #include #include +#include using namespace icinga; @@ -140,6 +143,16 @@ bool ObjectQueryHandler::HandleRequest( return true; } + if(umetas){ + ObjectLock olock(umetas); + for (String meta : umetas) { + if (!(meta == "used_by" || meta == "location")) { + response.SendJsonError(request.Params(), 400, "Invalid field specified for meta: " + meta); + return true; + } + } + } + bool allJoins = request.GetLastParameter("all_joins"); request.Params()->Set("type", type->GetName()); @@ -161,9 +174,6 @@ bool ObjectQueryHandler::HandleRequest( return true; } - ArrayData results; - results.reserve(objs.size()); - std::set joinAttrs; std::set userJoinAttrs; @@ -189,14 +199,21 @@ bool ObjectQueryHandler::HandleRequest( std::unordered_map>> typePermissions; std::unordered_map objectAccessAllowed; - for (ConfigObject::Ptr obj : objs) { + auto it = objs.begin(); + auto generatorFunc = [&]() -> std::optional { + if (it == objs.end()) { + return std::nullopt; + } + + ConfigObject::Ptr obj = *it; + ++it; + DictionaryData result1{ { "name", obj->GetName() }, { "type", obj->GetReflectionType()->GetName() } }; DictionaryData metaAttrs; - if (umetas) { ObjectLock olock(umetas); for (String meta : umetas) { @@ -212,9 +229,6 @@ bool ObjectQueryHandler::HandleRequest( } } else if (meta == "location") { metaAttrs.emplace_back("location", obj->GetSourceLocation()); - } else { - response.SendJsonError(request.Params(), 400, "Invalid field specified for meta: " + meta); - return true; } } } @@ -224,8 +238,12 @@ bool ObjectQueryHandler::HandleRequest( try { result1.emplace_back("attrs", SerializeObjectAttrs(obj, String(), uattrs, false, false)); } catch (const ScriptError& ex) { - response.SendJsonError(request.Params(), 400, ex.what()); - return true; + return new Dictionary{ + {"type", type->GetName()}, + {"name", obj->GetName()}, + {"code", 400}, + {"status", ex.what()} + }; } DictionaryData joins; @@ -234,18 +252,8 @@ bool ObjectQueryHandler::HandleRequest( Object::Ptr joinedObj; int fid = type->GetFieldId(joinAttr); - if (fid < 0) { - response.SendJsonError(request.Params(), 400, "Invalid field specified for join: " + joinAttr); - return true; - } - Field field = type->GetFieldInfo(fid); - if (!(field.Attributes & FANavigation)) { - response.SendJsonError(request.Params(), 400, "Not a joinable field: " + joinAttr); - return true; - } - joinedObj = obj->NavigateField(fid); if (!joinedObj) @@ -299,22 +307,30 @@ bool ObjectQueryHandler::HandleRequest( try { joins.emplace_back(prefix, SerializeObjectAttrs(joinedObj, prefix, ujoins, true, allJoins)); } catch (const ScriptError& ex) { - response.SendJsonError(request.Params(), 400, ex.what()); - return true; + return new Dictionary{ + {"type", type->GetName()}, + {"name", obj->GetName()}, + {"code", 400}, + {"status", ex.what()} + }; } } result1.emplace_back("joins", new Dictionary(std::move(joins))); - results.push_back(new Dictionary(std::move(result1))); - } - - Dictionary::Ptr result = new Dictionary({ - { "results", new Array(std::move(results)) } - }); + return new Dictionary{std::move(result1)}; + }; response.result(http::status::ok); - response.SendJsonBody(request.Params(), result); + response.set(http::field::content_type, "application/json"); + response.StartStreaming(); + + Dictionary::Ptr results = new Dictionary{{"results", new ValueGenerator{generatorFunc}}}; + results->Freeze(); + + auto adapter = std::make_shared>(response); + JsonEncoder encoder(adapter, request.IsPretty()); + encoder.Encode(results, &yc); return true; }