Files
qt-migration-legatus/qt6-after/qt6-migrated-legatus/include/rti/apputils/http/server/Connection.hpp
T

293 lines
8.9 KiB
C++

/*
* (c) Copyright, Real-Time Innovations, 2022.
* All rights reserved.
*
* No duplications, whole or partial, manual or electronic, may be made
* without express written permission. Any such copies, or
* revisions thereof, must display this notice unaltered.
* This code contains trade secrets of Real-Time Innovations, Inc.
*/
#ifndef HTTP_SERVER_CONNECTION_HPP
#define HTTP_SERVER_CONNECTION_HPP
#include <CivetServer.h>
#include <civetweb.h>
#include <nlohmann/json.hpp>
#include "rti/apputils/http/common/HttpUtils.hpp"
#include "rti/apputils/http/common/Response.hpp"
#include "rti/apputils/http/log/Log.hpp"
#include "log.peer.h"
#include "Request.hpp"
namespace rti { namespace apputils { namespace http { namespace server {
/**
* @brief This class implements the interfaces defined by rest::Connection to
* deal with CivetWeb's native connections.
*/
class Connection {
public:
/**
* @brief Constructor of the Connection class. It saves a reference to
* CivetWeb's native connection. It also constructs a Request from
* the connection passed by parameter.
*
* @param conn CivetWeb's connection that is wrapped in this class.
*/
explicit Connection(mg_connection *conn) : conn_(conn), request_(conn_)
{ }
/**
* Destructor of the Connection class.
*/
~Connection()
{ }
/**
* @brief This method returns the HTTP request.
*
* @return The HTTP Request.
*/
const Request& request() const
{
return request_;
}
/**
* @brief This method returns the CivetWeb's native connection.
*
* @return The CivetWeb's native connection.
*/
mg_connection *connection() const
{
return conn_;
}
/**
* @brief This method sends an "Error 501: Not Implemented" response.
*/
void send_not_implemented(std::string const& message = std::string())
{
auto response = Response();
response.http_content_type = HTTP_JSON_CONTENT_TYPE;
response.http_status_code =
static_cast<unsigned short>(StatusCode::not_implemented);
response.http_reason_phrase =
status_code_to_string(StatusCode::not_implemented);
response.http_content = message;
this->send_http_response(response);
}
/**
* @brief This method sends an "OK 204: No Content" response.
*/
void send_http_ok_no_content()
{
auto response = Response();
response.http_content_type = HTTP_JSON_CONTENT_TYPE;
response.http_status_code =
static_cast<unsigned short>(StatusCode::no_content);
response.http_reason_phrase =
status_code_to_string(StatusCode::no_content);
this->send_http_response(response);
}
/**
* @brief This method sends an "Error 400: Bad Request" response.
*/
void send_http_bad_request(std::string const& message = std::string())
{
auto response = Response();
response.http_content_type = HTTP_JSON_CONTENT_TYPE;
response.http_status_code =
static_cast<unsigned short>(StatusCode::bad_request);
response.http_reason_phrase =
status_code_to_string(StatusCode::bad_request);
response.http_content = message;
this->send_http_response(response);
}
/**
* @brief This method sends an "Error 404: Not Found" response.
*/
void send_http_not_found(std::string const& message = std::string())
{
auto response = Response();
response.http_content_type = HTTP_JSON_CONTENT_TYPE;
response.http_status_code =
static_cast<unsigned short>(StatusCode::not_found);
response.http_reason_phrase =
status_code_to_string(StatusCode::not_found);
response.http_content = message;
this->send_http_response(response);
}
/**
* @brief This method sends an "Error 405: Method Not Allowed" response.
*/
void send_http_method_not_allowed(
std::string const& message = std::string())
{
auto response = Response();
response.http_content_type = HTTP_JSON_CONTENT_TYPE;
response.http_status_code =
static_cast<unsigned short>(StatusCode::not_allowed);
response.http_reason_phrase =
status_code_to_string(StatusCode::not_allowed);
response.http_content = message;
this->send_http_response(response);
}
/**
* @brief This method sends an "OK 202: Accepted" response.
*/
void send_http_accepted(std::string const& message = std::string())
{
auto response = Response();
response.http_content_type = HTTP_JSON_CONTENT_TYPE;
response.http_status_code =
static_cast<unsigned short>(StatusCode::accepted);
response.http_reason_phrase =
status_code_to_string(StatusCode::accepted);
response.http_content = message;
this->send_http_response(response);
}
/**
* @brief This method sends an "OK 200: OK" response.
*/
void send_http_ok(std::string const& message = std::string())
{
auto response = Response();
response.http_content_type = HTTP_JSON_CONTENT_TYPE;
response.http_status_code = static_cast<unsigned short>(StatusCode::ok);
response.http_reason_phrase = status_code_to_string(StatusCode::ok);
response.http_content = message;
this->send_http_response(response);
}
/**
* @brief This operation constructs an HTTP response given its definition in
* Response format. Once the Response is constructed, is sent via CivetWeb's
* native APIs.
*/
void send_http_response(const Response& rpns)
{
// Constructs headers and body of the HTTP response.
auto mg_result = mg_printf(
conn_,
"HTTP/%s %u %s\r\n"
"Content-Type: %s\r\n"
"Cache-Control: %s\r\n"
"Content-Length: %lu\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Date: %s\r\n\r\n"
"%s",
HTTP_VERSION,
rpns.http_status_code,
rpns.http_reason_phrase.c_str(),
rpns.http_content_type.c_str(),
HTTP_CACHE_CONTROL_NO_CACHE,
rpns.http_content.length(),
HttpSettings::get_current_date().c_str(),
rpns.http_content.c_str());
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
mg_result >= 0,
msg_server_error_printf);
APPUTILSLogMessage_log(
RTI_LOG_BIT_LOCAL,
&APPUTILS_LOG_HTTP_SENT_RESPONSE_us,
rpns.http_status_code,
rpns.http_reason_phrase.c_str());
}
/**
* @brief Prepares and send the body of an HTTP response given an exception.
*
* @param [in] e Exception to be formatted and sent.
*/
void send_error_exception_response(const HttpException& e)
{
auto response = Response();
response.http_content_type = HTTP_JSON_CONTENT_TYPE;
response.http_status_code = static_cast<unsigned short>(e.error_code());
response.http_reason_phrase = status_code_to_string(e.error_code());
nlohmann::json http_content_json;
http_content_json["code"] = status_code_to_string(e.error_code());
http_content_json["message"] = e.what();
response.http_content = http_content_json.dump();
this->send_http_response(response);
}
/**
* @brief Read the content of an HTTP request.
*
* @param chunk_size size of the chunk to read.
* @return std::string with the read content.
*/
std::string read_content(std::size_t chunk_size = 256)
{
const auto request_info = mg_get_request_info(conn_);
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
request_info != nullptr,
msg_server_error_get_request_info);
if (request_info->content_length >= 0) {
return read_content_with_content_length(
conn_,
static_cast<std::size_t>(request_info->content_length));
}
return read_content_without_content_length(conn_, chunk_size);
}
/**
* @brief Check that content type is the expected one.
*
* @param expected_content_type
* @return true if the content type is the expected one. otherwise
* false.
*/
bool check_content_type(const std::string& expected_content_type)
{
auto ret = true;
// Check if Content-Type is application/json
if (this->request().get_header(
rti::apputils::http::HTTP_CONTENT_TYPE_HEADER)
!= expected_content_type) {
ret = false;
}
return ret;
}
private:
mg_connection *conn_;
Request request_;
};
}}}} // namespace rti::apputils::http::server
#endif // HTTP_SERVER_CONNECTION_HPP