Add correctly shutting down server and stopping threads

This commit is contained in:
Pablu23
2024-11-13 16:49:49 +01:00
parent a3a5280f17
commit c18d5f993d
8 changed files with 61 additions and 35 deletions

View File

@@ -22,7 +22,10 @@ fclean:
re: fclean $(NAME)
run: all
build: all
g++ -std=c++20 -o server main.cpp -L. -lhttpablu
run: build
g++ -std=c++20 -o server main.cpp -L. -lhttpablu
./server

View File

@@ -1,18 +1,33 @@
#include "http.hpp"
#include "router.hpp"
#include <csignal>
#include <cstdlib>
#include <iostream>
using namespace http;
void HelloWorld(Request req, Response *res) {
void hello_world(Request req, Response *res) {
res->set_payload("Hello World!");
res->set_content_type("text/plain");
}
static Router router(8181);
void quit(int s) {
router.stop();
std::cout << "Stopping Server" << std::endl;
}
int main() {
Router router(8181);
struct sigaction sig_int_handler;
sig_int_handler.sa_handler = quit;
sigemptyset(&sig_int_handler.sa_mask);
sig_int_handler.sa_flags = 0;
sigaction(SIGINT, &sig_int_handler, nullptr);
// Allow all Methods
router.handle("GET /helloWorld", HelloWorld);
router.handle("GET /helloWorld", hello_world);
router.handle("GET /healthz", [](Request req, Response *res) {
res->set_status_code(StatusCode::OK);
res->set_payload(std::vector<std::byte>());
@@ -38,6 +53,7 @@ int main() {
res->set_content_type("text/plain");
});
std::cout << "Starting Server" << std::endl;
router.start();
return 0;
}

View File

@@ -10,7 +10,7 @@ bool Request::protocol(std::stringstream *ss, int *procPart, char c) {
m_method = ss->str();
break;
case 1:
m_pathRaw = ss->str();
m_path_raw = ss->str();
break;
case 2:
m_protocol = ss->str();
@@ -72,17 +72,17 @@ Request::Request(std::vector<std::byte> buf) : path("") {
ss << c;
}
}
path = Path{m_pathRaw};
path = Path{m_path_raw};
}
void Request::Print() {
void Request::print() {
std::cout << "Protocol: " << m_protocol << "\n"
<< "Req: " << m_method << " " << m_pathRaw << std::endl;
<< "Req: " << m_method << " " << m_path_raw << std::endl;
for (const auto &[key, value] : m_headers) {
std::cout << "[" << key << "]: [" << value << "]\n";
}
if (HasData()) {
if (has_data()) {
std::cout << "Payload: " << std::endl;
for (auto &byte : m_payload) {
std::cout << static_cast<char>(byte);
@@ -91,6 +91,6 @@ void Request::Print() {
}
}
std::string Request::Method() { return m_method; }
bool Request::HasData() { return m_payload.size() != 0; }
std::vector<std::byte> Request::Data() { return m_payload; }
std::string Request::method() { return m_method; }
bool Request::has_data() { return m_payload.size() != 0; }
std::vector<std::byte> Request::data() { return m_payload; }

View File

@@ -8,26 +8,26 @@
using namespace http;
Response::Response(statuscode::statusCode statusCode) {
Response::Response(StatusCode::statusCode statusCode) {
m_statusCode = statusCode;
SetHeader("Connection", "close");
set_header("Connection", "close");
}
void Response::SetHeader(const std::string name, const std::string value) {
void Response::set_header(const std::string name, const std::string value) {
m_headers.insert_or_assign(name, value);
}
void Response::SetPayload(const std::vector<std::byte> data) {
void Response::set_payload(const std::vector<std::byte> data) {
m_headers.insert(std::pair<std::string, std::string>(
"Content-Length", std::to_string(data.size())));
m_payload = data;
}
void Response::SetStatusCode(statuscode::statusCode statuscode) {
void Response::set_status_code(StatusCode::statusCode statuscode) {
m_statusCode = statuscode;
}
void Response::SetPayload(const std::string data) {
void Response::set_payload(const std::string data) {
m_headers.insert(std::pair<std::string, std::string>(
"Content-Length", std::to_string(std::strlen(data.data()))));
@@ -36,14 +36,14 @@ void Response::SetPayload(const std::string data) {
[](char c) { return std::byte(c); });
}
void Response::SetContentType(const std::string type) {
void Response::set_content_type(const std::string type) {
m_headers.insert_or_assign("Content-Type", type);
}
void Response::Send(int clientSocket) {
std::string Response::compile() {
std::stringstream ss;
ss << "HTTP/1.1 " << m_statusCode << " "
<< statuscode::StatusCodeString(m_statusCode) << "\n";
<< StatusCode::status_code_string(m_statusCode) << "\n";
for (const auto &[key, value] : m_headers) {
ss << key << ": " << value << "\n";
}
@@ -54,11 +54,11 @@ void Response::Send(int clientSocket) {
ss << c;
}
}
std::string p = ss.str();
send(clientSocket, p.data(), p.size(), 0);
return ss.str();
// ::send(clientSocket, p.data(), p.size(), 0);
}
void Response::Print() {
void Response::print() {
for (const auto &[key, value] : m_headers) {
std::cout << "[" << key << "]: [" << value << "]\n";
}

View File

@@ -20,7 +20,7 @@ public:
void set_payload(const std::string data);
void set_content_type(const std::string type);
void set_status_code(const StatusCode::statusCode status_code);
void send(int client_socket);
std::string compile();
void print();
};
} // namespace http

View File

@@ -18,9 +18,11 @@ Router::Router(int port) {
m_address.sin_family = AF_INET;
m_address.sin_port = htons(port);
m_address.sin_addr.s_addr = INADDR_ANY;
m_running = false;
}
int Router::start() {
m_running = true;
int err = bind(m_socket, (struct sockaddr *)&m_address, sizeof(m_address));
if (err != 0)
return err;
@@ -31,14 +33,17 @@ int Router::start() {
if (err != 0)
return err;
while (true) {
while (m_running.load()) {
int client = accept(m_socket, nullptr, nullptr);
queue_client(client);
}
stop_thread_loop();
return 0;
}
void Router::stop() { m_running.store(false); }
void Router::queue_client(int fd) {
{
std::unique_lock<std::mutex> lock(m_mutex);
@@ -83,7 +88,8 @@ void Router::thread_loop() {
recv(client, buffer.data(), buffer.size(), 0);
Request req(buffer);
Response res = Route(req);
res.send(client);
auto payload = res.compile();
send(client, payload.data(), payload.size(), 0);
shutdown(client, SHUT_WR);
while (recv(client, buffer.data(), buffer.size(), 0) > 0) {

View File

@@ -19,6 +19,7 @@ private:
int m_socket;
sockaddr_in m_address;
Response Route(Request req);
std::atomic<bool> m_running;
private:
std::mutex m_mutex;
@@ -36,7 +37,7 @@ public:
void handle(std::string path_pattern,
std::function<void(Request, Response *)> func);
int start();
int stop();
void stop();
};
} // namespace http

View File

@@ -25,7 +25,7 @@ Node::Node(std::string sub, bool isValue,
Tree::Tree(std::string method) { m_method = method; }
void addNode(std::shared_ptr<Node> const &parent, std::string path,
void add_node(std::shared_ptr<Node> const &parent, std::string path,
std::vector<std::string> rest,
std::function<void(Request, Response *)> func) {
std::shared_ptr<Node> curr = parent->m_next[path];
@@ -45,13 +45,13 @@ void addNode(std::shared_ptr<Node> const &parent, std::string path,
auto newPath = rest.front();
// Ineffiecient, use deque
rest.erase(rest.begin());
addNode(curr, newPath, rest, func);
add_node(curr, newPath, rest, func);
} else {
auto newPath = rest.front();
rest.erase(rest.begin());
std::shared_ptr<Node> leaf = std::make_shared<Node>(Node{path});
parent->m_next.insert_or_assign(path, leaf);
addNode(leaf, newPath, rest, func);
add_node(leaf, newPath, rest, func);
}
}
@@ -71,10 +71,10 @@ void Tree::add_path(std::string path,
auto newPath = subPaths.front();
subPaths.erase(subPaths.begin());
addNode(m_root, newPath, subPaths, func);
add_node(m_root, newPath, subPaths, func);
}
void printNode(std::shared_ptr<Node> node, size_t depth, size_t max_depth) {
void print_node(std::shared_ptr<Node> node, size_t depth, size_t max_depth) {
if (depth >= max_depth) {
return;
}
@@ -82,7 +82,7 @@ void printNode(std::shared_ptr<Node> node, size_t depth, size_t max_depth) {
std::cout << std::string(depth, ' ') << "sub: \"" << node->m_sub_path
<< "\" IsDummy: " << node->m_is_dummy << std::endl;
for (auto &next : node->m_next) {
printNode(next.second, depth + 1, max_depth);
print_node(next.second, depth + 1, max_depth);
}
}
@@ -123,4 +123,4 @@ Tree::get(std::string path) {
return traverse(m_root, newPath, subs);
}
void Tree::debug_Print() { printNode(m_root, 0, 10); }
void Tree::debug_Print() { print_node(m_root, 0, 10); }