API: Fix error handling for invalid JSON request body

fixes #11757
This commit is contained in:
Michael Friedrich 2016-05-10 15:16:35 +02:00 committed by Gunnar Beutner
parent 06f97c87ed
commit 7f915dbfaf
28 changed files with 75 additions and 73 deletions

View File

@ -31,7 +31,7 @@ using namespace icinga;
REGISTER_URLHANDLER("/v1/actions", ActionsHandler);
bool ActionsHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
bool ActionsHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params)
{
if (request.RequestUrl->GetPath().size() != 3)
return false;
@ -50,8 +50,6 @@ bool ActionsHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& reques
QueryDescription qd;
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
const std::vector<String>& types = action->GetTypes();
std::vector<Value> objs;

View File

@ -30,7 +30,8 @@ class I2_REMOTE_API ActionsHandler : public HttpHandler
public:
DECLARE_PTR_TYPEDEFS(ActionsHandler);
virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response) override;
virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request,
HttpResponse& response, const Dictionary::Ptr& params) override;
};
}

View File

@ -29,13 +29,11 @@ using namespace icinga;
REGISTER_URLHANDLER("/v1/config/files", ConfigFilesHandler);
bool ConfigFilesHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
bool ConfigFilesHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params)
{
if (request.RequestMethod != "GET")
return false;
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
const std::vector<String>& urlPath = request.RequestUrl->GetPath();
if (urlPath.size() >= 4)

View File

@ -30,7 +30,8 @@ class I2_REMOTE_API ConfigFilesHandler : public HttpHandler
public:
DECLARE_PTR_TYPEDEFS(ConfigFilesHandler);
virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response) override;
virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request,
HttpResponse& response, const Dictionary::Ptr& params) override;
};
}

View File

