Only read body from authenticated connections

This means we are not allowing unauthenticated requests anymore
This commit is contained in:
Jean Flach 2018-02-01 15:10:28 +01:00
parent 81c4004894
commit 73b85bcccb
3 changed files with 160 additions and 133 deletions

View File

@ -25,19 +25,22 @@
using namespace icinga;
HttpRequest::HttpRequest(Stream::Ptr stream)
: Complete(false),
: CompleteHeaders(false),
CompleteBody(false),
ProtocolVersion(HttpVersion11),
Headers(new Dictionary()),
m_Stream(std::move(stream)),
m_State(HttpRequestStart)
{ }
bool HttpRequest::Parse(StreamReadContext& src, bool may_wait)
bool HttpRequest::ParseHeader(StreamReadContext& src, bool may_wait)
{
if (!m_Stream)
return false;
if (m_State != HttpRequestBody) {
if (m_State != HttpRequestStart && m_State != HttpRequestHeaders)
return false;
String line;
StreamReadStatus srs = m_Stream->ReadLine(&line, src, may_wait);
@ -73,16 +76,11 @@ bool HttpRequest::Parse(StreamReadContext& src, bool may_wait)
BOOST_THROW_EXCEPTION(std::invalid_argument("Unsupported HTTP version"));
m_State = HttpRequestHeaders;
} else if (m_State == HttpRequestHeaders) {
return true;
} else { // m_State = HttpRequestHeaders
if (line == "") {
m_State = HttpRequestBody;
/* we're done if the request doesn't contain a message body */
if (!Headers->Contains("content-length") && !Headers->Contains("transfer-encoding"))
Complete = true;
else
m_Body = new FIFO();
CompleteHeaders = true;
return true;
} else {
@ -99,11 +97,27 @@ bool HttpRequest::Parse(StreamReadContext& src, bool may_wait)
if (key == "x-http-method-override")
RequestMethod = value;
return true;
}
} else {
VERIFY(!"Invalid HTTP request state.");
}
} else if (m_State == HttpRequestBody) {
}
bool HttpRequest::ParseBody(StreamReadContext& src, bool may_wait)
{
if (!m_Stream || m_State != HttpRequestBody)
return false;
/* we're done if the request doesn't contain a message body */
if (!Headers->Contains("content-length") && !Headers->Contains("transfer-encoding")) {
CompleteBody = true;
return true;
} else if (!m_Body)
m_Body = new FIFO();
if (CompleteBody)
return true;
if (Headers->Get("transfer-encoding") == "chunked") {
if (!m_ChunkContext)
m_ChunkContext = std::make_shared<ChunkReadContext>(std::ref(src));
@ -120,7 +134,7 @@ bool HttpRequest::Parse(StreamReadContext& src, bool may_wait)
delete [] data;
if (size == 0) {
Complete = true;
CompleteBody = true;
return true;
}
} else {
@ -150,10 +164,9 @@ bool HttpRequest::Parse(StreamReadContext& src, bool may_wait)
m_Body->Write(src.Buffer, length_indicator);
src.DropData(length_indicator);
Complete = true;
CompleteBody = true;
return true;
}
}
return true;
}

View File

@ -52,7 +52,8 @@ enum HttpRequestState
struct HttpRequest
{
public:
bool Complete;
bool CompleteHeaders;
bool CompleteBody;
String RequestMethod;
Url::Ptr RequestUrl;
@ -62,7 +63,8 @@ public:
HttpRequest(Stream::Ptr stream);
bool Parse(StreamReadContext& src, bool may_wait);
bool ParseHeader(StreamReadContext& src, bool may_wait);
bool ParseBody(StreamReadContext& src, bool may_wait);
size_t ReadBody(char *data, size_t count);
void AddHeader(const String& key, const String& value);

View File

@ -92,7 +92,7 @@ bool HttpServerConnection::ProcessMessage()
bool res;
try {
res = m_CurrentRequest.Parse(m_Context, false);
res = m_CurrentRequest.ParseHeader(m_Context, false);
} catch (const std::invalid_argument& ex) {
HttpResponse response(m_Stream, m_CurrentRequest);
response.SetStatus(400, "Bad request");
@ -113,7 +113,7 @@ bool HttpServerConnection::ProcessMessage()
return false;
}
if (m_CurrentRequest.Complete) {
if (m_CurrentRequest.CompleteHeaders) {
m_RequestQueue.Enqueue(std::bind(&HttpServerConnection::ProcessMessageAsync,
HttpServerConnection::Ptr(this), m_CurrentRequest));
@ -240,6 +240,17 @@ void HttpServerConnection::ProcessMessageAsync(HttpRequest& request)
String msg = "<h1>Unauthorized. Please check your user credentials.</h1>";
response.WriteBody(msg.CStr(), msg.GetLength());
}
} else {
bool res = true;
while (!request.CompleteBody)
res = request.ParseBody(m_Context, false);
if (!res) {
Log(LogCritical, "HttpServerConnection", "Failed to read body");
Dictionary::Ptr result = new Dictionary({
{ "error", 400 },
{ "status", "Bad Request: Malformed body." }
});
HttpUtility::SendJsonBody(response, nullptr, result);
} else {
try {
HttpHandler::ProcessRequest(user, request, response);
@ -263,6 +274,7 @@ void HttpServerConnection::ProcessMessageAsync(HttpRequest& request)
}
}
}
}
response.Finish();