From dea773366e2074c18eb7a9bedc975a3e819e1021 Mon Sep 17 00:00:00 2001 From: Nicholas Orlowsky Date: Fri, 20 Oct 2023 00:27:35 -0400 Subject: [PATCH] cleanup --- src/Makefile | 4 +- src/backends/backend.cpp | 6 +++ src/backends/file_backend.cpp | 8 ++-- src/datastructures/smart_map.cpp | 3 +- src/http/constants.cpp | 66 ++++++++++++++++++++++++++++++++ src/http/http_response.cpp | 4 +- src/main.cpp | 30 ++++++++------- src/socket.cpp | 6 ++- 8 files changed, 103 insertions(+), 24 deletions(-) diff --git a/src/Makefile b/src/Makefile index fa4a540..2cfb102 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,10 +1,10 @@ .PHONY: format lint build build-release build-docker run debug build: - g++ main.cpp -g -o ./anthracite + g++ main.cpp --std=c++20 -g -o ./anthracite build-release: - g++ main.cpp -O3 -march=native -o ./anthracite + g++ main.cpp --std=c++20 -O3 -march=native -o ./anthracite build-docker: docker build . -t anthracite diff --git a/src/backends/backend.cpp b/src/backends/backend.cpp index bc262bf..3864a1b 100644 --- a/src/backends/backend.cpp +++ b/src/backends/backend.cpp @@ -5,5 +5,11 @@ class backend { public: + backend() = default; + virtual ~backend() = default; + backend(backend const&) = delete; + backend& operator = (backend const&) = delete; + backend(backend&&) = delete; + backend& operator=(backend&&) = delete; virtual std::unique_ptr handle_request(http_request& req) = 0; }; diff --git a/src/backends/file_backend.cpp b/src/backends/file_backend.cpp index aae1e6e..9deeae2 100644 --- a/src/backends/file_backend.cpp +++ b/src/backends/file_backend.cpp @@ -11,9 +11,9 @@ private: filename = file_dir + filename; auto file_info = file_cache.find(filename); - int status = 200; + int status = http_status_codes::OK; if (file_info == file_cache.end()) { - status = 404; + status = http_status_codes::NOT_FOUND; filename = "./error_pages/404.html"; file_info = file_cache.find(filename); } @@ -43,10 +43,12 @@ private: } public: - file_backend(std::string dir = "./www") : file_dir(dir) { + file_backend(std::string dir = "./www") : file_dir(std::move(dir)) { populate_cache(); } + ~file_backend() = default; + std::unique_ptr handle_request(http_request& req) override { return handle_request_cache(req); } diff --git a/src/datastructures/smart_map.cpp b/src/datastructures/smart_map.cpp index 0ea1c55..87c0bcc 100644 --- a/src/datastructures/smart_map.cpp +++ b/src/datastructures/smart_map.cpp @@ -17,6 +17,7 @@ #include constexpr int benchmark_loops = 100; +constexpr int SEED = 570; template class smart_map { @@ -57,7 +58,7 @@ class smart_map { void assess_datastructure() { std::vector> vals(hmap.begin(), hmap.end()); - std::shuffle(vals.begin(), vals.end(), std::default_random_engine(570)); + std::shuffle(vals.begin(), vals.end(), std::default_random_engine(SEED)); use_hmap = assess_hmap(vals) > assess_vmap(vals); } diff --git a/src/http/constants.cpp b/src/http/constants.cpp index d1a32a7..647df48 100644 --- a/src/http/constants.cpp +++ b/src/http/constants.cpp @@ -24,6 +24,72 @@ enum http_method { UNKNOWN }; +enum http_status_codes { + CONTINUE = 100, + SWITCHING_PROTOCOLS = 101, + PROCESSING = 102, + EARLY_HINTS = 103, + OK = 200, + CREATED = 201, + ACCEPTED = 202, + NON_AUTHORITATIVE_INFORMATION = 203, + NO_CONTENT = 204, + RESET_CONTENT = 205, + PARTIAL_CONTENT = 206, + MULTI_STATUS = 207, + ALREADY_REPORTED = 208, + IM_USED = 226, + MULTIPLE_CHOICES = 300, + MOVED_PERMANENTLY = 301, + FOUND = 302, + SEE_OTHER = 303, + NOT_MODIFIED = 304, + USE_PROXY = 305, + TEMPORARY_REDIRECT = 307, + PERMANENT_REDIRECT = 308, + BAD_REQUEST = 400, + UNAUTHORIZED = 401, + PAYMENT_REQUIRED = 402, + FORBIDDEN = 403, + NOT_FOUND = 404, + METHOD_NOT_ALLOWED = 405, + NOT_ACCEPTABLE = 406, + PROXY_AUTHENTICATION_REQUIRED = 407, + REQUEST_TIMEOUT = 408, + CONFLICT = 409, + GONE = 410, + LENGTH_REQUIRED = 411, + PRECONDITION_FAILED = 412, + PAYLOAD_TOO_LARGE = 413, + URI_TOO_LONG = 414, + UNSUPPORTED_MEDIA_TYPE = 415, + RANGE_NOT_SATISFIABLE = 416, + EXPECTATION_FAILED = 417, + I_AM_A_TEAPOT = 418, + ENHANCE_YOUR_CALM = 420, + MISDIRECTED_REQUEST = 421, + UNPROCESSABLE_ENTITY = 422, + LOCKED = 423, + FAILED_DEPENDENCY = 424, + TOO_EARLY = 425, + UPGRADE_REQUIRED = 426, + PRECONDITION_REQUIRED = 428, + TOO_MANY_REQUESTS = 429, + REQUEST_HEADER_FIELDS_TOO_LARGE = 431, + UNAVAILABLE_FOR_LEGAL_REASONS = 451, + INTERNAL_SERVER_ERROR = 500, + NOT_IMPLEMENTED = 501, + BAD_GATEWAY = 502, + SERVICE_UNAVAILABLE = 503, + GATEWAY_TIMEOUT = 504, + HTTP_VERSION_NOT_SUPPORTED = 505, + VARIANT_ALSO_NEGOTIATES = 506, + INSUFFICIENT_STORAGE = 507, + LOOP_DETECTED = 508, + NOT_EXTENDED = 510, + NETWORK_AUTHENTICATION_REQUIRED = 511 +}; + static std::unordered_map const http_method_map = { { "GET", http_method::GET }, { "POST", http_method::POST }, diff --git a/src/http/http_response.cpp b/src/http/http_response.cpp index 8f90cfa..423cc1f 100644 --- a/src/http/http_response.cpp +++ b/src/http/http_response.cpp @@ -8,7 +8,7 @@ private: std::unordered_map _headers; // kinda goofy, whatever public: - http_response(std::string& content, std::string filename, int status_code = 200) + 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)) @@ -32,7 +32,7 @@ public: 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"; + response += "HTTP/1.0 " + 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); diff --git a/src/main.cpp b/src/main.cpp index 890477c..b109e85 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -16,14 +17,10 @@ void log_request_and_response(http_request& req, std::unique_ptr& constexpr int default_port = 80; constexpr int max_worker_threads = 128; -int active_threads = 0; -std::mutex mtx; -std::condition_variable cv; - -void handle_client(anthracite_socket s, file_backend& fb) +void handle_client(anthracite_socket s, backend& b, std::mutex& thread_wait_mutex, std::condition_variable& thread_wait_condvar, int& active_threads) { http_request req(s); - std::unique_ptr resp = fb.handle_request(req); + std::unique_ptr resp = b.handle_request(req); log_request_and_response(req, resp); std::string header = resp->header_to_string(); s.send_message(header); @@ -31,32 +28,37 @@ void handle_client(anthracite_socket s, file_backend& fb) resp.reset(); s.close_conn(); { - std::lock_guard lock(mtx); + std::lock_guard lock(thread_wait_mutex); active_threads--; } - cv.notify_one(); + thread_wait_condvar.notify_one(); } int main(int argc, char** argv) { + auto args = std::span(argv, size_t(argc)); int port_number = default_port; if (argc > 1) { - port_number = atoi(argv[1]); + port_number = atoi(args[1]); } std::cout << "Initializing Anthracite" << std::endl; anthracite_socket s(port_number); - file_backend fb(argc > 2 ? argv[2] : "./www"); + file_backend fb(argc > 2 ? args[2] : "./www"); std::cout << "Initialization Complete" << std::endl; std::cout << "Listening for HTTP connections on port " << port_number << std::endl; + int active_threads = 0; + std::mutex thread_wait_mutex; + std::condition_variable thread_wait_condvar; + while (true) { s.wait_for_conn(); - std::unique_lock lock(mtx); - cv.wait(lock, [] { return active_threads < max_worker_threads; }); + std::unique_lock lock(thread_wait_mutex); + thread_wait_condvar.wait(lock, [active_threads] { return active_threads < max_worker_threads; }); active_threads++; - std::thread(handle_client, s, std::ref(fb)).detach(); + std::thread(handle_client, s, std::ref(fb), std::ref(thread_wait_mutex), std::ref(thread_wait_condvar), std::ref(active_threads)).detach(); } exit(0); @@ -64,5 +66,5 @@ int main(int argc, char** argv) void log_request_and_response(http_request& req, std::unique_ptr& resp) { - std::cout << "[" << resp->status_code() << " " + http_status_map.find(resp->status_code())->second + "] " + req.client_ip() + " " + http_reverse_method_map.find(req.method())->second + " " + req.path() << std::endl; + std::cout << "[" << resp->status_code() << " " + http_status_map.find(resp->status_code())->second + "] " + req.client_ip() + " " + http_reverse_method_map.find(req.method())->second + " " + req.path() << std::endl; } diff --git a/src/socket.cpp b/src/socket.cpp index 7c48da0..a41d80a 100644 --- a/src/socket.cpp +++ b/src/socket.cpp @@ -9,6 +9,8 @@ #include #include +constexpr int MAX_QUEUE_LENGTH = 100; + class anthracite_socket { private: int server_socket; @@ -18,7 +20,7 @@ private: socklen_t client_addr_len {}; public: - anthracite_socket(int port, int max_queue = 10) + anthracite_socket(int port, int max_queue = MAX_QUEUE_LENGTH) : server_socket(socket(AF_INET, SOCK_STREAM, 0)) , client_ip("") { @@ -62,7 +64,7 @@ public: send(client_socket, &msg[0], msg.length(), 0); } - std::string recv_message(int buffer_size = 1024) + std::string recv_message(int buffer_size) { if (client_socket == -1) { return "";