apifunction.cpp apilistener.cpp apilistener.thpp apilistener-sync.cpp
apiuser.cpp apiuser.thpp authority.cpp base64.cpp configfileshandler.cpp
configmoduleshandler.cpp configmoduleutility.cpp configstageshandler.cpp
- endpoint.cpp endpoint.thpp
- httpchunkedencoding.cpp httpconnection.cpp httpdemohandler.cpp httphandler.cpp httprequest.cpp httpresponse.cpp
+ endpoint.cpp endpoint.thpp filterutility.cpp
+ httpchunkedencoding.cpp httpconnection.cpp httphandler.cpp httprequest.cpp httpresponse.cpp
httputility.cpp jsonrpc.cpp jsonrpcconnection.cpp jsonrpcconnection-heartbeat.cpp
- messageorigin.cpp zone.cpp zone.thpp
+ messageorigin.cpp statusqueryhandler.cpp zone.cpp zone.thpp
url.cpp
)
REGISTER_URLHANDLER("/v1/config/files", ConfigFilesHandler);
-void ConfigFilesHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
+bool ConfigFilesHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
{
if (request.RequestMethod == "GET")
HandleGet(user, request, response);
else
response.SetStatus(400, "Bad request");
-}
-bool ConfigFilesHandler::CanAlsoHandleUrl(const Url::Ptr& url) const
-{
return true;
}
public:
DECLARE_PTR_TYPEDEFS(ConfigFilesHandler);
- virtual bool CanAlsoHandleUrl(const Url::Ptr& url) const;
- virtual void HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response);
+ virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response);
private:
void HandleGet(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response);
REGISTER_URLHANDLER("/v1/config/modules", ConfigModulesHandler);
-void ConfigModulesHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
+bool ConfigModulesHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
{
+ if (request.RequestUrl->GetPath().size() > 4)
+ return false;
+
if (request.RequestMethod == "GET")
HandleGet(user, request, response);
else if (request.RequestMethod == "POST")
HandleDelete(user, request, response);
else
response.SetStatus(400, "Bad request");
-}
-bool ConfigModulesHandler::CanAlsoHandleUrl(const Url::Ptr& url) const
-{
- if (url->GetPath().size() > 4)
- return false;
- else
- return true;
+ return true;
}
void ConfigModulesHandler::HandleGet(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
public:
DECLARE_PTR_TYPEDEFS(ConfigModulesHandler);
- virtual bool CanAlsoHandleUrl(const Url::Ptr& url) const;
- virtual void HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response);
+ virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response);
private:
void HandleGet(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response);
REGISTER_URLHANDLER("/v1/config/stages", ConfigStagesHandler);
-void ConfigStagesHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
+bool ConfigStagesHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
{
+ if (request.RequestUrl->GetPath().size() > 5)
+ return false;
+
if (request.RequestMethod == "GET")
HandleGet(user, request, response);
else if (request.RequestMethod == "POST")
HandleDelete(user, request, response);
else
response.SetStatus(400, "Bad request");
-}
-bool ConfigStagesHandler::CanAlsoHandleUrl(const Url::Ptr& url) const
-{
- if (url->GetPath().size() > 5)
- return false;
- else
- return true;
+ return true;
}
void ConfigStagesHandler::HandleGet(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
public:
DECLARE_PTR_TYPEDEFS(ConfigStagesHandler);
- virtual bool CanAlsoHandleUrl(const Url::Ptr& url) const;
- virtual void HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response);
+ virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response);
private:
void HandleGet(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response);
--- /dev/null
+/******************************************************************************
+ * Icinga 2 *
+ * Copyright (C) 2012-2015 Icinga Development Team (http://www.icinga.org) *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU General Public License *
+ * as published by the Free Software Foundation; either version 2 *
+ * of the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the Free Software Foundation *
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ******************************************************************************/
+
+#include "remote/filterutility.hpp"
+#include "config/configcompiler.hpp"
+#include "config/expression.hpp"
+#include "base/json.hpp"
+#include "base/dynamictype.hpp"
+#include <boost/foreach.hpp>
+#include <boost/algorithm/string.hpp>
+
+using namespace icinga;
+
+Type::Ptr FilterUtility::TypeFromPluralName(const String& pluralName)
+{
+ String uname = pluralName;
+ boost::algorithm::to_lower(uname);
+
+ BOOST_FOREACH(const DynamicType::Ptr& dtype, DynamicType::GetTypes()) {
+ Type::Ptr type = Type::GetByName(dtype->GetName());
+ ASSERT(type);
+
+ String pname = GetPluralName(type);
+ boost::algorithm::to_lower(pname);
+
+ if (uname == pname)
+ return type;
+ }
+
+ return Type::Ptr();
+}
+
+String FilterUtility::GetPluralName(const Type::Ptr& type)
+{
+ String name = type->GetName();
+
+ if (name[name.GetLength() - 1] == 'y')
+ return name.SubStr(0, name.GetLength() - 1) + "ies";
+ else
+ return name + "s";
+}
+
+DynamicObject::Ptr FilterUtility::GetObjectByTypeAndName(const String& type, const String& name)
+{
+ DynamicType::Ptr dtype = DynamicType::GetByName(type);
+ ASSERT(dtype);
+
+ return dtype->GetObject(name);
+}
+
+std::vector<DynamicObject::Ptr> FilterUtility::GetFilterTargets(const QueryDescription& qd, const Dictionary::Ptr& query)
+{
+ std::vector<DynamicObject::Ptr> result;
+
+ BOOST_FOREACH(const Type::Ptr& type, qd.Types) {
+ String attr = type->GetName();
+ boost::algorithm::to_lower(attr);
+
+ if (query->Contains(attr)) {
+ String name = query->Get(attr);
+ DynamicObject::Ptr obj = GetObjectByTypeAndName(type->GetName(), name);
+ if (!obj)
+ BOOST_THROW_EXCEPTION(std::invalid_argument("Object does not exist."));
+ result.push_back(obj);
+ }
+
+ attr = GetPluralName(type);
+ boost::algorithm::to_lower(attr);
+
+ if (query->Contains(attr)) {
+ Array::Ptr names = query->Get(attr);
+ ObjectLock olock(names);
+ BOOST_FOREACH(const String& name, names) {
+ DynamicObject::Ptr obj = GetObjectByTypeAndName(type->GetName(), name);
+ if (!obj)
+ BOOST_THROW_EXCEPTION(std::invalid_argument("Object does not exist."));
+ result.push_back(obj);
+ }
+ }
+ }
+
+ if (query->Contains("filter")) {
+ if (!query->Contains("type"))
+ BOOST_THROW_EXCEPTION(std::invalid_argument("Type must be specified when using a filter."));
+
+ String filter = query->Get("filter");
+ String type = query->Get("type");
+
+ Type::Ptr utype = Type::GetByName(type);
+
+ if (!utype)
+ BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid type specified."));
+
+ if (qd.Types.find(utype) == qd.Types.end())
+ BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid type specified for this query."));
+
+ DynamicType::Ptr dtype = DynamicType::GetByName(type);
+ ASSERT(dtype);
+
+ Expression *ufilter = ConfigCompiler::CompileText("<API query>", filter, false);
+ ScriptFrame frame;
+ frame.Sandboxed = true;
+
+ String varName = utype->GetName();
+ boost::algorithm::to_lower(varName);
+
+ try {
+ BOOST_FOREACH(const DynamicObject::Ptr& object, dtype->GetObjects()) {
+ frame.Locals->Set(varName, object);
+
+ if (Convert::ToBool(ufilter->Evaluate(frame)))
+ result.push_back(object);
+ }
+ } catch (const std::exception& ex) {
+ delete ufilter;
+ throw;
+ }
+
+ delete ufilter;
+ }
+
+ return result;
+}
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
-#include "remote/httpdemohandler.hpp"
+#ifndef FILTERUTILITY_H
+#define FILTERUTILITY_H
-using namespace icinga;
+#include "remote/i2-remote.hpp"
+#include "base/dictionary.hpp"
+#include "base/dynamicobject.hpp"
+#include <set>
-REGISTER_URLHANDLER("/demo", HttpDemoHandler);
+namespace icinga
+{
+
+struct QueryDescription
+{
+ std::set<Type::Ptr> Types;
+};
-void HttpDemoHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
+/**
+ * Filter utilities.
+ *
+ * @ingroup remote
+ */
+class I2_REMOTE_API FilterUtility
{
- if (request.RequestMethod == "GET") {
- String form = "<h1>Hallo " + user->GetName() + "</h1><form action=\"/demo\" method=\"post\"><input type=\"text\" name=\"msg\"><input type=\"submit\"></form>";
- response.SetStatus(200, "OK");
- response.AddHeader("Content-Type", "text/html");
- response.WriteBody(form.CStr(), form.GetLength());
- } else if (request.RequestMethod == "POST") {
- response.SetStatus(200, "OK");
- String msg = "You sent: ";
+public:
+ static String GetPluralName(const Type::Ptr& type);
+ static Type::Ptr TypeFromPluralName(const String& pluralName);
+ static DynamicObject::Ptr GetObjectByTypeAndName(const String& type, const String& name);
+ static std::vector<DynamicObject::Ptr> GetFilterTargets(const QueryDescription& qd, const Dictionary::Ptr& query);
+};
- char buffer[512];
- size_t count;
- while ((count = request.ReadBody(buffer, sizeof(buffer))) > 0)
- msg += String(buffer, buffer + count);
- response.WriteBody(msg.CStr(), msg.GetLength());
- } else {
- response.SetStatus(400, "Bad request");
- }
}
+#endif /* FILTERUTILITY_H */
} catch (const std::exception& ex) {
HttpResponse response(m_Stream, m_CurrentRequest);
response.SetStatus(400, "Bad request");
- String msg = "<h1>Bad request</h1>";
+ String msg = "<h1>Bad request</h1><p>" + DiagnosticInformation(ex) + "</p>";
response.WriteBody(msg.CStr(), msg.GetLength());
response.Finish();
node = sub_node;
}
- node->Set("handler", handler);
-}
+ Array::Ptr handlers = node->Get("handlers");
-bool HttpHandler::CanAlsoHandleUrl(const Url::Ptr& url) const
-{
- return false;
+ if (!handlers) {
+ handlers = new Array();
+ node->Set("handlers", handlers);
+ }
+
+ handlers->Add(handler);
}
void HttpHandler::ProcessRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
{
Dictionary::Ptr node = m_UrlTree;
- HttpHandler::Ptr current_handler, handler;
- bool exact_match = true;
+ std::vector<HttpHandler::Ptr> handlers;
BOOST_FOREACH(const String& elem, request.RequestUrl->GetPath()) {
- current_handler = node->Get("handler");
- if (current_handler)
- handler = current_handler;
+ Array::Ptr current_handlers = node->Get("handlers");
+
+ if (current_handlers) {
+ ObjectLock olock(current_handlers);
+ BOOST_FOREACH(const HttpHandler::Ptr current_handler, current_handlers) {
+ handlers.push_back(current_handler);
+ }
+ }
Dictionary::Ptr children = node->Get("children");
if (!children) {
- exact_match = false;
node.reset();
break;
}
node = children->Get(elem);
- if (!node) {
- exact_match = false;
+ if (!node)
break;
- }
}
- if (node) {
- current_handler = node->Get("handler");
- if (current_handler)
- handler = current_handler;
- }
+ std::reverse(handlers.begin(), handlers.end());
- if (!handler || (!exact_match && !handler->CanAlsoHandleUrl(request.RequestUrl))) {
+ bool processed = false;
+ BOOST_FOREACH(const HttpHandler::Ptr& handler, handlers) {
+ if (handler->HandleRequest(user, request, response)) {
+ processed = true;
+ break;
+ }
+ }
+ if (!processed) {
response.SetStatus(404, "Not found");
response.AddHeader("Content-Type", "text/html");
String msg = "<h1>Not found</h1>";
response.Finish();
return;
}
-
- handler->HandleRequest(user, request, response);
}
public:
DECLARE_PTR_TYPEDEFS(HttpHandler);
- virtual bool CanAlsoHandleUrl(const Url::Ptr& url) const;
- virtual void HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response) = 0;
+ virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response) = 0;
static void Register(const Url::Ptr& url, const HttpHandler::Ptr& handler);
static void ProcessRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response);
--- /dev/null
+/******************************************************************************
+ * Icinga 2 *
+ * Copyright (C) 2012-2015 Icinga Development Team (http://www.icinga.org) *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU General Public License *
+ * as published by the Free Software Foundation; either version 2 *
+ * of the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the Free Software Foundation *
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ******************************************************************************/
+
+#include "remote/statusqueryhandler.hpp"
+#include "remote/httputility.hpp"
+#include "remote/filterutility.hpp"
+#include "base/serializer.hpp"
+#include <boost/algorithm/string.hpp>
+
+using namespace icinga;
+
+REGISTER_URLHANDLER("/", StatusQueryHandler);
+
+bool StatusQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
+{
+ if (request.RequestUrl->GetPath().empty())
+ return false;
+
+ Type::Ptr type = FilterUtility::TypeFromPluralName(request.RequestUrl->GetPath()[0]);
+
+ if (!type)
+ return false;
+
+ QueryDescription qd;
+ qd.Types.insert(type);
+
+ Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
+
+ if (request.RequestUrl->GetPath().size() > 1) {
+ String attr = type->GetName();
+ boost::algorithm::to_lower(attr);
+ params->Set(attr, request.RequestUrl->GetPath()[1]);
+ }
+
+ std::vector<DynamicObject::Ptr> objs = FilterUtility::GetFilterTargets(qd, params);
+
+ Array::Ptr results = new Array();
+
+ BOOST_FOREACH(const DynamicObject::Ptr& obj, objs) {
+ Value result1 = Serialize(obj, FAConfig | FAState);
+ results->Add(result1);
+ }
+
+ Dictionary::Ptr result = new Dictionary();
+ result->Set("results", results);
+
+ response.SetStatus(200, "OK");
+ HttpUtility::SendJsonBody(response, result);
+
+ return true;
+}
+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
-#ifndef HTTPDEMOHANDLER_H
-#define HTTPDEMOHANDLER_H
+#ifndef STATUSQUERYHANDLER_H
+#define STATUSQUERYHANDLER_H
#include "remote/httphandler.hpp"
namespace icinga
{
-class I2_REMOTE_API HttpDemoHandler : public HttpHandler
+class I2_REMOTE_API StatusQueryHandler : public HttpHandler
{
public:
- DECLARE_PTR_TYPEDEFS(HttpDemoHandler);
+ DECLARE_PTR_TYPEDEFS(StatusQueryHandler);
- virtual void HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response);
+ virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response);
};
}
-#endif /* HTTPDEMOHANDLER_H */
+#endif /* STATUSQUERYHANDLER_H */