mirror of
				https://github.com/Icinga/icinga2.git
				synced 2025-10-30 02:33:50 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			160 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			160 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
 | |
| 
 | |
| #include "remote/httpclientconnection.hpp"
 | |
| #include "base/configtype.hpp"
 | |
| #include "base/objectlock.hpp"
 | |
| #include "base/base64.hpp"
 | |
| #include "base/utility.hpp"
 | |
| #include "base/logger.hpp"
 | |
| #include "base/exception.hpp"
 | |
| #include "base/convert.hpp"
 | |
| #include "base/tcpsocket.hpp"
 | |
| #include "base/tlsstream.hpp"
 | |
| #include "base/networkstream.hpp"
 | |
| 
 | |
| using namespace icinga;
 | |
| 
 | |
| HttpClientConnection::HttpClientConnection(String host, String port, bool tls)
 | |
| 	: m_Host(std::move(host)), m_Port(std::move(port)), m_Tls(tls)
 | |
| { }
 | |
| 
 | |
| void HttpClientConnection::Start()
 | |
| {
 | |
| 	/* Nothing to do here atm. */
 | |
| }
 | |
| 
 | |
| void HttpClientConnection::Reconnect()
 | |
| {
 | |
| 	if (m_Stream)
 | |
| 		m_Stream->Close();
 | |
| 
 | |
| 	m_Context.~StreamReadContext();
 | |
| 	new (&m_Context) StreamReadContext();
 | |
| 
 | |
| 	m_Requests.clear();
 | |
| 	m_CurrentResponse.reset();
 | |
| 
 | |
| 	TcpSocket::Ptr socket = new TcpSocket();
 | |
| 	socket->Connect(m_Host, m_Port);
 | |
| 
 | |
| 	if (m_Tls)
 | |
| 		m_Stream = new TlsStream(socket, m_Host, RoleClient);
 | |
| 	else
 | |
| 		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
 | |
| 		 */
 | |
| 
 | |
| 	/* the stream holds an owning reference to this object through the callback we're registering here */
 | |
| 	m_Stream->RegisterDataHandler(std::bind(&HttpClientConnection::DataAvailableHandler, HttpClientConnection::Ptr(this), _1));
 | |
| 	if (m_Stream->IsDataAvailable())
 | |
| 		DataAvailableHandler(m_Stream);
 | |
| }
 | |
| 
 | |
| Stream::Ptr HttpClientConnection::GetStream() const
 | |
| {
 | |
| 	return m_Stream;
 | |
| }
 | |
| 
 | |
| String HttpClientConnection::GetHost() const
 | |
| {
 | |
| 	return m_Host;
 | |
| }
 | |
| 
 | |
| String HttpClientConnection::GetPort() const
 | |
| {
 | |
| 	return m_Port;
 | |
| }
 | |
| 
 | |
| bool HttpClientConnection::GetTls() const
 | |
| {
 | |
| 	return m_Tls;
 | |
| }
 | |
| 
 | |
| void HttpClientConnection::Disconnect()
 | |
| {
 | |
| 	Log(LogDebug, "HttpClientConnection", "Http client disconnected");
 | |
| 
 | |
| 	m_Stream->Shutdown();
 | |
| }
 | |
| 
 | |
| bool HttpClientConnection::ProcessMessage()
 | |
| {
 | |
| 	bool res;
 | |
| 
 | |
| 	if (m_Requests.empty()) {
 | |
| 		m_Stream->Close();
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	const std::pair<std::shared_ptr<HttpRequest>, HttpCompletionCallback>& currentRequest = *m_Requests.begin();
 | |
| 	HttpRequest& request = *currentRequest.first.get();
 | |
| 	const HttpCompletionCallback& callback = currentRequest.second;
 | |
| 
 | |
| 	if (!m_CurrentResponse)
 | |
| 		m_CurrentResponse = std::make_shared<HttpResponse>(m_Stream, request);
 | |
| 
 | |
| 	std::shared_ptr<HttpResponse> currentResponse = m_CurrentResponse;
 | |
| 	HttpResponse& response = *currentResponse.get();
 | |
| 
 | |
| 	try {
 | |
| 		res = response.Parse(m_Context, false);
 | |
| 	} catch (const std::exception&) {
 | |
| 		callback(request, response);
 | |
| 
 | |
| 		m_Stream->Shutdown();
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	if (response.Complete) {
 | |
| 		callback(request, response);
 | |
| 
 | |
| 		m_Requests.pop_front();
 | |
| 		m_CurrentResponse.reset();
 | |
| 
 | |
| 		return true;
 | |
| 	}
 | |
| 
 | |
| 	return res;
 | |
| }
 | |
| 
 | |
| void HttpClientConnection::DataAvailableHandler(const Stream::Ptr& stream)
 | |
| {
 | |
| 	ASSERT(stream == m_Stream);
 | |
| 
 | |
| 	bool close = false;
 | |
| 
 | |
| 	if (!m_Stream->IsEof()) {
 | |
| 		boost::mutex::scoped_lock lock(m_DataHandlerMutex);
 | |
| 
 | |
| 		try {
 | |
| 			while (ProcessMessage())
 | |
| 				; /* empty loop body */
 | |
| 		} catch (const std::exception& ex) {
 | |
| 			Log(LogWarning, "HttpClientConnection")
 | |
| 				<< "Error while reading Http response: " << DiagnosticInformation(ex);
 | |
| 
 | |
| 			close = true;
 | |
| 			Disconnect();
 | |
| 		}
 | |
| 	} else
 | |
| 		close = true;
 | |
| 
 | |
| 	if (close)
 | |
| 		m_Stream->Close();
 | |
| }
 | |
| 
 | |
| std::shared_ptr<HttpRequest> HttpClientConnection::NewRequest()
 | |
| {
 | |
| 	Reconnect();
 | |
| 	return std::make_shared<HttpRequest>(m_Stream);
 | |
| }
 | |
| 
 | |
| void HttpClientConnection::SubmitRequest(const std::shared_ptr<HttpRequest>& request,
 | |
| 	const HttpCompletionCallback& callback)
 | |
| {
 | |
| 	m_Requests.emplace_back(request, callback);
 | |
| 	request->Finish();
 | |
| }
 | |
| 
 |