From a32934d4bc910da1deb2a4737750090ec8969240 Mon Sep 17 00:00:00 2001 From: Pablu23 Date: Mon, 8 Jul 2024 02:04:16 +0200 Subject: [PATCH] Initial commit --- .gitignore | 2 + server.cpp | 225 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 227 insertions(+) create mode 100644 .gitignore create mode 100644 server.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..752e637 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.out +server diff --git a/server.cpp b/server.cpp new file mode 100644 index 0000000..6b0eaed --- /dev/null +++ b/server.cpp @@ -0,0 +1,225 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class Request { +private: + std::map m_headers; + std::string m_method; + std::string m_path; + std::vector m_payload; + std::string m_protocol; + +private: + bool protocol(std::stringstream *ss, int *procPart, char c) { + if (c == ' ' || c == '\n') { + switch (*procPart) { + case 0: + m_method = ss->str(); + break; + case 1: + m_path = ss->str(); + break; + case 2: + m_protocol = ss->str(); + break; + } + (*procPart)++; + ss->str(""); + if (c == '\n') + return false; + } else { + ss->put(c); + } + return true; + } + +public: + Request(std::vector buf) { + std::string name; + std::stringstream ss; + bool header = true; + int procPart = 0; + bool data = false; + bool skipNext = false; + bool p = true; + for (auto &byte : buf) { + if (data) { + m_payload.push_back(byte); + continue; + } + + char c = static_cast(byte); + if (c == '\r') + continue; + + if (p) { + p = protocol(&ss, &procPart, c); + continue; + } + + if (skipNext && c == ' ') { + skipNext = false; + continue; + } + skipNext = false; + + if (c == ':' && header) { + skipNext = true; + header = false; + name = ss.str(); + ss.str(""); + } else if (c == '\n' && !name.empty()) { + m_headers.insert_or_assign(name, ss.str()); + ss.str(""); + name.clear(); + header = true; + } else if (c == '\n' && name.empty()) { + data = true; + } else { + ss << c; + } + } + } + + void Print() { + std::cout << "Protocol: " << m_protocol << "\n" + << "Req: " << m_method << " " << m_path << std::endl; + for (const auto &[key, value] : m_headers) { + std::cout << "[" << key << "]: [" << value << "]\n"; + } + + if (HasData()) { + std::cout << "Payload: " << std::endl; + for (auto &byte : m_payload) { + std::cout << static_cast(byte); + } + std::cout << std::endl; + } + } + bool HasData() { return m_payload.size() != 0; } + std::vector Data() { return m_payload; } +}; + +class Response { +private: + std::map m_headers; + std::vector m_payload; + +public: + Response(std::vector data) { + m_headers.insert(std::pair( + "content-length", std::to_string(data.size()))); + m_payload = data; + } + + Response(std::string data) { + m_headers.insert(std::pair( + "content-length", std::to_string(std::strlen(data.data())))); + + m_payload = std::vector(data.size() + 1); + std::transform(data.begin(), data.end(), m_payload.begin(), + [](char c) { return std::byte(c); }); + } + + void SetContentType(const std::string type) { + m_headers.insert_or_assign("content-type", type); + } + + void Send(int clientSocket) { + std::stringstream ss; + ss << "HTTP/1.1 200 OK\n"; + for (const auto &[key, value] : m_headers) { + ss << key << ": " << value << "\n"; + } + if (m_payload.size() >= 0) { + ss << "\n"; + for (auto &byte : m_payload) { + std::cout << int(byte) << ' '; + char c = static_cast(byte); + ss << c; + } + std::cout << std::endl; + } + std::string p = ss.str(); + send(clientSocket, p.data(), p.size(), 0); + } + + void Print() { + for (const auto &[key, value] : m_headers) { + std::cout << "[" << key << "]: [" << value << "]\n"; + } + + if (m_payload.size() != 0) { + std::cout << "Payload: " << std::endl; + for (auto &byte : m_payload) { + std::cout << static_cast(byte); + } + std::cout << std::endl; + } + } +}; + +int main() { + int serverSocket = socket(AF_INET, SOCK_STREAM, 0); + sockaddr_in serverAddress; + serverAddress.sin_family = AF_INET; + serverAddress.sin_port = htons(8080); + serverAddress.sin_addr.s_addr = INADDR_ANY; + + int err = bind(serverSocket, (struct sockaddr *)&serverAddress, + sizeof(serverAddress)); + if (err != 0) { + std::cout << "error binding " << strerror(errno) << std::endl; + exit(1); + } + + err = listen(serverSocket, 5); + if (err != 0) { + std::cout << "error listening " << strerror(errno) << std::endl; + exit(1); + } + + std::vector buffer(1024); + while (true) { + int clientSocket = accept(serverSocket, nullptr, nullptr); + int read = recv(clientSocket, buffer.data(), buffer.size(), 0); + buffer.resize(read); + Request req(buffer); + // req.Print(); + Response res = Response("Hello world!"); + if (req.HasData()) { + auto data = req.Data(); + res = Response(data); + } + + res.SetContentType("text/plain"); + // std::cout << "RESPONSE: " << std::endl; + // res.Print(); + res.Send(clientSocket); + close(clientSocket); + } + + if (shutdown(serverSocket, SHUT_RDWR) < 0) { + std::cout << "error shutdown " << strerror(errno) << std::endl; + exit(1); + } + + if (close(serverSocket) < 0) { + std::cout << "error closing socket " << strerror(errno) << std::endl; + exit(1); + } + + return 0; +}