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

168 lines
4.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_UTILS_H
#define HTTP_UTILS_H
#include <ctime>
#include <cstring>
#include <unordered_map>
#include <civetweb.h>
#include <reda/reda_string.h>
#include <dds_c/dds_c_printformat.h>
#include "HttpException.hpp"
#include "StatusCode.hpp"
namespace rti { namespace apputils { namespace http {
using StringMap = std::unordered_map<std::string, std::string>;
// Unfortunately Civetweb doesn't expose these constants, so we needed to
// copy the values from civetweb.c (static struct mg_option config_options[])
constexpr auto HTTP_CLIENT_TIMEOUT_MS = int { 1000 };
constexpr auto HTTP_SERVER_DEFAULT_PORT = int { 8080 };
constexpr auto HTTP_SERVER_DEFAULT_PORT_STR = "8080";
constexpr auto HTTP_SERVER_DEFAULT_HOST = "127.0.0.1";
constexpr auto HTTP_VERSION = "1.1";
constexpr auto HTTP_CACHE_CONTROL_NO_CACHE = "no-cache";
constexpr auto HTTP_BODY_INITIAL_LENGTH = std::size_t { 1000 };
constexpr auto HTTP_PLAIN_TEXT_CONTENT_TYPE = "text/plain";
constexpr auto HTTP_JSON_CONTENT_TYPE = "application/json";
constexpr auto HTTP_XML_CONTENT_TYPE = "application/xml";
constexpr auto HTTP_CONTENT_TYPE_HEADER = "Content-Type";
constexpr auto HTTP_DATE_STR_LENGTH = std::size_t { 64 };
/**
* Maximum URL length we handle is 2048. This value is based on the
* comments on this article http://stackoverflow.com/questions/417142
*/
constexpr auto MAX_URI_LENGTH = int { 2048 };
/**
* @brief This structure contains utility methods to generate HttpSettings that
* need to be set as part of the HTTP response.
*/
struct HttpSettings {
/**
* @brief This method converts time_t to a string. According to RFC2616,
* Sec 14.18, this must be included in all responses other than
* 100, 101, 5xx.
*
* @return A string containing the date in the format specified by RFC2616.
*/
static std::string get_current_date()
{
const auto curtime = std::time(nullptr);
if (curtime == (time_t) -1) {
return "Thu, 01 Jan 1970 00:00:00 GMT";
}
struct tm curr_tm;
#ifdef RTI_WIN32
if (gmtime_s(&curr_tm, &curtime) != 0) {
return "Thu, 01 Jan 1970 00:00:00 GMT";
}
#else
if (gmtime_r(&curtime, &curr_tm) != &curr_tm) {
return "Thu, 01 Jan 1970 00:00:00 GMT";
}
#endif
auto result = std::string(HTTP_DATE_STR_LENGTH, '\0');
const auto bytes_written = std::strftime(
&result[0],
result.size(),
"%a, %d %b %Y %H:%M:%S GMT",
&curr_tm);
RTI_SERVICE_CHECK_CONDITION_W_EXTRA_INFO(
bytes_written > 0,
"Error in std::strftime");
result.resize(bytes_written);
return result;
}
};
inline std::string read_content_with_content_length(
mg_connection *connection,
std::size_t content_length)
{
auto content = std::string(content_length, 0);
auto result = 0;
while (content_length > 0 && result >= 0) {
result = mg_read(connection,
&content[content.size() - content_length],
content_length);
content_length -= result;
}
return content;
}
inline std::string read_content_without_content_length(
mg_connection *connection,
std::size_t chunk_size = 256)
{
auto content = std::string();
auto bytes_read = std::size_t { 0 };
auto result = 0;
do {
bytes_read += result;
content.resize(bytes_read + chunk_size);
result = mg_read(connection, &content[bytes_read], chunk_size);
} while (result > 0);
content.resize(bytes_read);
return content;
}
inline std::string base64_encode(const std::string& in)
{
std::string out;
out.reserve(in.size() * 2);
const char *b64 =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
for (std::size_t i = 0; i < in.size(); i += 3) {
// Static cast to unsigned char to avoid cert_str34_c_violation
int a = static_cast<unsigned char>(in[i]);
int b = i + 1 >= in.size() ? 0 : static_cast<unsigned char>(in[i + 1]);
int c = i + 2 >= in.size() ? 0 : static_cast<unsigned char>(in[i + 2]);
out.push_back(b64[a >> 2]);
out.push_back(b64[((a & 3) << 4) | (b >> 4)]);
if (i + 1 < in.size()) {
out.push_back(b64[(b & 15) << 2 | (c >> 6)]);
}
if (i + 2 < in.size()) {
out.push_back(b64[c & 63]);
}
}
while (out.size() % 4 != 0) {
out.push_back('=');
}
out.shrink_to_fit();
return out;
}
}}} // namespace rti::apputils::http
#endif // HTTP_UTILS_H