cleanup
This commit is contained in:
parent
f1868ceea5
commit
dea773366e
|
@ -1,10 +1,10 @@
|
||||||
.PHONY: format lint build build-release build-docker run debug
|
.PHONY: format lint build build-release build-docker run debug
|
||||||
|
|
||||||
build:
|
build:
|
||||||
g++ main.cpp -g -o ./anthracite
|
g++ main.cpp --std=c++20 -g -o ./anthracite
|
||||||
|
|
||||||
build-release:
|
build-release:
|
||||||
g++ main.cpp -O3 -march=native -o ./anthracite
|
g++ main.cpp --std=c++20 -O3 -march=native -o ./anthracite
|
||||||
|
|
||||||
build-docker:
|
build-docker:
|
||||||
docker build . -t anthracite
|
docker build . -t anthracite
|
||||||
|
|
|
@ -5,5 +5,11 @@
|
||||||
|
|
||||||
class backend {
|
class backend {
|
||||||
public:
|
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<http_response> handle_request(http_request& req) = 0;
|
virtual std::unique_ptr<http_response> handle_request(http_request& req) = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,9 +11,9 @@ private:
|
||||||
filename = file_dir + filename;
|
filename = file_dir + filename;
|
||||||
auto file_info = file_cache.find(filename);
|
auto file_info = file_cache.find(filename);
|
||||||
|
|
||||||
int status = 200;
|
int status = http_status_codes::OK;
|
||||||
if (file_info == file_cache.end()) {
|
if (file_info == file_cache.end()) {
|
||||||
status = 404;
|
status = http_status_codes::NOT_FOUND;
|
||||||
filename = "./error_pages/404.html";
|
filename = "./error_pages/404.html";
|
||||||
file_info = file_cache.find(filename);
|
file_info = file_cache.find(filename);
|
||||||
}
|
}
|
||||||
|
@ -43,10 +43,12 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
file_backend(std::string dir = "./www") : file_dir(dir) {
|
file_backend(std::string dir = "./www") : file_dir(std::move(dir)) {
|
||||||
populate_cache();
|
populate_cache();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~file_backend() = default;
|
||||||
|
|
||||||
std::unique_ptr<http_response> handle_request(http_request& req) override {
|
std::unique_ptr<http_response> handle_request(http_request& req) override {
|
||||||
return handle_request_cache(req);
|
return handle_request_cache(req);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <bits/stdc++.h>
|
#include <bits/stdc++.h>
|
||||||
|
|
||||||
constexpr int benchmark_loops = 100;
|
constexpr int benchmark_loops = 100;
|
||||||
|
constexpr int SEED = 570;
|
||||||
|
|
||||||
template <typename KeyType, typename ValueType>
|
template <typename KeyType, typename ValueType>
|
||||||
class smart_map {
|
class smart_map {
|
||||||
|
@ -57,7 +58,7 @@ class smart_map {
|
||||||
|
|
||||||
void assess_datastructure() {
|
void assess_datastructure() {
|
||||||
std::vector<std::pair<KeyType, ValueType>> vals(hmap.begin(), hmap.end());
|
std::vector<std::pair<KeyType, ValueType>> 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);
|
use_hmap = assess_hmap(vals) > assess_vmap(vals);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,72 @@ enum http_method {
|
||||||
UNKNOWN
|
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<std::string, http_method> const http_method_map = {
|
static std::unordered_map<std::string, http_method> const http_method_map = {
|
||||||
{ "GET", http_method::GET },
|
{ "GET", http_method::GET },
|
||||||
{ "POST", http_method::POST },
|
{ "POST", http_method::POST },
|
||||||
|
|
|
@ -8,7 +8,7 @@ private:
|
||||||
std::unordered_map<std::string, http_header> _headers; // kinda goofy, whatever
|
std::unordered_map<std::string, http_header> _headers; // kinda goofy, whatever
|
||||||
|
|
||||||
public:
|
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)
|
: _content(content)
|
||||||
, _status_code(status_code)
|
, _status_code(status_code)
|
||||||
, _filename(std::move(filename))
|
, _filename(std::move(filename))
|
||||||
|
@ -32,7 +32,7 @@ public:
|
||||||
std::string header_to_string()
|
std::string header_to_string()
|
||||||
{
|
{
|
||||||
std::string response = "";
|
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 content_type = "text/html";
|
||||||
std::string file_extension = _filename.substr(_filename.rfind('.') + 1);
|
std::string file_extension = _filename.substr(_filename.rfind('.') + 1);
|
||||||
auto mime_type = mime_types.find(file_extension);
|
auto mime_type = mime_types.find(file_extension);
|
||||||
|
|
28
src/main.cpp
28
src/main.cpp
|
@ -5,6 +5,7 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
#include <span>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
@ -16,14 +17,10 @@ void log_request_and_response(http_request& req, std::unique_ptr<http_response>&
|
||||||
constexpr int default_port = 80;
|
constexpr int default_port = 80;
|
||||||
constexpr int max_worker_threads = 128;
|
constexpr int max_worker_threads = 128;
|
||||||
|
|
||||||
int active_threads = 0;
|
void handle_client(anthracite_socket s, backend& b, std::mutex& thread_wait_mutex, std::condition_variable& thread_wait_condvar, int& active_threads)
|
||||||
std::mutex mtx;
|
|
||||||
std::condition_variable cv;
|
|
||||||
|
|
||||||
void handle_client(anthracite_socket s, file_backend& fb)
|
|
||||||
{
|
{
|
||||||
http_request req(s);
|
http_request req(s);
|
||||||
std::unique_ptr<http_response> resp = fb.handle_request(req);
|
std::unique_ptr<http_response> resp = b.handle_request(req);
|
||||||
log_request_and_response(req, resp);
|
log_request_and_response(req, resp);
|
||||||
std::string header = resp->header_to_string();
|
std::string header = resp->header_to_string();
|
||||||
s.send_message(header);
|
s.send_message(header);
|
||||||
|
@ -31,32 +28,37 @@ void handle_client(anthracite_socket s, file_backend& fb)
|
||||||
resp.reset();
|
resp.reset();
|
||||||
s.close_conn();
|
s.close_conn();
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(mtx);
|
std::lock_guard<std::mutex> lock(thread_wait_mutex);
|
||||||
active_threads--;
|
active_threads--;
|
||||||
}
|
}
|
||||||
cv.notify_one();
|
thread_wait_condvar.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
|
auto args = std::span(argv, size_t(argc));
|
||||||
int port_number = default_port;
|
int port_number = default_port;
|
||||||
|
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
port_number = atoi(argv[1]);
|
port_number = atoi(args[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "Initializing Anthracite" << std::endl;
|
std::cout << "Initializing Anthracite" << std::endl;
|
||||||
anthracite_socket s(port_number);
|
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 << "Initialization Complete" << std::endl;
|
||||||
std::cout << "Listening for HTTP connections on port " << port_number << 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) {
|
while (true) {
|
||||||
s.wait_for_conn();
|
s.wait_for_conn();
|
||||||
std::unique_lock<std::mutex> lock(mtx);
|
std::unique_lock<std::mutex> lock(thread_wait_mutex);
|
||||||
cv.wait(lock, [] { return active_threads < max_worker_threads; });
|
thread_wait_condvar.wait(lock, [active_threads] { return active_threads < max_worker_threads; });
|
||||||
active_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);
|
exit(0);
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
|
constexpr int MAX_QUEUE_LENGTH = 100;
|
||||||
|
|
||||||
class anthracite_socket {
|
class anthracite_socket {
|
||||||
private:
|
private:
|
||||||
int server_socket;
|
int server_socket;
|
||||||
|
@ -18,7 +20,7 @@ private:
|
||||||
socklen_t client_addr_len {};
|
socklen_t client_addr_len {};
|
||||||
|
|
||||||
public:
|
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))
|
: server_socket(socket(AF_INET, SOCK_STREAM, 0))
|
||||||
, client_ip("")
|
, client_ip("")
|
||||||
{
|
{
|
||||||
|
@ -62,7 +64,7 @@ public:
|
||||||
send(client_socket, &msg[0], msg.length(), 0);
|
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) {
|
if (client_socket == -1) {
|
||||||
return "";
|
return "";
|
||||||
|
|
Loading…
Reference in a new issue