fix #54, this should fix issue #54 in dealing with segmented/fragemented HTTP requests; enhance debug messaging from REST API server;

pull/61/head
Bryan Biedenkapp 2 years ago
parent ad4aa9ac1f
commit e5e5462473

@ -34,6 +34,8 @@ namespace network
struct RequestMatch : std::smatch {
/// <summary>Initializes a new instance of the RequestMatch structure.</summary>
/// <param name="m"></param>
/// <param name="c"></param>
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<void(const Request&, Reply&, const RequestMatch&)> RequestHandlerType;
/// <summary>Initializes a new instance of the RequestMatcher structure.</summary>
/// <param name="expression"></param>
explicit RequestMatcher(const std::string& expression) : m_expression(expression), m_isRegEx(false) { /* stub */ }
/// <summary></summary>
/// <param name="handler"></param>
/// <returns></returns>
RequestMatcher<Request, Reply>& get(RequestHandlerType handler) {
m_handlers[HTTP_GET] = handler;
return *this;
}
/// <summary></summary>
/// <param name="handler"></param>
/// <returns></returns>
RequestMatcher<Request, Reply>& post(RequestHandlerType handler) {
m_handlers[HTTP_POST] = handler;
return *this;
}
/// <summary></summary>
/// <param name="handler"></param>
/// <returns></returns>
RequestMatcher<Request, Reply>& put(RequestHandlerType handler) {
m_handlers[HTTP_PUT] = handler;
return *this;
}
/// <summary></summary>
/// <param name="handler"></param>
/// <returns></returns>
RequestMatcher<Request, Reply>& del(RequestHandlerType handler) {
m_handlers[HTTP_DELETE] = handler;
return *this;
}
/// <summary></summary>
/// <param name="handler"></param>
/// <returns></returns>
RequestMatcher<Request, Reply>& options(RequestHandlerType handler) {
m_handlers[HTTP_OPTIONS] = handler;
return *this;
}
/// <summary></summary>
/// <returns></returns>
bool regex() const { return m_isRegEx; }
/// <summary></summary>
/// <param name="regEx"></param>
void setRegEx(bool regEx) { m_isRegEx = regEx; }
/// <summary></summary>
/// <param name="request"></param>
/// <param name="reply"></param>
/// <param name="what"></param>
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
/// <summary>Initializes a new instance of the RequestDispatcher class.</summary>
RequestDispatcher() : m_basePath(), m_debug(false) { /* stub */ }
/// <summary>Initializes a new instance of the RequestDispatcher class.</summary>
/// <param name="debug"></param>
RequestDispatcher(bool debug) : m_basePath(), m_debug(debug) { /* stub */ }
/// <summary>Initializes a new instance of the RequestDispatcher class.</summary>
/// <param name="basePath"></param>
/// <param name="debug"></param>
RequestDispatcher(const std::string& basePath, bool debug) : m_basePath(basePath), m_debug(debug) { /* stub */ }
/// <summary></summary>
/// <param name="expression"></param>
/// <param name="regex"></param>
/// <returns></returns>
MatcherType& match(const std::string& expression, bool regex = false)
{
MatcherTypePtr& p = m_matchers[expression];
@ -132,6 +158,8 @@ namespace network
}
/// <summary></summary>
/// <param name="request"></param>
/// <param name="reply"></param>
void handleRequest(const Request& request, Reply& reply)
{
for (const auto& matcher : m_matchers) {
@ -194,9 +222,12 @@ namespace network
/// <summary>Initializes a new instance of the DebugRequestDispatcher class.</summary>
BasicRequestDispatcher() { /* stub */ }
/// <summary>Initializes a new instance of the BasicRequestDispatcher class.</summary>
/// <param name="handler"></param>
BasicRequestDispatcher(RequestHandlerType handler) : m_handler(handler) { /* stub */ }
/// <summary></summary>
/// <param name="request"></param>
/// <param name="reply"></param>
void handleRequest(const Request& request, Reply& reply)
{
if (m_handler) {
@ -220,6 +251,8 @@ namespace network
DebugRequestDispatcher() { /* stub */ }
/// <summary></summary>
/// <param name="request"></param>
/// <param name="reply"></param>
void handleRequest(const Request& request, Reply& reply)
{
for (auto header : request.headers.headers())

@ -44,6 +44,8 @@ namespace network
ClientConnection(ClientConnection&) = delete;
/// <summary>Initializes a new instance of the ClientConnection class.</summary>
/// <param name="socket"></param>
/// <param name="handler"></param>
explicit ClientConnection(asio::ip::tcp::socket socket, RequestHandlerType& handler) :
m_socket(std::move(socket)),
m_requestHandler(handler),
@ -86,6 +88,7 @@ namespace network
}
/// <summary>Perform an synchronous write operation.</summary>
/// <param name="request"></param>
void send(HTTPPayload request)
{
request.attachHostHeader(m_socket.remote_endpoint());
@ -134,6 +137,7 @@ namespace network
}
/// <summary>Perform an synchronous write operation.</summary>
/// <param name="request"></param>
void write(HTTPPayload request)
{
try

@ -47,6 +47,8 @@ namespace network
HTTPClient(HTTPClient&) = delete;
/// <summary>Initializes a new instance of the HTTPClient class.</summary>
/// <param name="address"></param>
/// <param name="port"></param>
HTTPClient(const std::string& address, uint16_t port) :
m_address(address),
m_port(port),
@ -66,6 +68,8 @@ namespace network
}
/// <summary>Helper to set the HTTP request handlers.</summary>
/// <typeparam name="Handler"></typeparam>
/// <param name="handler"></param>
template<typename Handler>
void setHandler(Handler&& handler)
{
@ -73,6 +77,8 @@ namespace network
}
/// <summary>Send HTTP request to HTTP server.</summary>
/// <param name="request"></param>
/// <returns></returns>
bool request(HTTPPayload& request)
{
if (m_completed) {
@ -140,6 +146,7 @@ namespace network
}
/// <summary>Perform an asynchronous connect operation.</summary>
/// <param name="endpoints"></param>
void connect(asio::ip::basic_resolver_results<asio::ip::tcp>& endpoints)
{
asio::connect(m_socket, endpoints);

@ -59,6 +59,8 @@ namespace network
/// <summary>Clears the list of HTTP headers.</summary>
void clearHeaders() { m_headers = std::vector<Header>(); }
/// <summary>Helper to add a HTTP header.</summary>
/// <param name="name"></param>
/// <param name="value"></param>
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());
}
/// <summary>Helper to add a HTTP header.</summary>
/// <param name="headerName"></param>
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
}
}
/// <summary>Helper to find the named HTTP header.</summary>
/// <param name="headerName"></param>
std::string find(const std::string headerName) const
{
auto header = std::find_if(m_headers.begin(), m_headers.end(), [&](const Header& 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
*
*/
#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()
/// <returns></returns>
HTTPLexer::ResultType HTTPLexer::consume(HTTPPayload& req, char input)
{
m_consumed++;
switch (m_state)
{
/*

@ -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 };
/// <summary>Initializes a new instance of the HTTPLexer class.</summary>
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.</summary>
/// <typeparam name="InputIterator"></typeparam>
/// <param name="payload"></param>
/// <param name="begin"></param>
/// <param name="end"></param>
/// <returns></returns>
template <typename InputIterator>
std::tuple<ResultType, InputIterator> parse(HTTPPayload& payload, InputIterator begin, InputIterator end)
{
@ -63,6 +68,9 @@ namespace network
return std::make_tuple(INDETERMINATE, begin);
}
/// <summary></summary>
uint32_t consumed() const { return m_consumed; }
private:
/// <summary>Handle the next character of input.</summary>
ResultType consume(HTTPPayload& payload, char input);
@ -88,6 +96,7 @@ namespace network
std::vector<LexedHeader> m_headers;
uint16_t m_status;
bool m_clientLexer = false;
uint32_t m_consumed;
enum state
{

@ -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;

@ -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;
/// <summary>Initializes a new instance of the HTTPServer class.</summary>
explicit HTTPServer(const std::string& address, uint16_t port) :
/// <param name="address"></param>
/// <param name="port"></param>
/// <param name="debug"></param>
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
}
/// <summary>Helper to set the HTTP request handlers.</summary>
/// <typeparam name="Handler"></typeparam>
/// <param name="handler"></param>
template<typename Handler>
void setHandler(Handler&& handler)
{
@ -112,7 +118,7 @@ namespace network
}
if (!ec) {
m_connectionManager.start(std::make_shared<ConnectionType>(std::move(m_socket), m_connectionManager, m_requestHandler));
m_connectionManager.start(std::make_shared<ConnectionType>(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

@ -47,6 +47,9 @@ namespace network
SecureClientConnection(SecureClientConnection&) = delete;
/// <summary>Initializes a new instance of the SecureClientConnection class.</summary>
/// <param name="socket"></param>
/// <param name="context"></param>
/// <param name="handler"></param>
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
}
/// <summary>Perform an synchronous write operation.</summary>
/// <param name="request"></param>
void send(HTTPPayload request)
{
request.attachHostHeader(m_socket.lowest_layer().remote_endpoint());
@ -101,6 +105,8 @@ namespace network
}
private:
/// <summary>Perform an SSL certificate verification.</summary>
/// <param name="preverified"></param>
/// <param name="context"></param>
bool verify_certificate(bool preverified, asio::ssl::verify_context& context)
{
return true; // ignore always valid
@ -148,6 +154,7 @@ namespace network
}
/// <summary>Perform an synchronous write operation.</summary>
/// <param name="request"></param>
void write(HTTPPayload request)
{
try

@ -50,6 +50,8 @@ namespace network
SecureHTTPClient(SecureHTTPClient&) = delete;
/// <summary>Initializes a new instance of the SecureHTTPClient class.</summary>
/// <param name="address"></param>
/// <param name="port"></param>
SecureHTTPClient(const std::string& address, uint16_t port) :
m_address(address),
m_port(port),
@ -70,6 +72,8 @@ namespace network
}
/// <summary>Helper to set the HTTP request handlers.</summary>
/// <typeparam name="Handler"></param>
/// <param name="handler"></param>
template<typename Handler>
void setHandler(Handler&& handler)
{
@ -77,6 +81,7 @@ namespace network
}
/// <summary>Send HTTP request to HTTP server.</summary>
/// <param name="request"></param>
bool request(HTTPPayload& request)
{
if (m_completed) {
@ -144,6 +149,7 @@ namespace network
}
/// <summary>Perform an asynchronous connect operation.</summary>
/// <param name="endpoints"></param>
void connect(asio::ip::basic_resolver_results<asio::ip::tcp>& endpoints)
{
asio::connect(m_socket, endpoints);

@ -51,19 +51,25 @@ namespace network
SecureHTTPServer(SecureHTTPServer&) = delete;
/// <summary>Initializes a new instance of the SecureHTTPServer class.</summary>
explicit SecureHTTPServer(const std::string& address, uint16_t port) :
/// <param name="address"></param>
/// <param name="port"></param>
/// <param name="debug"></param>
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);
}
/// <summary>Helper to set the SSL certificate and private key.</summary>
/// <param name="keyFile"></param>
/// <param name="certFile"></param>
bool setCertAndKey(const std::string& keyFile, const std::string& certFile)
{
try
@ -79,6 +85,8 @@ namespace network
}
/// <summary>Helper to set the HTTP request handlers.</summary>
/// <typeparam name="Handler"></typeparam>
/// <param name="handler"></param>
template<typename Handler>
void setHandler(Handler&& handler)
{
@ -130,7 +138,7 @@ namespace network
}
if (!ec) {
m_connectionManager.start(std::make_shared<ConnectionType>(std::move(m_socket), m_context, m_connectionManager, m_requestHandler));
m_connectionManager.start(std::make_shared<ConnectionType>(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

@ -58,13 +58,22 @@ namespace network
SecureServerConnection(SecureServerConnection&) = delete;
/// <summary>Initializes a new instance of the SecureServerConnection class.</summary>
/// <param name="socket"></param>
/// <param name="context"></param>
/// <param name="manager"></param>
/// <param name="handler"></param>
/// <param name="persistent"></param>
/// <param name="debug"></param>
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

@ -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 <array>
#include <memory>
@ -55,13 +56,21 @@ namespace network
ServerConnection(ServerConnection&) = delete;
/// <summary>Initializes a new instance of the ServerConnection class.</summary>
/// <param name="socket"></param>
/// <param name="manager"></param>
/// <param name="handler"></param>
/// <param name="persistent"></param>
/// <param name="debug"></param>
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

@ -44,6 +44,7 @@ namespace network
ServerConnectionManager() = default;
/// <summary>Add the specified connection to the manager and start it.</summary>
/// <param name="c"></param>
void start(ConnectionPtr c)
{
std::lock_guard<std::mutex> guard(m_lock);
@ -54,6 +55,7 @@ namespace network
}
/// <summary>Stop the specified connection.</summary>
/// <param name="c"></param>
void stop(ConnectionPtr c)
{
std::lock_guard<std::mutex> guard(m_lock);

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

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

Loading…
Cancel
Save

Powered by TurnKey Linux.