File icinga2-boost-8185-8190.patch of Package icinga2

From 45dd71e0f9a93369e08d6cb26f97940f9c9594aa Mon Sep 17 00:00:00 2001
From: "Alexander A. Klimov" <alexander.klimov@icinga.com>
Date: Wed, 26 Aug 2020 13:56:26 +0200
Subject: [PATCH] Introduce HttpUtility::Set()

refs #8185
---
 lib/cli/consolecommand.cpp           |  9 ++++---
 lib/perfdata/elasticsearchwriter.cpp | 13 ++++-----
 lib/perfdata/influxdbwriter.cpp      |  7 ++---
 lib/remote/configfileshandler.cpp    |  4 +--
 lib/remote/eventshandler.cpp         |  2 +-
 lib/remote/httpserverconnection.cpp  | 40 ++++++++++++++--------------
 lib/remote/httputility.cpp           |  4 +--
 lib/remote/httputility.hpp           | 28 +++++++++++++++++++
 lib/remote/infohandler.cpp           |  6 ++---
 plugins/check_nscp_api.cpp           |  9 ++++---
 10 files changed, 77 insertions(+), 45 deletions(-)

diff --git a/lib/cli/consolecommand.cpp b/lib/cli/consolecommand.cpp
index 41b6590e4c..42c5c63133 100644
--- a/lib/cli/consolecommand.cpp
+++ b/lib/cli/consolecommand.cpp
@@ -3,6 +3,7 @@
 #include "cli/consolecommand.hpp"
 #include "config/configcompiler.hpp"
 #include "remote/consolehandler.hpp"
+#include "remote/httputility.hpp"
 #include "remote/url.hpp"
 #include "base/configwriter.hpp"
 #include "base/serializer.hpp"
@@ -580,11 +581,11 @@ Dictionary::Ptr ConsoleCommand::SendRequest()
 
 	http::request<http::string_body> request(http::verb::post, std::string(l_Url->Format(false)), 10);
 
-	request.set(http::field::user_agent, "Icinga/DebugConsole/" + Application::GetAppVersion());
-	request.set(http::field::host, l_Url->GetHost() + ":" + l_Url->GetPort());
+	HttpUtility::Set(request, http::field::user_agent, "Icinga/DebugConsole/" + Application::GetAppVersion());
+	HttpUtility::Set(request, http::field::host, l_Url->GetHost() + ":" + l_Url->GetPort());
 
