11/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
22
33#include " remote/objectqueryhandler.hpp"
4+ #include " base/generator.hpp"
5+ #include " base/json.hpp"
46#include " remote/httputility.hpp"
57#include " remote/filterutility.hpp"
68#include " base/serializer.hpp"
911#include < boost/algorithm/string/case_conv.hpp>
1012#include < set>
1113#include < unordered_map>
14+ #include < memory>
1215
1316using namespace icinga ;
1417
@@ -144,6 +147,22 @@ bool ObjectQueryHandler::HandleRequest(
144147 return true ;
145148 }
146149
150+ bool includeUsedBy = false ;
151+ bool includeLocation = false ;
152+ if (umetas) {
153+ ObjectLock olock (umetas);
154+ for (String meta : umetas) {
155+ if (meta == " used_by" ) {
156+ includeUsedBy = true ;
157+ } else if (meta == " location" ) {
158+ includeLocation = true ;
159+ } else {
160+ HttpUtility::SendJsonError (response, params, 400 , " Invalid field specified for meta: " + meta);
161+ return true ;
162+ }
163+ }
164+ }
165+
147166 bool allJoins = HttpUtility::GetLastParameter (params, " all_joins" );
148167
149168 params->Set (" type" , type->GetName ());
@@ -165,10 +184,7 @@ bool ObjectQueryHandler::HandleRequest(
165184 return true ;
166185 }
167186
168- ArrayData results;
169- results.reserve (objs.size ());
170-
171- std::set<String> joinAttrs;
187+ std::set<int > joinAttrs;
172188 std::set<String> userJoinAttrs;
173189
174190 if (ujoins) {
@@ -187,70 +203,63 @@ bool ObjectQueryHandler::HandleRequest(
187203 if (!allJoins && userJoinAttrs.find (field.NavigationName ) == userJoinAttrs.end ())
188204 continue ;
189205
190- joinAttrs.insert (field. Name );
206+ joinAttrs.insert (fid );
191207 }
192208
193209 std::unordered_map<Type*, std::pair<bool , std::unique_ptr<Expression>>> typePermissions;
194210 std::unordered_map<Object*, bool > objectAccessAllowed;
195211
196- for (ConfigObject::Ptr obj : objs) {
212+ auto it = objs.begin ();
213+ auto generatorFunc = [&]() -> std::optional<Value> {
214+ if (it == objs.end ()) {
215+ return std::nullopt ;
216+ }
217+
218+ ConfigObject::Ptr obj = *it;
219+ ++it;
220+
197221 DictionaryData result1{
198222 { " name" , obj->GetName () },
199223 { " type" , obj->GetReflectionType ()->GetName () }
200224 };
201225
202226 DictionaryData metaAttrs;
203-
204- if (umetas) {
205- ObjectLock olock (umetas);
206- for (String meta : umetas) {
207- if (meta == " used_by" ) {
208- Array::Ptr used_by = new Array ();
209- metaAttrs.emplace_back (" used_by" , used_by);
210-
211- for (auto & configObj : DependencyGraph::GetChildren (obj)) {
212- used_by->Add (new Dictionary ({
213- { " type" , configObj->GetReflectionType ()->GetName () },
214- { " name" , configObj->GetName () }
215- }));
216- }
217- } else if (meta == " location" ) {
218- metaAttrs.emplace_back (" location" , obj->GetSourceLocation ());
219- } else {
220- HttpUtility::SendJsonError (response, params, 400 , " Invalid field specified for meta: " + meta);
221- return true ;
222- }
227+ if (includeUsedBy) {
228+ Array::Ptr used_by = new Array ();
229+ metaAttrs.emplace_back (" used_by" , used_by);
230+
231+ for (auto & configObj : DependencyGraph::GetChildren (obj)) {
232+ used_by->Add (new Dictionary ({
233+ {" type" , configObj->GetReflectionType ()->GetName ()},
234+ {" name" , configObj->GetName ()}
235+ }));
223236 }
224237 }
225238
239+ if (includeLocation) {
240+ metaAttrs.emplace_back (" location" , obj->GetSourceLocation ());
241+ }
242+
226243 result1.emplace_back (" meta" , new Dictionary (std::move (metaAttrs)));
227244
228245 try {
229246 result1.emplace_back (" attrs" , SerializeObjectAttrs (obj, String (), uattrs, false , false ));
230247 } catch (const ScriptError& ex) {
231- HttpUtility::SendJsonError (response, params, 400 , ex.what ());
232- return true ;
248+ return new Dictionary{
249+ {" type" , type->GetName ()},
250+ {" name" , obj->GetName ()},
251+ {" code" , 400 },
252+ {" status" , ex.what ()}
253+ };
233254 }
234255
235256 DictionaryData joins;
236257
237- for (const String& joinAttr : joinAttrs) {
258+ for (auto joinAttr : joinAttrs) {
238259 Object::Ptr joinedObj;
239- int fid = type->GetFieldId (joinAttr);
240-
241- if (fid < 0 ) {
242- HttpUtility::SendJsonError (response, params, 400 , " Invalid field specified for join: " + joinAttr);
243- return true ;
244- }
260+ Field field = type->GetFieldInfo (joinAttr);
245261
246- Field field = type->GetFieldInfo (fid);
247-
248- if (!(field.Attributes & FANavigation)) {
249- HttpUtility::SendJsonError (response, params, 400 , " Not a joinable field: " + joinAttr);
250- return true ;
251- }
252-
253- joinedObj = obj->NavigateField (fid);
262+ joinedObj = obj->NavigateField (joinAttr);
254263
255264 if (!joinedObj)
256265 continue ;
@@ -303,22 +312,29 @@ bool ObjectQueryHandler::HandleRequest(
303312 try {
304313 joins.emplace_back (prefix, SerializeObjectAttrs (joinedObj, prefix, ujoins, true , allJoins));
305314 } catch (const ScriptError& ex) {
306- HttpUtility::SendJsonError (response, params, 400 , ex.what ());
307- return true ;
315+ return new Dictionary{
316+ {" type" , type->GetName ()},
317+ {" name" , obj->GetName ()},
318+ {" code" , 400 },
319+ {" status" , ex.what ()}
320+ };
308321 }
309322 }
310323
311324 result1.emplace_back (" joins" , new Dictionary (std::move (joins)));
312325
313- results.push_back (new Dictionary (std::move (result1)));
314- }
315-
316- Dictionary::Ptr result = new Dictionary ({
317- { " results" , new Array (std::move (results)) }
318- });
326+ return new Dictionary{std::move (result1)};
327+ };
319328
320329 response.result (http::status::ok);
321- HttpUtility::SendJsonBody (response, params, result);
330+ response.set (http::field::content_type, " application/json" );
331+ response.StartStreaming ();
332+
333+ Dictionary::Ptr results = new Dictionary{{" results" , new ValueGenerator{generatorFunc}}};
334+ results->Freeze ();
335+
336+ bool pretty = HttpUtility::GetLastParameter (params, " pretty" );
337+ response.GetJsonEncoder (pretty).Encode (results, &yc);
322338
323339 return true ;
324340}
0 commit comments