From 0ebdb346013f2006d7de0318d328da9b6db36ea2 Mon Sep 17 00:00:00 2001 From: Nicholas Orlowsky Date: Tue, 4 Feb 2025 11:44:34 -0500 Subject: [PATCH] format + README --- CMakeLists.txt | 1 + README.md | 12 +- format.sh | 2 + lib/anthracite.cpp | 10 +- lib/backends/file_backend.cpp | 104 +++++++------ lib/http/request.cpp | 278 +++++++++++++++++----------------- lib/http/response.cpp | 91 +++++------ lib/log/log.cpp | 39 +++-- lib/socket/socket.cpp | 111 +++++++------- lib/socket/socket.hpp | 4 +- src/api_main.cpp | 60 ++++---- src/file_main.cpp | 3 +- 12 files changed, 370 insertions(+), 345 deletions(-) create mode 100755 format.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index d84a16e..94046c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,7 @@ project(anthracite) set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED True) set(CMAKE_CXX_FLAGS_RELEASE "-O3") +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) add_custom_target(build-version COMMAND cd ../build_supp && ./version.sh diff --git a/README.md b/README.md index d53b17a..b9606d3 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,9 @@ A simple web server written in C++. Supports HTTP 1.0 & 1.1. ## Developing -To build/develop Anthracite, you must have C++20, Make, and Python3 installed. +To build/develop Anthracite, you must have C++23, CMake, Make, and Python3 installed. -You can run Anthracite with: `make run` +Create a `build/` directory, run `cmake ..`, and then `make` to build. ## Todo - [x] HTTP/1.0 @@ -14,14 +14,14 @@ You can run Anthracite with: `make run` - [x] Add module-based backend system for handling requests - [x] Multithreading - [x] HTTP/1.1 -- [ ] Improve benchmarking infrastructure +- [x] Enhance logging +- [-] Build out module-based backend system for handling requests - [ ] Faster parsing +- [ ] HTTP/2 +- [ ] Improve benchmarking infrastructure - [ ] Fix glaring security issues - [ ] Proper error handling - [ ] User configuration -- [ ] Build out module-based backend system for handling requests -- [ ] HTTP/2 -- [ ] Enhance logging - [ ] Cleanup (this one will never truly be done) ## Screenshots diff --git a/format.sh b/format.sh new file mode 100755 index 0000000..939e22c --- /dev/null +++ b/format.sh @@ -0,0 +1,2 @@ +git ls-files -- '*.cpp' '*.h' | xargs clang-format -i -style=file +git diff --exit-code --color diff --git a/lib/anthracite.cpp b/lib/anthracite.cpp index ea77812..1ff27d7 100644 --- a/lib/anthracite.cpp +++ b/lib/anthracite.cpp @@ -1,15 +1,15 @@ -#include "backends/file_backend.hpp" #include "./anthracite.hpp" +#include "./log/log.hpp" +#include "./socket/socket.hpp" +#include "backends/file_backend.hpp" #include #include #include #include +#include #include #include #include -#include -#include "./log/log.hpp" -#include "./socket/socket.hpp" using namespace anthracite; @@ -44,7 +44,7 @@ void handle_client(socket::anthracite_socket s, backends::backend& b, backends:: thread_wait_condvar.notify_one(); } -//int main(int argc, char** argv) +// int main(int argc, char** argv) int anthracite_main(int argc, char** argv, backends::backend& be) { log::logger.initialize(log::LOG_LEVEL_INFO); diff --git a/lib/backends/file_backend.cpp b/lib/backends/file_backend.cpp index 5166a05..5999b51 100644 --- a/lib/backends/file_backend.cpp +++ b/lib/backends/file_backend.cpp @@ -1,40 +1,40 @@ #include "./file_backend.hpp" #include "../log/log.hpp" -#include #include - +#include namespace anthracite::backends { - - std::unique_ptr file_backend::handle_request_cache(http::request& req) { - std::string filename = req.path() == "/" ? "/index.html" : req.path(); - filename = file_dir + filename; - auto file_info = file_cache.find(filename); +std::unique_ptr file_backend::handle_request_cache(http::request& req) +{ + std::string filename = req.path() == "/" ? "/index.html" : req.path(); + filename = file_dir + filename; + auto file_info = file_cache.find(filename); - int status = http::status_codes::OK; - if (file_info == file_cache.end()) { - return handle_error(http::status_codes::NOT_FOUND); - } + int status = http::status_codes::OK; + if (file_info == file_cache.end()) { + return handle_error(http::status_codes::NOT_FOUND); + } - std::unique_ptr resp = std::make_unique(); - - std::string file_extension = file_info->first.substr(file_info->first.rfind('.') + 1); - std::string content_type = "text/html"; + std::unique_ptr resp = std::make_unique(); - auto mime_type = http::mime_types.find(file_extension); - if (mime_type != http::mime_types.end()) { - content_type = mime_type->second; - } + std::string file_extension = file_info->first.substr(file_info->first.rfind('.') + 1); + std::string content_type = "text/html"; - resp->add_body_ref(&file_info->second); - resp->add_status(http::status_codes::OK); - resp->add_header(http::header("Content-Type", content_type), false); + auto mime_type = http::mime_types.find(file_extension); + if (mime_type != http::mime_types.end()) { + content_type = mime_type->second; + } - return resp; - } + resp->add_body_ref(&file_info->second); + resp->add_status(http::status_codes::OK); + resp->add_header(http::header("Content-Type", content_type), false); - void file_backend::populate_cache_dir(std::string dir) { + return resp; +} + +void file_backend::populate_cache_dir(std::string dir) +{ std::filesystem::recursive_directory_iterator cur = begin(std::filesystem::recursive_directory_iterator(dir)); std::filesystem::recursive_directory_iterator fin = end(std::filesystem::recursive_directory_iterator(dir)); @@ -48,40 +48,44 @@ namespace anthracite::backends { log::verbose << "File at " << filename << " cached (" << file_cache[filename].size() << " bytes)" << std::endl; ++cur; } - } +} - void file_backend::populate_cache() { +void file_backend::populate_cache() +{ populate_cache_dir(file_dir); populate_cache_dir("./error_pages/"); - } +} - file_backend::file_backend(std::string dir) : file_dir(std::move(dir)) { +file_backend::file_backend(std::string dir) + : file_dir(std::move(dir)) +{ populate_cache(); - } +} - - std::unique_ptr file_backend::handle_request(http::request& req) { +std::unique_ptr file_backend::handle_request(http::request& req) +{ return handle_request_cache(req); - } - - std::unique_ptr file_backend::handle_error(const http::status_codes& error) { - std::string filename = "./error_pages/" + std::to_string(error) + ".html"; - auto file_info = file_cache.find(filename); +} - http::status_codes status = error; - if (file_info == file_cache.end()) { - status = http::status_codes::NOT_FOUND; - filename = "./error_pages/404.html"; - file_info = file_cache.find(filename); - } +std::unique_ptr file_backend::handle_error(const http::status_codes& error) +{ + std::string filename = "./error_pages/" + std::to_string(error) + ".html"; + auto file_info = file_cache.find(filename); - std::unique_ptr resp = std::make_unique(); - - resp->add_body_ref(&file_info->second); - resp->add_status(error); - resp->add_header(http::header("Content-Type", "text/html"), false); + http::status_codes status = error; + if (file_info == file_cache.end()) { + status = http::status_codes::NOT_FOUND; + filename = "./error_pages/404.html"; + file_info = file_cache.find(filename); + } - return resp; - } + std::unique_ptr resp = std::make_unique(); + + resp->add_body_ref(&file_info->second); + resp->add_status(error); + resp->add_header(http::header("Content-Type", "text/html"), false); + + return resp; +} }; diff --git a/lib/http/request.cpp b/lib/http/request.cpp index a8ca8aa..0d1bc2a 100644 --- a/lib/http/request.cpp +++ b/lib/http/request.cpp @@ -1,165 +1,169 @@ #include "request.hpp" -#include "constants.hpp" #include "../log/log.hpp" +#include "constants.hpp" #include namespace anthracite::http { - request::request(std::string& raw_data, const std::string& client_ip) - : _path(""), _client_ipaddr(client_ip) - { +request::request(std::string& raw_data, const std::string& client_ip) + : _path("") + , _client_ipaddr(client_ip) +{ - parser_state state = METHOD; + parser_state state = METHOD; - std::string scratch = ""; - std::string scratch_2 = ""; - for (int i = 0; i < raw_data.length(); i++) { - switch (state) { - case METHOD: { - if (raw_data[i] == ' ') { - if (method_map.find(scratch) == method_map.end()) { - _method = method::UNKNOWN; - } else { - _method = method_map.find(scratch)->second; - } - scratch = ""; - state = PATH; + std::string scratch = ""; + std::string scratch_2 = ""; + for (int i = 0; i < raw_data.length(); i++) { + switch (state) { + case METHOD: { + if (raw_data[i] == ' ') { + if (method_map.find(scratch) == method_map.end()) { + _method = method::UNKNOWN; } else { - scratch += raw_data[i]; + _method = method_map.find(scratch)->second; } - } break; - - case PATH: { - switch (raw_data[i]) { - case ' ': - state = VERSION; - break; - case '?': - state = QUERY_PARAM_NAME; - break; - default: - _path += raw_data[i]; - break; - } - } break; - - case QUERY_PARAM_NAME: { - if (raw_data[i] == ' ') { - scratch = ""; - state = VERSION; - } else if (raw_data[i] == '=') { - state = QUERY_PARAM_VALUE; - } else { - scratch += raw_data[i]; - } - } break; - - case QUERY_PARAM_VALUE: { - if (raw_data[i] == ' ') { - _query_params[scratch] = query_param(scratch, scratch_2); - scratch = ""; - scratch_2 = ""; - state = VERSION; - } else if (raw_data[i] == '&') { - _query_params[scratch] = query_param(scratch, scratch_2); - scratch = ""; - scratch_2 = ""; - state = QUERY_PARAM_NAME; - } else { - scratch_2 += raw_data[i]; - } - } break; - - case VERSION: { - if (raw_data[i] == '\n') { - _http_version = version_map.find(scratch)->second; - scratch = ""; - state = HEADER_NAME; - } else if (raw_data[i] != '\r') { - scratch += raw_data[i]; - } - } break; - - case HEADER_NAME: { - if (raw_data[i] == '\n') { - scratch = ""; - scratch_2 = ""; - state = BODY_CONTENT; - break; - } else if (raw_data[i] == ' ') { - scratch = ""; - break; - } else if (raw_data[i] == ':') { - state = HEADER_VALUE; - i++; - } else { - scratch += raw_data[i]; - } - } break; - - case HEADER_VALUE: { - if (raw_data[i] == '\n') { - _headers[scratch] = header(scratch, scratch_2); - scratch = ""; - scratch_2 = ""; - state = HEADER_NAME; - } else if (raw_data[i] != '\r') { - scratch_2 += raw_data[i]; - } - } break; - - case BODY_CONTENT: { - _body_content += raw_data[i]; - } break; + scratch = ""; + state = PATH; + } else { + scratch += raw_data[i]; } + } break; + + case PATH: { + switch (raw_data[i]) { + case ' ': + state = VERSION; + break; + case '?': + state = QUERY_PARAM_NAME; + break; + default: + _path += raw_data[i]; + break; + } + } break; + + case QUERY_PARAM_NAME: { + if (raw_data[i] == ' ') { + scratch = ""; + state = VERSION; + } else if (raw_data[i] == '=') { + state = QUERY_PARAM_VALUE; + } else { + scratch += raw_data[i]; + } + } break; + + case QUERY_PARAM_VALUE: { + if (raw_data[i] == ' ') { + _query_params[scratch] = query_param(scratch, scratch_2); + scratch = ""; + scratch_2 = ""; + state = VERSION; + } else if (raw_data[i] == '&') { + _query_params[scratch] = query_param(scratch, scratch_2); + scratch = ""; + scratch_2 = ""; + state = QUERY_PARAM_NAME; + } else { + scratch_2 += raw_data[i]; + } + } break; + + case VERSION: { + if (raw_data[i] == '\n') { + _http_version = version_map.find(scratch)->second; + scratch = ""; + state = HEADER_NAME; + } else if (raw_data[i] != '\r') { + scratch += raw_data[i]; + } + } break; + + case HEADER_NAME: { + if (raw_data[i] == '\n') { + scratch = ""; + scratch_2 = ""; + state = BODY_CONTENT; + break; + } else if (raw_data[i] == ' ') { + scratch = ""; + break; + } else if (raw_data[i] == ':') { + state = HEADER_VALUE; + i++; + } else { + scratch += raw_data[i]; + } + } break; + + case HEADER_VALUE: { + if (raw_data[i] == '\n') { + _headers[scratch] = header(scratch, scratch_2); + scratch = ""; + scratch_2 = ""; + state = HEADER_NAME; + } else if (raw_data[i] != '\r') { + scratch_2 += raw_data[i]; + } + } break; + + case BODY_CONTENT: { + _body_content += raw_data[i]; + } break; } } +} - std::string request::path() { return _path; } +std::string request::path() { return _path; } - method request::get_method() { return _method; } +method request::get_method() { return _method; } - std::string request::client_ip() { return _client_ipaddr; } +std::string request::client_ip() { return _client_ipaddr; } - version request::get_http_version() { - return _http_version; - } +version request::get_http_version() +{ + return _http_version; +} - 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 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 request::close_connection() { - const auto& header = _headers.find("Connection"); - const bool found = header != _headers.end(); +bool request::close_connection() +{ + const auto& header = _headers.find("Connection"); + const bool found = header != _headers.end(); - if(found && header->second.value() == "keep-alive") { + if (found && header->second.value() == "keep-alive") { return false; - } - - return true; } - std::string request::to_string() - { - std::string response = ""; - response += reverse_method_map.find(_method)->second + " " + _path + "?"; + return true; +} - for (auto qp : _query_params) { - response += qp.second.to_string() + "&"; - } +std::string request::to_string() +{ + std::string response = ""; + response += reverse_method_map.find(_method)->second + " " + _path + "?"; - response += " " + reverse_version_map.find(_http_version)->second + "\r\n"; - - for (auto header : _headers) { - response += header.second.to_string(); - } - - response += "\r\n"; - response += _body_content; - - return response; + for (auto qp : _query_params) { + response += qp.second.to_string() + "&"; } + response += " " + reverse_version_map.find(_http_version)->second + "\r\n"; + + for (auto header : _headers) { + response += header.second.to_string(); + } + + response += "\r\n"; + response += _body_content; + + return response; +} + }; diff --git a/lib/http/response.cpp b/lib/http/response.cpp index 214ba49..2efce6f 100644 --- a/lib/http/response.cpp +++ b/lib/http/response.cpp @@ -3,56 +3,59 @@ namespace anthracite::http { - response::response() {}; +response::response() {}; - int response::status_code() { return _status_code; } +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(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_body_ref(std::string* body) { - _content = body; +} + +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(); } - void response::add_header(header header, bool override_existing) - { - if (override_existing || _headers.find(header.name()) == _headers.end()) { - _headers[header.name()] = header; - } - } + response += "\r\n"; - void response::add_status(int code) { - _status_code = code; - } + return response; +} - 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; - } +std::string response::to_string() +{ + return header_to_string() + *_content; +} }; diff --git a/lib/log/log.cpp b/lib/log/log.cpp index aa0d35a..4c59e8b 100644 --- a/lib/log/log.cpp +++ b/lib/log/log.cpp @@ -1,22 +1,29 @@ #include "./log.hpp" namespace anthracite::log { - enum LOG_LEVEL Logger::_level = LOG_LEVEL_NONE; +enum LOG_LEVEL Logger::_level = LOG_LEVEL_NONE; - // TODO: implement logger as a singleton to prevent duplicates - Logger::Logger() = default; - void Logger::initialize(enum LOG_LEVEL level) { - _level = level; +// TODO: implement logger as a singleton to prevent duplicates +Logger::Logger() = default; +void Logger::initialize(enum LOG_LEVEL level) +{ + _level = level; +} + +LogBuf::LogBuf(std::ostream& output_stream, const std::string& tag, enum LOG_LEVEL level) + : _output_stream(output_stream) + , _tag(tag) + , _level(level) +{ +} + +int LogBuf::sync() +{ + if (this->_level <= logger._level) { + std::cout << "[" << this->_tag << "] " << this->str(); + std::cout.flush(); } - - LogBuf::LogBuf(std::ostream& output_stream, const std::string& tag, enum LOG_LEVEL level) : _output_stream(output_stream), _tag(tag), _level(level) {} - - int LogBuf::sync() { - if (this->_level <= logger._level) { - std::cout << "[" << this ->_tag << "] " << this->str(); - std::cout.flush(); - } - this->str(""); - return 0; - } + this->str(""); + return 0; +} }; diff --git a/lib/socket/socket.cpp b/lib/socket/socket.cpp index 43a6280..055d7a7 100644 --- a/lib/socket/socket.cpp +++ b/lib/socket/socket.cpp @@ -1,3 +1,4 @@ +#include "./socket.hpp" #include #include #include @@ -7,71 +8,69 @@ #include #include #include -#include "./socket.hpp" namespace anthracite::socket { - anthracite_socket::anthracite_socket(int port, int max_queue) - : server_socket(::socket(AF_INET, SOCK_STREAM, 0)) - , client_ip("") - { - struct sockaddr_in address {}; - address.sin_family = AF_INET; - address.sin_port = htons(port); - address.sin_addr.s_addr = INADDR_ANY; + : server_socket(::socket(AF_INET, SOCK_STREAM, 0)) + , client_ip("") +{ + struct sockaddr_in address {}; + address.sin_family = AF_INET; + address.sin_port = htons(port); + address.sin_addr.s_addr = INADDR_ANY; - int reuse_opt = 1; - setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &reuse_opt, sizeof(reuse_opt)); - bind(server_socket, reinterpret_cast(&address), sizeof(address)); + int reuse_opt = 1; + setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &reuse_opt, sizeof(reuse_opt)); + bind(server_socket, reinterpret_cast(&address), sizeof(address)); - listen(server_socket, max_queue); + listen(server_socket, max_queue); +} + +void anthracite_socket::wait_for_conn() +{ + client_ip = ""; + client_socket = accept(server_socket, reinterpret_cast(&client_addr), &client_addr_len); + std::array ip_str { 0 }; + inet_ntop(AF_INET, &client_addr.sin_addr, ip_str.data(), INET_ADDRSTRLEN); + client_ip = std::string(ip_str.data()); +} + +const std::string& anthracite_socket::get_client_ip() +{ + return client_ip; +} + +void anthracite_socket::close_conn() +{ + close(client_socket); + client_socket = -1; +} + +void anthracite_socket::send_message(std::string& msg) +{ + if (client_socket == -1) { + return; + } + send(client_socket, &msg[0], msg.length(), 0); +} + +std::string anthracite_socket::recv_message(int buffer_size) +{ + if (client_socket == -1) { + return ""; } - void anthracite_socket::wait_for_conn() - { - client_ip = ""; - client_socket = accept(server_socket, reinterpret_cast(&client_addr), &client_addr_len); - std::array ip_str { 0 }; - inet_ntop(AF_INET, &client_addr.sin_addr, ip_str.data(), INET_ADDRSTRLEN); - client_ip = std::string(ip_str.data()); + setsockopt(client_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout_tv, sizeof timeout_tv); + std::vector response(buffer_size + 1); + ssize_t result = recv(client_socket, response.data(), buffer_size + 1, 0); + + if (result < 1) { + return ""; } - const std::string& anthracite_socket::get_client_ip() - { - return client_ip; - } - - void anthracite_socket::close_conn() - { - close(client_socket); - client_socket = -1; - } - - void anthracite_socket::send_message(std::string& msg) - { - if (client_socket == -1) { - return; - } - send(client_socket, &msg[0], msg.length(), 0); - } - - std::string anthracite_socket::recv_message(int buffer_size) - { - if (client_socket == -1) { - return ""; - } - - setsockopt(client_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout_tv, sizeof timeout_tv); - std::vector response(buffer_size + 1); - ssize_t result = recv(client_socket, response.data(), buffer_size + 1, 0); - - if (result < 1) { - return ""; - } - - response[buffer_size] = '\0'; - return { response.data() }; - } + response[buffer_size] = '\0'; + return { response.data() }; +} }; diff --git a/lib/socket/socket.hpp b/lib/socket/socket.hpp index fb1eaf1..7a57de7 100644 --- a/lib/socket/socket.hpp +++ b/lib/socket/socket.hpp @@ -17,9 +17,7 @@ private: std::string client_ip; struct sockaddr_in client_addr {}; socklen_t client_addr_len {}; - static constexpr struct timeval timeout_tv { - .tv_sec = 5, .tv_usec = 0 - }; + static const struct timeval timeout_tv; public: anthracite_socket(int port, int max_queue = MAX_QUEUE_LENGTH); diff --git a/src/api_main.cpp b/src/api_main.cpp index 0da5502..4a42858 100644 --- a/src/api_main.cpp +++ b/src/api_main.cpp @@ -1,30 +1,33 @@ #include "../lib/anthracite.hpp" #include "../lib/backends/backend.hpp" #include "../lib/http/constants.hpp" +#include #include #include #include #include #include -#include using namespace anthracite; - using CallbackType = std::unique_ptr (*)(http::request&); +using CallbackType = std::unique_ptr (*)(http::request&); class api_backend : public backends::backend { class RouteNode { - public: - + public: std::optional callback; - RouteNode() : callback(std::nullopt) {} + RouteNode() + : callback(std::nullopt) + { + } std::unordered_map routes; }; RouteNode root; - - std::unique_ptr default_route(http::request& req) { + + std::unique_ptr default_route(http::request& req) + { std::unique_ptr resp = std::make_unique(); resp->add_body("Not Found"); @@ -34,14 +37,15 @@ class api_backend : public backends::backend { return resp; } - std::unique_ptr find_handler(http::request& req) { + std::unique_ptr find_handler(http::request& req) + { std::string filename = req.path().substr(1); std::vector result; - std::stringstream ss (filename); + std::stringstream ss(filename); std::string item; RouteNode* cur = &root; - while (getline (ss, item, '/')) { + while (getline(ss, item, '/')) { if (cur->routes.find(item) == cur->routes.end()) { if (cur->routes.find("*") == cur->routes.end()) { break; @@ -58,28 +62,28 @@ class api_backend : public backends::backend { } else { return default_route(req); } - - } - std::unique_ptr handle_request(http::request& req) override { + std::unique_ptr handle_request(http::request& req) override + { return find_handler(req); } - public: - - api_backend() { +public: + api_backend() + { root.routes = std::unordered_map(); } - void register_endpoint(std::string pathspec, CallbackType callback) { + void register_endpoint(std::string pathspec, CallbackType callback) + { std::vector result; - std::stringstream ss (pathspec); + std::stringstream ss(pathspec); std::string item; RouteNode* cur = &root; - while (getline (ss, item, '/')) { - cur->routes[item] = RouteNode{}; + while (getline(ss, item, '/')) { + cur->routes[item] = RouteNode {}; cur = &cur->routes[item]; } @@ -87,17 +91,19 @@ class api_backend : public backends::backend { } }; -std::unique_ptr handle_request(http::request& req) { - std::unique_ptr resp = std::make_unique(); +std::unique_ptr handle_request(http::request& req) +{ + std::unique_ptr resp = std::make_unique(); - resp->add_body(R"({"user": "endpoint"}")"); - resp->add_header(http::header("Content-Type", "application/json")); - resp->add_status(http::status_codes::OK); + resp->add_body(R"({"user": "endpoint"}")"); + resp->add_header(http::header("Content-Type", "application/json")); + resp->add_status(http::status_codes::OK); - return resp; + return resp; } -int main(int argc, char** argv) { +int main(int argc, char** argv) +{ auto args = std::span(argv, size_t(argc)); api_backend ab; ab.register_endpoint("users/*", handle_request); diff --git a/src/file_main.cpp b/src/file_main.cpp index 6bc3b54..c81b1e9 100644 --- a/src/file_main.cpp +++ b/src/file_main.cpp @@ -3,7 +3,8 @@ using namespace anthracite; -int main(int argc, char** argv) { +int main(int argc, char** argv) +{ auto args = std::span(argv, size_t(argc)); backends::file_backend fb(argc > 2 ? args[2] : "./www"); anthracite_main(argc, argv, fb);