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 e1c46cedd1
commit a46dc64e6a
3 changed files with 162 additions and 138 deletions

View File

@ -29,19 +29,22 @@
using namespace icinga;
HttpRequest::HttpRequest(const Stream::Ptr& stream)
: Complete(false),
: CompleteHeaders(false),
CompleteBody(false),
ProtocolVersion(HttpVersion11),
Headers(new Dictionary()),
m_Stream(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);
@ -60,8 +63,7 @@ bool HttpRequest::Parse(StreamReadContext& src, bool may_wait)
if (line == "")
return true;
std::vector<String> tokens;
boost::algorithm::split(tokens, line, boost::is_any_of(" "));
std::vector<String> tokens = line.Split(" ");
Log(LogDebug, "HttpRequest")
<< "line: " << line << ", tokens: " << tokens.size();
if (tokens.size() != 3)
@ -78,16 +80,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 {
@ -104,11 +101,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 = boost::make_shared<ChunkReadContext>(boost::ref(src));
@ -125,7 +138,7 @@ bool HttpRequest::Parse(StreamReadContext& src, bool may_wait)
delete [] data;
if (size == 0) {
Complete = true;
CompleteBody = true;
return true;
}
} else {
@ -155,10 +168,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 I2_REMOTE_API HttpRequest
{
public:
bool Complete;
bool CompleteHeaders;
bool CompleteBody;
String RequestMethod;
Url::Ptr RequestUrl;
@ -62,7 +63,8 @@ public:
HttpRequest(const 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(void)
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(void)
return false;
}
if (m_CurrentRequest.Complete) {
if (m_CurrentRequest.CompleteHeaders) {
m_RequestQueue.Enqueue(boost::bind(&HttpServerConnection::ProcessMessageAsync,
HttpServerConnection::Ptr(this), m_CurrentRequest));
@ -240,6 +240,16 @@ 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;
result->Set("error", 404);
result->Set("status", "Bad Request: Malformed body.");
HttpUtility::SendJsonBody(response, result);
} else {
try {
HttpHandler::ProcessRequest(user, request, response);
@ -252,7 +262,6 @@ void HttpServerConnection::ProcessMessageAsync(HttpRequest& request)
if (request.Headers->Get("accept") == "application/json") {
Dictionary::Ptr result = new Dictionary();
result->Set("error", 503);
result->Set("status", errorInfo);
@ -263,6 +272,7 @@ void HttpServerConnection::ProcessMessageAsync(HttpRequest& request)
}
}
}
}
response.Finish();