233 lines
6.9 KiB
C++
233 lines
6.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_REQUEST_HPP
|
|
#define HTTP_SERVER_REQUEST_HPP
|
|
|
|
#include <string>
|
|
#include <cstring>
|
|
|
|
#include <CivetServer.h>
|
|
#include <civetweb.h>
|
|
|
|
#include "rti/apputils/StringBuffer.hpp"
|
|
#include "rti/apputils/http/common/Method.hpp"
|
|
#include "rti/apputils/http/common/HttpException.hpp"
|
|
|
|
namespace rti { namespace apputils { namespace http { namespace server {
|
|
|
|
/**
|
|
* @brief This class implements the Request to handle Requests, that is
|
|
* requests provided by the CivetWeb server.
|
|
*/
|
|
class Request {
|
|
public:
|
|
/**
|
|
* @brief Constructor of the Request. Retrieves information from the
|
|
* mg_request_info provided by CivetWeb's connection.
|
|
*
|
|
* @param conn Civetweb's connection.
|
|
*/
|
|
explicit Request(mg_connection *conn) : conn_(conn)
|
|
{ }
|
|
|
|
/**
|
|
* @brief Destructor of the Request class.
|
|
*/
|
|
~Request()
|
|
{ }
|
|
|
|
/**
|
|
* @brief Returns the URL of CivetWeb's request.
|
|
*
|
|
* @return URL of the HTTP request.
|
|
*/
|
|
const char *uri() const
|
|
{
|
|
const auto req = mg_get_request_info(conn_);
|
|
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
|
|
req != nullptr,
|
|
msg_server_error_get_request_info);
|
|
|
|
return req->local_uri;
|
|
}
|
|
|
|
/**
|
|
* @brief Gets a URI parameter given its name.
|
|
*
|
|
* @param value The value of the parameter.
|
|
* @param name of the parameter to be retrieved.
|
|
* @return Indicates whether the parameter was found.
|
|
*/
|
|
bool uri_param(std::string& value, const std::string& name) const
|
|
{
|
|
const auto req = mg_get_request_info(conn_);
|
|
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
|
|
req != nullptr,
|
|
msg_server_error_get_request_info);
|
|
if (req->query_string == nullptr) {
|
|
return false;
|
|
}
|
|
return CivetServer::getParam(req->query_string, name.c_str(), value);
|
|
}
|
|
|
|
/**
|
|
* @brief Constructs a map with the query parameters in a given URI.
|
|
*
|
|
* @param params Map with decoded names and values of all the query
|
|
* parameters in the URI.
|
|
* @return Boolean value indicating whether query parameters were retrieved
|
|
* or not.
|
|
*/
|
|
bool uri_params(StringMap& params) const
|
|
{
|
|
const auto req = mg_get_request_info(conn_);
|
|
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
|
|
req != nullptr,
|
|
msg_server_error_get_request_info);
|
|
|
|
if (req->query_string == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
const auto query_string = req->query_string;
|
|
auto query_string_length = strlen(query_string);
|
|
auto i = std::size_t { 0 };
|
|
|
|
while (i < query_string_length) {
|
|
// Get Name
|
|
auto i0 = i;
|
|
while ((i < query_string_length) && query_string[i] != '='
|
|
&& query_string[i] != '&') {
|
|
i++;
|
|
}
|
|
auto name = std::string();
|
|
CivetServer::urlDecode(&query_string[i0], i - i0, name, true);
|
|
if (i < query_string_length && query_string[i] == '=') {
|
|
i++;
|
|
}
|
|
|
|
// Get Value
|
|
i0 = i;
|
|
while ((i < query_string_length) && query_string[i] != '&') {
|
|
i++;
|
|
}
|
|
|
|
auto value = std::string();
|
|
CivetServer::urlDecode(&query_string[i0], i - i0, value, true);
|
|
if (i < query_string_length && query_string[i] == '&') {
|
|
i++;
|
|
}
|
|
|
|
// Add key-value pair to the map
|
|
params[name] = value;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @brief Gets a URI header given its name.
|
|
*
|
|
* @param Name of the header to be retrieved.
|
|
* @return Gets the value of an HTTP header given its name.
|
|
*/
|
|
const char *get_header(const char *name) const
|
|
{
|
|
const char *value = mg_get_header(conn_, name);
|
|
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
|
|
value != nullptr,
|
|
msg_server_error_get_header);
|
|
|
|
return value;
|
|
}
|
|
|
|
/**
|
|
* @brief This method saves the body of the HTTP request in the body buffer.
|
|
*
|
|
* @param [out] Body of the HTTP request.
|
|
* @param [in,out] Length of the body of the HTTP request.
|
|
*/
|
|
void get_body(char *& body, size_t& body_length) const
|
|
{
|
|
auto mg_result = mg_read(conn_, body, body_length);
|
|
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
|
|
mg_result >= 0,
|
|
msg_server_error_read);
|
|
}
|
|
|
|
/**
|
|
* @brief Saves the body of the HTTP request in a string buffer.
|
|
*
|
|
* @param [out] Body of the HTTP request in StringBuffer.
|
|
*/
|
|
void get_body(StringBuffer& body) const
|
|
{
|
|
const auto body_length = get_body_length();
|
|
body.ensure_capacity(body_length + 1);
|
|
|
|
auto mg_result = mg_read(conn_, body.c_str_ptr(), body_length);
|
|
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
|
|
mg_result >= 0,
|
|
msg_server_error_read);
|
|
}
|
|
|
|
/**
|
|
* @brief Returns the length of the body of the HTTP request.
|
|
*
|
|
* @return Body length.
|
|
*/
|
|
size_t get_body_length() const
|
|
{
|
|
const auto req = mg_get_request_info(conn_);
|
|
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
|
|
req != nullptr,
|
|
msg_server_error_get_request_info);
|
|
|
|
auto content_length = req->content_length;
|
|
|
|
// Check that the content_length is not negative (except for GET,
|
|
// DELETE, and PUT operations) where it is permitted.
|
|
if ((content_length < 0) && (strcmp(req->request_method, "GET") != 0)
|
|
&& (strcmp(req->request_method, "DELETE") != 0)
|
|
&& (strcmp(req->request_method, "PUT") != 0)) {
|
|
RTI_THROW_HTTP_EXCEPTION(
|
|
StatusCode::bad_request,
|
|
&RTI_LOG_ANY_FAILURE_s,
|
|
"Content-length of the HTTP request is invalid.");
|
|
}
|
|
|
|
return content_length < 0 ? 0 : static_cast<size_t>(content_length);
|
|
}
|
|
|
|
/**
|
|
* @brief Returns the method of the HTTP request.
|
|
*
|
|
* @return Method of the HTTP request.
|
|
*/
|
|
Method get_http_method() const
|
|
{
|
|
const struct mg_request_info *req = mg_get_request_info(conn_);
|
|
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
|
|
req != nullptr,
|
|
msg_server_error_get_request_info);
|
|
|
|
return method_from_string(
|
|
req->request_method == nullptr ? "" : req->request_method);
|
|
}
|
|
|
|
private:
|
|
struct mg_connection *conn_;
|
|
};
|
|
|
|
}}}} // namespace rti::apputils::http::server
|
|
|
|
#endif // HTTP_SERVER_REQUEST_HPP
|