while ((count = response.ReadBody(buffer, sizeof(buffer))) > 0)
body += String(buffer, buffer + count);
+ std::vector<ApiType::Ptr> types;
+
if (response.StatusCode < 200 || response.StatusCode > 299) {
Log(LogCritical, "ApiClient")
<< "Failed HTTP request; Code: " << response.StatusCode << "; Body: " << body;
- return;
- }
+ } else {
+ try {
+ result = JsonDecode(body);
- std::vector<ApiType::Ptr> types;
+ Array::Ptr results = result->Get("results");
- try {
- result = JsonDecode(body);
-
- Array::Ptr results = result->Get("results");
-
- ObjectLock olock(results);
- BOOST_FOREACH(const Dictionary::Ptr typeInfo, results)
- {
- ApiType::Ptr type = new ApiType();;
- type->Abstract = typeInfo->Get("abstract");
- type->BaseName = typeInfo->Get("base");
- type->Name = typeInfo->Get("name");
- type->PluralName = typeInfo->Get("plural_name");
- // TODO: attributes
- types.push_back(type);
+ ObjectLock olock(results);
+ BOOST_FOREACH(const Dictionary::Ptr typeInfo, results)
+ {
+ ApiType::Ptr type = new ApiType();;
+ type->Abstract = typeInfo->Get("abstract");
+ type->BaseName = typeInfo->Get("base");
+ type->Name = typeInfo->Get("name");
+ type->PluralName = typeInfo->Get("plural_name");
+ // TODO: attributes
+ types.push_back(type);
+ }
+ } catch (const std::exception& ex) {
+ Log(LogCritical, "ApiClient")
+ << "Error while decoding response: " << DiagnosticInformation(ex);
}
- } catch (const std::exception& ex) {
- Log(LogCritical, "ApiClient")
- << "Error while decoding response: " << DiagnosticInformation(ex);
}
callback(types);
while ((count = response.ReadBody(buffer, sizeof(buffer))) > 0)
body += String(buffer, buffer + count);
+ std::vector<ApiObject::Ptr> objects;
+
if (response.StatusCode < 200 || response.StatusCode > 299) {
Log(LogCritical, "ApiClient")
<< "Failed HTTP request; Code: " << response.StatusCode << "; Body: " << body;
return;
- }
+ } else {
+ try {
+ result = JsonDecode(body);
- std::vector<ApiObject::Ptr> objects;
-
- try {
- result = JsonDecode(body);
-
- Array::Ptr results = result->Get("results");
+ Array::Ptr results = result->Get("results");
- if (results) {
- ObjectLock olock(results);
- BOOST_FOREACH(const Dictionary::Ptr objectInfo, results)
- {
- ApiObject::Ptr object = new ApiObject();
+ if (results) {
+ ObjectLock olock(results);
+ BOOST_FOREACH(const Dictionary::Ptr objectInfo, results)
+ {
+ ApiObject::Ptr object = new ApiObject();
- Dictionary::Ptr attrs = objectInfo->Get("attrs");
+ Dictionary::Ptr attrs = objectInfo->Get("attrs");
- {
- ObjectLock olock(attrs);
- BOOST_FOREACH(const Dictionary::Pair& kv, attrs)
{
- object->Attrs[kv.first] = kv.second;
+ ObjectLock olock(attrs);
+ BOOST_FOREACH(const Dictionary::Pair& kv, attrs)
+ {
+ object->Attrs[kv.first] = kv.second;
+ }
}
- }
- Array::Ptr used_by = objectInfo->Get("used_by");
+ Array::Ptr used_by = objectInfo->Get("used_by");
- {
- ObjectLock olock(used_by);
- BOOST_FOREACH(const Dictionary::Ptr& refInfo, used_by)
{
- ApiObjectReference ref;
- ref.Name = refInfo->Get("name");
- ref.Type = refInfo->Get("type");
- object->UsedBy.push_back(ref);
+ ObjectLock olock(used_by);
+ BOOST_FOREACH(const Dictionary::Ptr& refInfo, used_by)
+ {
+ ApiObjectReference ref;
+ ref.Name = refInfo->Get("name");
+ ref.Type = refInfo->Get("type");
+ object->UsedBy.push_back(ref);
+ }
}
- }
- objects.push_back(object);
+ objects.push_back(object);
+ }
}
+ } catch (const std::exception& ex) {
+ Log(LogCritical, "ApiClient")
+ << "Error while decoding response: " << DiagnosticInformation(ex);
}
- } catch (const std::exception& ex) {
- Log(LogCritical, "ApiClient")
- << "Error while decoding response: " << DiagnosticInformation(ex);
}
callback(objects);
l_SocketIOFDChanged = true;
- (void) send(l_SocketIOEventFDs[1], "T", 1, 0);
+ while (l_SocketIOFDChanged) {
+ (void) send(l_SocketIOEventFDs[1], "T", 1, 0);
- while (l_SocketIOFDChanged)
- l_SocketIOCV.wait(lock);
+ boost::system_time const timeout = boost::get_system_time() + boost::posix_time::milliseconds(50);
+ l_SocketIOCV.timed_wait(lock, timeout);
+ }
}
} else {
(void) send(l_SocketIOEventFDs[1], "T", 1, 0);
using namespace icinga;
-void Stream::RegisterDataHandler(const boost::function<void(void)>& handler)
+void Stream::RegisterDataHandler(const boost::function<void(const Stream::Ptr&)>& handler)
{
if (SupportsWaiting())
OnDataAvailable.connect(handler);
void Stream::SignalDataAvailable(void)
{
- OnDataAvailable();
+ OnDataAvailable(this);
{
boost::mutex::scoped_lock lock(m_Mutex);
virtual bool IsDataAvailable(void) const;
- void RegisterDataHandler(const boost::function<void(void)>& handler);
+ void RegisterDataHandler(const boost::function<void(const Stream::Ptr&)>& handler);
StreamReadStatus ReadLine(String *line, StreamReadContext& context, bool may_wait = false);
void SignalDataAvailable(void);
private:
- boost::signals2::signal<void(void)> OnDataAvailable;
+ boost::signals2::signal<void(const Stream::Ptr&)> OnDataAvailable;
boost::mutex m_Mutex;
boost::condition_variable m_CV;
if (rc > 0) {
m_CurrentAction = TlsActionNone;
- if (m_SendQ->GetAvailableBytes() > 0)
- ChangeEvents(POLLIN|POLLOUT);
- else
- ChangeEvents(POLLIN);
+ if (!m_Eof) {
+ if (m_SendQ->GetAvailableBytes() > 0)
+ ChangeEvents(POLLIN|POLLOUT);
+ else
+ ChangeEvents(POLLIN);
+ }
lock.unlock();
m_Context.~StreamReadContext();
new (&m_Context) StreamReadContext();
+ m_Requests.clear();
+ m_CurrentResponse.reset();
+
TcpSocket::Ptr socket = new TcpSocket();
socket->Connect(m_Host, m_Port);
/* 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, _1));
if (m_Stream->IsDataAvailable())
- DataAvailableHandler();
+ DataAvailableHandler(m_Stream);
}
Stream::Ptr HttpClientConnection::GetStream(void) const
{
bool res;
- if (m_Requests.empty())
+ if (m_Requests.empty()) {
+ m_Stream->Close();
return false;
+ }
const std::pair<boost::shared_ptr<HttpRequest>, HttpCompletionCallback>& currentRequest = *m_Requests.begin();
HttpRequest& request = *currentRequest.first.get();
return res;
}
-void HttpClientConnection::DataAvailableHandler(void)
+void HttpClientConnection::DataAvailableHandler(const Stream::Ptr& stream)
{
boost::mutex::scoped_lock lock(m_DataHandlerMutex);
+ ASSERT(stream == m_Stream);
+
try {
while (ProcessMessage())
; /* empty loop body */
} catch (const std::exception& ex) {
Log(LogWarning, "HttpClientConnection")
- << "Error while reading Http request: " << DiagnosticInformation(ex);
+ << "Error while reading Http response: " << DiagnosticInformation(ex);
Disconnect();
}
+
+ if (m_Context.Eof) {
+ Log(LogWarning, "HttpClientConnection", "Encountered unexpected EOF while reading Http response.");
+ m_Stream->Close();
+ }
}
boost::shared_ptr<HttpRequest> HttpClientConnection::NewRequest(void)
void Reconnect(void);
bool ProcessMessage(void);
- void DataAvailableHandler(void);
+ void DataAvailableHandler(const Stream::Ptr& stream);
void ProcessMessageAsync(HttpRequest& request);
};
void HttpResponse::SetStatus(int code, const String& message)
{
- ASSERT(m_State == HttpResponseStart);
ASSERT(code >= 100 && code <= 599);
ASSERT(!message.IsEmpty());
+ if (m_State != HttpResponseStart) {
+ Log(LogWarning, "HttpResponse", "Tried to set Http response status after headers had already been sent.");
+ return;
+ }
+
String status = "HTTP/";
if (m_Request.ProtocolVersion == HttpVersion10)
void HttpResponse::AddHeader(const String& key, const String& value)
{
- ASSERT(m_State = HttpResponseHeaders);
+ if (m_State != HttpResponseHeaders) {
+ Log(LogWarning, "HttpResponse", "Tried to add header after headers had already been sent.");
+ return;
+ }
+
String header = key + ": " + value + "\r\n";
m_Stream->Write(header.CStr(), header.GetLength());
}
try {
HttpHandler::ProcessRequest(user, request, response);
} catch (const std::exception& ex) {
+ Log(LogCritical, "HttpServerConnection")
+ << "Unhandled exception while processing Http request: " << DiagnosticInformation(ex);
response.SetStatus(503, "Unhandled exception");
response.AddHeader("Content-Type", "text/plain");
String errorInfo = DiagnosticInformation(ex);