-	request.set(http::field::accept, "application/json");
-	request.set(http::field::authorization, "Basic " + Base64::Encode(l_Url->GetUsername() + ":" + l_Url->GetPassword()));
+	HttpUtility::Set(request, http::field::accept, "application/json");
+	HttpUtility::Set(request, http::field::authorization, "Basic " + Base64::Encode(l_Url->GetUsername() + ":" + l_Url->GetPassword()));
 
 	try {
 		http::write(*l_TlsStream, request);
diff --git a/lib/perfdata/elasticsearchwriter.cpp b/lib/perfdata/elasticsearchwriter.cpp
index 6870198e45..3764bf536b 100644
--- a/lib/perfdata/elasticsearchwriter.cpp
+++ b/lib/perfdata/elasticsearchwriter.cpp
@@ -2,6 +2,7 @@
 
 #include "perfdata/elasticsearchwriter.hpp"
 #include "perfdata/elasticsearchwriter-ti.cpp"
+#include "remote/httputility.hpp"
 #include "remote/url.hpp"
 #include "icinga/compatutility.hpp"
 #include "icinga/service.hpp"
@@ -474,27 +475,27 @@ void ElasticsearchWriter::SendRequest(const String& body)
 
 	http::request<http::string_body> request (http::verb::post, std::string(url->Format(true)), 10);
 
-	request.set(http::field::user_agent, "Icinga/" + Application::GetAppVersion());
-	request.set(http::field::host, url->GetHost() + ":" + url->GetPort());
+	HttpUtility::Set(request, http::field::user_agent, "Icinga/" + Application::GetAppVersion());
+	HttpUtility::Set(request, http::field::host, url->GetHost() + ":" + url->GetPort());
 
 	/* Specify required headers by Elasticsearch. */
-	request.set(http::field::accept, "application/json");
+	HttpUtility::Set(request, http::field::accept, "application/json");
 
 	/* Use application/x-ndjson for bulk streams. While ES
 	 * is able to handle application/json, the newline separator
 	 * causes problems with Logstash (#6609).
 	 */
-	request.set(http::field::content_type, "application/x-ndjson");
+	HttpUtility::Set(request, http::field::content_type, "application/x-ndjson");
 
 	/* Send authentication if configured. */
 	String username = GetUsername();
 	String password = GetPassword();
 
 	if (!username.IsEmpty() && !password.IsEmpty())
-		request.set(http::field::authorization, "Basic " + Base64::Encode(username + ":" + password));
+		HttpUtility::Set(request, http::field::authorization, "Basic " + Base64::Encode(username + ":" + password));
 
 	request.body() = body;
-	request.set(http::field::content_length, request.body().size());
+	HttpUtility::Set(request, http::field::content_length, request.body().size());
 
 	/* Don't log the request body to debug log, this is already done above. */
 	Log(LogDebug, "ElasticsearchWriter")
diff --git a/lib/perfdata/influxdbwriter.cpp b/lib/perfdata/influxdbwriter.cpp
index 4692b8b5df..0ddd582447 100644
--- a/lib/perfdata/influxdbwriter.cpp
+++ b/lib/perfdata/influxdbwriter.cpp
@@ -2,6 +2,7 @@
 
 #include "perfdata/influxdbwriter.hpp"
 #include "perfdata/influxdbwriter-ti.cpp"
+#include "remote/httputility.hpp"
 #include "remote/url.hpp"
 #include "icinga/service.hpp"
 #include "icinga/macroprocessor.hpp"
@@ -501,11 +502,11 @@ void InfluxdbWriter::Flush()
 
 	http::request<http::string_body> request (http::verb::post, std::string(url->Format(true)), 10);
 
-	request.set(http::field::user_agent, "Icinga/" + Application::GetAppVersion());
-	request.set(http::field::host, url->GetHost() + ":" + url->GetPort());
+	HttpUtility::Set(request, http::field::user_agent, "Icinga/" + Application::GetAppVersion());
+	HttpUtility::Set(request, http::field::host, url->GetHost() + ":" + url->GetPort());
 
 	request.body() = body;
-	request.set(http::field::content_length, request.body().size());
+	HttpUtility::Set(request, http::field::content_length, request.body().size());
 
 	try {
 		if (stream.first) {
diff --git a/lib/remote/configfileshandler.cpp b/lib/remote/configfileshandler.cpp
index d714f4d864..5c2bfdb405 100644
--- a/lib/remote/configfileshandler.cpp
+++ b/lib/remote/configfileshandler.cpp
@@ -82,9 +82,9 @@ bool ConfigFilesHandler::HandleRequest(
 
 		String content((std::istreambuf_iterator<char>(fp)), std::istreambuf_iterator<char>());
 		response.result(http::status::ok);
-		response.set(http::field::content_type, "application/octet-stream");
+		HttpUtility::Set(response, http::field::content_type, "application/octet-stream");
 		response.body() = content;
-		response.set(http::field::content_length, response.body().size());
+		HttpUtility::Set(response, http::field::content_length, response.body().size());
 	} catch (const std::exception& ex) {
 		HttpUtility::SendJsonError(response, params, 500, "Could not read file.",
 			DiagnosticInformation(ex));
diff --git a/lib/remote/eventshandler.cpp b/lib/remote/eventshandler.cpp
index e92b14a2d4..e41b4711c6 100644
--- a/lib/remote/eventshandler.cpp
+++ b/lib/remote/eventshandler.cpp
@@ -100,7 +100,7 @@ bool EventsHandler::HandleRequest(
 	server.StartStreaming();
 
 	response.result(http::status::ok);
-	response.set(http::field::content_type, "application/json");
+	HttpUtility::Set(response, http::field::content_type, "application/json");
 
 	IoBoundWorkSlot dontLockTheIoThread (yc);
 
diff --git a/lib/remote/httpserverconnection.cpp b/lib/remote/httpserverconnection.cpp
index d4eac7d074..688392c821 100644
--- a/lib/remote/httpserverconnection.cpp
+++ b/lib/remote/httpserverconnection.cpp
@@ -184,12 +184,12 @@ bool EnsureValidHeaders(
 				{ "status", String("Bad Request: ") + errorMsg }
 			}));
 		} else {
-			response.set(http::field::content_type, "text/html");
+			HttpUtility::Set(response, http::field::content_type, "text/html");
 			response.body() = String("<h1>Bad Request</h1><p><pre>") + errorMsg + "</pre></p>";
-			response.set(http::field::content_length, response.body().size());
+			HttpUtility::Set(response, http::field::content_length, response.body().size());
 		}
 
-		response.set(http::field::connection, "close");
+		HttpUtility::Set(response, http::field::connection, "close");
 
 		boost::system::error_code ec;
 
@@ -247,20 +247,20 @@ bool HandleAccessControl(
 				auto& origin (request[http::field::origin]);
 
 				if (allowedOrigins.find(origin.to_string()) != allowedOrigins.end()) {
-					response.set(http::field::access_control_allow_origin, origin);
+					HttpUtility::Set(response, http::field::access_control_allow_origin, origin);
 				}
 
 				allowOriginHeader.Done();
 
-				response.set(http::field::access_control_allow_credentials, "true");
+				HttpUtility::Set(response, http::field::access_control_allow_credentials, "true");
 
 				if (request.method() == http::verb::options && !request[http::field::access_control_request_method].empty()) {
 					response.result(http::status::ok);
-					response.set(http::field::access_control_allow_methods, "GET, POST, PUT, DELETE");
-					response.set(http::field::access_control_allow_headers, "Authorization, X-HTTP-Method-Override");
+					HttpUtility::Set(response, http::field::access_control_allow_methods, "GET, POST, PUT, DELETE");
+					HttpUtility::Set(response, http::field::access_control_allow_headers, "Authorization, X-HTTP-Method-Override");
 					response.body() = "Preflight OK";
-					response.set(http::field::content_length, response.body().size());
-					response.set(http::field::connection, "close");
+					HttpUtility::Set(response, http::field::content_length, response.body().size());
+					HttpUtility::Set(response, http::field::connection, "close");
 
 					boost::system::error_code ec;
 
@@ -288,10 +288,10 @@ bool EnsureAcceptHeader(
 
 	if (request.method() != http::verb::get && request[http::field::accept] != "application/json") {
 		response.result(http::status::bad_request);
-		response.set(http::field::content_type, "text/html");
+		HttpUtility::Set(response, http::field::content_type, "text/html");
 		response.body() = "<h1>Accept header is missing or not set to 'application/json'.</h1>";
-		response.set(http::field::content_length, response.body().size());
-		response.set(http::field::connection, "close");
+		HttpUtility::Set(response, http::field::content_length, response.body().size());
+		HttpUtility::Set(response, http::field::connection, "close");
 
 		boost::system::error_code ec;
 
@@ -320,8 +320,8 @@ bool EnsureAuthenticatedUser(
 			<< "Unauthorized request: " << request.method_string() << ' ' << request.target();
 
 		response.result(http::status::unauthorized);
-		response.set(http::field::www_authenticate, "Basic realm=\"Icinga 2\"");
-		response.set(http::field::connection, "close");
+		HttpUtility::Set(response, http::field::www_authenticate, "Basic realm=\"Icinga 2\"");
+		HttpUtility::Set(response, http::field::connection, "close");
 
 		if (request[http::field::accept] == "application/json") {
 			HttpUtility::SendJsonBody(response, nullptr, new Dictionary({
@@ -329,9 +329,9 @@ bool EnsureAuthenticatedUser(
 				{ "status", "Unauthorized. Please check your user credentials." }
 			}));
 		} else {
-			response.set(http::field::content_type, "text/html");
+			HttpUtility::Set(response, http::field::content_type, "text/html");
 			response.body() = "<h1>Unauthorized. Please check your user credentials.</h1>";
-			response.set(http::field::content_length, response.body().size());
+			HttpUtility::Set(response, http::field::content_length, response.body().size());
 		}
 
 		boost::system::error_code ec;
@@ -421,12 +421,12 @@ bool EnsureValidBody(
 				{ "status", String("Bad Request: ") + ec.message() }
 			}));
 		} else {
-			response.set(http::field::content_type, "text/html");
+			HttpUtility::Set(response, http::field::content_type, "text/html");
 			response.body() = String("<h1>Bad Request</h1><p><pre>") + ec.message() + "</pre></p>";
-			response.set(http::field::content_length, response.body().size());
+			HttpUtility::Set(response, http::field::content_length, response.body().size());
 		}
 
-		response.set(http::field::connection, "close");
+		HttpUtility::Set(response, http::field::connection, "close");
 
 		http::async_write(stream, response, yc[ec]);
 		stream.async_flush(yc[ec]);
@@ -511,7 +511,7 @@ void HttpServerConnection::ProcessMessages(boost::asio::yield_context yc)
 			parser.header_limit(1024 * 1024);
 			parser.body_limit(-1);
 
-			response.set(http::field::server, l_ServerHeader);
+			HttpUtility::Set(response, http::field::server, l_ServerHeader);
 
 			if (!EnsureValidHeaders(*m_Stream, buf, parser, response, m_ShuttingDown, yc)) {
 				break;
diff --git a/lib/remote/httputility.cpp b/lib/remote/httputility.cpp
index 91902ba501..e46e990ecf 100644
--- a/lib/remote/httputility.cpp
+++ b/lib/remote/httputility.cpp
@@ -56,9 +56,9 @@ void HttpUtility::SendJsonBody(boost::beast::http::response<boost::beast::http::
 {
 	namespace http = boost::beast::http;
 
-	response.set(http::field::content_type, "application/json");
+	HttpUtility::Set(response, http::field::content_type, "application/json");
 	response.body() = JsonEncode(val, params && GetLastParameter(params, "pretty"));
-	response.set(http::field::content_length, response.body().size());
+	HttpUtility::Set(response, http::field::content_length, response.body().size());
 }
 
 void HttpUtility::SendJsonError(boost::beast::http::response<boost::beast::http::string_body>& response,
diff --git a/lib/remote/httputility.hpp b/lib/remote/httputility.hpp
index 6465b4af92..be600d4090 100644
--- a/lib/remote/httputility.hpp
+++ b/lib/remote/httputility.hpp
@@ -5,8 +5,12 @@
 
 #include "remote/url.hpp"
 #include "base/dictionary.hpp"
+#include "base/string.hpp"
 #include <boost/beast/http.hpp>
+#include <boost/lexical_cast.hpp>
 #include <string>
+#include <type_traits>
+#include <utility>
 
 namespace icinga
 {
@@ -26,6 +30,30 @@ class HttpUtility
 	static void SendJsonBody(boost::beast::http::response<boost::beast::http::string_body>& response, const Dictionary::Ptr& params, const Value& val);
 	static void SendJsonError(boost::beast::http::response<boost::beast::http::string_body>& response, const Dictionary::Ptr& params, const int code,
 		const String& verbose = String(), const String& diagnosticInformation = String());
+
+	template<class Message, class Key, class Value, typename std::enable_if<std::is_arithmetic<Value>::value, int>::type = 0>
+	static void Set(Message& message, Key&& key, Value value)
+	{
+		Set(message, std::forward<Key>(key), boost::lexical_cast<std::string>(value));
+	}
+
+	template<class Message, class Key>
+	static void Set(Message& message, Key&& key, const String& value)
+	{
+		Set(message, std::forward<Key>(key), value.GetData());
+	}
+
+	template<class Message, class Key>
+	static void Set(Message& message, Key&& key, String&& value)
+	{
+		Set(message, std::forward<Key>(key), value.GetData());
+	}
+
+	template<class Message, class Key, class Value, typename std::enable_if<!std::is_arithmetic<Value>::value, int>::type = 0>
+	static void Set(Message& message, Key&& key, Value&& value)
+	{
+		message.set(std::forward<Key>(key), std::forward<Value>(value));
+	}
 };
 
 }
diff --git a/lib/remote/infohandler.cpp b/lib/remote/infohandler.cpp
index 18c18c0e04..daec628047 100644
--- a/lib/remote/infohandler.cpp
+++ b/lib/remote/infohandler.cpp
@@ -29,7 +29,7 @@ bool InfoHandler::HandleRequest(
 
 	if (url->GetPath().empty()) {
 		response.result(http::status::found);
-		response.set(http::field::location, "/v1");
+		HttpUtility::Set(response, http::field::location, "/v1");
 		return true;
 	}
 
@@ -74,7 +74,7 @@ bool InfoHandler::HandleRequest(
 
 		HttpUtility::SendJsonBody(response, params, result);
 	} else {
-		response.set(http::field::content_type, "text/html");
+		HttpUtility::Set(response, http::field::content_type, "text/html");
 
 		String body = "<html><head><title>Icinga 2</title></head><h1>Hello from Icinga 2 (Version: " + Application::GetAppVersion() + ")!</h1>";
 		body += "<p>You are authenticated as <b>" + user->GetName() + "</b>. ";
@@ -92,7 +92,7 @@ bool InfoHandler::HandleRequest(
 
 		body += R"(<p>More information about API requests is available in the <a href="https://icinga.com/docs/icinga2/latest/" target="_blank">documentation</a>.</p></html>)";
 		response.body() = body;
-		response.set(http::field::content_length, response.body().size());
+		HttpUtility::Set(response, http::field::content_length, response.body().size());
 	}
 
 	return true;
diff --git a/plugins/check_nscp_api.cpp b/plugins/check_nscp_api.cpp
index 3f6843ec29..ad15e62527 100644
--- a/plugins/check_nscp_api.cpp
+++ b/plugins/check_nscp_api.cpp
@@ -16,6 +16,7 @@
 #include "base/tcpsocket.hpp" /* include global icinga::Connect */
 #include "base/tlsstream.hpp"
 #include "base/base64.hpp"
+#include "remote/httputility.hpp"
 #include "remote/url.hpp"
 #include <remote/url-characters.hpp>
 #include <boost/program_options.hpp>
@@ -365,11 +366,11 @@ static Dictionary::Ptr FetchData(const String& host, const String& port, const S
 
 	http::request<http::string_body> request (http::verb::get, std::string(url->Format(true)), 10);
 
-	request.set(http::field::user_agent, "Icinga/check_nscp_api/" + String(VERSION));
-	request.set(http::field::host, host + ":" + port);
+	HttpUtility::Set(request, http::field::user_agent, "Icinga/check_nscp_api/" + String(VERSION));
+	HttpUtility::Set(request, http::field::host, host + ":" + port);
 
-	request.set(http::field::accept, "application/json");
-	request.set("password", password);
+	HttpUtility::Set(request, http::field::accept, "application/json");
+	HttpUtility::Set(request, "password", password);
 
 	if (l_Debug) {
 		std::cout << "Sending request to " << url->Format(false, false) << "'.\n";
 
openSUSE Build Service is sponsored by