cleanup of source + build system

* seperated most parts into headers & source files
* seperated anthracite into libanthracite and anthracite-bin for modules
* built demo webAPI module
* rewrote some code to do things in the
* changed cmakelists to not build in src directory
This commit is contained in:
Nicholas Orlowsky 2025-02-04 02:03:27 -05:00
parent c4540a1397
commit 54d82b8c66
Signed by: nickorlow
GPG key ID: 838827D8C4611687
26 changed files with 607 additions and 378 deletions

View file

@ -1,9 +1,13 @@
#pragma once
#include <string>
#include <unordered_map>
constexpr int HTTP_HEADER_BYTES = 8190;
namespace anthracite::http {
enum http_method {
constexpr int HEADER_BYTES = 8190;
enum method {
GET,
POST,
DELETE,
@ -24,7 +28,7 @@ enum http_method {
UNKNOWN
};
enum http_status_codes {
enum status_codes {
CONTINUE = 100,
SWITCHING_PROTOCOLS = 101,
PROCESSING = 102,
@ -90,49 +94,49 @@ enum http_status_codes {
NETWORK_AUTHENTICATION_REQUIRED = 511
};
static std::unordered_map<std::string, http_method> const http_method_map = {
{ "GET", http_method::GET },
{ "POST", http_method::POST },
{ "DELETE", http_method::DELETE },
{ "PUT", http_method::PUT },
{ "PATCH", http_method::PATCH },
{ "HEAD", http_method::HEAD },
{ "OPTIONS", http_method::OPTIONS },
{ "CONNECT", http_method::CONNECT },
{ "TRACE", http_method::TRACE },
{ "COPY", http_method::COPY },
{ "LINK", http_method::LINK },
{ "UNLINK", http_method::UNLINK },
{ "PURGE", http_method::PURGE },
{ "LOCK", http_method::LOCK },
{ "UNLOCK", http_method::UNLOCK },
{ "PROPFIND", http_method::PROPFIND },
{ "VIEW", http_method::VIEW },
{ "UNKNOWN", http_method::UNKNOWN }
static std::unordered_map<std::string, method> const method_map = {
{ "GET", method::GET },
{ "POST", method::POST },
{ "DELETE", method::DELETE },
{ "PUT", method::PUT },
{ "PATCH", method::PATCH },
{ "HEAD", method::HEAD },
{ "OPTIONS", method::OPTIONS },
{ "CONNECT", method::CONNECT },
{ "TRACE", method::TRACE },
{ "COPY", method::COPY },
{ "LINK", method::LINK },
{ "UNLINK", method::UNLINK },
{ "PURGE", method::PURGE },
{ "LOCK", method::LOCK },
{ "UNLOCK", method::UNLOCK },
{ "PROPFIND", method::PROPFIND },
{ "VIEW", method::VIEW },
{ "UNKNOWN", method::UNKNOWN }
};
static std::unordered_map<http_method, std::string> const http_reverse_method_map = {
{ http_method::GET, "GET" },
{ http_method::POST, "POST" },
{ http_method::DELETE, "DELETE" },
{ http_method::PUT, "PUT" },
{ http_method::PATCH, "PATCH" },
{ http_method::HEAD, "HEAD" },
{ http_method::OPTIONS, "OPTIONS" },
{ http_method::CONNECT, "CONNECT" },
{ http_method::TRACE, "TRACE" },
{ http_method::COPY, "COPY" },
{ http_method::LINK, "LINK" },
{ http_method::UNLINK, "UNLINK" },
{ http_method::PURGE, "PURGE" },
{ http_method::LOCK, "LOCK" },
{ http_method::UNLOCK, "UNLOCK" },
{ http_method::PROPFIND, "PROPFIND" },
{ http_method::VIEW, "VIEW" },
{ http_method::UNKNOWN, "UNKNOWN" }
static std::unordered_map<method, std::string> const reverse_method_map = {
{ method::GET, "GET" },
{ method::POST, "POST" },
{ method::DELETE, "DELETE" },
{ method::PUT, "PUT" },
{ method::PATCH, "PATCH" },
{ method::HEAD, "HEAD" },
{ method::OPTIONS, "OPTIONS" },
{ method::CONNECT, "CONNECT" },
{ method::TRACE, "TRACE" },
{ method::COPY, "COPY" },
{ method::LINK, "LINK" },
{ method::UNLINK, "UNLINK" },
{ method::PURGE, "PURGE" },
{ method::LOCK, "LOCK" },
{ method::UNLOCK, "UNLOCK" },
{ method::PROPFIND, "PROPFIND" },
{ method::VIEW, "VIEW" },
{ method::UNKNOWN, "UNKNOWN" }
};
static std::unordered_map<int, std::string> const http_status_map = {
static std::unordered_map<int, std::string> const status_map = {
{ 100, "CONTINUE" },
{ 101, "SWITCHING PROTOCOLS" },
{ 200, "OK" },
@ -196,6 +200,7 @@ static std::unordered_map<std::string, std::string> const mime_types = {
{ "css", "text/css" },
{ "js", "application/javascript" },
{ "json", "application/json" },
{ "pdf", "application/pdf" },
{ "ico", "image/x-icon" },
@ -212,13 +217,13 @@ static std::unordered_map<std::string, std::string> const mime_types = {
{ "wmv", "video/x-ms-wmv" },
};
enum http_version { HTTP_0_9,
enum version { HTTP_0_9,
HTTP_1_0,
HTTP_1_1,
HTTP_2_0,
HTTP_3_0 };
static std::unordered_map<std::string, http_version> const http_version_map = {
static std::unordered_map<std::string, version> const version_map = {
// This is because HTTP 0.9 didn't specify version in the header
{ "", HTTP_0_9 },
{ "HTTP/0.9", HTTP_0_9 },
@ -228,7 +233,7 @@ static std::unordered_map<std::string, http_version> const http_version_map = {
{ "HTTP/3.0", HTTP_3_0 }
};
static std::unordered_map<http_version, std::string> const http_reverse_version_map = {
static std::unordered_map<version, std::string> const reverse_version_map = {
{ HTTP_0_9, "HTTP/0.9" },
{ HTTP_1_0, "HTTP/1.0" },
{ HTTP_1_1, "HTTP/1.1" },
@ -236,6 +241,4 @@ static std::unordered_map<http_version, std::string> const http_reverse_version_
{ HTTP_3_0, "HTTP/3.0" }
};
};

View file

@ -1,5 +1,8 @@
#pragma once
#include <string>
namespace anthracite::http {
class name_value {
private:
std::string _name;
@ -26,13 +29,13 @@ public:
virtual std::string to_string() { return ""; }
};
class http_header : public name_value {
class header : public name_value {
public:
http_header()
header()
: name_value()
{
}
http_header(std::string name, std::string value)
header(std::string name, std::string value)
: name_value(name, value)
{
}
@ -53,3 +56,5 @@ public:
std::string to_string() override { return name() + "=" + value(); }
};
};

View file

@ -1,8 +0,0 @@
#pragma once
#include <string>
#include <unordered_map>
#include "constants.cpp"
#include "header_query.cpp"
#include "../socket.cpp"
#include "../build/version.cpp"

View file

@ -1,61 +0,0 @@
#include "http.hpp"
class http_response {
private:
int _status_code;
std::string& _content;
std::string _filename;
std::unordered_map<std::string, http_header> _headers; // kinda goofy, whatever
public:
http_response(std::string& content, std::string filename, int status_code = http_status_codes::OK)
: _content(content)
, _status_code(status_code)
, _filename(std::move(filename))
{
}
int status_code() { return _status_code; }
void add_header(http_header header, bool override_existing = true)
{
if (override_existing || _headers.find(header.name()) == _headers.end()) {
_headers[header.name()] = header;
}
}
std::string& content()
{
return _content;
}
std::string header_to_string()
{
std::string response = "";
response += "HTTP/1.1 " + std::to_string(_status_code) + " " + http_status_map.find(_status_code)->second + "\r\n";
std::string content_type = "text/html";
std::string file_extension = _filename.substr(_filename.rfind('.') + 1);
auto mime_type = mime_types.find(file_extension);
if (mime_type != mime_types.end()) {
content_type = mime_type->second;
}
add_header(http_header("Content-Type", content_type), false);
add_header(http_header("Content-Length", std::to_string(_content.length())), false);
add_header(http_header("Server", ANTHRACITE_FULL_VERSION_STRING), false);
add_header(http_header("Origin-Server", ANTHRACITE_FULL_VERSION_STRING), false);
for (auto header : _headers) {
response += header.second.to_string();
}
response += "\r\n";
return response;
}
std::string to_string()
{
return header_to_string() + _content;
}
};

View file

@ -1,25 +1,11 @@
#include "http.hpp"
#include "request.hpp"
#include "constants.hpp"
#include "../log/log.hpp"
#include <stdio.h>
class http_request {
private:
enum parser_state { METHOD,
PATH,
QUERY_PARAM_NAME,
QUERY_PARAM_VALUE,
VERSION,
HEADER_NAME,
HEADER_VALUE,
BODY_CONTENT };
http_method _method;
http_version _http_version;
std::string _path;
std::string _client_ipaddr;
std::string _body_content;
std::unordered_map<std::string, http_header> _headers; // kinda goofy, whatever
std::unordered_map<std::string, query_param> _query_params; // kinda goofy, whatever
namespace anthracite::http {
public:
http_request(std::string& raw_data, std::string client_ip)
request::request(std::string& raw_data, const std::string& client_ip)
: _path(""), _client_ipaddr(client_ip)
{
@ -31,10 +17,10 @@ public:
switch (state) {
case METHOD: {
if (raw_data[i] == ' ') {
if (http_method_map.find(scratch) == http_method_map.end()) {
_method = http_method::UNKNOWN;
if (method_map.find(scratch) == method_map.end()) {
_method = method::UNKNOWN;
} else {
_method = http_method_map.find(scratch)->second;
_method = method_map.find(scratch)->second;
}
scratch = "";
state = PATH;
@ -86,7 +72,7 @@ public:
case VERSION: {
if (raw_data[i] == '\n') {
_http_version = http_version_map.find(scratch)->second;
_http_version = version_map.find(scratch)->second;
scratch = "";
state = HEADER_NAME;
} else if (raw_data[i] != '\r') {
@ -113,7 +99,7 @@ public:
case HEADER_VALUE: {
if (raw_data[i] == '\n') {
_headers[scratch] = http_header(scratch, scratch_2);
_headers[scratch] = header(scratch, scratch_2);
scratch = "";
scratch_2 = "";
state = HEADER_NAME;
@ -129,21 +115,22 @@ public:
}
}
std::string path() { return _path; }
std::string request::path() { return _path; }
http_method method() { return _method; }
method request::get_method() { return _method; }
std::string client_ip() { return _client_ipaddr; }
std::string request::client_ip() { return _client_ipaddr; }
http_version get_http_version() {
version request::get_http_version() {
return _http_version;
}
bool is_supported_version() {
return _http_version == HTTP_1_1 || _http_version == HTTP_1_0;
bool request::is_supported_version() {
//log::err << reverse_version_map.find(_http_version)->second << std::endl;
return _http_version == HTTP_1_1 || _http_version == HTTP_1_0;
}
bool close_connection() {
bool request::close_connection() {
const auto& header = _headers.find("Connection");
const bool found = header != _headers.end();
@ -154,16 +141,16 @@ public:
return true;
}
std::string to_string()
std::string request::to_string()
{
std::string response = "";
response += http_reverse_method_map.find(_method)->second + " " + _path + "?";
response += reverse_method_map.find(_method)->second + " " + _path + "?";
for (auto qp : _query_params) {
response += qp.second.to_string() + "&";
}
response += " " + http_reverse_version_map.find(_http_version)->second + "\r\n";
response += " " + reverse_version_map.find(_http_version)->second + "\r\n";
for (auto header : _headers) {
response += header.second.to_string();
@ -174,4 +161,5 @@ public:
return response;
}
};

39
src/http/request.hpp Normal file
View file

@ -0,0 +1,39 @@
#pragma once
#include <string>
#include <unordered_map>
#include "./header_query.hpp"
#include "./constants.hpp"
namespace anthracite::http {
class request {
private:
enum parser_state { METHOD,
PATH,
QUERY_PARAM_NAME,
QUERY_PARAM_VALUE,
VERSION,
HEADER_NAME,
HEADER_VALUE,
BODY_CONTENT };
method _method;
version _http_version;
std::string _path;
std::string _client_ipaddr;
std::string _body_content;
std::unordered_map<std::string, header> _headers; // kinda goofy, whatever
std::unordered_map<std::string, query_param> _query_params; // kinda goofy, whatever
public:
request(std::string& raw_data, const std::string& client_ip);
std::string path();
method get_method();
std::string client_ip();
version get_http_version();
bool is_supported_version();
bool close_connection();
std::string to_string();
};
};

58
src/http/response.cpp Normal file
View file

@ -0,0 +1,58 @@
#include "response.hpp"
#include "../build_supp/version.cpp"
namespace anthracite::http {
response::response() {};
int response::status_code() { return _status_code; }
void response::add_body(const std::string body) {
_content_noref = body;
_content = &_content_noref;
}
void response::add_body_ref(std::string* body) {
_content = body;
}
void response::add_header(header header, bool override_existing)
{
if (override_existing || _headers.find(header.name()) == _headers.end()) {
_headers[header.name()] = header;
}
}
void response::add_status(int code) {
_status_code = code;
}
std::string& response::content()
{
return *_content;
}
std::string response::header_to_string()
{
std::string response = "";
response += "HTTP/1.1 " + std::to_string(_status_code) + " " + status_map.find(_status_code)->second + "\r\n";
add_header(header("Content-Length", std::to_string(_content->length())), false);
add_header(header("Server", ANTHRACITE_FULL_VERSION_STRING), false);
add_header(header("Origin-Server", ANTHRACITE_FULL_VERSION_STRING), false);
for (auto header : _headers) {
response += header.second.to_string();
}
response += "\r\n";
return response;
}
std::string response::to_string()
{
return header_to_string() + *_content;
}
};

31
src/http/response.hpp Normal file
View file

@ -0,0 +1,31 @@
#pragma once
#include <string>
#include <unordered_map>
#include "header_query.hpp"
#include "constants.hpp"
#include <optional>
namespace anthracite::http {
class response {
private:
int _status_code;
std::string* _content;
std::string _content_noref;
std::unordered_map<std::string, header> _headers; // kinda goofy, whatever
public:
response();
int status_code();
void add_body(const std::string body);
void add_body_ref(std::string* body);
void add_status(int);
void add_header(header header, bool override_existing = true);
std::string& content();
std::string header_to_string();
std::string to_string();
};
};