1
0
Fork 0
mirror of https://github.com/KingDuckZ/kamokan.git synced 2025-01-17 20:06:35 +00:00
kamokan/src/tawashi_implem/http_header.cpp
King_DuckZ cdd23d35d0 Make on_process() return an HttpHeader.
Response type is now decided by on_process' return value.
2017-05-18 19:17:22 +01:00

153 lines
5.3 KiB
C++

/* Copyright 2017, Michele Santullo
* This file is part of "tawashi".
*
* "tawashi" is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* "tawashi" is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with "tawashi". If not, see <http://www.gnu.org/licenses/>.
*/
#include "http_header.hpp"
#include "duckhandy/lexical_cast.hpp"
#include "duckhandy/sequence_bt.hpp"
#include "sprout/array/array.hpp"
#include <utility>
#include <spdlog/spdlog.h>
namespace tawashi {
namespace {
constexpr const char* get_status_code_desc (HttpStatusCodes parCode) {
switch (parCode) {
case HttpStatusCodes::Code301_MovedPermanently: return "Moved Permanently";
case HttpStatusCodes::Code302_Found: return "Found";
case HttpStatusCodes::Code303_SeeOther: return "See Other";
case HttpStatusCodes::Code400_BadRequest: return "Bad Request";
case HttpStatusCodes::Code403_Forbidden: return "Forbidden";
case HttpStatusCodes::Code404_NotFound: return "Not Found";
case HttpStatusCodes::Code413_PayloadTooLarge: return "Payload Too Large";
case HttpStatusCodes::Code429_TooManyRequests: return "Too Many Requests";
case HttpStatusCodes::Code431_RequestHeaderFieldsTooLarge: return "Request Header Fields Too Large";
case HttpStatusCodes::Code500_InternalServerError: return "Internal Server Error";
case HttpStatusCodes::Code501_NotImplemented: return "Not Implemented";
case HttpStatusCodes::Code503_ServiceUnavailable: return "Service Unavailable";
}
return "INVALID STATUS CODE";
}
inline constexpr uint16_t single_status_code_to_code (const char* parCode) {
std::size_t idx = 0;
uint16_t ret_num = 0;
uint16_t digits = 0;
char cur_char = 0;
while ((cur_char = parCode[idx++]) and digits < 3) {
if (cur_char >= '0' and cur_char <= '9') {
uint16_t multip = 1;
for (uint16_t z = 1; z < (3 - digits); ++z) {
multip *= 10;
}
ret_num += multip * (cur_char - '0');
++digits;
}
}
return ret_num;
}
template <int... Values>
inline constexpr sprout::array<uint16_t, sizeof...(Values)> make_status_codes_lookup (dhandy::bt::number_seq<int, Values...>) {
return sprout::array<uint16_t, sizeof...(Values)> {
single_status_code_to_code(HttpStatusCodes::_names()[Values])...
};
}
uint16_t status_code_name_to_num (HttpStatusCodes parCode) {
constexpr const auto status_codes = make_status_codes_lookup(dhandy::bt::number_range<int, 0, HttpStatusCodes::_size() - 1>());
return status_codes[parCode._to_integral()];
}
constexpr auto g_status_code_descriptions = ::better_enums::make_map(get_status_code_desc);
} //unnamed namespace
HttpHeader::HttpHeader() :
m_param("text/html"),
m_status_code(HttpStatusCodes::CodeNone),
m_header_type(ContentType)
{
}
HttpHeader::HttpHeader (Types parType, HttpStatusCodes parCode, std::string&& parParam) :
m_param(std::move(parParam)),
m_status_code(parCode),
m_header_type(parType)
{
}
void HttpHeader::set_status (HttpStatusCodes parCode) {
m_status_code = parCode;
}
void HttpHeader::unset_status() {
m_status_code = HttpStatusCodes::CodeNone;
}
void HttpHeader::set_type (Types parType, std::string&& parParameter) {
m_header_type = parType;
m_param = std::move(parParameter);
}
std::ostream& operator<< (std::ostream& parStream, const HttpHeader& parHeader) {
const HttpStatusCodes code_none = HttpStatusCodes::CodeNone;
if (parHeader.status_code() != code_none) {
parStream <<
"Status: " <<
status_code_name_to_num(parHeader.status_code()) <<
g_status_code_descriptions[parHeader.status_code()] <<
'\n'
;
}
switch (parHeader.type()) {
case HttpHeader::ContentType:
SPDLOG_TRACE(spdlog::get("statuslog"), "Response is a Content-type (data)");
parStream << "Content-type: " << parHeader.parameter() << '\n';
break;
case HttpHeader::Location:
SPDLOG_TRACE(spdlog::get("statuslog"), "Response is a Location (redirect)");
parStream << "Location: " << parHeader.parameter() << '\n';
break;
}
parStream << '\n';
return parStream;
}
HttpHeader make_header_type_html() {
return HttpHeader(HttpHeader::ContentType, HttpStatusCodes::CodeNone, "text/html");
}
HttpHeader make_header_type_text_utf8() {
return HttpHeader(HttpHeader::ContentType, HttpStatusCodes::CodeNone, "text/plain; charset=utf-8");
}
HttpStatusCodes int_to_status_code (uint16_t parCode) {
constexpr const auto status_codes = make_status_codes_lookup(dhandy::bt::number_range<int, 0, HttpStatusCodes::_size() - 1>());
auto it_found_code = std::find(status_codes.begin(), status_codes.end(), parCode);
if (it_found_code != status_codes.end()) {
const auto index = it_found_code - status_codes.begin();
assert(index < HttpStatusCodes::_size() - 1);
return HttpStatusCodes::_from_integral(index);
}
else {
return HttpStatusCodes::CodeNone;
}
}
bool HttpHeader::body_required() const {
return type() == ContentType;
}
} //namespace tawashi