@ -28,7 +28,7 @@ using namespace icinga;
REGISTER_URLHANDLER("/v1/config/packages", ConfigPackagesHandler);
bool ConfigPackagesHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
bool ConfigPackagesHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params)
{
if (request.RequestUrl->GetPath().size() > 4)
return false;
@ -36,9 +36,9 @@ bool ConfigPackagesHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest&
if (request.RequestMethod == "GET")
HandleGet(user, request, response);
else if (request.RequestMethod == "POST")
HandlePost(user, request, response);
HandlePost(user, request, response, params);
else if (request.RequestMethod == "DELETE")
HandleDelete(user, request, response);
HandleDelete(user, request, response, params);
else
return false;
@ -68,12 +68,10 @@ void ConfigPackagesHandler::HandleGet(const ApiUser::Ptr& user, HttpRequest& req
HttpUtility::SendJsonBody(response, result);
}
void ConfigPackagesHandler::HandlePost(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
void ConfigPackagesHandler::HandlePost(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params)
{
FilterUtility::CheckPermission(user, "config/modify");
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
if (request.RequestUrl->GetPath().size() >= 4)
params->Set("package", request.RequestUrl->GetPath()[3]);
@ -106,12 +104,10 @@ void ConfigPackagesHandler::HandlePost(const ApiUser::Ptr& user, HttpRequest& re
HttpUtility::SendJsonBody(response, result);
}
void ConfigPackagesHandler::HandleDelete(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
void ConfigPackagesHandler::HandleDelete(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params)
{
FilterUtility::CheckPermission(user, "config/modify");
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
if (request.RequestUrl->GetPath().size() >= 4)
params->Set("package", request.RequestUrl->GetPath()[3]);

View File

@ -30,12 +30,16 @@ class I2_REMOTE_API ConfigPackagesHandler : public HttpHandler
public:
DECLARE_PTR_TYPEDEFS(ConfigPackagesHandler);
virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response) override;
virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request,
HttpResponse& response, const Dictionary::Ptr& params) override;
private:
void HandleGet(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response);
void HandlePost(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response);
void HandleDelete(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response);
void HandleGet(const ApiUser::Ptr& user, HttpRequest& request,
HttpResponse& response);
void HandlePost(const ApiUser::Ptr& user, HttpRequest& request,
HttpResponse& response, const Dictionary::Ptr& params);
void HandleDelete(const ApiUser::Ptr& user, HttpRequest& request,
HttpResponse& response, const Dictionary::Ptr& params);
};

View File

@ -30,29 +30,27 @@ using namespace icinga;
REGISTER_URLHANDLER("/v1/config/stages", ConfigStagesHandler);
bool ConfigStagesHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
bool ConfigStagesHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params)
{
if (request.RequestUrl->GetPath().size() > 5)
return false;
if (request.RequestMethod == "GET")
HandleGet(user, request, response);
HandleGet(user, request, response, params);
else if (request.RequestMethod == "POST")
HandlePost(user, request, response);
HandlePost(user, request, response, params);
else if (request.RequestMethod == "DELETE")
HandleDelete(user, request, response);
HandleDelete(user, request, response, params);
else
return false;
return true;
}
void ConfigStagesHandler::HandleGet(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
void ConfigStagesHandler::HandleGet(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params)
{
FilterUtility::CheckPermission(user, "config/query");
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
if (request.RequestUrl->GetPath().size() >= 4)
params->Set("package", request.RequestUrl->GetPath()[3]);
@ -89,12 +87,10 @@ void ConfigStagesHandler::HandleGet(const ApiUser::Ptr& user, HttpRequest& reque
HttpUtility::SendJsonBody(response, result);
}
void ConfigStagesHandler::HandlePost(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
void ConfigStagesHandler::HandlePost(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params)
{
FilterUtility::CheckPermission(user, "config/modify");
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
if (request.RequestUrl->GetPath().size() >= 4)
params->Set("package", request.RequestUrl->GetPath()[3]);
@ -138,12 +134,10 @@ void ConfigStagesHandler::HandlePost(const ApiUser::Ptr& user, HttpRequest& requ
HttpUtility::SendJsonBody(response, result);
}
void ConfigStagesHandler::HandleDelete(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
void ConfigStagesHandler::HandleDelete(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params)
{
FilterUtility::CheckPermission(user, "config/modify");
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
if (request.RequestUrl->GetPath().size() >= 4)
params->Set("package", request.RequestUrl->GetPath()[3]);

View File

@ -30,12 +30,16 @@ class I2_REMOTE_API ConfigStagesHandler : public HttpHandler
public:
DECLARE_PTR_TYPEDEFS(ConfigStagesHandler);
virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response) override;
virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request,
HttpResponse& response, const Dictionary::Ptr& params) override;
private:
void HandleGet(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response);
void HandlePost(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response);
void HandleDelete(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response);
void HandleGet(const ApiUser::Ptr& user, HttpRequest& request,
HttpResponse& response, const Dictionary::Ptr& params);
void HandlePost(const ApiUser::Ptr& user, HttpRequest& request,
HttpResponse& response, const Dictionary::Ptr& params);
void HandleDelete(const ApiUser::Ptr& user, HttpRequest& request,
HttpResponse& response, const Dictionary::Ptr& params);
};

View File

@ -67,7 +67,7 @@ static void InitScriptFrameCleanup(void)
INITIALIZE_ONCE(InitScriptFrameCleanup);
bool ConsoleHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
bool ConsoleHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params)
{
if (request.RequestUrl->GetPath().size() > 3)
return false;
@ -76,10 +76,9 @@ bool ConsoleHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& reques
return false;
QueryDescription qd;
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
String methodName = request.RequestUrl->GetPath()[2];
FilterUtility::CheckPermission(user, "console");
String session = HttpUtility::GetLastParameter(params, "session");

View File

@ -43,7 +43,8 @@ class I2_REMOTE_API ConsoleHandler : public HttpHandler
public:
DECLARE_PTR_TYPEDEFS(ConsoleHandler);
virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response) override;
virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request,
HttpResponse& response, const Dictionary::Ptr& params) override;
static std::vector<String> GetAutocompletionSuggestions(const String& word, ScriptFrame& frame);

View File

@ -30,7 +30,7 @@ using namespace icinga;
REGISTER_URLHANDLER("/v1/objects", CreateObjectHandler);
bool CreateObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
bool CreateObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params)
{
if (request.RequestUrl->GetPath().size() != 4)
return false;
@ -48,7 +48,6 @@ bool CreateObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& r
FilterUtility::CheckPermission(user, "objects/create/" + type->GetName());
String name = request.RequestUrl->GetPath()[3];
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
Array::Ptr templates = params->Get("templates");
Dictionary::Ptr attrs = params->Get("attrs");

View File

@ -30,7 +30,8 @@ class I2_REMOTE_API CreateObjectHandler : public HttpHandler
public:
DECLARE_PTR_TYPEDEFS(CreateObjectHandler);
virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response) override;
virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request,
HttpResponse& response, const Dictionary::Ptr& params) override;
};
}

