mirror of
https://github.com/Icinga/icinga2.git
synced 2025-07-22 21:24:41 +02:00
parent
d0d5bd9b0a
commit
5ef4204d06
@ -33,11 +33,13 @@ 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)
|
||||||
{
|
{
|
||||||
if (request.RequestUrl->GetPath().size() < 3)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (request.RequestMethod != "POST") {
|
if (request.RequestMethod != "POST") {
|
||||||
response.SetStatus(400, "Bad request");
|
HttpUtility::SendJsonError(response, 400, "Invalid request type. Must be POST.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.RequestUrl->GetPath().size() < 3) {
|
||||||
|
HttpUtility::SendJsonError(response, 400, "Action is missing.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,8 +47,10 @@ bool ActionsHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& reques
|
|||||||
|
|
||||||
ApiAction::Ptr action = ApiAction::GetByName(actionName);
|
ApiAction::Ptr action = ApiAction::GetByName(actionName);
|
||||||
|
|
||||||
if (!action)
|
if (!action) {
|
||||||
return false;
|
HttpUtility::SendJsonError(response, 404, "Action '" + actionName + "' could not be found.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
QueryDescription qd;
|
QueryDescription qd;
|
||||||
|
|
||||||
@ -58,7 +62,14 @@ bool ActionsHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& reques
|
|||||||
if (!types.empty()) {
|
if (!types.empty()) {
|
||||||
qd.Types = std::set<String>(types.begin(), types.end());
|
qd.Types = std::set<String>(types.begin(), types.end());
|
||||||
|
|
||||||
|
try {
|
||||||
objs = FilterUtility::GetFilterTargets(qd, params);
|
objs = FilterUtility::GetFilterTargets(qd, params);
|
||||||
|
} catch (const std::exception& ex) {
|
||||||
|
HttpUtility::SendJsonError(response, 400,
|
||||||
|
"Type/Filter was required but not provided or was invalid.",
|
||||||
|
request.GetVerboseErrors() ? DiagnosticInformation(ex) : "");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
} else
|
} else
|
||||||
objs.push_back(ConfigObject::Ptr());
|
objs.push_back(ConfigObject::Ptr());
|
||||||
|
|
||||||
@ -72,8 +83,10 @@ bool ActionsHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& reques
|
|||||||
results->Add(action->Invoke(obj, params));
|
results->Add(action->Invoke(obj, params));
|
||||||
} catch (const std::exception& ex) {
|
} catch (const std::exception& ex) {
|
||||||
Dictionary::Ptr fail = new Dictionary();
|
Dictionary::Ptr fail = new Dictionary();
|
||||||
fail->Set("code", 501);
|
fail->Set("code", 500);
|
||||||
fail->Set("status", "Error: " + DiagnosticInformation(ex));
|
fail->Set("status", "Action execution failed.");
|
||||||
|
if (request.GetVerboseErrors())
|
||||||
|
fail->Set("diagnostic information", DiagnosticInformation(ex));
|
||||||
results->Add(fail);
|
results->Add(fail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,13 +57,15 @@ void ApiListener::OnConfigLoaded(void)
|
|||||||
try {
|
try {
|
||||||
cert = GetX509Certificate(GetCertPath());
|
cert = GetX509Certificate(GetCertPath());
|
||||||
} catch (const std::exception&) {
|
} catch (const std::exception&) {
|
||||||
BOOST_THROW_EXCEPTION(ScriptError("Cannot get certificate from cert path: '" + GetCertPath() + "'.", GetDebugInfo()));
|
BOOST_THROW_EXCEPTION(ScriptError("Cannot get certificate from cert path: '"
|
||||||
|
+ GetCertPath() + "'.", GetDebugInfo()));
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
SetIdentity(GetCertificateCN(cert));
|
SetIdentity(GetCertificateCN(cert));
|
||||||
} catch (const std::exception&) {
|
} catch (const std::exception&) {
|
||||||
BOOST_THROW_EXCEPTION(ScriptError("Cannot get certificate common name from cert path: '" + GetCertPath() + "'.", GetDebugInfo()));
|
BOOST_THROW_EXCEPTION(ScriptError("Cannot get certificate common name from cert path: '"
|
||||||
|
+ GetCertPath() + "'.", GetDebugInfo()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Log(LogInformation, "ApiListener")
|
Log(LogInformation, "ApiListener")
|
||||||
@ -72,14 +74,16 @@ void ApiListener::OnConfigLoaded(void)
|
|||||||
try {
|
try {
|
||||||
m_SSLContext = MakeSSLContext(GetCertPath(), GetKeyPath(), GetCaPath());
|
m_SSLContext = MakeSSLContext(GetCertPath(), GetKeyPath(), GetCaPath());
|
||||||
} catch (const std::exception&) {
|
} catch (const std::exception&) {
|
||||||
BOOST_THROW_EXCEPTION(ScriptError("Cannot make SSL context for cert path: '" + GetCertPath() + "' key path: '" + GetKeyPath() + "' ca path: '" + GetCaPath() + "'.", GetDebugInfo()));
|
BOOST_THROW_EXCEPTION(ScriptError("Cannot make SSL context for cert path: '"
|
||||||
|
+ GetCertPath() + "' key path: '" + GetKeyPath() + "' ca path: '" + GetCaPath() + "'.", GetDebugInfo()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!GetCrlPath().IsEmpty()) {
|
if (!GetCrlPath().IsEmpty()) {
|
||||||
try {
|
try {
|
||||||
AddCRLToSSLContext(m_SSLContext, GetCrlPath());
|
AddCRLToSSLContext(m_SSLContext, GetCrlPath());
|
||||||
} catch (const std::exception&) {
|
} catch (const std::exception&) {
|
||||||
BOOST_THROW_EXCEPTION(ScriptError("Cannot add certificate revocation list to SSL context for crl path: '" + GetCrlPath() + "'.", GetDebugInfo()));
|
BOOST_THROW_EXCEPTION(ScriptError("Cannot add certificate revocation list to SSL context for crl path: '"
|
||||||
|
+ GetCrlPath() + "'.", GetDebugInfo()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,7 +101,8 @@ void ApiListener::Start(void)
|
|||||||
{
|
{
|
||||||
SyncZoneDirs();
|
SyncZoneDirs();
|
||||||
|
|
||||||
if (std::distance(ConfigType::GetObjectsByType<ApiListener>().first, ConfigType::GetObjectsByType<ApiListener>().second) > 1) {
|
if (std::distance(ConfigType::GetObjectsByType<ApiListener>().first,
|
||||||
|
ConfigType::GetObjectsByType<ApiListener>().second) > 1) {
|
||||||
Log(LogCritical, "ApiListener", "Only one ApiListener object is allowed.");
|
Log(LogCritical, "ApiListener", "Only one ApiListener object is allowed.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -433,7 +438,8 @@ void ApiListener::ApiTimerHandler(void)
|
|||||||
/* only connect to endpoints in a) the same zone b) our parent zone c) immediate child zones */
|
/* only connect to endpoints in a) the same zone b) our parent zone c) immediate child zones */
|
||||||
if (my_zone != zone && my_zone != zone->GetParent() && zone != my_zone->GetParent()) {
|
if (my_zone != zone && my_zone != zone->GetParent() && zone != my_zone->GetParent()) {
|
||||||
Log(LogDebug, "ApiListener")
|
Log(LogDebug, "ApiListener")
|
||||||
<< "Not connecting to Zone '" << zone->GetName() << "' because it's not in the same zone, a parent or a child zone.";
|
<< "Not connecting to Zone '" << zone->GetName()
|
||||||
|
<< "' because it's not in the same zone, a parent or a child zone.";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -448,21 +454,24 @@ void ApiListener::ApiTimerHandler(void)
|
|||||||
/* don't try to connect to endpoints which don't have a host and port */
|
/* don't try to connect to endpoints which don't have a host and port */
|
||||||
if (endpoint->GetHost().IsEmpty() || endpoint->GetPort().IsEmpty()) {
|
if (endpoint->GetHost().IsEmpty() || endpoint->GetPort().IsEmpty()) {
|
||||||
Log(LogDebug, "ApiListener")
|
Log(LogDebug, "ApiListener")
|
||||||
<< "Not connecting to Endpoint '" << endpoint->GetName() << "' because the host/port attributes are missing.";
|
<< "Not connecting to Endpoint '" << endpoint->GetName()
|
||||||
|
<< "' because the host/port attributes are missing.";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* don't try to connect if there's already a connection attempt */
|
/* don't try to connect if there's already a connection attempt */
|
||||||
if (endpoint->GetConnecting()) {
|
if (endpoint->GetConnecting()) {
|
||||||
Log(LogDebug, "ApiListener")
|
Log(LogDebug, "ApiListener")
|
||||||
<< "Not connecting to Endpoint '" << endpoint->GetName() << "' because we're already trying to connect to it.";
|
<< "Not connecting to Endpoint '" << endpoint->GetName()
|
||||||
|
<< "' because we're already trying to connect to it.";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* don't try to connect if we're already connected */
|
/* don't try to connect if we're already connected */
|
||||||
if (endpoint->IsConnected()) {
|
if (endpoint->IsConnected()) {
|
||||||
Log(LogDebug, "ApiListener")
|
Log(LogDebug, "ApiListener")
|
||||||
<< "Not connecting to Endpoint '" << endpoint->GetName() << "' because we're already connected to it.";
|
<< "Not connecting to Endpoint '" << endpoint->GetName()
|
||||||
|
<< "' because we're already connected to it.";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -511,7 +520,8 @@ void ApiListener::ApiTimerHandler(void)
|
|||||||
<< "Connected endpoints: " << Utility::NaturalJoin(names);
|
<< "Connected endpoints: " << Utility::NaturalJoin(names);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApiListener::RelayMessage(const MessageOrigin::Ptr& origin, const ConfigObject::Ptr& secobj, const Dictionary::Ptr& message, bool log)
|
void ApiListener::RelayMessage(const MessageOrigin::Ptr& origin,
|
||||||
|
const ConfigObject::Ptr& secobj, const Dictionary::Ptr& message, bool log)
|
||||||
{
|
{
|
||||||
m_RelayQueue.Enqueue(boost::bind(&ApiListener::SyncRelayMessage, this, origin, secobj, message, log), true);
|
m_RelayQueue.Enqueue(boost::bind(&ApiListener::SyncRelayMessage, this, origin, secobj, message, log), true);
|
||||||
}
|
}
|
||||||
@ -526,7 +536,6 @@ void ApiListener::PersistMessage(const Dictionary::Ptr& message, const ConfigObj
|
|||||||
pmessage->Set("timestamp", ts);
|
pmessage->Set("timestamp", ts);
|
||||||
|
|
||||||
pmessage->Set("message", JsonEncode(message));
|
pmessage->Set("message", JsonEncode(message));
|
||||||
|
|
||||||
Dictionary::Ptr secname = new Dictionary();
|
Dictionary::Ptr secname = new Dictionary();
|
||||||
secname->Set("type", secobj->GetType()->GetName());
|
secname->Set("type", secobj->GetType()->GetName());
|
||||||
secname->Set("name", secobj->GetName());
|
secname->Set("name", secobj->GetName());
|
||||||
@ -560,7 +569,8 @@ void ApiListener::SyncSendMessage(const Endpoint::Ptr& endpoint, const Dictionar
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ApiListener::SyncRelayMessage(const MessageOrigin::Ptr& origin, const ConfigObject::Ptr& secobj, const Dictionary::Ptr& message, bool log)
|
void ApiListener::SyncRelayMessage(const MessageOrigin::Ptr& origin,
|
||||||
|
const ConfigObject::Ptr& secobj, const Dictionary::Ptr& message, bool log)
|
||||||
{
|
{
|
||||||
double ts = Utility::GetTime();
|
double ts = Utility::GetTime();
|
||||||
message->Set("ts", ts);
|
message->Set("ts", ts);
|
||||||
|
@ -33,7 +33,7 @@ bool ConfigFilesHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& re
|
|||||||
if (request.RequestMethod == "GET")
|
if (request.RequestMethod == "GET")
|
||||||
HandleGet(user, request, response);
|
HandleGet(user, request, response);
|
||||||
else
|
else
|
||||||
response.SetStatus(400, "Bad request");
|
HttpUtility::SendJsonError(response, 400, "Invalid request type. Must be GET.");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -58,24 +58,21 @@ void ConfigFilesHandler::HandleGet(const ApiUser::Ptr& user, HttpRequest& reques
|
|||||||
String packageName = HttpUtility::GetLastParameter(params, "package");
|
String packageName = HttpUtility::GetLastParameter(params, "package");
|
||||||
String stageName = HttpUtility::GetLastParameter(params, "stage");
|
String stageName = HttpUtility::GetLastParameter(params, "stage");
|
||||||
|
|
||||||
if (!ConfigPackageUtility::ValidateName(packageName) || !ConfigPackageUtility::ValidateName(stageName)) {
|
if (!ConfigPackageUtility::ValidateName(packageName))
|
||||||
response.SetStatus(403, "Forbidden");
|
return HttpUtility::SendJsonError(response, 404, "Package is not valid or does not exist.");
|
||||||
return;
|
|
||||||
}
|
if (!ConfigPackageUtility::ValidateName(stageName))
|
||||||
|
return HttpUtility::SendJsonError(response, 404, "Stage is not valid or does not exist.");
|
||||||
|
|
||||||
String relativePath = HttpUtility::GetLastParameter(params, "path");
|
String relativePath = HttpUtility::GetLastParameter(params, "path");
|
||||||
|
|
||||||
if (ConfigPackageUtility::ContainsDotDot(relativePath)) {
|
if (ConfigPackageUtility::ContainsDotDot(relativePath))
|
||||||
response.SetStatus(403, "Forbidden");
|
return HttpUtility::SendJsonError(response, 403, "Path contains '..' (not allowed).");
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String path = ConfigPackageUtility::GetPackageDir() + "/" + packageName + "/" + stageName + "/" + relativePath;
|
String path = ConfigPackageUtility::GetPackageDir() + "/" + packageName + "/" + stageName + "/" + relativePath;
|
||||||
|
|
||||||
if (!Utility::PathExists(path)) {
|
if (!Utility::PathExists(path))
|
||||||
response.SetStatus(404, "File not found");
|
return HttpUtility::SendJsonError(response, 404, "Path not found.");
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
std::ifstream fp(path.CStr(), std::ifstream::in | std::ifstream::binary);
|
std::ifstream fp(path.CStr(), std::ifstream::in | std::ifstream::binary);
|
||||||
@ -86,7 +83,8 @@ void ConfigFilesHandler::HandleGet(const ApiUser::Ptr& user, HttpRequest& reques
|
|||||||
response.AddHeader("Content-Type", "application/octet-stream");
|
response.AddHeader("Content-Type", "application/octet-stream");
|
||||||
response.WriteBody(content.CStr(), content.GetLength());
|
response.WriteBody(content.CStr(), content.GetLength());
|
||||||
} catch (const std::exception& ex) {
|
} catch (const std::exception& ex) {
|
||||||
response.SetStatus(503, "Could not read file");
|
return HttpUtility::SendJsonError(response, 500, "Could not read file.",
|
||||||
|
request.GetVerboseErrors() ? DiagnosticInformation(ex) : "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,7 +135,8 @@ bool ConfigObjectUtility::DeleteObjectHelper(const ConfigObject::Ptr& object, bo
|
|||||||
|
|
||||||
if (!parents.empty() && !cascade) {
|
if (!parents.empty() && !cascade) {
|
||||||
if (errors)
|
if (errors)
|
||||||
errors->Add("Object cannot be deleted because other objects depend on it. Use cascading delete to delete it anyway.");
|
errors->Add("Object cannot be deleted because other objects depend on it. "
|
||||||
|
"Use cascading delete to delete it anyway.");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "remote/configpackageutility.hpp"
|
#include "remote/configpackageutility.hpp"
|
||||||
#include "remote/httputility.hpp"
|
#include "remote/httputility.hpp"
|
||||||
#include "base/exception.hpp"
|
#include "base/exception.hpp"
|
||||||
|
#include <boost/algorithm/string/join.hpp>
|
||||||
|
|
||||||
using namespace icinga;
|
using namespace icinga;
|
||||||
|
|
||||||
@ -28,8 +29,11 @@ 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)
|
||||||
{
|
{
|
||||||
if (request.RequestUrl->GetPath().size() > 4)
|
if (request.RequestUrl->GetPath().size() > 4) {
|
||||||
return false;
|
String path = boost::algorithm::join(request.RequestUrl->GetPath(), "/");
|
||||||
|
HttpUtility::SendJsonError(response, 404, "The requested path is too long to match any config package requests");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (request.RequestMethod == "GET")
|
if (request.RequestMethod == "GET")
|
||||||
HandleGet(user, request, response);
|
HandleGet(user, request, response);
|
||||||
@ -38,7 +42,7 @@ bool ConfigPackagesHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest&
|
|||||||
else if (request.RequestMethod == "DELETE")
|
else if (request.RequestMethod == "DELETE")
|
||||||
HandleDelete(user, request, response);
|
HandleDelete(user, request, response);
|
||||||
else
|
else
|
||||||
response.SetStatus(400, "Bad request");
|
HttpUtility::SendJsonError(response, 400, "Invalid request type. Must be GET, POST or DELETE.");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -74,25 +78,21 @@ void ConfigPackagesHandler::HandlePost(const ApiUser::Ptr& user, HttpRequest& re
|
|||||||
String packageName = HttpUtility::GetLastParameter(params, "package");
|
String packageName = HttpUtility::GetLastParameter(params, "package");
|
||||||
|
|
||||||
if (!ConfigPackageUtility::ValidateName(packageName)) {
|
if (!ConfigPackageUtility::ValidateName(packageName)) {
|
||||||
response.SetStatus(403, "Forbidden");
|
HttpUtility::SendJsonError(response, 404, "Package is not valid or does not exist.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int code = 200;
|
|
||||||
String status = "Created package.";
|
|
||||||
|
|
||||||
try {
|
|
||||||
ConfigPackageUtility::CreatePackage(packageName);
|
|
||||||
} catch (const std::exception& ex) {
|
|
||||||
code = 501;
|
|
||||||
status = "Error: " + DiagnosticInformation(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
Dictionary::Ptr result1 = new Dictionary();
|
Dictionary::Ptr result1 = new Dictionary();
|
||||||
|
|
||||||
result1->Set("package", packageName);
|
try {
|
||||||
result1->Set("code", code);
|
ConfigPackageUtility::CreatePackage(packageName);
|
||||||
result1->Set("status", status);
|
} catch (const std::exception& ex) {
|
||||||
|
HttpUtility::SendJsonError(response, 500, "Could not create package.",
|
||||||
|
request.GetVerboseErrors() ? DiagnosticInformation(ex) : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
result1->Set("code", 200);
|
||||||
|
result1->Set("status", "Created package.");
|
||||||
|
|
||||||
Array::Ptr results = new Array();
|
Array::Ptr results = new Array();
|
||||||
results->Add(result1);
|
results->Add(result1);
|
||||||
@ -100,7 +100,7 @@ void ConfigPackagesHandler::HandlePost(const ApiUser::Ptr& user, HttpRequest& re
|
|||||||
Dictionary::Ptr result = new Dictionary();
|
Dictionary::Ptr result = new Dictionary();
|
||||||
result->Set("results", results);
|
result->Set("results", results);
|
||||||
|
|
||||||
response.SetStatus(code, (code == 200) ? "OK" : "Error");
|
response.SetStatus(200, "OK");
|
||||||
HttpUtility::SendJsonBody(response, result);
|
HttpUtility::SendJsonBody(response, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,21 +114,23 @@ void ConfigPackagesHandler::HandleDelete(const ApiUser::Ptr& user, HttpRequest&
|
|||||||
String packageName = HttpUtility::GetLastParameter(params, "package");
|
String packageName = HttpUtility::GetLastParameter(params, "package");
|
||||||
|
|
||||||
if (!ConfigPackageUtility::ValidateName(packageName)) {
|
if (!ConfigPackageUtility::ValidateName(packageName)) {
|
||||||
response.SetStatus(403, "Forbidden");
|
HttpUtility::SendJsonError(response, 404, "Package is not valid or does not exist.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int code = 200;
|
int code = 200;
|
||||||
String status = "Deleted package.";
|
String status = "Deleted package.";
|
||||||
|
Dictionary::Ptr result1 = new Dictionary();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ConfigPackageUtility::DeletePackage(packageName);
|
ConfigPackageUtility::DeletePackage(packageName);
|
||||||
} catch (const std::exception& ex) {
|
} catch (const std::exception& ex) {
|
||||||
code = 501;
|
code = 500;
|
||||||
status = "Error: " + DiagnosticInformation(ex);
|
status = "Failed to delete package.";
|
||||||
|
if (request.GetVerboseErrors())
|
||||||
|
result1->Set("diagnostic information", DiagnosticInformation(ex));
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary::Ptr result1 = new Dictionary();
|
|
||||||
|
|
||||||
result1->Set("package", packageName);
|
result1->Set("package", packageName);
|
||||||
result1->Set("code", code);
|
result1->Set("code", code);
|
||||||
@ -140,7 +142,7 @@ void ConfigPackagesHandler::HandleDelete(const ApiUser::Ptr& user, HttpRequest&
|
|||||||
Dictionary::Ptr result = new Dictionary();
|
Dictionary::Ptr result = new Dictionary();
|
||||||
result->Set("results", results);
|
result->Set("results", results);
|
||||||
|
|
||||||
response.SetStatus(code, (code == 200) ? "OK" : "Error");
|
response.SetStatus(code, (code == 200) ? "OK" : "Internal Server Error");
|
||||||
HttpUtility::SendJsonBody(response, result);
|
HttpUtility::SendJsonBody(response, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +60,8 @@ void ConfigPackageUtility::DeletePackage(const String& name)
|
|||||||
std::vector<String> ConfigPackageUtility::GetPackages(void)
|
std::vector<String> ConfigPackageUtility::GetPackages(void)
|
||||||
{
|
{
|
||||||
std::vector<String> packages;
|
std::vector<String> packages;
|
||||||
Utility::Glob(GetPackageDir() + "/*", boost::bind(&ConfigPackageUtility::CollectDirNames, _1, boost::ref(packages)), GlobDirectory);
|
Utility::Glob(GetPackageDir() + "/*", boost::bind(&ConfigPackageUtility::CollectDirNames,
|
||||||
|
_1, boost::ref(packages)), GlobDirectory);
|
||||||
return packages;
|
return packages;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,4 +314,3 @@ bool ConfigPackageUtility::ValidateName(const String& name)
|
|||||||
return (!boost::regex_search(name.GetData(), what, expr));
|
return (!boost::regex_search(name.GetData(), what, expr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "base/application.hpp"
|
#include "base/application.hpp"
|
||||||
#include "base/exception.hpp"
|
#include "base/exception.hpp"
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
|
#include <boost/algorithm/string/join.hpp>
|
||||||
|
|
||||||
using namespace icinga;
|
using namespace icinga;
|
||||||
|
|
||||||
@ -30,8 +31,11 @@ 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)
|
||||||
{
|
{
|
||||||
if (request.RequestUrl->GetPath().size() > 5)
|
if (request.RequestUrl->GetPath().size() > 5) {
|
||||||
return false;
|
String path = boost::algorithm::join(request.RequestUrl->GetPath(), "/");
|
||||||
|
HttpUtility::SendJsonError(response, 404, "The requested path is too long to match any config tag requests.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (request.RequestMethod == "GET")
|
if (request.RequestMethod == "GET")
|
||||||
HandleGet(user, request, response);
|
HandleGet(user, request, response);
|
||||||
@ -40,7 +44,7 @@ bool ConfigStagesHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& r
|
|||||||
else if (request.RequestMethod == "DELETE")
|
else if (request.RequestMethod == "DELETE")
|
||||||
HandleDelete(user, request, response);
|
HandleDelete(user, request, response);
|
||||||
else
|
else
|
||||||
response.SetStatus(400, "Bad request");
|
HttpUtility::SendJsonError(response, 400, "Invalid request type. Must be GET, POST or DELETE.");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -58,10 +62,11 @@ void ConfigStagesHandler::HandleGet(const ApiUser::Ptr& user, HttpRequest& reque
|
|||||||
String packageName = HttpUtility::GetLastParameter(params, "package");
|
String packageName = HttpUtility::GetLastParameter(params, "package");
|
||||||
String stageName = HttpUtility::GetLastParameter(params, "stage");
|
String stageName = HttpUtility::GetLastParameter(params, "stage");
|
||||||
|
|
||||||
if (!ConfigPackageUtility::ValidateName(packageName) || !ConfigPackageUtility::ValidateName(stageName)) {
|
if (!ConfigPackageUtility::ValidateName(packageName))
|
||||||
response.SetStatus(403, "Forbidden");
|
return HttpUtility::SendJsonError(response, 404, "Package is not valid or does not exist.");
|
||||||
return;
|
|
||||||
}
|
if (!ConfigPackageUtility::ValidateName(stageName))
|
||||||
|
return HttpUtility::SendJsonError(response, 404, "Stage is not valid or does not exist.");
|
||||||
|
|
||||||
Array::Ptr results = new Array();
|
Array::Ptr results = new Array();
|
||||||
|
|
||||||
@ -93,15 +98,11 @@ void ConfigStagesHandler::HandlePost(const ApiUser::Ptr& user, HttpRequest& requ
|
|||||||
|
|
||||||
String packageName = HttpUtility::GetLastParameter(params, "package");
|
String packageName = HttpUtility::GetLastParameter(params, "package");
|
||||||
|
|
||||||
if (!ConfigPackageUtility::ValidateName(packageName)) {
|
if (!ConfigPackageUtility::ValidateName(packageName))
|
||||||
response.SetStatus(403, "Forbidden");
|
return HttpUtility::SendJsonError(response, 404, "Package is not valid or does not exist.");
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Dictionary::Ptr files = params->Get("files");
|
Dictionary::Ptr files = params->Get("files");
|
||||||
|
|
||||||
int code = 200;
|
|
||||||
String status = "Created stage.";
|
|
||||||
String stageName;
|
String stageName;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -113,16 +114,15 @@ void ConfigStagesHandler::HandlePost(const ApiUser::Ptr& user, HttpRequest& requ
|
|||||||
/* validate the config. on success, activate stage and reload */
|
/* validate the config. on success, activate stage and reload */
|
||||||
ConfigPackageUtility::AsyncTryActivateStage(packageName, stageName);
|
ConfigPackageUtility::AsyncTryActivateStage(packageName, stageName);
|
||||||
} catch (const std::exception& ex) {
|
} catch (const std::exception& ex) {
|
||||||
code = 501;
|
return HttpUtility::SendJsonError(response, 500,
|
||||||
status = "Error: " + DiagnosticInformation(ex);
|
"Stage creation failed.",
|
||||||
|
request.GetVerboseErrors() ? DiagnosticInformation(ex) : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary::Ptr result1 = new Dictionary();
|
Dictionary::Ptr result1 = new Dictionary();
|
||||||
|
|
||||||
result1->Set("package", packageName);
|
result1->Set("code", 200);
|
||||||
result1->Set("stage", stageName);
|
result1->Set("status", "Created stage.");
|
||||||
result1->Set("code", code);
|
|
||||||
result1->Set("status", status);
|
|
||||||
|
|
||||||
Array::Ptr results = new Array();
|
Array::Ptr results = new Array();
|
||||||
results->Add(result1);
|
results->Add(result1);
|
||||||
@ -130,7 +130,7 @@ void ConfigStagesHandler::HandlePost(const ApiUser::Ptr& user, HttpRequest& requ
|
|||||||
Dictionary::Ptr result = new Dictionary();
|
Dictionary::Ptr result = new Dictionary();
|
||||||
result->Set("results", results);
|
result->Set("results", results);
|
||||||
|
|
||||||
response.SetStatus(code, (code == 200) ? "OK" : "Error");
|
response.SetStatus(200, "OK");
|
||||||
HttpUtility::SendJsonBody(response, result);
|
HttpUtility::SendJsonBody(response, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,27 +147,24 @@ void ConfigStagesHandler::HandleDelete(const ApiUser::Ptr& user, HttpRequest& re
|
|||||||
String packageName = HttpUtility::GetLastParameter(params, "package");
|
String packageName = HttpUtility::GetLastParameter(params, "package");
|
||||||
String stageName = HttpUtility::GetLastParameter(params, "stage");
|
String stageName = HttpUtility::GetLastParameter(params, "stage");
|
||||||
|
|
||||||
if (!ConfigPackageUtility::ValidateName(packageName) || !ConfigPackageUtility::ValidateName(stageName)) {
|
if (!ConfigPackageUtility::ValidateName(packageName))
|
||||||
response.SetStatus(403, "Forbidden");
|
return HttpUtility::SendJsonError(response, 404, "Package is not valid or does not exist.");
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int code = 200;
|
if (!ConfigPackageUtility::ValidateName(stageName))
|
||||||
String status = "Deleted stage.";
|
return HttpUtility::SendJsonError(response, 404, "Stage is not valid or does not exist.");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ConfigPackageUtility::DeleteStage(packageName, stageName);
|
ConfigPackageUtility::DeleteStage(packageName, stageName);
|
||||||
} catch (const std::exception& ex) {
|
} catch (const std::exception& ex) {
|
||||||
code = 501;
|
return HttpUtility::SendJsonError(response, 500,
|
||||||
status = "Error: " + DiagnosticInformation(ex);
|
"Failed to delete stage.",
|
||||||
|
request.GetVerboseErrors() ? DiagnosticInformation(ex) : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary::Ptr result1 = new Dictionary();
|
Dictionary::Ptr result1 = new Dictionary();
|
||||||
|
|
||||||
result1->Set("package", packageName);
|
result1->Set("code", 200);
|
||||||
result1->Set("stage", stageName);
|
result1->Set("status", "Stage deleted");
|
||||||
result1->Set("code", code);
|
|
||||||
result1->Set("status", status);
|
|
||||||
|
|
||||||
Array::Ptr results = new Array();
|
Array::Ptr results = new Array();
|
||||||
results->Add(result1);
|
results->Add(result1);
|
||||||
@ -175,7 +172,7 @@ void ConfigStagesHandler::HandleDelete(const ApiUser::Ptr& user, HttpRequest& re
|
|||||||
Dictionary::Ptr result = new Dictionary();
|
Dictionary::Ptr result = new Dictionary();
|
||||||
result->Set("results", results);
|
result->Set("results", results);
|
||||||
|
|
||||||
response.SetStatus(code, (code == 200) ? "OK" : "Error");
|
response.SetStatus(200, "OK");
|
||||||
HttpUtility::SendJsonBody(response, result);
|
HttpUtility::SendJsonBody(response, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,16 +31,22 @@ REGISTER_URLHANDLER("/v1", CreateObjectHandler);
|
|||||||
|
|
||||||
bool CreateObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
|
bool CreateObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
|
||||||
{
|
{
|
||||||
if (request.RequestMethod != "PUT")
|
if (request.RequestMethod != "PUT") {
|
||||||
return false;
|
HttpUtility::SendJsonError(response, 400, "Invalid request type. Must be PUT.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (request.RequestUrl->GetPath().size() < 3)
|
if (request.RequestUrl->GetPath().size() < 3) {
|
||||||
return false;
|
HttpUtility::SendJsonError(response, 400, "Object name is missing.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Type::Ptr type = FilterUtility::TypeFromPluralName(request.RequestUrl->GetPath()[1]);
|
Type::Ptr type = FilterUtility::TypeFromPluralName(request.RequestUrl->GetPath()[1]);
|
||||||
|
|
||||||
if (!type)
|
if (!type) {
|
||||||
return false;
|
HttpUtility::SendJsonError(response, 403, "Erroneous type was supplied.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
String name = request.RequestUrl->GetPath()[2];
|
String name = request.RequestUrl->GetPath()[2];
|
||||||
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
|
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
|
||||||
@ -56,15 +62,12 @@ bool CreateObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& r
|
|||||||
|
|
||||||
if (!ConfigObjectUtility::CreateObject(type, name, config, errors)) {
|
if (!ConfigObjectUtility::CreateObject(type, name, config, errors)) {
|
||||||
result1->Set("errors", errors);
|
result1->Set("errors", errors);
|
||||||
code = 500;
|
HttpUtility::SendJsonError(response, 500, "Object could not be created.");
|
||||||
status = "Object could not be created.";
|
return true;
|
||||||
} else {
|
|
||||||
code = 200;
|
|
||||||
status = "Object was created.";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result1->Set("code", code);
|
result1->Set("code", 200);
|
||||||
result1->Set("status", status);
|
result1->Set("status", "Object was created");
|
||||||
|
|
||||||
Array::Ptr results = new Array();
|
Array::Ptr results = new Array();
|
||||||
results->Add(result1);
|
results->Add(result1);
|
||||||
@ -72,7 +75,7 @@ bool CreateObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& r
|
|||||||
Dictionary::Ptr result = new Dictionary();
|
Dictionary::Ptr result = new Dictionary();
|
||||||
result->Set("results", results);
|
result->Set("results", results);
|
||||||
|
|
||||||
response.SetStatus(code, status);
|
response.SetStatus(200, "OK");
|
||||||
HttpUtility::SendJsonBody(response, result);
|
HttpUtility::SendJsonBody(response, result);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -34,16 +34,23 @@ REGISTER_URLHANDLER("/v1", DeleteObjectHandler);
|
|||||||
|
|
||||||
bool DeleteObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
|
bool DeleteObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
|
||||||
{
|
{
|
||||||
if (request.RequestMethod != "DELETE")
|
if (request.RequestMethod != "DELETE") {
|
||||||
return false;
|
HttpUtility::SendJsonError(response, 400, "Invalid request type. Must be DELETE.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (request.RequestUrl->GetPath().size() < 2)
|
if (request.RequestUrl->GetPath().size() < 2) {
|
||||||
return false;
|
String path = boost::algorithm::join(request.RequestUrl->GetPath(), "/");
|
||||||
|
HttpUtility::SendJsonError(response, 404, "The requested path is too long to match any config tag requests.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Type::Ptr type = FilterUtility::TypeFromPluralName(request.RequestUrl->GetPath()[1]);
|
Type::Ptr type = FilterUtility::TypeFromPluralName(request.RequestUrl->GetPath()[1]);
|
||||||
|
|
||||||
if (!type)
|
if (!type) {
|
||||||
return false;
|
HttpUtility::SendJsonError(response, 400, "Erroneous type was supplied.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
QueryDescription qd;
|
QueryDescription qd;
|
||||||
qd.Types.insert(type->GetName());
|
qd.Types.insert(type->GetName());
|
||||||
|
@ -47,14 +47,16 @@ void Endpoint::OnAllConfigLoaded(void)
|
|||||||
|
|
||||||
if (members.find(this) != members.end()) {
|
if (members.find(this) != members.end()) {
|
||||||
if (m_Zone)
|
if (m_Zone)
|
||||||
BOOST_THROW_EXCEPTION(ScriptError("Endpoint '" + GetName() + "' is in more than one zone.", GetDebugInfo()));
|
BOOST_THROW_EXCEPTION(ScriptError("Endpoint '" + GetName()
|
||||||
|
+ "' is in more than one zone.", GetDebugInfo()));
|
||||||
|
|
||||||
m_Zone = zone;
|
m_Zone = zone;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_Zone)
|
if (!m_Zone)
|
||||||
BOOST_THROW_EXCEPTION(ScriptError("Endpoint '" + GetName() + "' does not belong to a zone.", GetDebugInfo()));
|
BOOST_THROW_EXCEPTION(ScriptError("Endpoint '" + GetName() +
|
||||||
|
"' does not belong to a zone.", GetDebugInfo()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Endpoint::AddClient(const JsonRpcConnection::Ptr& client)
|
void Endpoint::AddClient(const JsonRpcConnection::Ptr& client)
|
||||||
|
@ -183,3 +183,4 @@ std::vector<Value> FilterUtility::GetFilterTargets(const QueryDescription& qd, c
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +56,8 @@ void HttpClientConnection::Reconnect(void)
|
|||||||
m_Stream = new TlsStream(socket, m_Host, RoleClient);
|
m_Stream = new TlsStream(socket, m_Host, RoleClient);
|
||||||
else
|
else
|
||||||
ASSERT(!"Non-TLS HTTP connections not supported.");
|
ASSERT(!"Non-TLS HTTP connections not supported.");
|
||||||
//m_Stream = new NetworkStream(socket); -- does not currently work because the NetworkStream class doesn't support async I/O
|
/* m_Stream = new NetworkStream(socket);
|
||||||
|
-- does not currently work because the NetworkStream class doesn't support async I/O */
|
||||||
|
|
||||||
m_Stream->RegisterDataHandler(boost::bind(&HttpClientConnection::DataAvailableHandler, this));
|
m_Stream->RegisterDataHandler(boost::bind(&HttpClientConnection::DataAvailableHandler, this));
|
||||||
if (m_Stream->IsDataAvailable())
|
if (m_Stream->IsDataAvailable())
|
||||||
@ -149,8 +150,10 @@ boost::shared_ptr<HttpRequest> HttpClientConnection::NewRequest(void)
|
|||||||
return boost::make_shared<HttpRequest>(m_Stream);
|
return boost::make_shared<HttpRequest>(m_Stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpClientConnection::SubmitRequest(const boost::shared_ptr<HttpRequest>& request, const HttpCompletionCallback& callback)
|
void HttpClientConnection::SubmitRequest(const boost::shared_ptr<HttpRequest>& request,
|
||||||
|
const HttpCompletionCallback& callback)
|
||||||
{
|
{
|
||||||
m_Requests.push_back(std::make_pair(request, callback));
|
m_Requests.push_back(std::make_pair(request, callback));
|
||||||
request->Finish();
|
request->Finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,9 @@
|
|||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#include "remote/httphandler.hpp"
|
#include "remote/httphandler.hpp"
|
||||||
|
#include "remote/httputility.hpp"
|
||||||
#include "base/singleton.hpp"
|
#include "base/singleton.hpp"
|
||||||
|
#include <boost/algorithm/string/join.hpp>
|
||||||
|
|
||||||
using namespace icinga;
|
using namespace icinga;
|
||||||
|
|
||||||
@ -100,10 +102,10 @@ void HttpHandler::ProcessRequest(const ApiUser::Ptr& user, HttpRequest& request,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!processed) {
|
if (!processed) {
|
||||||
response.SetStatus(404, "Not found");
|
String path = boost::algorithm::join(request.RequestUrl->GetPath(), "/");
|
||||||
response.AddHeader("Content-Type", "text/html");
|
HttpUtility::SendJsonError(response, 404, "The requested API '" + path +
|
||||||
String msg = "<h1>Not found</h1>";
|
"' could not be found. Please check it for common errors like spelling and consult the docs.");
|
||||||
response.WriteBody(msg.CStr(), msg.GetLength());
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,8 @@ HttpRequest::HttpRequest(const Stream::Ptr& stream)
|
|||||||
ProtocolVersion(HttpVersion11),
|
ProtocolVersion(HttpVersion11),
|
||||||
Headers(new Dictionary()),
|
Headers(new Dictionary()),
|
||||||
m_Stream(stream),
|
m_Stream(stream),
|
||||||
m_State(HttpRequestStart)
|
m_State(HttpRequestStart),
|
||||||
|
verboseErrors(false)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
bool HttpRequest::Parse(StreamReadContext& src, bool may_wait)
|
bool HttpRequest::Parse(StreamReadContext& src, bool may_wait)
|
||||||
@ -57,8 +58,10 @@ bool HttpRequest::Parse(StreamReadContext& src, bool may_wait)
|
|||||||
<< "line: " << line << ", tokens: " << tokens.size();
|
<< "line: " << line << ", tokens: " << tokens.size();
|
||||||
if (tokens.size() != 3)
|
if (tokens.size() != 3)
|
||||||
BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid HTTP request"));
|
BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid HTTP request"));
|
||||||
|
|
||||||
RequestMethod = tokens[0];
|
RequestMethod = tokens[0];
|
||||||
RequestUrl = new class Url(tokens[1]);
|
RequestUrl = new class Url(tokens[1]);
|
||||||
|
verboseErrors = (RequestUrl->GetQueryElement("verboseErrors") == "true");
|
||||||
|
|
||||||
if (tokens[2] == "HTTP/1.0")
|
if (tokens[2] == "HTTP/1.0")
|
||||||
ProtocolVersion = HttpVersion10;
|
ProtocolVersion = HttpVersion10;
|
||||||
@ -84,8 +87,8 @@ bool HttpRequest::Parse(StreamReadContext& src, bool may_wait)
|
|||||||
String::SizeType pos = line.FindFirstOf(":");
|
String::SizeType pos = line.FindFirstOf(":");
|
||||||
if (pos == String::NPos)
|
if (pos == String::NPos)
|
||||||
BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid HTTP request"));
|
BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid HTTP request"));
|
||||||
String key = line.SubStr(0, pos).ToLower().Trim();
|
|
||||||
|
|
||||||
|
String key = line.SubStr(0, pos).ToLower().Trim();
|
||||||
String value = line.SubStr(pos + 1).Trim();
|
String value = line.SubStr(pos + 1).Trim();
|
||||||
Headers->Set(key, value);
|
Headers->Set(key, value);
|
||||||
|
|
||||||
@ -230,3 +233,4 @@ void HttpRequest::Finish(void)
|
|||||||
|
|
||||||
m_State = HttpRequestEnd;
|
m_State = HttpRequestEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,11 +69,15 @@ public:
|
|||||||
void WriteBody(const char *data, size_t count);
|
void WriteBody(const char *data, size_t count);
|
||||||
void Finish(void);
|
void Finish(void);
|
||||||
|
|
||||||
|
inline bool GetVerboseErrors(void)
|
||||||
|
{ return verboseErrors; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Stream::Ptr m_Stream;
|
Stream::Ptr m_Stream;
|
||||||
boost::shared_ptr<ChunkReadContext> m_ChunkContext;
|
boost::shared_ptr<ChunkReadContext> m_ChunkContext;
|
||||||
HttpRequestState m_State;
|
HttpRequestState m_State;
|
||||||
FIFO::Ptr m_Body;
|
FIFO::Ptr m_Body;
|
||||||
|
bool verboseErrors;
|
||||||
|
|
||||||
void FinishHeaders(void);
|
void FinishHeaders(void);
|
||||||
};
|
};
|
||||||
|
@ -232,3 +232,4 @@ size_t HttpResponse::ReadBody(char *data, size_t count)
|
|||||||
else
|
else
|
||||||
return m_Body->Read(data, count, true);
|
return m_Body->Read(data, count, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +98,8 @@ bool HttpServerConnection::ProcessMessage(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m_CurrentRequest.Complete) {
|
if (m_CurrentRequest.Complete) {
|
||||||
m_RequestQueue.Enqueue(boost::bind(&HttpServerConnection::ProcessMessageAsync, HttpServerConnection::Ptr(this), m_CurrentRequest));
|
m_RequestQueue.Enqueue(boost::bind(&HttpServerConnection::ProcessMessageAsync,
|
||||||
|
HttpServerConnection::Ptr(this), m_CurrentRequest));
|
||||||
|
|
||||||
m_Seen = Utility::GetTime();
|
m_Seen = Utility::GetTime();
|
||||||
m_PendingRequests++;
|
m_PendingRequests++;
|
||||||
@ -200,3 +201,4 @@ void HttpServerConnection::TimeoutTimerHandler(void)
|
|||||||
client->CheckLiveness();
|
client->CheckLiveness();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,3 +70,45 @@ Value HttpUtility::GetLastParameter(const Dictionary::Ptr& params, const String&
|
|||||||
else
|
else
|
||||||
return arr->Get(arr->GetLength() - 1);
|
return arr->Get(arr->GetLength() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HttpUtility::SendJsonError(HttpResponse& response, const int code,
|
||||||
|
const String& info, const String& diagnosticInformation)
|
||||||
|
{
|
||||||
|
Dictionary::Ptr result = new Dictionary();
|
||||||
|
response.SetStatus(code, HttpUtility::GetErrorNameByCode(code));
|
||||||
|
result->Set("error", code);
|
||||||
|
if (!info.IsEmpty())
|
||||||
|
result->Set("status", info);
|
||||||
|
if (!diagnosticInformation.IsEmpty())
|
||||||
|
result->Set("diagnostic information", diagnosticInformation);
|
||||||
|
HttpUtility::SendJsonBody(response, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
String HttpUtility::GetErrorNameByCode(const int code)
|
||||||
|
{
|
||||||
|
switch(code) {
|
||||||
|
case 200:
|
||||||
|
return "OK";
|
||||||
|
case 201:
|
||||||
|
return "Created";
|
||||||
|
case 204:
|
||||||
|
return "No Content";
|
||||||
|
case 304:
|
||||||
|
return "Not Modified";
|
||||||
|
case 400:
|
||||||
|
return "Bad Request";
|
||||||
|
case 401:
|
||||||
|
return "Unauthorized";
|
||||||
|
case 403:
|
||||||
|
return "Forbidden";
|
||||||
|
case 404:
|
||||||
|
return "Not Found";
|
||||||
|
case 409:
|
||||||
|
return "Conflict";
|
||||||
|
case 500:
|
||||||
|
return "Internal Server Error";
|
||||||
|
default:
|
||||||
|
return "Unknown Error Code";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -39,6 +39,12 @@ public:
|
|||||||
static Dictionary::Ptr FetchRequestParameters(HttpRequest& request);
|
static Dictionary::Ptr FetchRequestParameters(HttpRequest& request);
|
||||||
static void SendJsonBody(HttpResponse& response, const Value& val);
|
static void SendJsonBody(HttpResponse& response, const Value& val);
|
||||||
static Value GetLastParameter(const Dictionary::Ptr& params, const String& key);
|
static Value GetLastParameter(const Dictionary::Ptr& params, const String& key);
|
||||||
|
static void SendJsonError(HttpResponse& response, const int code,
|
||||||
|
const String& verbose="", const String& diagnosticInformation="");
|
||||||
|
|
||||||
|
private:
|
||||||
|
static String GetErrorNameByCode(int code);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
#include "remote/jsonrpc.hpp"
|
#include "remote/jsonrpc.hpp"
|
||||||
#include "base/netstring.hpp"
|
#include "base/netstring.hpp"
|
||||||
#include "base/json.hpp"
|
#include "base/json.hpp"
|
||||||
//#include <iostream>
|
|
||||||
|
|
||||||
using namespace icinga;
|
using namespace icinga;
|
||||||
|
|
||||||
@ -32,7 +31,6 @@ using namespace icinga;
|
|||||||
void JsonRpc::SendMessage(const Stream::Ptr& stream, const Dictionary::Ptr& message)
|
void JsonRpc::SendMessage(const Stream::Ptr& stream, const Dictionary::Ptr& message)
|
||||||
{
|
{
|
||||||
String json = JsonEncode(message);
|
String json = JsonEncode(message);
|
||||||
//std::cerr << ">> " << json << std::endl;
|
|
||||||
NetString::WriteStringToStream(stream, json);
|
NetString::WriteStringToStream(stream, json);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +42,6 @@ StreamReadStatus JsonRpc::ReadMessage(const Stream::Ptr& stream, Dictionary::Ptr
|
|||||||
if (srs != StatusNewItem)
|
if (srs != StatusNewItem)
|
||||||
return srs;
|
return srs;
|
||||||
|
|
||||||
//std::cerr << "<< " << jsonString << std::endl;
|
|
||||||
Value value = JsonDecode(jsonString);
|
Value value = JsonDecode(jsonString);
|
||||||
|
|
||||||
if (!value.IsObjectType<Dictionary>()) {
|
if (!value.IsObjectType<Dictionary>()) {
|
||||||
@ -56,3 +53,4 @@ StreamReadStatus JsonRpc::ReadMessage(const Stream::Ptr& stream, Dictionary::Ptr
|
|||||||
|
|
||||||
return StatusNewItem;
|
return StatusNewItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,8 +38,10 @@ REGISTER_APIFUNCTION(RequestCertificate, pki, &RequestCertificateHandler);
|
|||||||
static boost::once_flag l_JsonRpcConnectionOnceFlag = BOOST_ONCE_INIT;
|
static boost::once_flag l_JsonRpcConnectionOnceFlag = BOOST_ONCE_INIT;
|
||||||
static Timer::Ptr l_JsonRpcConnectionTimeoutTimer;
|
static Timer::Ptr l_JsonRpcConnectionTimeoutTimer;
|
||||||
|
|
||||||
JsonRpcConnection::JsonRpcConnection(const String& identity, bool authenticated, const TlsStream::Ptr& stream, ConnectionRole role)
|
JsonRpcConnection::JsonRpcConnection(const String& identity, bool authenticated,
|
||||||
: m_Identity(identity), m_Authenticated(authenticated), m_Stream(stream), m_Role(role), m_Seen(Utility::GetTime()),
|
const TlsStream::Ptr& stream, ConnectionRole role)
|
||||||
|
: m_Identity(identity), m_Authenticated(authenticated), m_Stream(stream),
|
||||||
|
m_Role(role), m_Seen(Utility::GetTime()),
|
||||||
m_NextHeartbeat(0), m_HeartbeatTimeout(0)
|
m_NextHeartbeat(0), m_HeartbeatTimeout(0)
|
||||||
{
|
{
|
||||||
boost::call_once(l_JsonRpcConnectionOnceFlag, &JsonRpcConnection::StaticInitialize);
|
boost::call_once(l_JsonRpcConnectionOnceFlag, &JsonRpcConnection::StaticInitialize);
|
||||||
@ -174,7 +176,7 @@ bool JsonRpcConnection::ProcessMessage(void)
|
|||||||
|
|
||||||
resultMessage->Set("result", afunc->Invoke(origin, message->Get("params")));
|
resultMessage->Set("result", afunc->Invoke(origin, message->Get("params")));
|
||||||
} catch (const std::exception& ex) {
|
} catch (const std::exception& ex) {
|
||||||
//TODO: Add a user readable error message for the remote caller
|
/* TODO: Add a user readable error message for the remote caller */
|
||||||
resultMessage->Set("error", DiagnosticInformation(ex));
|
resultMessage->Set("error", DiagnosticInformation(ex));
|
||||||
std::ostringstream info;
|
std::ostringstream info;
|
||||||
info << "Error while processing message for identity '" << m_Identity << "'";
|
info << "Error while processing message for identity '" << m_Identity << "'";
|
||||||
@ -200,7 +202,8 @@ void JsonRpcConnection::DataAvailableHandler(void)
|
|||||||
; /* empty loop body */
|
; /* empty loop body */
|
||||||
} catch (const std::exception& ex) {
|
} catch (const std::exception& ex) {
|
||||||
Log(LogWarning, "JsonRpcConnection")
|
Log(LogWarning, "JsonRpcConnection")
|
||||||
<< "Error while reading JSON-RPC message for identity '" << m_Identity << "': " << DiagnosticInformation(ex);
|
<< "Error while reading JSON-RPC message for identity '" << m_Identity
|
||||||
|
<< "': " << DiagnosticInformation(ex);
|
||||||
|
|
||||||
Disconnect();
|
Disconnect();
|
||||||
}
|
}
|
||||||
@ -286,3 +289,4 @@ void JsonRpcConnection::TimeoutTimerHandler(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +35,8 @@ class TypeTargetProvider : public TargetProvider
|
|||||||
public:
|
public:
|
||||||
DECLARE_PTR_TYPEDEFS(TypeTargetProvider);
|
DECLARE_PTR_TYPEDEFS(TypeTargetProvider);
|
||||||
|
|
||||||
virtual void FindTargets(const String& type, const boost::function<void (const Value&)>& addTarget) const override
|
virtual void FindTargets(const String& type,
|
||||||
|
const boost::function<void (const Value&)>& addTarget) const override
|
||||||
{
|
{
|
||||||
std::vector<Type::Ptr> targets;
|
std::vector<Type::Ptr> targets;
|
||||||
|
|
||||||
|
@ -343,7 +343,7 @@ bool Url::ParsePath(const String& path)
|
|||||||
|
|
||||||
bool Url::ParseQuery(const String& query)
|
bool Url::ParseQuery(const String& query)
|
||||||
{
|
{
|
||||||
//Tokenizer does not like String AT ALL
|
/* Tokenizer does not like String AT ALL */
|
||||||
std::string queryStr = query;
|
std::string queryStr = query;
|
||||||
boost::char_separator<char> sep("&");
|
boost::char_separator<char> sep("&");
|
||||||
boost::tokenizer<boost::char_separator<char> > tokens(queryStr, sep);
|
boost::tokenizer<boost::char_separator<char> > tokens(queryStr, sep);
|
||||||
@ -407,3 +407,4 @@ bool Url::ValidateToken(const String& token, const String& symbols)
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,3 +97,4 @@ Zone::Ptr Zone::GetLocalZone(void)
|
|||||||
|
|
||||||
return local->GetZone();
|
return local->GetZone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user