diff --git a/src/common/network/rest/RequestDispatcher.h b/src/common/network/rest/RequestDispatcher.h
index 9dc99999..3fb57a26 100644
--- a/src/common/network/rest/RequestDispatcher.h
+++ b/src/common/network/rest/RequestDispatcher.h
@@ -34,6 +34,8 @@ namespace network
struct RequestMatch : std::smatch {
/// Initializes a new instance of the RequestMatch structure.
+ ///
+ ///
RequestMatch(const std::smatch& m, const std::string& c) : std::smatch(m), content(c) { /* stub */ }
std::string content;
@@ -49,38 +51,56 @@ namespace network
typedef std::function RequestHandlerType;
/// Initializes a new instance of the RequestMatcher structure.
+ ///
explicit RequestMatcher(const std::string& expression) : m_expression(expression), m_isRegEx(false) { /* stub */ }
///
+ ///
+ ///
RequestMatcher& get(RequestHandlerType handler) {
m_handlers[HTTP_GET] = handler;
return *this;
}
///
+ ///
+ ///
RequestMatcher& post(RequestHandlerType handler) {
m_handlers[HTTP_POST] = handler;
return *this;
}
///
+ ///
+ ///
RequestMatcher& put(RequestHandlerType handler) {
m_handlers[HTTP_PUT] = handler;
return *this;
}
///
+ ///
+ ///
RequestMatcher& del(RequestHandlerType handler) {
m_handlers[HTTP_DELETE] = handler;
return *this;
}
///
+ ///
+ ///
RequestMatcher& options(RequestHandlerType handler) {
m_handlers[HTTP_OPTIONS] = handler;
return *this;
}
+ ///
+ ///
bool regex() const { return m_isRegEx; }
+ ///
+ ///
void setRegEx(bool regEx) { m_isRegEx = regEx; }
///
+ ///
+ ///
+ ///
void handleRequest(const Request& request, Reply& reply, const std::smatch &what) {
// dispatching to matching based on handler
RequestMatch match(what, request.content);
@@ -108,11 +128,17 @@ namespace network
/// Initializes a new instance of the RequestDispatcher class.
RequestDispatcher() : m_basePath(), m_debug(false) { /* stub */ }
/// Initializes a new instance of the RequestDispatcher class.
+ ///
RequestDispatcher(bool debug) : m_basePath(), m_debug(debug) { /* stub */ }
/// Initializes a new instance of the RequestDispatcher class.
+ ///
+ ///
RequestDispatcher(const std::string& basePath, bool debug) : m_basePath(basePath), m_debug(debug) { /* stub */ }
///
+ ///
+ ///
+ ///
MatcherType& match(const std::string& expression, bool regex = false)
{
MatcherTypePtr& p = m_matchers[expression];
@@ -132,6 +158,8 @@ namespace network
}
///
+ ///
+ ///
void handleRequest(const Request& request, Reply& reply)
{
for (const auto& matcher : m_matchers) {
@@ -194,9 +222,12 @@ namespace network
/// Initializes a new instance of the DebugRequestDispatcher class.
BasicRequestDispatcher() { /* stub */ }
/// Initializes a new instance of the BasicRequestDispatcher class.
+ ///
BasicRequestDispatcher(RequestHandlerType handler) : m_handler(handler) { /* stub */ }
///
+ ///
+ ///
void handleRequest(const Request& request, Reply& reply)
{
if (m_handler) {
@@ -220,6 +251,8 @@ namespace network
DebugRequestDispatcher() { /* stub */ }
///
+ ///
+ ///
void handleRequest(const Request& request, Reply& reply)
{
for (auto header : request.headers.headers())
diff --git a/src/common/network/rest/http/ClientConnection.h b/src/common/network/rest/http/ClientConnection.h
index cdf6da62..63cdb143 100644
--- a/src/common/network/rest/http/ClientConnection.h
+++ b/src/common/network/rest/http/ClientConnection.h
@@ -44,6 +44,8 @@ namespace network
ClientConnection(ClientConnection&) = delete;
/// Initializes a new instance of the ClientConnection class.
+ ///
+ ///
explicit ClientConnection(asio::ip::tcp::socket socket, RequestHandlerType& handler) :
m_socket(std::move(socket)),
m_requestHandler(handler),
@@ -86,6 +88,7 @@ namespace network
}
/// Perform an synchronous write operation.
+ ///
void send(HTTPPayload request)
{
request.attachHostHeader(m_socket.remote_endpoint());
@@ -134,6 +137,7 @@ namespace network
}
/// Perform an synchronous write operation.
+ ///
void write(HTTPPayload request)
{
try
diff --git a/src/common/network/rest/http/HTTPClient.h b/src/common/network/rest/http/HTTPClient.h
index fb4191ba..d33bfa55 100644
--- a/src/common/network/rest/http/HTTPClient.h
+++ b/src/common/network/rest/http/HTTPClient.h
@@ -47,6 +47,8 @@ namespace network
HTTPClient(HTTPClient&) = delete;
/// Initializes a new instance of the HTTPClient class.
+ ///
+ ///
HTTPClient(const std::string& address, uint16_t port) :
m_address(address),
m_port(port),
@@ -66,6 +68,8 @@ namespace network
}
/// Helper to set the HTTP request handlers.
+ ///
+ ///
template
void setHandler(Handler&& handler)
{
@@ -73,6 +77,8 @@ namespace network
}
/// Send HTTP request to HTTP server.
+ ///
+ ///
bool request(HTTPPayload& request)
{
if (m_completed) {
@@ -140,6 +146,7 @@ namespace network
}
/// Perform an asynchronous connect operation.
+ ///
void connect(asio::ip::basic_resolver_results& endpoints)
{
asio::connect(m_socket, endpoints);
diff --git a/src/common/network/rest/http/HTTPHeaders.h b/src/common/network/rest/http/HTTPHeaders.h
index f562a91b..f966d87d 100644
--- a/src/common/network/rest/http/HTTPHeaders.h
+++ b/src/common/network/rest/http/HTTPHeaders.h
@@ -59,6 +59,8 @@ namespace network
/// Clears the list of HTTP headers.
void clearHeaders() { m_headers = std::vector(); }
/// Helper to add a HTTP header.
+ ///
+ ///
void add(const std::string& name, const std::string& value)
{
//::LogDebug(LOG_REST, "HTTPHeaders::add(), header = %s, value = %s", name.c_str(), value.c_str());
@@ -74,6 +76,7 @@ namespace network
// ::LogDebug(LOG_REST, "HTTPHeaders::add() m_headers.header = %s, m_headers.value = %s", header.name.c_str(), header.value.c_str());
}
/// Helper to add a HTTP header.
+ ///
void remove(const std::string headerName)
{
auto header = std::find_if(m_headers.begin(), m_headers.end(), [&](const Header& h) {
@@ -85,6 +88,7 @@ namespace network
}
}
/// Helper to find the named HTTP header.
+ ///
std::string find(const std::string headerName) const
{
auto header = std::find_if(m_headers.begin(), m_headers.end(), [&](const Header& h) {
diff --git a/src/common/network/rest/http/HTTPLexer.cpp b/src/common/network/rest/http/HTTPLexer.cpp
index eb04deb2..3a0bf3ea 100644
--- a/src/common/network/rest/http/HTTPLexer.cpp
+++ b/src/common/network/rest/http/HTTPLexer.cpp
@@ -9,7 +9,7 @@
* @license BSL-1.0 License (https://opensource.org/license/bsl1-0-html)
*
* Copyright (c) 2003-2013 Christopher M. Kohlhoff
-* Copyright (C) 2023 Bryan Biedenkapp, N2PLL
+* Copyright (C) 2023-2024 Bryan Biedenkapp, N2PLL
*
*/
#include "Defines.h"
@@ -32,6 +32,7 @@ using namespace network::rest::http;
HTTPLexer::HTTPLexer(bool clientLexer) :
m_headers(),
m_clientLexer(clientLexer),
+ m_consumed(0U),
m_state(METHOD_START)
{
if (m_clientLexer) {
@@ -62,6 +63,7 @@ void HTTPLexer::reset()
///
HTTPLexer::ResultType HTTPLexer::consume(HTTPPayload& req, char input)
{
+ m_consumed++;
switch (m_state)
{
/*
diff --git a/src/common/network/rest/http/HTTPLexer.h b/src/common/network/rest/http/HTTPLexer.h
index 2b7f332c..50a8a099 100644
--- a/src/common/network/rest/http/HTTPLexer.h
+++ b/src/common/network/rest/http/HTTPLexer.h
@@ -9,7 +9,7 @@
* @license BSL-1.0 License (https://opensource.org/license/bsl1-0-html)
*
* Copyright (c) 2003-2013 Christopher M. Kohlhoff
-* Copyright (C) 2023 Bryan Biedenkapp, N2PLL
+* Copyright (C) 2023-2024 Bryan Biedenkapp, N2PLL
*
*/
#if !defined(__REST_HTTP__HTTP_LEXER_H__)
@@ -40,7 +40,7 @@ namespace network
class HTTPLexer {
public:
- enum ResultType { GOOD, BAD, INDETERMINATE };
+ enum ResultType { GOOD, BAD, INDETERMINATE, CONTINUE };
/// Initializes a new instance of the HTTPLexer class.
HTTPLexer(bool clientLexer);
@@ -52,6 +52,11 @@ namespace network
/// been parsed, bad if the data is invalid, indeterminate when more data is
/// required. The InputIterator return value indicates how much of the input
/// has been consumed.
+ ///
+ ///
+ ///
+ ///
+ ///
template
std::tuple parse(HTTPPayload& payload, InputIterator begin, InputIterator end)
{
@@ -63,6 +68,9 @@ namespace network
return std::make_tuple(INDETERMINATE, begin);
}
+ ///
+ uint32_t consumed() const { return m_consumed; }
+
private:
/// Handle the next character of input.
ResultType consume(HTTPPayload& payload, char input);
@@ -88,6 +96,7 @@ namespace network
std::vector m_headers;
uint16_t m_status;
bool m_clientLexer = false;
+ uint32_t m_consumed;
enum state
{
diff --git a/src/common/network/rest/http/HTTPPayload.h b/src/common/network/rest/http/HTTPPayload.h
index bf192739..e6f3ebd9 100644
--- a/src/common/network/rest/http/HTTPPayload.h
+++ b/src/common/network/rest/http/HTTPPayload.h
@@ -9,7 +9,7 @@
* @license BSL-1.0 License (https://opensource.org/license/bsl1-0-html)
*
* Copyright (c) 2003-2013 Christopher M. Kohlhoff
-* Copyright (C) 2023 Bryan Biedenkapp, N2PLL
+* Copyright (C) 2023-2024 Bryan Biedenkapp, N2PLL
*
*/
#if !defined(__REST_HTTP__HTTP_REPLY_H__)
@@ -72,6 +72,7 @@ namespace network
HTTPHeaders headers;
std::string content;
+ size_t contentLength;
std::string method;
std::string uri;
diff --git a/src/common/network/rest/http/HTTPServer.h b/src/common/network/rest/http/HTTPServer.h
index c147182b..520a2164 100644
--- a/src/common/network/rest/http/HTTPServer.h
+++ b/src/common/network/rest/http/HTTPServer.h
@@ -9,7 +9,7 @@
* @license BSL-1.0 License (https://opensource.org/license/bsl1-0-html)
*
* Copyright (c) 2003-2013 Christopher M. Kohlhoff
-* Copyright (C) 2023,2024 Bryan Biedenkapp, N2PLL
+* Copyright (C) 2023-2024 Bryan Biedenkapp, N2PLL
*
*/
#if !defined(__REST_HTTP__HTTP_SERVER_H__)
@@ -48,12 +48,16 @@ namespace network
HTTPServer(HTTPServer&) = delete;
/// Initializes a new instance of the HTTPServer class.
- explicit HTTPServer(const std::string& address, uint16_t port) :
+ ///
+ ///
+ ///
+ explicit HTTPServer(const std::string& address, uint16_t port, bool debug) :
m_ioService(),
m_acceptor(m_ioService),
m_connectionManager(),
m_socket(m_ioService),
- m_requestHandler()
+ m_requestHandler(),
+ m_debug(debug)
{
// open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR)
asio::ip::address ipAddress = asio::ip::address::from_string(address);
@@ -61,6 +65,8 @@ namespace network
}
/// Helper to set the HTTP request handlers.
+ ///
+ ///
template
void setHandler(Handler&& handler)
{
@@ -112,7 +118,7 @@ namespace network
}
if (!ec) {
- m_connectionManager.start(std::make_shared(std::move(m_socket), m_connectionManager, m_requestHandler));
+ m_connectionManager.start(std::make_shared(std::move(m_socket), m_connectionManager, m_requestHandler, false, m_debug));
}
accept();
@@ -132,6 +138,7 @@ namespace network
asio::ip::tcp::socket m_socket;
RequestHandlerType m_requestHandler;
+ bool m_debug;
};
} // namespace http
} // namespace rest
diff --git a/src/common/network/rest/http/SecureClientConnection.h b/src/common/network/rest/http/SecureClientConnection.h
index e8ded3a5..b007d90f 100644
--- a/src/common/network/rest/http/SecureClientConnection.h
+++ b/src/common/network/rest/http/SecureClientConnection.h
@@ -47,6 +47,9 @@ namespace network
SecureClientConnection(SecureClientConnection&) = delete;
/// Initializes a new instance of the SecureClientConnection class.
+ ///
+ ///
+ ///
explicit SecureClientConnection(asio::ip::tcp::socket socket, asio::ssl::context& context, RequestHandlerType& handler) :
m_socket(std::move(socket), context),
m_requestHandler(handler),
@@ -94,6 +97,7 @@ namespace network
}
/// Perform an synchronous write operation.
+ ///
void send(HTTPPayload request)
{
request.attachHostHeader(m_socket.lowest_layer().remote_endpoint());
@@ -101,6 +105,8 @@ namespace network
}
private:
/// Perform an SSL certificate verification.
+ ///
+ ///
bool verify_certificate(bool preverified, asio::ssl::verify_context& context)
{
return true; // ignore always valid
@@ -148,6 +154,7 @@ namespace network
}
/// Perform an synchronous write operation.
+ ///
void write(HTTPPayload request)
{
try
diff --git a/src/common/network/rest/http/SecureHTTPClient.h b/src/common/network/rest/http/SecureHTTPClient.h
index 243cde54..5f0f6b37 100644
--- a/src/common/network/rest/http/SecureHTTPClient.h
+++ b/src/common/network/rest/http/SecureHTTPClient.h
@@ -50,6 +50,8 @@ namespace network
SecureHTTPClient(SecureHTTPClient&) = delete;
/// Initializes a new instance of the SecureHTTPClient class.
+ ///
+ ///
SecureHTTPClient(const std::string& address, uint16_t port) :
m_address(address),
m_port(port),
@@ -70,6 +72,8 @@ namespace network
}
/// Helper to set the HTTP request handlers.
+ ///
+ ///
template
void setHandler(Handler&& handler)
{
@@ -77,6 +81,7 @@ namespace network
}
/// Send HTTP request to HTTP server.
+ ///
bool request(HTTPPayload& request)
{
if (m_completed) {
@@ -144,6 +149,7 @@ namespace network
}
/// Perform an asynchronous connect operation.
+ ///
void connect(asio::ip::basic_resolver_results& endpoints)
{
asio::connect(m_socket, endpoints);
diff --git a/src/common/network/rest/http/SecureHTTPServer.h b/src/common/network/rest/http/SecureHTTPServer.h
index 4fb47cf0..df2306eb 100644
--- a/src/common/network/rest/http/SecureHTTPServer.h
+++ b/src/common/network/rest/http/SecureHTTPServer.h
@@ -51,19 +51,25 @@ namespace network
SecureHTTPServer(SecureHTTPServer&) = delete;
/// Initializes a new instance of the SecureHTTPServer class.
- explicit SecureHTTPServer(const std::string& address, uint16_t port) :
+ ///
+ ///
+ ///
+ explicit SecureHTTPServer(const std::string& address, uint16_t port, bool debug) :
m_ioService(),
m_acceptor(m_ioService),
m_connectionManager(),
m_context(asio::ssl::context::tlsv12),
m_socket(m_ioService),
- m_requestHandler()
+ m_requestHandler(),
+ m_debug(debug)
{
asio::ip::address ipAddress = asio::ip::address::from_string(address);
m_endpoint = asio::ip::tcp::endpoint(ipAddress, port);
}
/// Helper to set the SSL certificate and private key.
+ ///
+ ///
bool setCertAndKey(const std::string& keyFile, const std::string& certFile)
{
try
@@ -79,6 +85,8 @@ namespace network
}
/// Helper to set the HTTP request handlers.
+ ///
+ ///
template
void setHandler(Handler&& handler)
{
@@ -130,7 +138,7 @@ namespace network
}
if (!ec) {
- m_connectionManager.start(std::make_shared(std::move(m_socket), m_context, m_connectionManager, m_requestHandler));
+ m_connectionManager.start(std::make_shared(std::move(m_socket), m_context, m_connectionManager, m_requestHandler, false, m_debug));
}
accept();
@@ -154,6 +162,7 @@ namespace network
std::string m_keyFile;
RequestHandlerType m_requestHandler;
+ bool m_debug;
};
} // namespace http
} // namespace rest
diff --git a/src/common/network/rest/http/SecureServerConnection.h b/src/common/network/rest/http/SecureServerConnection.h
index 402739b6..960c1429 100644
--- a/src/common/network/rest/http/SecureServerConnection.h
+++ b/src/common/network/rest/http/SecureServerConnection.h
@@ -58,13 +58,22 @@ namespace network
SecureServerConnection(SecureServerConnection&) = delete;
/// Initializes a new instance of the SecureServerConnection class.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
explicit SecureServerConnection(asio::ip::tcp::socket socket, asio::ssl::context& context, ConnectionManagerType& manager, RequestHandlerType& handler,
- bool persistent = false) :
+ bool persistent = false, bool debug = false) :
m_socket(std::move(socket), context),
m_connectionManager(manager),
m_requestHandler(handler),
m_lexer(HTTPLexer(false)),
- m_persistent(persistent)
+ m_continue(false),
+ m_contResult(HTTPLexer::INDETERMINATE),
+ m_persistent(persistent),
+ m_debug(debug)
{
/* stub */
}
@@ -105,29 +114,74 @@ namespace network
auto self(this->shared_from_this());
}
- m_socket.async_read_some(asio::buffer(m_buffer), [=](asio::error_code ec, std::size_t bytes_transferred) {
+ m_socket.async_read_some(asio::buffer(m_buffer), [=](asio::error_code ec, std::size_t recvLength) {
if (!ec) {
- HTTPLexer::ResultType result;
+ HTTPLexer::ResultType result = HTTPLexer::GOOD;
char* content;
// catch exceptions here so we don't blatently crash the system
try
{
- std::tie(result, content) = m_lexer.parse(m_request, m_buffer.data(), m_buffer.data() + bytes_transferred);
+ if (!m_continue) {
+ std::tie(result, content) = m_lexer.parse(m_request, m_buffer.data(), m_buffer.data() + recvLength);
- std::string contentLength = m_request.headers.find("Content-Length");
- if (contentLength != "") {
- size_t length = (size_t)::strtoul(contentLength.c_str(), NULL, 10);
- m_request.content = std::string(content, length);
- }
+ m_request.content = std::string();
+ std::string contentLength = m_request.headers.find("Content-Length");
+ if (contentLength != "" && (::strlen(content) != 0)) {
+ size_t length = (size_t)::strtoul(contentLength.c_str(), NULL, 10);
+ m_request.contentLength = length;
+ m_request.content = std::string(content, length);
+ }
+
+ m_request.headers.add("RemoteHost", m_socket.lowest_layer().remote_endpoint().address().to_string());
+
+ uint32_t consumed = m_lexer.consumed();
+ if (result == HTTPLexer::GOOD && consumed == recvLength &&
+ ((m_request.method == HTTP_POST) || (m_request.method == HTTP_PUT))) {
+ if (m_debug) {
+ LogDebug(LOG_REST, "HTTPS Partial Request, recvLength = %u, consumed = %u, result = %u", recvLength, consumed, result);
+ Utils::dump(1U, "m_buffer", (uint8_t*)m_buffer.data(), recvLength);
+ }
- m_request.headers.add("RemoteHost", m_socket.lowest_layer().remote_endpoint().address().to_string());
+ result = HTTPLexer::INDETERMINATE;
+ m_continue = true;
+ }
+ } else {
+ if (m_debug) {
+ LogDebug(LOG_REST, "HTTP Partial Request, recvLength = %u, result = %u", recvLength, result);
+ Utils::dump(1U, "m_buffer", (uint8_t*)m_buffer.data(), recvLength);
+ }
+
+ if (m_contResult == HTTPLexer::INDETERMINATE) {
+ m_request.content = std::string(m_buffer.data(), recvLength);
+ } else {
+ m_request.content.append(std::string(m_buffer.data(), recvLength));
+ }
+
+ if (m_request.contentLength != 0 && recvLength < m_request.contentLength) {
+ m_contResult = result = HTTPLexer::CONTINUE;
+ m_continue = true;
+ }
+ }
if (result == HTTPLexer::GOOD) {
+ if (m_debug) {
+ Utils::dump(1U, "HTTPS Request Content", (uint8_t*)m_request.content.c_str(), m_request.content.length());
+ }
+
+ m_continue = false;
+ m_contResult = HTTPLexer::INDETERMINATE;
m_requestHandler.handleRequest(m_request, m_reply);
+
+ if (m_debug) {
+ Utils::dump(1U, "HTTP Reply Content", (uint8_t*)m_reply.content.c_str(), m_reply.content.length());
+ }
+
write();
}
else if (result == HTTPLexer::BAD) {
+ m_continue = false;
+ m_contResult = HTTPLexer::INDETERMINATE;
m_reply = HTTPPayload::statusPayload(HTTPPayload::BAD_REQUEST);
write();
}
@@ -135,13 +189,18 @@ namespace network
read();
}
}
- catch(const std::exception& e) { ::LogError(LOG_REST, "SecureServerConnection::read(), %s", ec.message().c_str()); }
+ catch(const std::exception& e) {
+ ::LogError(LOG_REST, "SecureServerConnection::read(), %s", ec.message().c_str());
+ m_continue = false;
+ m_contResult = HTTPLexer::INDETERMINATE;
+ }
}
else if (ec != asio::error::operation_aborted) {
if (ec) {
::LogError(LOG_REST, "SecureServerConnection::read(), %s, code = %u", ec.message().c_str(), ec.value());
}
m_connectionManager.stop(this->shared_from_this());
+ m_continue = false;
}
});
}
@@ -197,7 +256,11 @@ namespace network
HTTPLexer m_lexer;
HTTPPayload m_reply;
+ bool m_continue;
+ HTTPLexer::ResultType m_contResult;
+
bool m_persistent;
+ bool m_debug;
};
} // namespace http
} // namespace rest
diff --git a/src/common/network/rest/http/ServerConnection.h b/src/common/network/rest/http/ServerConnection.h
index b13b6706..cb46c130 100644
--- a/src/common/network/rest/http/ServerConnection.h
+++ b/src/common/network/rest/http/ServerConnection.h
@@ -9,7 +9,7 @@
* @license BSL-1.0 License (https://opensource.org/license/bsl1-0-html)
*
* Copyright (c) 2003-2013 Christopher M. Kohlhoff
-* Copyright (C) 2023,2024 Bryan Biedenkapp, N2PLL
+* Copyright (C) 2023-2024 Bryan Biedenkapp, N2PLL
*
*/
#if !defined(__REST_HTTP__SERVER_CONNECTION_H__)
@@ -19,6 +19,7 @@
#include "common/network/rest/http/HTTPLexer.h"
#include "common/network/rest/http/HTTPPayload.h"
#include "common/Log.h"
+#include "common/Utils.h"
#include
#include
@@ -55,13 +56,21 @@ namespace network
ServerConnection(ServerConnection&) = delete;
/// Initializes a new instance of the ServerConnection class.
+ ///
+ ///
+ ///
+ ///
+ ///
explicit ServerConnection(asio::ip::tcp::socket socket, ConnectionManagerType& manager, RequestHandlerType& handler,
- bool persistent = false) :
+ bool persistent = false, bool debug = false) :
m_socket(std::move(socket)),
m_connectionManager(manager),
m_requestHandler(handler),
m_lexer(HTTPLexer(false)),
- m_persistent(persistent)
+ m_continue(false),
+ m_contResult(HTTPLexer::INDETERMINATE),
+ m_persistent(persistent),
+ m_debug(debug)
{
/* stub */
}
@@ -88,29 +97,74 @@ namespace network
auto self(this->shared_from_this());
}
- m_socket.async_read_some(asio::buffer(m_buffer), [=](asio::error_code ec, std::size_t bytes_transferred) {
+ m_socket.async_read_some(asio::buffer(m_buffer), [=](asio::error_code ec, std::size_t recvLength) {
if (!ec) {
- HTTPLexer::ResultType result;
+ HTTPLexer::ResultType result = HTTPLexer::GOOD;
char* content;
// catch exceptions here so we don't blatently crash the system
try
{
- std::tie(result, content) = m_lexer.parse(m_request, m_buffer.data(), m_buffer.data() + bytes_transferred);
-
- std::string contentLength = m_request.headers.find("Content-Length");
- if (contentLength != "") {
- size_t length = (size_t)::strtoul(contentLength.c_str(), NULL, 10);
- m_request.content = std::string(content, length);
+ if (!m_continue) {
+ std::tie(result, content) = m_lexer.parse(m_request, m_buffer.data(), m_buffer.data() + recvLength);
+
+ m_request.content = std::string();
+ std::string contentLength = m_request.headers.find("Content-Length");
+ if (contentLength != "" && (::strlen(content) != 0)) {
+ size_t length = (size_t)::strtoul(contentLength.c_str(), NULL, 10);
+ m_request.contentLength = length;
+ m_request.content = std::string(content, length);
+ }
+
+ m_request.headers.add("RemoteHost", m_socket.remote_endpoint().address().to_string());
+
+ uint32_t consumed = m_lexer.consumed();
+ if (result == HTTPLexer::GOOD && consumed == recvLength &&
+ ((m_request.method == HTTP_POST) || (m_request.method == HTTP_PUT))) {
+ if (m_debug) {
+ LogDebug(LOG_REST, "HTTP Partial Request, recvLength = %u, consumed = %u, result = %u", recvLength, consumed, result);
+ Utils::dump(1U, "m_buffer", (uint8_t*)m_buffer.data(), recvLength);
+ }
+
+ m_contResult = result = HTTPLexer::INDETERMINATE;
+ m_continue = true;
+ }
+ } else {
+ if (m_debug) {
+ LogDebug(LOG_REST, "HTTP Partial Request, recvLength = %u, result = %u", recvLength, result);
+ Utils::dump(1U, "m_buffer", (uint8_t*)m_buffer.data(), recvLength);
+ }
+
+ if (m_contResult == HTTPLexer::INDETERMINATE) {
+ m_request.content = std::string(m_buffer.data(), recvLength);
+ } else {
+ m_request.content.append(std::string(m_buffer.data(), recvLength));
+ }
+
+ if (m_request.contentLength != 0 && recvLength < m_request.contentLength) {
+ m_contResult = result = HTTPLexer::CONTINUE;
+ m_continue = true;
+ }
}
- m_request.headers.add("RemoteHost", m_socket.remote_endpoint().address().to_string());
-
if (result == HTTPLexer::GOOD) {
+ if (m_debug) {
+ Utils::dump(1U, "HTTP Request Content", (uint8_t*)m_request.content.c_str(), m_request.content.length());
+ }
+
+ m_continue = false;
+ m_contResult = HTTPLexer::INDETERMINATE;
m_requestHandler.handleRequest(m_request, m_reply);
+
+ if (m_debug) {
+ Utils::dump(1U, "HTTP Reply Content", (uint8_t*)m_reply.content.c_str(), m_reply.content.length());
+ }
+
write();
}
else if (result == HTTPLexer::BAD) {
+ m_continue = false;
+ m_contResult = HTTPLexer::INDETERMINATE;
m_reply = HTTPPayload::statusPayload(HTTPPayload::BAD_REQUEST);
write();
}
@@ -118,13 +172,19 @@ namespace network
read();
}
}
- catch(const std::exception& e) { ::LogError(LOG_REST, "ServerConnection::read(), %s", ec.message().c_str()); }
+ catch(const std::exception& e) {
+ ::LogError(LOG_REST, "ServerConnection::read(), %s", ec.message().c_str());
+ m_continue = false;
+ m_contResult = HTTPLexer::INDETERMINATE;
+ }
}
else if (ec != asio::error::operation_aborted) {
if (ec) {
::LogError(LOG_REST, "ServerConnection::read(), %s, code = %u", ec.message().c_str(), ec.value());
}
m_connectionManager.stop(this->shared_from_this());
+ m_continue = false;
+ m_contResult = HTTPLexer::INDETERMINATE;
}
});
}
@@ -180,7 +240,11 @@ namespace network
HTTPLexer m_lexer;
HTTPPayload m_reply;
+ bool m_continue;
+ HTTPLexer::ResultType m_contResult;
+
bool m_persistent;
+ bool m_debug;
};
} // namespace http
} // namespace rest
diff --git a/src/common/network/rest/http/ServerConnectionManager.h b/src/common/network/rest/http/ServerConnectionManager.h
index 85e18be4..16d91c53 100644
--- a/src/common/network/rest/http/ServerConnectionManager.h
+++ b/src/common/network/rest/http/ServerConnectionManager.h
@@ -44,6 +44,7 @@ namespace network
ServerConnectionManager() = default;
/// Add the specified connection to the manager and start it.
+ ///
void start(ConnectionPtr c)
{
std::lock_guard guard(m_lock);
@@ -54,6 +55,7 @@ namespace network
}
/// Stop the specified connection.
+ ///
void stop(ConnectionPtr c)
{
std::lock_guard guard(m_lock);
diff --git a/src/fne/network/RESTAPI.cpp b/src/fne/network/RESTAPI.cpp
index 6bea52fb..3e365dcb 100644
--- a/src/fne/network/RESTAPI.cpp
+++ b/src/fne/network/RESTAPI.cpp
@@ -422,9 +422,9 @@ TalkgroupRuleGroupVoice jsonToTG(json::object& req, HTTPPayload& reply)
RESTAPI::RESTAPI(const std::string& address, uint16_t port, const std::string& password,
const std::string& keyFile, const std::string& certFile, bool enableSSL, HostFNE* host, bool debug) :
m_dispatcher(debug),
- m_restServer(address, port),
+ m_restServer(address, port, debug),
#if defined(ENABLE_TCP_SSL)
- m_restSecureServer(address, port),
+ m_restSecureServer(address, port, debug),
m_enableSSL(enableSSL),
#endif // ENABLE_TCP_SSL
m_random(),
diff --git a/src/host/network/RESTAPI.cpp b/src/host/network/RESTAPI.cpp
index 0e413c9b..edc35a6c 100644
--- a/src/host/network/RESTAPI.cpp
+++ b/src/host/network/RESTAPI.cpp
@@ -143,9 +143,9 @@ bool parseRequestBody(const HTTPPayload& request, HTTPPayload& reply, json::obje
RESTAPI::RESTAPI(const std::string& address, uint16_t port, const std::string& password,
const std::string& keyFile, const std::string& certFile, bool enableSSL, Host* host, bool debug) :
m_dispatcher(debug),
- m_restServer(address, port),
+ m_restServer(address, port, debug),
#if defined(ENABLE_TCP_SSL)
- m_restSecureServer(address, port),
+ m_restSecureServer(address, port, debug),
m_enableSSL(enableSSL),
#endif // ENABLE_TCP_SSL
m_random(),