View File

@ -32,7 +32,7 @@ using namespace icinga;
REGISTER_URLHANDLER("/v1/objects", DeleteObjectHandler);
bool DeleteObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
bool DeleteObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params)
{
if (request.RequestUrl->GetPath().size() < 3 || request.RequestUrl->GetPath().size() > 4)
return false;
@ -51,8 +51,6 @@ bool DeleteObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& r
qd.Types.insert(type->GetName());
qd.Permission = "objects/delete/" + type->GetName();
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
params->Set("type", type->GetName());
if (request.RequestUrl->GetPath().size() >= 4) {

View File

@ -30,7 +30,8 @@ class I2_REMOTE_API DeleteObjectHandler : public HttpHandler
public:
DECLARE_PTR_TYPEDEFS(DeleteObjectHandler);
virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response) override;
virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request,
HttpResponse& response, const Dictionary::Ptr& params) override;
};
}

View File

@ -31,7 +31,7 @@ using namespace icinga;
REGISTER_URLHANDLER("/v1/events", EventsHandler);
bool EventsHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
bool EventsHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params)
{
if (request.RequestUrl->GetPath().size() != 2)
return false;
@ -44,8 +44,6 @@ bool EventsHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request
return true;
}
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
Array::Ptr types = params->Get("types");
if (!types) {

View File

@ -31,7 +31,8 @@ class I2_REMOTE_API EventsHandler : public HttpHandler
public:
DECLARE_PTR_TYPEDEFS(EventsHandler);
virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response) override;
virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request,
HttpResponse& response, const Dictionary::Ptr& params) override;
};
}

View File

@ -20,6 +20,7 @@
#include "remote/httphandler.hpp"
#include "remote/httputility.hpp"
#include "base/singleton.hpp"
#include "base/exception.hpp"
#include <boost/algorithm/string/join.hpp>
using namespace icinga;
@ -94,13 +95,23 @@ void HttpHandler::ProcessRequest(const ApiUser::Ptr& user, HttpRequest& request,
std::reverse(handlers.begin(), handlers.end());
Dictionary::Ptr params;
try {
params = HttpUtility::FetchRequestParameters(request);
} catch (const std::exception& ex) {
HttpUtility::SendJsonError(response, 400, "Invalid request body: " + DiagnosticInformation(ex, false));
return;
}
bool processed = false;
BOOST_FOREACH(const HttpHandler::Ptr& handler, handlers) {
if (handler->HandleRequest(user, request, response)) {
if (handler->HandleRequest(user, request, response, params)) {
processed = true;
break;
}
}
if (!processed) {
String path = boost::algorithm::join(request.RequestUrl->GetPath(), "/");
HttpUtility::SendJsonError(response, 404, "The requested path '" + path +

View File

@ -40,7 +40,7 @@ class I2_REMOTE_API HttpHandler : public Object
public:
DECLARE_PTR_TYPEDEFS(HttpHandler);
virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response) = 0;
virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) = 0;
static void Register(const Url::Ptr& url, const HttpHandler::Ptr& handler);
static void ProcessRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response);

View File

@ -24,7 +24,7 @@ using namespace icinga;
REGISTER_URLHANDLER("/", InfoHandler);
bool InfoHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
bool InfoHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params)
{
if (request.RequestUrl->GetPath().size() > 2)
return false;

View File

@ -30,7 +30,8 @@ class I2_REMOTE_API InfoHandler : public HttpHandler
public:
DECLARE_PTR_TYPEDEFS(InfoHandler);
virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response) override;
virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request,
HttpResponse& response, const Dictionary::Ptr& params) override;
};
}

