Implemented request bodies
This commit is contained in:
@@ -7,6 +7,10 @@
|
|||||||
// esp-idf includes
|
// esp-idf includes
|
||||||
#include <esp_log.h>
|
#include <esp_log.h>
|
||||||
|
|
||||||
|
// 3rdparty lib includes
|
||||||
|
#include <numberparsing.h>
|
||||||
|
#include <strutils.h>
|
||||||
|
|
||||||
// local includes
|
// local includes
|
||||||
#include "webserver.h"
|
#include "webserver.h"
|
||||||
#include "responsehandler.h"
|
#include "responsehandler.h"
|
||||||
@@ -76,6 +80,45 @@ void ClientConnection::readyRead(std::error_code ec, std::size_t length)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_state == State::RequestBody)
|
||||||
|
{
|
||||||
|
if (!m_responseHandler)
|
||||||
|
{
|
||||||
|
ESP_LOGW(TAG, "invalid response handler (%s:%hi)",
|
||||||
|
m_remote_endpoint.address().to_string().c_str(), m_remote_endpoint.port());
|
||||||
|
m_socket.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_requestBodySize)
|
||||||
|
goto requestFinished;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (length <= m_requestBodySize)
|
||||||
|
{
|
||||||
|
m_responseHandler->requestBodyReceived({m_receiveBuffer, length});
|
||||||
|
m_requestBodySize -= length;
|
||||||
|
length = 0;
|
||||||
|
|
||||||
|
if (!m_requestBodySize)
|
||||||
|
goto requestFinished;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_responseHandler->requestBodyReceived({m_receiveBuffer, m_requestBodySize});
|
||||||
|
// TODO how to erase from m_receiveBuffer ?
|
||||||
|
m_requestBodySize = 0;
|
||||||
|
goto requestFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
requestFinished:
|
||||||
|
// ESP_LOGV(TAG, "state changed to Response");
|
||||||
|
m_state = State::Response;
|
||||||
|
|
||||||
|
m_responseHandler->sendResponse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ESP_LOGV(TAG, "received: %zd \"%.*s\"", length, length, m_data);
|
// ESP_LOGV(TAG, "received: %zd \"%.*s\"", length, length, m_data);
|
||||||
m_parsingBuffer.append(m_receiveBuffer, length);
|
m_parsingBuffer.append(m_receiveBuffer, length);
|
||||||
|
|
||||||
@@ -88,14 +131,14 @@ void ClientConnection::readyRead(std::error_code ec, std::size_t length)
|
|||||||
if (index == std::string::npos)
|
if (index == std::string::npos)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
std::string_view line{m_parsingBuffer.data(), index};
|
std::string line{m_parsingBuffer.data(), index};
|
||||||
|
|
||||||
// ESP_LOGD(TAG, "line: %zd \"%.*s\"", line.size(), line.size(), line.data());
|
// ESP_LOGD(TAG, "line: %zd \"%.*s\"", line.size(), line.size(), line.data());
|
||||||
|
|
||||||
|
m_parsingBuffer.erase(std::begin(m_parsingBuffer), std::next(std::begin(m_parsingBuffer), line.size() + newLine.size()));
|
||||||
|
|
||||||
if (!readyReadLine(line))
|
if (!readyReadLine(line))
|
||||||
shouldDoRead = false;
|
shouldDoRead = false;
|
||||||
|
|
||||||
m_parsingBuffer.erase(std::begin(m_parsingBuffer), std::next(std::begin(m_parsingBuffer), line.size() + newLine.size()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldDoRead)
|
if (shouldDoRead)
|
||||||
@@ -195,6 +238,19 @@ bool ClientConnection::parseRequestHeader(std::string_view line)
|
|||||||
|
|
||||||
// ESP_LOGD(TAG, "header key=\"%.*s\" value=\"%.*s\"", key.size(), key.data(), value.size(), value.data());
|
// ESP_LOGD(TAG, "header key=\"%.*s\" value=\"%.*s\"", key.size(), key.data(), value.size(), value.data());
|
||||||
|
|
||||||
|
if (cpputils::stringEqualsIgnoreCase(key, "Content-Length"))
|
||||||
|
{
|
||||||
|
if (const auto parsed = cpputils::fromString<std::size_t>(value); !parsed)
|
||||||
|
{
|
||||||
|
ESP_LOGW(TAG, "invalid Content-Length %.*s %.*s", value.size(), value.data(),
|
||||||
|
parsed.error().size(), parsed.error().data());
|
||||||
|
m_socket.close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_requestBodySize = *parsed;
|
||||||
|
}
|
||||||
|
|
||||||
if (!m_responseHandler)
|
if (!m_responseHandler)
|
||||||
{
|
{
|
||||||
ESP_LOGW(TAG, "invalid response handler (%s:%hi)",
|
ESP_LOGW(TAG, "invalid response handler (%s:%hi)",
|
||||||
@@ -209,19 +265,52 @@ bool ClientConnection::parseRequestHeader(std::string_view line)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// ESP_LOGV(TAG, "state changed to Response");
|
|
||||||
m_state = State::Response;
|
|
||||||
|
|
||||||
if (!m_responseHandler)
|
if (!m_responseHandler)
|
||||||
{
|
{
|
||||||
ESP_LOGW(TAG, "invalid response handler ESP_LOGI",
|
ESP_LOGW(TAG, "invalid response handler (%s:%hi)",
|
||||||
m_remote_endpoint.address().to_string().c_str(), m_remote_endpoint.port());
|
m_remote_endpoint.address().to_string().c_str(), m_remote_endpoint.port());
|
||||||
m_socket.close();
|
m_socket.close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_responseHandler->sendResponse();
|
if (m_requestBodySize)
|
||||||
|
{
|
||||||
|
// ESP_LOGV(TAG, "state changed to RequestBody");
|
||||||
|
m_state = State::RequestBody;
|
||||||
|
|
||||||
return false;
|
if (!m_parsingBuffer.empty())
|
||||||
|
{
|
||||||
|
if (m_parsingBuffer.size() <= m_requestBodySize)
|
||||||
|
{
|
||||||
|
m_responseHandler->requestBodyReceived(m_parsingBuffer);
|
||||||
|
m_requestBodySize -= m_parsingBuffer.size();
|
||||||
|
m_parsingBuffer.clear();
|
||||||
|
|
||||||
|
if (!m_requestBodySize)
|
||||||
|
goto requestFinished;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_responseHandler->requestBodyReceived({m_parsingBuffer.data(), m_requestBodySize});
|
||||||
|
m_parsingBuffer.erase(std::begin(m_parsingBuffer), std::next(std::begin(m_parsingBuffer), m_requestBodySize));
|
||||||
|
m_requestBodySize = 0;
|
||||||
|
goto requestFinished;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
requestFinished:
|
||||||
|
// ESP_LOGV(TAG, "state changed to Response");
|
||||||
|
m_state = State::Response;
|
||||||
|
|
||||||
|
m_responseHandler->sendResponse();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -9,5 +9,6 @@ public:
|
|||||||
virtual ~ResponseHandler() = default;
|
virtual ~ResponseHandler() = default;
|
||||||
|
|
||||||
virtual void requestHeaderReceived(std::string_view key, std::string_view value) = 0;
|
virtual void requestHeaderReceived(std::string_view key, std::string_view value) = 0;
|
||||||
|
virtual void requestBodyReceived(std::string_view body) = 0;
|
||||||
virtual void sendResponse() = 0;
|
virtual void sendResponse() = 0;
|
||||||
};
|
};
|
||||||
|
@@ -29,6 +29,10 @@ void ChunkedResponseHandler::requestHeaderReceived(std::string_view key, std::st
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ChunkedResponseHandler::requestBodyReceived(std::string_view body)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void ChunkedResponseHandler::sendResponse()
|
void ChunkedResponseHandler::sendResponse()
|
||||||
{
|
{
|
||||||
ESP_LOGI(TAG, "sending response (header) for (%s:%hi)",
|
ESP_LOGI(TAG, "sending response (header) for (%s:%hi)",
|
||||||
|
@@ -11,13 +11,14 @@
|
|||||||
// forward declarations
|
// forward declarations
|
||||||
class ClientConnection;
|
class ClientConnection;
|
||||||
|
|
||||||
class ChunkedResponseHandler : public ResponseHandler
|
class ChunkedResponseHandler final : public ResponseHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ChunkedResponseHandler(ClientConnection &clientConnection);
|
ChunkedResponseHandler(ClientConnection &clientConnection);
|
||||||
~ChunkedResponseHandler() override;
|
~ChunkedResponseHandler() final;
|
||||||
|
|
||||||
void requestHeaderReceived(std::string_view key, std::string_view value) final;
|
void requestHeaderReceived(std::string_view key, std::string_view value) final;
|
||||||
|
void requestBodyReceived(std::string_view body) final;
|
||||||
void sendResponse() final;
|
void sendResponse() final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@@ -30,6 +30,11 @@ void DebugResponseHandler::requestHeaderReceived(std::string_view key, std::stri
|
|||||||
m_requestHeaders.emplace_back(std::make_pair(std::string{key}, std::string{value}));
|
m_requestHeaders.emplace_back(std::make_pair(std::string{key}, std::string{value}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DebugResponseHandler::requestBodyReceived(std::string_view body)
|
||||||
|
{
|
||||||
|
m_requestBody += body;
|
||||||
|
}
|
||||||
|
|
||||||
void DebugResponseHandler::sendResponse()
|
void DebugResponseHandler::sendResponse()
|
||||||
{
|
{
|
||||||
ESP_LOGI(TAG, "sending response for %.*s %.*s (%s:%hi)", m_method.size(), m_method.data(), m_path.size(), m_path.data(),
|
ESP_LOGI(TAG, "sending response for %.*s %.*s (%s:%hi)", m_method.size(), m_method.data(), m_path.size(), m_path.data(),
|
||||||
@@ -56,10 +61,19 @@ void DebugResponseHandler::sendResponse()
|
|||||||
m_response += fmt::format( "<tr><th>{}</th><td>{}</td></tr>",
|
m_response += fmt::format( "<tr><th>{}</th><td>{}</td></tr>",
|
||||||
pair.first, pair.second);
|
pair.first, pair.second);
|
||||||
|
|
||||||
m_response += fmt::format( "</table>"
|
m_response += "</table>"
|
||||||
"</td>"
|
"</td>"
|
||||||
"</tr>"
|
"</tr>";
|
||||||
"</tbody>"
|
|
||||||
|
if (!m_requestBody.empty())
|
||||||
|
{
|
||||||
|
m_response += fmt::format( "<tr>"
|
||||||
|
"<th>Request body:</th>"
|
||||||
|
"<td><pre>{}</pre></td>"
|
||||||
|
"</tr>", m_requestBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_response += "</tbody>"
|
||||||
"</table>"
|
"</table>"
|
||||||
"<form method=\"GET\">"
|
"<form method=\"GET\">"
|
||||||
"<fieldset>"
|
"<fieldset>"
|
||||||
@@ -90,7 +104,7 @@ void DebugResponseHandler::sendResponse()
|
|||||||
"</fieldset>"
|
"</fieldset>"
|
||||||
"</form>"
|
"</form>"
|
||||||
"</body>"
|
"</body>"
|
||||||
"</html>");
|
"</html>";
|
||||||
|
|
||||||
m_response = fmt::format("HTTP/1.1 200 Ok\r\n"
|
m_response = fmt::format("HTTP/1.1 200 Ok\r\n"
|
||||||
"Content-Type: text/html\r\n"
|
"Content-Type: text/html\r\n"
|
||||||
|
@@ -13,13 +13,14 @@
|
|||||||
// forward declarations
|
// forward declarations
|
||||||
class ClientConnection;
|
class ClientConnection;
|
||||||
|
|
||||||
class DebugResponseHandler : public ResponseHandler
|
class DebugResponseHandler final : public ResponseHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DebugResponseHandler(ClientConnection &clientConnection, std::string_view method, std::string_view path, std::string_view protocol);
|
DebugResponseHandler(ClientConnection &clientConnection, std::string_view method, std::string_view path, std::string_view protocol);
|
||||||
~DebugResponseHandler() override;
|
~DebugResponseHandler() final;
|
||||||
|
|
||||||
void requestHeaderReceived(std::string_view key, std::string_view value) final;
|
void requestHeaderReceived(std::string_view key, std::string_view value) final;
|
||||||
|
void requestBodyReceived(std::string_view body) final;
|
||||||
void sendResponse() final;
|
void sendResponse() final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -32,5 +33,7 @@ private:
|
|||||||
|
|
||||||
std::vector<std::pair<std::string, std::string>> m_requestHeaders;
|
std::vector<std::pair<std::string, std::string>> m_requestHeaders;
|
||||||
|
|
||||||
|
std::string m_requestBody;
|
||||||
|
|
||||||
std::string m_response;
|
std::string m_response;
|
||||||
};
|
};
|
||||||
|
@@ -30,6 +30,10 @@ void ErrorResponseHandler::requestHeaderReceived(std::string_view key, std::stri
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ErrorResponseHandler::requestBodyReceived(std::string_view body)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void ErrorResponseHandler::sendResponse()
|
void ErrorResponseHandler::sendResponse()
|
||||||
{
|
{
|
||||||
ESP_LOGI(TAG, "sending response for %.*s (%s:%hi)", m_path.size(), m_path.data(),
|
ESP_LOGI(TAG, "sending response for %.*s (%s:%hi)", m_path.size(), m_path.data(),
|
||||||
|
@@ -11,13 +11,14 @@
|
|||||||
// forward declarations
|
// forward declarations
|
||||||
class ClientConnection;
|
class ClientConnection;
|
||||||
|
|
||||||
class ErrorResponseHandler : public ResponseHandler
|
class ErrorResponseHandler final : public ResponseHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ErrorResponseHandler(ClientConnection &clientConnection, std::string_view path);
|
ErrorResponseHandler(ClientConnection &clientConnection, std::string_view path);
|
||||||
~ErrorResponseHandler() override;
|
~ErrorResponseHandler() final;
|
||||||
|
|
||||||
void requestHeaderReceived(std::string_view key, std::string_view value) final;
|
void requestHeaderReceived(std::string_view key, std::string_view value) final;
|
||||||
|
void requestBodyReceived(std::string_view body) final;
|
||||||
void sendResponse() final;
|
void sendResponse() final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@@ -29,6 +29,10 @@ void RootResponseHandler::requestHeaderReceived(std::string_view key, std::strin
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RootResponseHandler::requestBodyReceived(std::string_view body)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void RootResponseHandler::sendResponse()
|
void RootResponseHandler::sendResponse()
|
||||||
{
|
{
|
||||||
ESP_LOGI(TAG, "sending response for (%s:%hi)",
|
ESP_LOGI(TAG, "sending response for (%s:%hi)",
|
||||||
@@ -40,8 +44,10 @@ void RootResponseHandler::sendResponse()
|
|||||||
"</head>"
|
"</head>"
|
||||||
"<body>"
|
"<body>"
|
||||||
"<h1>asio test webserver</h1>"
|
"<h1>asio test webserver</h1>"
|
||||||
"<a href=\"/debug\">Debug</a>"
|
"<ul>"
|
||||||
"<a href=\"/chunked\">Chunked</a>"
|
"<li><a href=\"/debug\">Debug</a></li>"
|
||||||
|
"<li><a href=\"/chunked\">Chunked</a></li>"
|
||||||
|
"</ul>"
|
||||||
"</body>"
|
"</body>"
|
||||||
"</html>");
|
"</html>");
|
||||||
|
|
||||||
|
@@ -11,13 +11,14 @@
|
|||||||
// forward declarations
|
// forward declarations
|
||||||
class ClientConnection;
|
class ClientConnection;
|
||||||
|
|
||||||
class RootResponseHandler : public ResponseHandler
|
class RootResponseHandler final : public ResponseHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RootResponseHandler(ClientConnection &clientConnection);
|
RootResponseHandler(ClientConnection &clientConnection);
|
||||||
~RootResponseHandler() override;
|
~RootResponseHandler() override;
|
||||||
|
|
||||||
void requestHeaderReceived(std::string_view key, std::string_view value) final;
|
void requestHeaderReceived(std::string_view key, std::string_view value) final;
|
||||||
|
void requestBodyReceived(std::string_view body) final;
|
||||||
void sendResponse() final;
|
void sendResponse() final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Reference in New Issue
Block a user