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(),