Add correctly shutting down server and stopping threads
This commit is contained in:
5
Makefile
5
Makefile
@@ -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
|
||||
|
||||
|
||||
22
main.cpp
22
main.cpp
@@ -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;
|
||||
}
|
||||
|
||||
16
request.cpp
16
request.cpp
@@ -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; }
|
||||
|
||||
24
response.cpp
24
response.cpp
@@ -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";
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
10
router.cpp
10
router.cpp
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
14
tree.cpp
14
tree.cpp
@@ -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); }
|
||||
|
||||
Reference in New Issue
Block a user