View File

@ -30,7 +30,7 @@ using namespace icinga;
REGISTER_URLHANDLER("/v1/objects", ModifyObjectHandler);
bool ModifyObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
bool ModifyObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params)
{
if (request.RequestUrl->GetPath().size() < 3 || request.RequestUrl->GetPath().size() > 4)
return false;
@ -49,8 +49,6 @@ bool ModifyObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& r
qd.Types.insert(type->GetName());
qd.Permission = "objects/modify/" + type->GetName();
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
params->Set("type", type->GetName());
if (request.RequestUrl->GetPath().size() >= 4) {

View File

@ -30,7 +30,8 @@ class I2_REMOTE_API ModifyObjectHandler : public HttpHandler
public:
DECLARE_PTR_TYPEDEFS(ModifyObjectHandler);
virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response) override;
virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request,
HttpResponse& response, const Dictionary::Ptr& params) override;
};
}

View File

@ -104,7 +104,7 @@ Dictionary::Ptr ObjectQueryHandler::SerializeObjectAttrs(const Object::Ptr& obje
return resultAttrs;
}
bool ObjectQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
bool ObjectQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params)
{
if (request.RequestUrl->GetPath().size() < 3 || request.RequestUrl->GetPath().size() > 4)
return false;
@ -123,8 +123,6 @@ bool ObjectQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& re
qd.Types.insert(type->GetName());
qd.Permission = "objects/query/" + type->GetName();
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
Array::Ptr uattrs = params->Get("attrs");
Array::Ptr ujoins = params->Get("joins");
Array::Ptr umetas = params->Get("meta");

View File

@ -30,7 +30,8 @@ class I2_REMOTE_API ObjectQueryHandler : public HttpHandler
public:
DECLARE_PTR_TYPEDEFS(ObjectQueryHandler);
virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response) override;
virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request,
HttpResponse& response, const Dictionary::Ptr& params) override;
private:
static Dictionary::Ptr SerializeObjectAttrs(const Object::Ptr& object, const String& attrPrefix,

View File

@ -72,7 +72,7 @@ public:
}
};
bool StatusHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
bool StatusHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params)
{
if (request.RequestUrl->GetPath().size() > 3)
return false;
@ -85,8 +85,6 @@ bool StatusHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request
qd.Provider = new StatusTargetProvider();
qd.Permission = "status/query";
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
params->Set("type", "Status");
if (request.RequestUrl->GetPath().size() >= 3)

View File

@ -30,7 +30,8 @@ class I2_REMOTE_API StatusHandler : public HttpHandler
public:
DECLARE_PTR_TYPEDEFS(StatusHandler);
virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response) override;
virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request,
HttpResponse& response, const Dictionary::Ptr& params) override;
};
}

View File

@ -75,7 +75,7 @@ public:
}
};
bool TypeQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
bool TypeQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params)
{
if (request.RequestUrl->GetPath().size() > 3)
return false;
@ -87,8 +87,6 @@ bool TypeQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& requ
qd.Types.insert("Type");
qd.Provider = new TypeTargetProvider();
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
if (params->Contains("type"))
params->Set("name", params->Get("type"));

View File

@ -30,7 +30,8 @@ class I2_REMOTE_API TypeQueryHandler : public HttpHandler
public:
DECLARE_PTR_TYPEDEFS(TypeQueryHandler);
virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response) override;
virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request,
HttpResponse& response, const Dictionary::Ptr& params) override;
};
}