From d36b046e9b2045ae88bd80821483361ca48aca9a Mon Sep 17 00:00:00 2001 From: Luiza Medeiros bezerra Date: Sat, 6 Jul 2024 20:03:29 -0300 Subject: [PATCH 1/4] faltou a msg --- .vscode/settings.json | 56 +++++++++++++++++++++++++ include/Client.hpp | 14 +++++-- include/Server.hpp | 9 ++-- include/common.hpp | 10 +++-- src/Client.cpp | 22 ++++++++-- src/Server.cpp | 95 +++++++++++++++++++++++++++++++++++-------- src/main.cpp | 16 ++------ 7 files changed, 180 insertions(+), 42 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..9f0d403 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,56 @@ +{ + "files.associations": { + "stdexcept": "cpp", + "iostream": "cpp", + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "*.tcc": "cpp", + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "compare": "cpp", + "concepts": "cpp", + "csignal": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "map": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "optional": "cpp", + "random": "cpp", + "string": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "fstream": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "istream": "cpp", + "limits": "cpp", + "new": "cpp", + "ostream": "cpp", + "ranges": "cpp", + "sstream": "cpp", + "streambuf": "cpp", + "typeinfo": "cpp" + } +} \ No newline at end of file diff --git a/include/Client.hpp b/include/Client.hpp index c717d75..275d574 100644 --- a/include/Client.hpp +++ b/include/Client.hpp @@ -3,10 +3,10 @@ /* ::: :::::::: */ /* Client.hpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: bmoretti +#+ +:+ +#+ */ +/* By: lumedeir < lumedeir@student.42sp.org.br +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/27 14:40:02 by bmoretti #+# #+# */ -/* Updated: 2024/07/01 13:47:27 by bmoretti ### ########.fr */ +/* Updated: 2024/07/06 16:09:27 by lumedeir ### ########.fr */ /* */ /* ************************************************************************** */ @@ -21,14 +21,22 @@ class Client Client(); ~Client(); void connectToServer(const int serverSocket); + void _setNonBlock(void); int getClientSocket(void) const; + int getPortClient(void) const; + bool _isConnected(void) const; + void _setConnected(bool status); + void _setClientSocket(int socket); + +protected: + bool _connected; private: int _clientSocket; struct sockaddr_in _address; void _createClientSocket(void); - void _setNonBlock(void); + }; diff --git a/include/Server.hpp b/include/Server.hpp index 5fec4b6..de74030 100644 --- a/include/Server.hpp +++ b/include/Server.hpp @@ -3,10 +3,10 @@ /* ::: :::::::: */ /* Server.hpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: bmoretti +#+ +:+ +#+ */ +/* By: lumedeir < lumedeir@student.42sp.org.br +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/27 10:40:41 by bmoretti #+# #+# */ -/* Updated: 2024/07/02 11:49:50 by bmoretti ### ########.fr */ +/* Updated: 2024/07/06 18:40:23 by lumedeir ### ########.fr */ /* */ /* ************************************************************************** */ @@ -23,6 +23,7 @@ class Server { private: int _serverSocket; + bool _isSigInt; struct sockaddr_in _address; std::vector _clients; @@ -31,9 +32,11 @@ class Server { void _bindServer(void); void _listen(void); void _polling(void); + void _verifyClients(void); + static void _handleSignal(int c); // Client management - void _acceptClient(void); + void _acceptClient(int socket); }; diff --git a/include/common.hpp b/include/common.hpp index f5c4a3e..c27d8db 100644 --- a/include/common.hpp +++ b/include/common.hpp @@ -3,10 +3,10 @@ /* ::: :::::::: */ /* common.hpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: bmoretti +#+ +:+ +#+ */ +/* By: lumedeir < lumedeir@student.42sp.org.br +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/27 11:24:48 by bmoretti #+# #+# */ -/* Updated: 2024/07/03 12:48:13 by vde-frei ### ########.fr */ +/* Updated: 2024/07/06 17:15:43 by lumedeir ### ########.fr */ /* */ /* ************************************************************************** */ @@ -26,11 +26,15 @@ # include # include # include +# include +# include +# include +# include // C++ LIBS # include -# include # include +# include # include # include # include diff --git a/src/Client.cpp b/src/Client.cpp index 0125eac..0969891 100644 --- a/src/Client.cpp +++ b/src/Client.cpp @@ -3,10 +3,10 @@ /* ::: :::::::: */ /* Client.cpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: bmoretti +#+ +:+ +#+ */ +/* By: lumedeir < lumedeir@student.42sp.org.br +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/27 14:46:10 by bmoretti #+# #+# */ -/* Updated: 2024/07/01 14:10:31 by bmoretti ### ########.fr */ +/* Updated: 2024/07/06 17:26:24 by lumedeir ### ########.fr */ /* */ /* ************************************************************************** */ @@ -22,7 +22,7 @@ Client::~Client() { void Client::connectToServer(const int serverSocket) { socklen_t addressSize = sizeof(this->_address); - this->_clientSocket = accept(serverSocket, + this->_clientSocket = accept(serverSocket, (struct sockaddr *)&this->_address, &addressSize); if (this->_clientSocket == -1) { throw std::runtime_error("Error connecting to the server"); @@ -34,6 +34,18 @@ int Client::getClientSocket(void) const { return this->_clientSocket; } +void Client::_setClientSocket(int socket) { + this->_clientSocket = socket; +} + +void Client::_setConnected(bool status) { + this->_connected = status; +} + +bool Client::_isConnected(void) const { + return this->_connected; +} + void Client::_createClientSocket(void) { this->_clientSocket = socket(AF_INET, SOCK_STREAM, 0); if (this->_clientSocket == -1) { @@ -53,3 +65,7 @@ void Client::_setNonBlock(void) { throw std::runtime_error("Error setting client to nonblock"); } } + +int Client::getPortClient(void) const{ + return this->_address.sin_port; +} \ No newline at end of file diff --git a/src/Server.cpp b/src/Server.cpp index e836e06..d679b9c 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -3,17 +3,19 @@ /* ::: :::::::: */ /* Server.cpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: bmoretti +#+ +:+ +#+ */ +/* By: lumedeir < lumedeir@student.42sp.org.br +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/27 10:40:35 by bmoretti #+# #+# */ -/* Updated: 2024/07/02 11:52:58 by bmoretti ### ########.fr */ +/* Updated: 2024/07/06 18:50:23 by lumedeir ### ########.fr */ /* */ /* ************************************************************************** */ #include "Server.hpp" +#include "common.hpp" -// PUBLIC FUNCTIONS +static bool isSigInt = false; +// PUBLIC FUNCTIONS Server::Server() { this->_address.sin_family = AF_INET; this->_address.sin_addr.s_addr = INADDR_ANY; @@ -25,6 +27,7 @@ Server::Server() { } Server::~Server() { + std::cout << "Client disconnected" << std::endl; for (std::vector::iterator it = this->_clients.begin(); it != this->_clients.end(); it++) { delete *it; @@ -54,13 +57,32 @@ void Server::_listen(void) { } } -void Server::_acceptClient(void) { +void Server::_acceptClient(int socket) { Client *client = new Client(); - client->connectToServer(this->_serverSocket); + // client->connectToServer(this->_serverSocket); + client->_setClientSocket(socket); + if (client->_isConnected() == true) + return; + client->_setNonBlock(); + // client->_setConnected(true); this->_clients.push_back(client); } +// void Server::_verifyClients(void) { +// for (std::vector::iterator it = this->_clients.begin(); +// it != this->_clients.end(); it++) { +// it +// //do_use_fd(*it); +// } +// } + +void Server::_handleSignal(int) +{ + isSigInt = true; + OUTNL(RED("\r[HALT]: STOPPING THE SERVER... \n")); +} + void Server::_polling(void) { struct epoll_event ev, events[MAX_EVENTS]; int conn_sock, nfds, epollfd; @@ -81,18 +103,57 @@ void Server::_polling(void) { } for (int n = 0; n < nfds; ++n) { if (events[n].data.fd == this->_serverSocket) { - this->_acceptClient(); - conn_sock = this->_clients.back()->getClientSocket(); - } - ev.events = EPOLLIN | EPOLLET; - ev.data.fd = conn_sock; - if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, &ev) == -1) { - throw std::runtime_error("Error adding client to server poll"); - } - else { - //RESOLVER OS EVENTOS DO NOSSO SERVER - std::cout << "teste" << std::endl; - //do_use_fd(events[n].data.fd); + conn_sock = accept(this->_serverSocket, (struct sockaddr *) &this->_address, (socklen_t*)&this->_address); + if (conn_sock < 0) { + throw std::runtime_error("Error accepting client"); + } + this->_acceptClient(conn_sock); + + if(send(conn_sock, "Hello, world!\n", 14, 0) != -1) + std::cout << "Mensagem enviada" << std::endl; + else + std::cout << "Erro ao enviar mensagem" << std::endl; + } + ev.events = EPOLLIN | EPOLLET; + ev.data.fd = conn_sock; + if (!this->_clients.back()->_isConnected() && epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, &ev) == -1) { + throw std::runtime_error("Error adding client server poll"); + } + else if (!this->_clients.back()->_isConnected()){ + this->_clients.back()->_setConnected(true); + } + else if (events[n].events & EPOLLIN) { + char buffer[1024]; + ssize_t bytesRead = read(events[n].data.fd, buffer, sizeof(buffer) - 1); + if (bytesRead > 0) { + buffer[bytesRead] = '\0'; // Null-terminate the buffer + std::string data(buffer); + std::istringstream ss(data); + std::string line; + while (std::getline(ss, line)) { + std::cout << "Received from client " << events[n].data.fd << " " << line << std::endl; + if (line == "exit\r"){ + close(events[n].data.fd); + for (std::vector::iterator it = this->_clients.begin(); + it != this->_clients.end(); it++) { + if ((*it)->getClientSocket() == events[n].data.fd){ + delete *it; + this->_clients.erase(it); + break; + } + } + } + else { + std::string response = "You said: " + line + "\n"; + send(events[n].data.fd, response.c_str(), response.size(), 0); + } + } + } else if (bytesRead == 0) { + // Conexão fechada pelo cliente + close(events[n].data.fd); + } else { + std::cerr << "Error reading from client" << std::endl; + } } } } diff --git a/src/main.cpp b/src/main.cpp index a3822c1..ac79d16 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,25 +1,15 @@ # include "Server.hpp" - -bool g_sigint = false; - -void handle_signal(int c) -{ - (void)c; - g_sigint = true; - OUTNL(RED("\r[HALT]: STOPPING THE SERVER... \n")); -} +# include int main(void) { signal(SIGPIPE, SIG_IGN); - signal(SIGINT, handle_signal); + signal(SIGINT, Server::_handleSignal); try { Server serv; } - - catch (std::exception &e) - { + catch (std::exception &e){ std::cerr << e.what() << std::endl; } return 0; From ea0447f5641559034afe692c248ef9630c016c67 Mon Sep 17 00:00:00 2001 From: LuMedeir Date: Wed, 17 Jul 2024 20:33:58 -0300 Subject: [PATCH 2/4] parser --- .vscode/launch.json | 33 ---- .vscode/settings.json | 56 ------- arquivo.conf | 60 +++++++ include/Client.hpp | 14 +- include/Config.hpp | 42 +++++ include/Request.hpp | 42 +++++ include/Response.hpp | 45 +++++ include/Server.hpp | 46 ++--- include/common.hpp | 21 ++- src/Client.cpp | 22 +-- src/Config.cpp | 147 ++++++++++++++++ src/Request.cpp | 59 +++++++ src/Response.cpp | 70 ++++++++ src/Server.cpp | 370 ++++++++++++++++++++++++++--------------- src/main.cpp | 24 +-- src/utils.cpp | 10 ++ tests/testClient.cpp | 68 -------- tests/testItoa.cpp | 23 +++ tests/testParser.cpp | 63 +++++++ tests/testRequest.cpp | 25 +++ tests/testResponse.hpp | 28 ++++ tests/testServer.cpp | 255 +++++++++++++++++++++++++--- web/index.html | 10 ++ 23 files changed, 1153 insertions(+), 380 deletions(-) delete mode 100644 .vscode/launch.json delete mode 100644 .vscode/settings.json create mode 100644 arquivo.conf create mode 100644 include/Config.hpp create mode 100644 include/Request.hpp create mode 100644 include/Response.hpp create mode 100644 src/Config.cpp create mode 100644 src/Request.cpp create mode 100644 src/Response.cpp create mode 100644 src/utils.cpp delete mode 100644 tests/testClient.cpp create mode 100644 tests/testItoa.cpp create mode 100644 tests/testParser.cpp create mode 100644 tests/testRequest.cpp create mode 100644 tests/testResponse.hpp create mode 100644 web/index.html diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index f454299..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "(gdb) Launch", - "type": "cppdbg", - "request": "launch", - "program": "${workspaceFolder}/bin/webserv", - "args": [], - "stopAtEntry": true, - "cwd": "${workspaceFolder}", - "environment": [], - "externalConsole": false, - "MIMode": "gdb", - "setupCommands": [ - { - "description": "Enable pretty-printing for gdb", - "text": "-enable-pretty-printing", - "ignoreFailures": true - }, - { - "description": "Set Disassembly Flavor to Intel", - "text": "-gdb-set disassembly-flavor intel", - "ignoreFailures": true - } - ] - } - - ] -} diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 9f0d403..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "files.associations": { - "stdexcept": "cpp", - "iostream": "cpp", - "array": "cpp", - "atomic": "cpp", - "bit": "cpp", - "*.tcc": "cpp", - "cctype": "cpp", - "clocale": "cpp", - "cmath": "cpp", - "compare": "cpp", - "concepts": "cpp", - "csignal": "cpp", - "cstdarg": "cpp", - "cstddef": "cpp", - "cstdint": "cpp", - "cstdio": "cpp", - "cstdlib": "cpp", - "cstring": "cpp", - "ctime": "cpp", - "cwchar": "cpp", - "cwctype": "cpp", - "deque": "cpp", - "map": "cpp", - "unordered_map": "cpp", - "vector": "cpp", - "exception": "cpp", - "algorithm": "cpp", - "functional": "cpp", - "iterator": "cpp", - "memory": "cpp", - "memory_resource": "cpp", - "numeric": "cpp", - "optional": "cpp", - "random": "cpp", - "string": "cpp", - "string_view": "cpp", - "system_error": "cpp", - "tuple": "cpp", - "type_traits": "cpp", - "utility": "cpp", - "fstream": "cpp", - "initializer_list": "cpp", - "iomanip": "cpp", - "iosfwd": "cpp", - "istream": "cpp", - "limits": "cpp", - "new": "cpp", - "ostream": "cpp", - "ranges": "cpp", - "sstream": "cpp", - "streambuf": "cpp", - "typeinfo": "cpp" - } -} \ No newline at end of file diff --git a/arquivo.conf b/arquivo.conf new file mode 100644 index 0000000..d136441 --- /dev/null +++ b/arquivo.conf @@ -0,0 +1,60 @@ +server { + server_name server.com; + listen 127.0.0.1:4242; + error_page 403 error_pages/403.html; + error_page 404 error_pages/404.html; + error_page 405 error_pages/405.html; + error_page 413 error_pages/413.html; + error_page 500 error_pages/500.html; + client_max_body_size 100000; + + location / { + autoindex on; + allow_methods GET POST DELETE; + root web_root; + upload_dir web_root/uploads + index index.html index.php; + cgi .php cgi-bin/php-cgi; + } + + location /potato/ { + autoindex on; + root web_root; + allow_methods GET POST DELETE; + } + + location /redirect/ { + return 301 https://google.com; + } + +} +server { + server_name server2.com; + listen 127.0.0.1:4242; + error_page 403 error_pages/403.html; + error_page 404 error_pages/404.html; + error_page 405 error_pages/405.html; + error_page 413 error_pages/413.html; + error_page 500 error_pages/500.html; + client_max_body_size 100; + + location / { + autoindex off; + allow_methods GET POST; + root web_root; + upload_dir web_root/uploads + index index.html index.php; + cgi .php cgi-bin/php-cgi; + } + + location /potato2/ { + autoindex on; + root web_root; + allow_methods GET; + } + + location /redirect/ { + return 301 https://google.com; + } + +} \ No newline at end of file diff --git a/include/Client.hpp b/include/Client.hpp index 275d574..c717d75 100644 --- a/include/Client.hpp +++ b/include/Client.hpp @@ -3,10 +3,10 @@ /* ::: :::::::: */ /* Client.hpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: lumedeir < lumedeir@student.42sp.org.br +#+ +:+ +#+ */ +/* By: bmoretti +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/27 14:40:02 by bmoretti #+# #+# */ -/* Updated: 2024/07/06 16:09:27 by lumedeir ### ########.fr */ +/* Updated: 2024/07/01 13:47:27 by bmoretti ### ########.fr */ /* */ /* ************************************************************************** */ @@ -21,22 +21,14 @@ class Client Client(); ~Client(); void connectToServer(const int serverSocket); - void _setNonBlock(void); int getClientSocket(void) const; - int getPortClient(void) const; - bool _isConnected(void) const; - void _setConnected(bool status); - void _setClientSocket(int socket); - -protected: - bool _connected; private: int _clientSocket; struct sockaddr_in _address; void _createClientSocket(void); - + void _setNonBlock(void); }; diff --git a/include/Config.hpp b/include/Config.hpp new file mode 100644 index 0000000..83d45c3 --- /dev/null +++ b/include/Config.hpp @@ -0,0 +1,42 @@ +#ifndef CONFIG_HPP +#define CONFIG_HPP + +#include "common.hpp" + +struct LocationConfig { + std::string path; + bool autoindex; + std::vector allow_methods; + std::string root; + std::string upload_dir; + std::vector index; + std::string cgi_extension; + std::string cgi_path; + std::string redirect; +}; + +struct ServerConfig { + std::string server_name; + std::string listen; + std::map error_pages; + size_t client_max_body_size; + std::vector locations; +}; + +class Config { + public: + Config(const std::string &filePath); + const std::vector& getServers() const; + void printServers() const; + + private: + std::string filePath; + std::vector servers; + + void parseConfigFile(); + void parseServerBlock(const std::vector &lines, size_t &index); + void parseLocationBlock(const std::vector &lines, size_t &index, ServerConfig &server); + std::string trim(const std::string& str); +}; + +#endif diff --git a/include/Request.hpp b/include/Request.hpp new file mode 100644 index 0000000..a9270dc --- /dev/null +++ b/include/Request.hpp @@ -0,0 +1,42 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* Request.hpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: bmoretti +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/07/11 18:24:18 by bmoretti #+# #+# */ +/* Updated: 2024/07/11 18:58:26 by bmoretti ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef REQUEST_HPP +# define REQUEST_HPP + +# include "common.hpp" + +typedef struct s_request +{ + std::string method; + std::string uri; + std::map headers; +} t_request; + +class Request +{ +public: + Request(const char * str); + ~Request(); + + t_request getRequest() const; + +private: + const char * _str; + t_request _request; + + std::string _trim(const std::string & str); + void _parseHTTPRequest(); + +}; + +#endif diff --git a/include/Response.hpp b/include/Response.hpp new file mode 100644 index 0000000..3918b99 --- /dev/null +++ b/include/Response.hpp @@ -0,0 +1,45 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* Response.hpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: bmoretti +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/07/13 13:06:55 by bmoretti #+# #+# */ +/* Updated: 2024/07/13 14:02:44 by bmoretti ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef RESPONSE_HPP +# define RESPONSE_HPP + +# include "common.hpp" +# include "Request.hpp" + +typedef struct s_response +{ + std::string statusLine; + std::map headers; + std::string body; +} t_response; + +class Response +{ +public: + Response(Request & request); + ~Response(); + + std::string getResponse() const; + +private: + Request & _request; + t_response _response; + + void _generateStatusLine(); + void _generateHeaders(); + void _generateBody(); + std::string _generateResponse() const; + +}; + +#endif diff --git a/include/Server.hpp b/include/Server.hpp index de74030..553c697 100644 --- a/include/Server.hpp +++ b/include/Server.hpp @@ -3,41 +3,41 @@ /* ::: :::::::: */ /* Server.hpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: lumedeir < lumedeir@student.42sp.org.br +#+ +:+ +#+ */ +/* By: bmoretti +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/27 10:40:41 by bmoretti #+# #+# */ -/* Updated: 2024/07/06 18:40:23 by lumedeir ### ########.fr */ +/* Updated: 2024/07/13 14:14:47 by bmoretti ### ########.fr */ /* */ /* ************************************************************************** */ #ifndef SERVER_HPP -#define SERVER_HPP +# define SERVER_HPP -#include "Client.hpp" -#include "common.hpp" +# include "common.hpp" +# include "Request.hpp" +# include "Response.hpp" +# include "Config.hpp" -class Server { +class Server +{ public: - Server(); + Server(const std::string &address, int port); ~Server(); -private: - int _serverSocket; - bool _isSigInt; - struct sockaddr_in _address; - std::vector _clients; - -// Server initialization - void _createServerSocket(void); - void _bindServer(void); - void _listen(void); - void _polling(void); - void _verifyClients(void); - static void _handleSignal(int c); - -// Client management - void _acceptClient(int socket); + void run(); +private: + /* Server initialization */ + void _initServer(); + void handleConnection(int client_fd); + void handleEvents(); + void setNonBlocking(int fd); + + std::string _address; + int _port; + int _server_fd; + int _epoll_fd; + struct epoll_event _events[MAX_EVENTS]; }; #endif diff --git a/include/common.hpp b/include/common.hpp index c27d8db..7675bda 100644 --- a/include/common.hpp +++ b/include/common.hpp @@ -3,10 +3,10 @@ /* ::: :::::::: */ /* common.hpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: lumedeir < lumedeir@student.42sp.org.br +#+ +:+ +#+ */ +/* By: bmoretti +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/27 11:24:48 by bmoretti #+# #+# */ -/* Updated: 2024/07/06 17:15:43 by lumedeir ### ########.fr */ +/* Updated: 2024/07/13 15:19:10 by bmoretti ### ########.fr */ /* */ /* ************************************************************************** */ @@ -19,22 +19,26 @@ # define MAX_EVENTS 10 // C libs +# include +# include # include +# include +# include # include # include # include # include # include # include -# include -# include -# include -# include // C++ LIBS +# include # include +# include +# include +# include # include -# include +# include # include # include # include @@ -67,4 +71,7 @@ # define BG_WHITE(text) "\033[47m" << text << "\033[0m" # define BG_BLACK(text) "\033[40m" << text << "\033[0m" +// functions +std::string itoa(int value); + #endif diff --git a/src/Client.cpp b/src/Client.cpp index 0969891..0125eac 100644 --- a/src/Client.cpp +++ b/src/Client.cpp @@ -3,10 +3,10 @@ /* ::: :::::::: */ /* Client.cpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: lumedeir < lumedeir@student.42sp.org.br +#+ +:+ +#+ */ +/* By: bmoretti +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/27 14:46:10 by bmoretti #+# #+# */ -/* Updated: 2024/07/06 17:26:24 by lumedeir ### ########.fr */ +/* Updated: 2024/07/01 14:10:31 by bmoretti ### ########.fr */ /* */ /* ************************************************************************** */ @@ -22,7 +22,7 @@ Client::~Client() { void Client::connectToServer(const int serverSocket) { socklen_t addressSize = sizeof(this->_address); - this->_clientSocket = accept(serverSocket, + this->_clientSocket = accept(serverSocket, (struct sockaddr *)&this->_address, &addressSize); if (this->_clientSocket == -1) { throw std::runtime_error("Error connecting to the server"); @@ -34,18 +34,6 @@ int Client::getClientSocket(void) const { return this->_clientSocket; } -void Client::_setClientSocket(int socket) { - this->_clientSocket = socket; -} - -void Client::_setConnected(bool status) { - this->_connected = status; -} - -bool Client::_isConnected(void) const { - return this->_connected; -} - void Client::_createClientSocket(void) { this->_clientSocket = socket(AF_INET, SOCK_STREAM, 0); if (this->_clientSocket == -1) { @@ -65,7 +53,3 @@ void Client::_setNonBlock(void) { throw std::runtime_error("Error setting client to nonblock"); } } - -int Client::getPortClient(void) const{ - return this->_address.sin_port; -} \ No newline at end of file diff --git a/src/Config.cpp b/src/Config.cpp new file mode 100644 index 0000000..89df398 --- /dev/null +++ b/src/Config.cpp @@ -0,0 +1,147 @@ +#include "Config.hpp" + +Config::Config(const std::string& filePath) : filePath(filePath) { + parseConfigFile(); +} + +void Config::parseConfigFile() { + std::ifstream configFile(filePath.c_str()); + if (!configFile.is_open()) { + std::cerr << "Error opening config file: " << filePath << std::endl; + return; + } + + std::string line; + std::vector lines; + while (std::getline(configFile, line)) + lines.push_back(line); + size_t index = 0; + while (index < lines.size()) { + std::string trimmedLine = trim(lines[index]); + if (trimmedLine == "server {") + parseServerBlock(lines, index); + ++index; + } +} + +void Config::parseServerBlock(const std::vector& lines, size_t& index) { + ServerConfig server; + + while (++index < lines.size()) { + std::string trimmedLine = trim(lines[index]); + if (trimmedLine == "}") + break; + else if (trimmedLine.find("server_name") == 0) + server.server_name = trimmedLine.substr(12); + else if (trimmedLine.find("listen") == 0) { + std::istringstream iss(trimmedLine.substr(7)); + iss >> server.listen; + } + else if (trimmedLine.find("client_max_body_size") == 0) { + std::istringstream iss(trimmedLine.substr(21)); + iss >> server.client_max_body_size; + } + else if (trimmedLine.find("error_page") == 0) { + size_t pos = trimmedLine.find(' ', 11); + int errorCode; + std::istringstream iss(trimmedLine.substr(11, pos - 11)); + iss >> errorCode; + std::string errorPage = trimmedLine.substr(pos + 1); + server.error_pages[errorCode] = errorPage; + } + else if (trimmedLine.find("location") == 0) + parseLocationBlock(lines, index, server); + } + + servers.push_back(server); +} + + +void Config::parseLocationBlock(const std::vector& lines, size_t& index, ServerConfig& server) { + LocationConfig location; + + size_t pos = lines[index].find(' '); + location.path = lines[index].substr(pos + 1); + + while (++index < lines.size()) { + std::string trimmedLine = trim(lines[index]); + if (trimmedLine == "}") + break; + else if (trimmedLine.find("autoindex") == 0) + location.autoindex = (trimmedLine.substr(10) == "on"); + else if (trimmedLine.find("root") == 0) + location.root = trimmedLine.substr(5); + else if (trimmedLine.find("upload_dir") == 0) + location.upload_dir = trimmedLine.substr(11); + else if (trimmedLine.find("index") == 0) { + std::istringstream iss(trimmedLine.substr(6)); + std::string idx; + while (iss >> idx) + location.index.push_back(idx); + } + else if (trimmedLine.find("allow_methods") == 0) { + std::istringstream iss(trimmedLine.substr(14)); + std::string method; + while (iss >> method) + location.allow_methods.push_back(method); + } + else if (trimmedLine.find("cgi_extension") == 0) + location.cgi_extension = trimmedLine.substr(14); + else if (trimmedLine.find("cgi_path") == 0) + location.cgi_path = trimmedLine.substr(9); + else if (trimmedLine.find("redirect") == 0) + location.redirect = trimmedLine.substr(9); + } + + server.locations.push_back(location); +} + +std::string Config::trim(const std::string& str) { + size_t first = 0; + size_t last = str.size() - 1; + + while (first <= last && std::isspace(str[first])) + ++first; + while (last >= first && std::isspace(str[last])) + --last; + if (first > last) + return ""; + return str.substr(first, last - first + 1); +} + +void Config::printServers() const { + std::cout << "Number of servers: " << servers.size() << "\n\n"; + for (size_t i = 0; i < servers.size(); ++i) { + const ServerConfig& server = servers[i]; + std::cout << "Server Name: " << server.server_name << "\n"; + std::cout << "Listen: " << server.listen << "\n"; + std::cout << "Client Max Body Size: " << server.client_max_body_size << "\n"; + + for (std::map::const_iterator it = server.error_pages.begin(); it != server.error_pages.end(); ++it) { + std::cout << "Error Page " << it->first << ": " << it->second << "\n"; + } + + for (size_t j = 0; j < server.locations.size(); ++j) { + const LocationConfig& location = server.locations[j]; + std::cout << "Location: " << location.path << "\n"; + std::cout << " Autoindex: " << (location.autoindex ? "on" : "off") << "\n"; + std::cout << " Root: " << location.root << "\n"; + std::cout << " Upload Dir: " << location.upload_dir << "\n"; + std::cout << " Index: "; + for (size_t k = 0; k < location.index.size(); ++k) + std::cout << location.index[k] << " "; + std::cout << "\n"; + std::cout << " Allow Methods: "; + for (size_t k = 0; k < location.allow_methods.size(); ++k) + std::cout << location.allow_methods[k] << " "; + std::cout << "\n"; + if (!location.cgi_extension.empty()) { + std::cout << " CGI Extension: " << location.cgi_extension << "\n"; + std::cout << " CGI Path: " << location.cgi_path << "\n"; + } + if (!location.redirect.empty()) + std::cout << " Redirect: " << location.redirect << "\n"; + } + std::cout << "\n"; + } +} diff --git a/src/Request.cpp b/src/Request.cpp new file mode 100644 index 0000000..ea543db --- /dev/null +++ b/src/Request.cpp @@ -0,0 +1,59 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* Request.cpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: bmoretti +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/07/11 18:29:18 by bmoretti #+# #+# */ +/* Updated: 2024/07/13 13:29:09 by bmoretti ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "Request.hpp" + +Request::Request(const char * str) : _str(str) +{ + this->_parseHTTPRequest(); +} + +Request::~Request() +{ + +} + +t_request Request::getRequest() const +{ + return this->_request; +} + +std::string Request::_trim(const std::string & str) +{ + std::string::size_type first = str.find_first_not_of(' '); + std::string::size_type last = str.find_last_not_of(' '); + + if (first == std::string::npos || last == std::string::npos) { + return ""; + } + return str.substr(first, last - first + 1); +} + +void Request::_parseHTTPRequest() +{ + std::istringstream requestStream(this->_str); + std::string line; + + std::getline(requestStream, line); + std::istringstream requestLineStream(line); + requestLineStream >> this->_request.method; + requestLineStream >> this->_request.uri; + + while (std::getline(requestStream, line) && line != "\r") { + std::string::size_type pos = line.find(':'); + if (pos != std::string::npos) { + std::string key = this->_trim(line.substr(0, pos)); + std::string value = this->_trim(line.substr(pos + 1)); + this->_request.headers[key] = value; + } + } +} diff --git a/src/Response.cpp b/src/Response.cpp new file mode 100644 index 0000000..81680cd --- /dev/null +++ b/src/Response.cpp @@ -0,0 +1,70 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* Response.cpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: bmoretti +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/07/13 13:07:40 by bmoretti #+# #+# */ +/* Updated: 2024/07/13 15:41:19 by bmoretti ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "Response.hpp" + +Response::Response(Request & request) : _request(request) +{ + this->_generateStatusLine(); + this->_generateHeaders(); + this->_generateBody(); +} + +Response::~Response() +{ +} + +std::string Response::getResponse() const +{ + return this->_generateResponse(); +} + +void Response::_generateStatusLine() +{ + // mocking the status line + this->_response.statusLine = "HTTP/1.1 200 OK"; +} + +void Response::_generateHeaders() +{ + // mocking the headers + this->_response.headers["Content-Type"] = "text/html"; +} + +void Response::_generateBody() +{ + std::ifstream file("./web/index.html"); + + if (file.is_open()) { + std::stringstream buffer; + std::string bufferStr; + buffer << file.rdbuf(); + bufferStr = buffer.str(); + this->_response.body = bufferStr; + this->_response.headers["Content-Length"] = itoa(bufferStr.size()); + file.close(); + } else { + // [TODO] mensagem de arquivo não encontrado + } +} + +std::string Response::_generateResponse() const +{ + std::string response = this->_response.statusLine + "\r\n"; + for (std::map::const_iterator it = + this->_response.headers.begin(); it != this->_response.headers.end(); + ++it) { + response += it->first + ": " + it->second + "\r\n"; + } + response += "\r\n" + this->_response.body; + return response; +} diff --git a/src/Server.cpp b/src/Server.cpp index d679b9c..01ab2bc 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -3,158 +3,264 @@ /* ::: :::::::: */ /* Server.cpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: lumedeir < lumedeir@student.42sp.org.br +#+ +:+ +#+ */ +/* By: bmoretti +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/27 10:40:35 by bmoretti #+# #+# */ -/* Updated: 2024/07/06 18:50:23 by lumedeir ### ########.fr */ +/* Updated: 2024/07/13 15:31:38 by bmoretti ### ########.fr */ /* */ /* ************************************************************************** */ -#include "Server.hpp" -#include "common.hpp" +#include "../include/Server.hpp" -static bool isSigInt = false; - -// PUBLIC FUNCTIONS -Server::Server() { - this->_address.sin_family = AF_INET; - this->_address.sin_addr.s_addr = INADDR_ANY; - this->_address.sin_port = htons(PORT); - this->_createServerSocket(); - this->_bindServer(); - this->_listen(); - this->_polling(); +Server::Server(const std::string &address, int port) : _address(address), + _port(port), _server_fd(-1), _epoll_fd(-1) +{ + _initServer(); } -Server::~Server() { - std::cout << "Client disconnected" << std::endl; - for (std::vector::iterator it = this->_clients.begin(); - it != this->_clients.end(); it++) { - delete *it; - } - close(this->_serverSocket); -} +Server::~Server() +{ + /* verificar se o os fds sao diferentes de -1 para dar close */ + if (_server_fd != -1) + { + close(_server_fd); + } -// PRIVATE FUNCTIONS + if (_epoll_fd != -1) + { + close(_epoll_fd); + } -void Server::_createServerSocket(void) { - this->_serverSocket = socket(AF_INET, SOCK_STREAM, 0); - if (this->_serverSocket == -1) { - throw std::runtime_error("Error creating the server socket"); - } } - -void Server::_bindServer(void) { - if (bind(this->_serverSocket, (struct sockaddr *)&this->_address, - sizeof(this->_address)) == -1) { - throw std::runtime_error("Error binding the server"); +void Server::_initServer() +{ + /* criando o socket/fd e verificando se ele continua -1 (se continuar, erro) */ + this->_server_fd = socket(AF_INET, SOCK_STREAM, 0); + if (this->_server_fd == -1) { + throw std::runtime_error("Failed to create socket"); } -} -void Server::_listen(void) { - if (listen(this->_serverSocket, MAX_CONNECTIONS) == -1) { - throw std::runtime_error("Error listening the server"); - } -} + /* configurando o socket/fd do servidor para poder ser reutilizado assim que + * for fechado, eh bom para casos em que voce precisa reiniciar o servidor + * sem esperar em que o sistema operacional liberar a porta automaticamente + * (normalmente tem um tempo para isso ocorrer) + **/ + int opt = 1; // argumento para ser usado com o novo valor para setar. + if (setsockopt(_server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) + { + throw std::runtime_error("Failed to set socket options"); + } + + /* estrutura para usar com o protocolo IPv4 e contem campos para especificar o endereco de IP + * numero da porta dentro outras coisas. + **/ + sockaddr_in server_addr; + + /* inicializando todo os bytes para do server_addr para 0 para assegurar que todos os campos vao inicar + * com o mesmo valor + **/ + memset(&server_addr, 0, sizeof(server_addr)); + + /* sin_famlily = Address Family Internet - sever para especificar que esta usando IPV4 */ + server_addr.sin_family = AF_INET; + + /* a funcao inet_addr recebe uma representacao de uma string(char *) com um endereco IPv4 e retorna + * a representacao binaria do ip para operacoes de rede. + * e essa linha so esta setando o endereco de ip para o ip passado via string para a inet_addr + **/ + server_addr.sin_addr.s_addr = inet_addr(_address.c_str()); + + /* variavel da struct server_addr em que voce indica a porta que sera utilizada + * a funcao htons ("Host TO Network Short") converte o numero da porta para bytes de ordem de host + * ela garante que o numero da porta estara corretamente interpretado independente da arquitetura + * do sistema. + * */ + server_addr.sin_port = htons(_port); -void Server::_acceptClient(int socket) { - Client *client = new Client(); + /* a funcao bind associa o socket referido pelo fd '_server_fd' com o endereco de IP local + * e com a porta especificada na estrutura 'server_addr' e informa ao sistema que a aplicacao + * quer receber dados no ip e na porta direcionada. + **/ + if (bind(_server_fd, (sockaddr*)&server_addr, sizeof(server_addr)) == -1) + { + throw std::runtime_error("Failed to bind socket"); + } - // client->connectToServer(this->_serverSocket); - client->_setClientSocket(socket); - if (client->_isConnected() == true) - return; - client->_setNonBlock(); - // client->_setConnected(true); - this->_clients.push_back(client); + /* apos o binding a funcao listen server parr colocar o socket no estado de espera. + * Significa que o socket esta pronto para aceitar as requisicoes de conexao de + * entrada dos clientes. + **/ + if (listen(_server_fd, MAX_CONNECTIONS) == -1) + { + throw std::runtime_error("Failed to listen socket"); + } + + /* maiores explicacoes dentro da funcao principal + * mas a funcao apenas captura e altera as flags do fd recebido + * como parametro + **/ + setNonBlocking(this->_server_fd); + + /* epoll_create1 eh mais simples que a epoll_create, ela recebe apenas a flags como parametro. + * ela eh usada para iniciar a interface de fds, que eh um mecanismo para monitorar multiplos fds + * epoll_create recebe o tamanho (quantidade de fds) que ira monitorar, porem a '1' nao precisa + * porque ela adiciona dinamicamente. + **/ + this->_epoll_fd = epoll_create1(0); + if (this->_epoll_fd == -1) + { + throw std::runtime_error("Failed to create epoll file descriptor"); + } + + /* essa parte do codigo configura um evento 'epoll' para monitorar um socket '_server_fd' + * em busca de novas conexoes. Ele utiliza um mecanismo de notificacao de entrada e saida + * escalavel + * primeiro criamos a variavel que vai monitorar. + **/ + epoll_event event; + + /* configurando o evento + * EPOLLIN - Indica que o evento pode ser adicionado quando houver dados disponiveis + * para leitura no fd. Normalmente significa que um novo pedido de conexao chegou. + * EPOLLET - Esse eh acionado uma vez por serie de eventos. + **/ + event.events = EPOLLIN | EPOLLET; + + /* associando o fd/socket que sera monitorado */ + event.data.fd = this->_server_fd; + + /* epoll_ctl eh chamada para adicionar, modificar ou deletar eventos na instancia epoll + * atrelada ao _server_fd + **/ + if (epoll_ctl(_epoll_fd, EPOLL_CTL_ADD, _server_fd, &event) == -1) + { + throw std::runtime_error("Failed to add server socket to epoll"); + } } -// void Server::_verifyClients(void) { -// for (std::vector::iterator it = this->_clients.begin(); -// it != this->_clients.end(); it++) { -// it -// //do_use_fd(*it); -// } -// } +/* essa funcao 'run' foi feita para esperar eventos de varios clients (fds) de maneira eficiente + * ela monitora a instancia do epoll_fd permitindo que o sevidor esperar atividade de varios fds + **/ +void Server::run() +{ + /* esse eh o loop geral para o servidor ficar esperando por eventos */ + while (true) + { + /* essa funcao espera por eventos de fds registrados na instancia epoll determinada + * na _epoll_fd + **/ + int event_count = epoll_wait(_epoll_fd, _events, MAX_EVENTS, -1); + if (event_count == -1) + { + throw std::runtime_error("Failed to wait on epoll"); + } + + /* esse loop eh para processamento do eventos detectados */ + for (int i = 0; i < event_count; i++) + { + /* aqui ele ficar verificando se o evento pertence ao fd do server + * ou do cliente ja conectado. + * Se for do servidor, ele tentara aceitar novas conexoes em um loop + * e para cada nova conexao ele configura o fd do cliente para o modo + * nao bloqueante e registra o descritor na epoll para futuras operacoes + * de leitura. + **/ + if (_events[i].data.fd == _server_fd) + { + /* configurando o fd do cliente e aceitando a conexao */ + while (true) + { + sockaddr_in client_addr; + socklen_t client_addr_len = sizeof(client_addr); + int client_fd = accept(_server_fd, (sockaddr*)&client_addr, &client_addr_len); + if (client_fd == -1) + { + if (errno == EAGAIN || errno == EWOULDBLOCK) + break; + else + { + std::cerr << "Failed to accept client connection" << std::endl; + break; + } + } + setNonBlocking(client_fd); -void Server::_handleSignal(int) + epoll_event event; + event.events = EPOLLIN | EPOLLET; + event.data.fd = client_fd; + if (epoll_ctl(_epoll_fd, EPOLL_CTL_ADD, client_fd, &event) == -1) + { + std::cerr << "Failed to add client socket to epoll" << std::endl; + close(client_fd); + } + } + } else { + handleConnection(_events[i].data.fd); // Se o evento nao for do servidor + // e sim um cliente ja conectado, essa funcao eh chamada para processar os dados recebidos + // desse cliente + } + } + } +} + +void Server::handleConnection(int client_fd) { - isSigInt = true; - OUTNL(RED("\r[HALT]: STOPPING THE SERVER... \n")); + char buffer[BUFFER_SIZE]; + while (true) + { + ssize_t bytes_read = read(client_fd, buffer, sizeof(buffer) - 1); + if (bytes_read == -1) + { + if (errno == EAGAIN || errno == EWOULDBLOCK) + break ; // no more data to read + else + { + std::cerr << "Read error" << std::endl; + close(client_fd); + break ; + } + } + else if (bytes_read == 0) + { + close(client_fd); + break ; // client closed connection + } + else { + buffer[bytes_read] = '\0'; + // std::cout << "From client: " << client_fd << " | Received: " << buffer; + + Request request(buffer); + Response response(request); + std::string responseStr = response.getResponse(); + const char *respStr = responseStr.c_str(); + + // const char *response = "HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello, World!"; + ssize_t bytes_written = write(client_fd, respStr, strlen(respStr)); + if (bytes_written == -1) + { + std::cerr << "Write error" << std::endl; + } + // close(client_fd); // descomentar para ter apenas uma 'requisicao e fechar a conexao + // acho que isso nao vai precisar, provavelmente vamos precisar lidar com sinais. + } + } } -void Server::_polling(void) { - struct epoll_event ev, events[MAX_EVENTS]; - int conn_sock, nfds, epollfd; +void Server::setNonBlocking(int fd) +{ + /* essa funcao eh usada para manipular as flags dos files descriptors. + * nessa parte do codigo estamos usando para pegar as atuais flags do + * fd passado no primero parametro. + **/ + int flags = fcntl(fd, F_GETFL, 0); + if (flags == -1) + { + throw std::runtime_error("Failed to get file descriptor flags"); + } - epollfd = epoll_create1(0); - if (epollfd == -1) { - throw std::runtime_error("Error polling"); - } - ev.events = EPOLLIN; - ev.data.fd = this->_serverSocket; - if (epoll_ctl(epollfd, EPOLL_CTL_ADD, this->_serverSocket, &ev) == -1) { - throw std::runtime_error("Error polling the server socket"); - } - for (;;) { - nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1); - if (nfds == -1) { - throw std::runtime_error("Error polling events"); - } - for (int n = 0; n < nfds; ++n) { - if (events[n].data.fd == this->_serverSocket) { - conn_sock = accept(this->_serverSocket, (struct sockaddr *) &this->_address, (socklen_t*)&this->_address); - if (conn_sock < 0) { - throw std::runtime_error("Error accepting client"); - } - this->_acceptClient(conn_sock); - - if(send(conn_sock, "Hello, world!\n", 14, 0) != -1) - std::cout << "Mensagem enviada" << std::endl; - else - std::cout << "Erro ao enviar mensagem" << std::endl; - } - ev.events = EPOLLIN | EPOLLET; - ev.data.fd = conn_sock; - if (!this->_clients.back()->_isConnected() && epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, &ev) == -1) { - throw std::runtime_error("Error adding client server poll"); - } - else if (!this->_clients.back()->_isConnected()){ - this->_clients.back()->_setConnected(true); - } - else if (events[n].events & EPOLLIN) { - char buffer[1024]; - ssize_t bytesRead = read(events[n].data.fd, buffer, sizeof(buffer) - 1); - if (bytesRead > 0) { - buffer[bytesRead] = '\0'; // Null-terminate the buffer - std::string data(buffer); - std::istringstream ss(data); - std::string line; - while (std::getline(ss, line)) { - std::cout << "Received from client " << events[n].data.fd << " " << line << std::endl; - if (line == "exit\r"){ - close(events[n].data.fd); - for (std::vector::iterator it = this->_clients.begin(); - it != this->_clients.end(); it++) { - if ((*it)->getClientSocket() == events[n].data.fd){ - delete *it; - this->_clients.erase(it); - break; - } - } - } - else { - std::string response = "You said: " + line + "\n"; - send(events[n].data.fd, response.c_str(), response.size(), 0); - } - } - } else if (bytesRead == 0) { - // Conexão fechada pelo cliente - close(events[n].data.fd); - } else { - std::cerr << "Error reading from client" << std::endl; - } - } - } - } + /* essa parte eh para adicionar a flag non-blocking ao set de flags existente do fd. */ + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) + { + throw std::runtime_error("Failed to set non-blocking mode"); + } } diff --git a/src/main.cpp b/src/main.cpp index ac79d16..ec2cb81 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,16 +1,16 @@ -# include "Server.hpp" -# include +# include "../include/Server.hpp" int main(void) { - signal(SIGPIPE, SIG_IGN); - signal(SIGINT, Server::_handleSignal); + Config config("arquivo.conf"); + config.printServers(); - try { - Server serv; - } - catch (std::exception &e){ - std::cerr << e.what() << std::endl; - } - return 0; -} + + // try { + // Server server("127.0.0.1", PORT); + // server.run(); + // } catch (std::exception &e) { + // std::cerr << RED("Error: ") << e.what() << std::endl; + // } + // return 0; +} \ No newline at end of file diff --git a/src/utils.cpp b/src/utils.cpp new file mode 100644 index 0000000..c1a49e0 --- /dev/null +++ b/src/utils.cpp @@ -0,0 +1,10 @@ +#include "common.hpp" + +std::string itoa(int value) +{ + std::string str; + std::stringstream ss; + ss << value; + ss >> str; + return str; +} diff --git a/tests/testClient.cpp b/tests/testClient.cpp deleted file mode 100644 index 22ba0da..0000000 --- a/tests/testClient.cpp +++ /dev/null @@ -1,68 +0,0 @@ -// tests/test_Client.cpp -#include -#include "../include/Client.hpp" - -// Mocking socket functions for testing -#include -#include - -class ClientTest : public ::testing::Test { -protected: - void SetUp() override { - // Set up any common initialization here - } - - void TearDown() override { - // Clean up any common cleanup here - } -}; - -TEST_F(ClientTest, ConstructorDestructor) { - Client client; - // If the destructor runs without exceptions, the test will pass -} - -TEST_F(ClientTest, ConnectToServerSuccess) { - Client client; - int serverSocket = socket(AF_INET, SOCK_STREAM, 0); - ASSERT_NE(serverSocket, -1) << "Failed to create server socket"; - - // Bind and listen to the socket to simulate a server - struct sockaddr_in serverAddress; - serverAddress.sin_family = AF_INET; - serverAddress.sin_addr.s_addr = htonl(INADDR_ANY); - serverAddress.sin_port = htons(8080); - - int bindResult = bind(serverSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress)); - ASSERT_NE(bindResult, -1) << "Failed to bind server socket"; - - int listenResult = listen(serverSocket, 1); - ASSERT_NE(listenResult, -1) << "Failed to listen on server socket"; - - // Create a client socket to connect to the server - int clientSocket = socket(AF_INET, SOCK_STREAM, 0); - ASSERT_NE(clientSocket, -1) << "Failed to create client socket"; - - // Connect to the server - struct sockaddr_in clientAddress; - clientAddress.sin_family = AF_INET; - clientAddress.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - clientAddress.sin_port = htons(8080); - - int connectResult = connect(clientSocket, (struct sockaddr*)&clientAddress, sizeof(clientAddress)); - ASSERT_NE(connectResult, -1) << "Failed to connect to the server"; - - // Use the client's connectToServer method to accept the connection - client.connectToServer(serverSocket); - - close(serverSocket); - close(clientSocket); -} - -TEST_F(ClientTest, ConnectToServerFailure) { - Client client; - int invalidServerSocket = -1; // Invalid server socket - - EXPECT_THROW(client.connectToServer(invalidServerSocket), std::runtime_error); -} - diff --git a/tests/testItoa.cpp b/tests/testItoa.cpp new file mode 100644 index 0000000..fa856f5 --- /dev/null +++ b/tests/testItoa.cpp @@ -0,0 +1,23 @@ +#include "../include/common.hpp" +#include + +TEST(ItoaTest, ZeroValue) { + EXPECT_EQ(itoa(0), "0"); +} + +TEST(ItoaTest, PositiveValues) { + EXPECT_EQ(itoa(123), "123"); + EXPECT_EQ(itoa(4567), "4567"); + EXPECT_EQ(itoa(98765), "98765"); +} + +TEST(ItoaTest, NegativeValues) { + EXPECT_EQ(itoa(-123), "-123"); + EXPECT_EQ(itoa(-4567), "-4567"); + EXPECT_EQ(itoa(-98765), "-98765"); +} + +TEST(ItoaTest, LargeValues) { + EXPECT_EQ(itoa(2147483647), "2147483647"); // Maximum positive int + EXPECT_EQ(itoa(-2147483648), "-2147483648"); // Minimum negative int (implementation-dependent) +} diff --git a/tests/testParser.cpp b/tests/testParser.cpp new file mode 100644 index 0000000..86285a9 --- /dev/null +++ b/tests/testParser.cpp @@ -0,0 +1,63 @@ +// #include "../include/Parser.hpp" +// #include +// #include +// #include +// #include +// #include + + +// class testParser : public ::testing::Test +// { +// protected: +// Parser* parser; +// std::thread parserThread; + +// virtual void SetUp() {} + +// virtual void TearDown() {} +// }; + +// TEST(ParserTest, EmptyInput) +// { +// Parser parser(""); +// t_request request = parser.getRequest(); +// EXPECT_EQ(request.method, ""); +// EXPECT_EQ(request.uri, ""); +// EXPECT_EQ(request.headers.size(), 0); +// } + +// TEST(ParserTest, SingleLineRequest) +// { +// Parser parser("GET /index.html"); +// t_request request = parser.getRequest(); +// EXPECT_EQ(request.method, "GET"); +// EXPECT_EQ(request.uri, "/index.html"); +// EXPECT_EQ(request.headers.size(), 0); +// } + +// TEST(ParserTest, RequestWithHeaders) +// { +// const char* requestStr = "GET /about HTTP/1.1\r\n" +// "Host: example.com\r\n" +// "Connection: keep-alive\r\n\r\n"; +// Parser parser(requestStr); +// t_request request = parser.getRequest(); +// EXPECT_EQ(request.method, "GET"); +// EXPECT_EQ(request.uri, "/about"); +// EXPECT_EQ(request.headers.size(), 2); +// EXPECT_EQ(request.headers["Host"], "example.com"); +// EXPECT_EQ(request.headers["Connection"], "keep-alive"); +// } + +// TEST(ParserTest, EmptyLineAfterHeaders) +// { +// const char* requestStr = "GET /contact\r\n" +// "Content-Length: 100\r\n" +// "\r\n"; +// Parser parser(requestStr); +// t_request request = parser.getRequest(); +// EXPECT_EQ(request.method, "GET"); +// EXPECT_EQ(request.uri, "/contact"); +// EXPECT_EQ(request.headers.size(), 1); +// EXPECT_EQ(request.headers["Content-Length"], "100"); +// } diff --git a/tests/testRequest.cpp b/tests/testRequest.cpp new file mode 100644 index 0000000..6684e99 --- /dev/null +++ b/tests/testRequest.cpp @@ -0,0 +1,25 @@ +#include +#include "Request.hpp" + +TEST(RequestTest, ParseSimpleGetRequest) { + const char * requestStr = "GET /index.html HTTP/1.1\r\nHost: example.com\r\n\r\n"; + Request request(requestStr); + t_request parsedRequest = request.getRequest(); + + EXPECT_EQ(parsedRequest.method, "GET"); + EXPECT_EQ(parsedRequest.uri, "/index.html"); + ASSERT_EQ(parsedRequest.headers.size(), 1); + EXPECT_EQ(parsedRequest.headers["Host"], "example.com"); +} + +TEST(RequestTest, ParseRequestWithMultipleHeaders) { + const char * requestStr = "POST /submit HTTP/1.1\r\nHost: example.com\r\nContent-Length: 27\r\n\r\n"; + Request request(requestStr); + t_request parsedRequest = request.getRequest(); + + EXPECT_EQ(parsedRequest.method, "POST"); + EXPECT_EQ(parsedRequest.uri, "/submit"); + ASSERT_EQ(parsedRequest.headers.size(), 2); + EXPECT_EQ(parsedRequest.headers["Host"], "example.com"); + EXPECT_EQ(parsedRequest.headers["Content-Length"], "27"); +} diff --git a/tests/testResponse.hpp b/tests/testResponse.hpp new file mode 100644 index 0000000..d3a97ec --- /dev/null +++ b/tests/testResponse.hpp @@ -0,0 +1,28 @@ +#include +#include "../include/Response.hpp" +#include "../include/Request.hpp" + +class ResponseTest : public ::testing::Test { +protected: + void SetUp() override { + const char * requestStr = "GET /index.html HTTP/1.1\r\nHost: example.com\r\n\r\n"; + request = new Request(requestStr); + response = new Response(*request); + } + + void TearDown() override { + delete response; + delete request; + } + + Request *request; + Response *response; +}; + +TEST_F(ResponseTest, GenerateResponse) { + std::string responseStr = response->getResponse(); + EXPECT_NE(responseStr.find("HTTP/1.1 200 OK"), std::string::npos); + EXPECT_NE(responseStr.find("Content-Type: text/html"), std::string::npos); + EXPECT_NE(responseStr.find("Content-Length"), std::string::npos); + EXPECT_NE(responseStr.find(""), std::string::npos); // Assuming your index.html has tag +} diff --git a/tests/testServer.cpp b/tests/testServer.cpp index 9666125..77a8c99 100644 --- a/tests/testServer.cpp +++ b/tests/testServer.cpp @@ -1,29 +1,246 @@ #include "../include/Server.hpp" #include +#include +#include +#include +#include +#include +#include -/** - * to create tests for your classes and function - * you need to create a class that inherit from - * 'public ::testing::Test' - **/ class ServerTest : public ::testing::Test { protected: - Server *server; + Server* server; + std::thread serverThread; - // to initialize with what you need to run your tests - virtual void SetUp() { server = new Server(); } + virtual void SetUp() { + server = new Server("127.0.0.1", PORT); + serverThread = std::thread([this]() { + server->run(); + }); + // Give the server a moment to start up + std::this_thread::sleep_for(std::chrono::seconds(1)); + } - // to destroy, delete or do things that you should do when test ends. - virtual void TearDown() { delete server; } + virtual void TearDown() { + // Stop the server thread + if (serverThread.joinable()) { + serverThread.detach(); + } + delete server; + } }; -/** - * TEST_F is the MACRO to you start the assertions first param is the class - * that you make above second param is the name of you test. inside of brackets - * you should insert your asserts - * - * this assert test the constructor and all functions - * even the private functions, becaus the constructor use all. - **/ +TEST_F(ServerTest, ServerStartsSuccessfully) { + // Test if the server starts and listens successfully + int sock = socket(AF_INET, SOCK_STREAM, 0); + ASSERT_NE(sock, -1); -TEST_F(ServerTest, Cosntructor) { ASSERT_NE(server, nullptr); } + sockaddr_in server_addr; + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); + server_addr.sin_port = htons(PORT); + + int result = connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)); + ASSERT_NE(result, -1); + + close(sock); +} + +// TEST_F(ServerTest, ServerHandlesClientConnection) { +// // Test if the server can handle a client connection +// int sock = socket(AF_INET, SOCK_STREAM, 0); +// ASSERT_NE(sock, -1); + +// sockaddr_in server_addr; +// memset(&server_addr, 0, sizeof(server_addr)); +// server_addr.sin_family = AF_INET; +// server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); +// server_addr.sin_port = htons(PORT); + +// int result = connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)); +// ASSERT_NE(result, -1); + +// const char* message = "Hello Server"; +// send(sock, message, strlen(message), 0); + +// char buffer[BUFFER_SIZE]; +// int bytes_received = recv(sock, buffer, sizeof(buffer) - 1, 0); +// ASSERT_GT(bytes_received, 0); + +// buffer[bytes_received] = '\0'; +// std::string response(buffer); +// ASSERT_EQ(response, "HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello, World!"); + +// close(sock); +// } + +// TEST_F(ServerTest, HandlesMultipleClientConnections) { +// const int num_clients = 5; +// int client_socks[num_clients]; + +// for (int i = 0; i < num_clients; ++i) { +// client_socks[i] = socket(AF_INET, SOCK_STREAM, 0); +// ASSERT_NE(client_socks[i], -1); + +// sockaddr_in server_addr; +// memset(&server_addr, 0, sizeof(server_addr)); +// server_addr.sin_family = AF_INET; +// server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); +// server_addr.sin_port = htons(PORT); + +// int result = connect(client_socks[i], (struct sockaddr*)&server_addr, sizeof(server_addr)); +// ASSERT_NE(result, -1); +// } + +// for (int i = 0; i < num_clients; ++i) { +// const char* message = "Hello Server"; +// send(client_socks[i], message, strlen(message), 0); + +// char buffer[BUFFER_SIZE]; +// int bytes_received = recv(client_socks[i], buffer, sizeof(buffer) - 1, 0); +// ASSERT_GT(bytes_received, 0); + +// buffer[bytes_received] = '\0'; +// std::string response(buffer); +// ASSERT_EQ(response, "HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello, World!"); + +// close(client_socks[i]); +// } +// } + +// TEST_F(ServerTest, HandlesInvalidClientConnections) { +// int sock = socket(AF_INET, SOCK_STREAM, 0); +// ASSERT_NE(sock, -1); + +// sockaddr_in server_addr; +// memset(&server_addr, 0, sizeof(server_addr)); +// server_addr.sin_family = AF_INET; +// server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); +// server_addr.sin_port = htons(PORT); + +// int result = connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)); +// ASSERT_NE(result, -1); + +// const char* message = ""; +// send(sock, message, strlen(message), 0); + +// char buffer[BUFFER_SIZE]; +// int bytes_received = recv(sock, buffer, sizeof(buffer) - 1, 0); +// ASSERT_EQ(bytes_received, 0); + +// close(sock); +// } + +// TEST_F(ServerTest, HandlesServerShutdown) { +// serverThread.detach(); // Detach the thread to simulate shutdown +// delete server; // Delete the server instance to simulate shutdown + +// // Attempt to connect after shutdown +// int sock = socket(AF_INET, SOCK_STREAM, 0); +// ASSERT_NE(sock, -1); + +// sockaddr_in server_addr; +// memset(&server_addr, 0, sizeof(server_addr)); +// server_addr.sin_family = AF_INET; +// server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); +// server_addr.sin_port = htons(PORT); + +// int result = connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)); +// ASSERT_EQ(result, -1); // Connection should fail + +// close(sock); +// } + +// TEST_F(ServerTest, NonBlockingBehavior) { +// int sock = socket(AF_INET, SOCK_STREAM, 0); +// ASSERT_NE(sock, -1); + +// sockaddr_in server_addr; +// memset(&server_addr, 0, sizeof(server_addr)); +// server_addr.sin_family = AF_INET; +// server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); +// server_addr.sin_port = htons(PORT); + +// int result = connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)); +// ASSERT_NE(result, -1); + +// const char* message = "Hello Server"; +// send(sock, message, strlen(message), 0); + +// char buffer[1024]; +// int flags = fcntl(sock, F_GETFL, 0); +// ASSERT_NE(flags, -1); +// fcntl(sock, F_SETFL, flags | O_NONBLOCK); + +// int bytes_received = recv(sock, buffer, sizeof(buffer) - 1, 0); +// if (bytes_received == -1) { +// ASSERT_EQ(errno, EAGAIN); +// } else { +// ASSERT_GT(bytes_received, 0); +// } +// close(sock); +// } + +// // tests/test_Server.cpp (continuation) +// TEST_F(ServerTest, HandlesLargePayload) { +// int sock = socket(AF_INET, SOCK_STREAM, 0); +// ASSERT_NE(sock, -1); + +// sockaddr_in server_addr; +// memset(&server_addr, 0, sizeof(server_addr)); +// server_addr.sin_family = AF_INET; +// server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); +// server_addr.sin_port = htons(8080); + +// int result = connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)); +// ASSERT_NE(result, -1); + +// std::string large_message(10000, 'A'); +// send(sock, large_message.c_str(), large_message.size(), 0); + +// char buffer[1024]; +// int bytes_received = recv(sock, buffer, sizeof(buffer) - 1, 0); +// ASSERT_GT(bytes_received, 0); + +// buffer[bytes_received] = '\0'; +// std::string response(buffer); +// ASSERT_EQ(response, "HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello, World!"); + +// close(sock); +// } + +// TEST_F(ServerTest, EdgeTriggeredEvents) { +// int sock = socket(AF_INET, SOCK_STREAM, 0); +// ASSERT_NE(sock, -1); + +// sockaddr_in server_addr; +// memset(&server_addr, 0, sizeof(server_addr)); +// server_addr.sin_family = AF_INET; +// server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); +// server_addr.sin_port = htons(8080); + +// int result = connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)); +// ASSERT_NE(result, -1); + +// const char* message = "Hello Server"; +// send(sock, message, strlen(message), 0); + +// char buffer[1024]; +// int bytes_received = recv(sock, buffer, sizeof(buffer) - 1, 0); +// ASSERT_GT(bytes_received, 0); + +// buffer[bytes_received] = '\0'; +// std::string response(buffer); +// ASSERT_EQ(response, "HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello, World!"); + +// send(sock, message, strlen(message), 0); +// bytes_received = recv(sock, buffer, sizeof(buffer) - 1, 0); +// ASSERT_GT(bytes_received, 0); + +// buffer[bytes_received] = '\0'; +// response = std::string(buffer); +// ASSERT_EQ(response, "HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello, World!"); + +// close(sock); +// } diff --git a/web/index.html b/web/index.html new file mode 100644 index 0000000..ee5d379 --- /dev/null +++ b/web/index.html @@ -0,0 +1,10 @@ + + + + Webserv Project + + +

Web serv ou não?

+

Bruno, Luiza e Vini!

+ + From 8d529b341013214fa26cfd330f78d82a8b94865b Mon Sep 17 00:00:00 2001 From: Luiza Medeiros bezerra Date: Sat, 6 Jul 2024 20:03:29 -0300 Subject: [PATCH 3/4] faltou a msg --- include/Client.hpp | 14 +++++++++++--- include/Server.hpp | 2 +- include/common.hpp | 6 +++++- src/Client.cpp | 22 +++++++++++++++++++--- src/Server.cpp | 2 +- 5 files changed, 37 insertions(+), 9 deletions(-) diff --git a/include/Client.hpp b/include/Client.hpp index c717d75..275d574 100644 --- a/include/Client.hpp +++ b/include/Client.hpp @@ -3,10 +3,10 @@ /* ::: :::::::: */ /* Client.hpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: bmoretti +#+ +:+ +#+ */ +/* By: lumedeir < lumedeir@student.42sp.org.br +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/27 14:40:02 by bmoretti #+# #+# */ -/* Updated: 2024/07/01 13:47:27 by bmoretti ### ########.fr */ +/* Updated: 2024/07/06 16:09:27 by lumedeir ### ########.fr */ /* */ /* ************************************************************************** */ @@ -21,14 +21,22 @@ class Client Client(); ~Client(); void connectToServer(const int serverSocket); + void _setNonBlock(void); int getClientSocket(void) const; + int getPortClient(void) const; + bool _isConnected(void) const; + void _setConnected(bool status); + void _setClientSocket(int socket); + +protected: + bool _connected; private: int _clientSocket; struct sockaddr_in _address; void _createClientSocket(void); - void _setNonBlock(void); + }; diff --git a/include/Server.hpp b/include/Server.hpp index ebce47e..ddab2a7 100644 --- a/include/Server.hpp +++ b/include/Server.hpp @@ -3,7 +3,7 @@ /* ::: :::::::: */ /* Server.hpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: bmoretti +#+ +:+ +#+ */ +/* By: lumedeir < lumedeir@student.42sp.org.br +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/27 10:40:41 by bmoretti #+# #+# */ /* Updated: 2024/07/16 14:54:14 by bmoretti ### ########.fr */ diff --git a/include/common.hpp b/include/common.hpp index 7675bda..77238bc 100644 --- a/include/common.hpp +++ b/include/common.hpp @@ -3,7 +3,7 @@ /* ::: :::::::: */ /* common.hpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: bmoretti +#+ +:+ +#+ */ +/* By: lumedeir < lumedeir@student.42sp.org.br +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/27 11:24:48 by bmoretti #+# #+# */ /* Updated: 2024/07/13 15:19:10 by bmoretti ### ########.fr */ @@ -30,6 +30,10 @@ # include # include # include +# include +# include +# include +# include // C++ LIBS # include diff --git a/src/Client.cpp b/src/Client.cpp index 0125eac..0969891 100644 --- a/src/Client.cpp +++ b/src/Client.cpp @@ -3,10 +3,10 @@ /* ::: :::::::: */ /* Client.cpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: bmoretti +#+ +:+ +#+ */ +/* By: lumedeir < lumedeir@student.42sp.org.br +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/27 14:46:10 by bmoretti #+# #+# */ -/* Updated: 2024/07/01 14:10:31 by bmoretti ### ########.fr */ +/* Updated: 2024/07/06 17:26:24 by lumedeir ### ########.fr */ /* */ /* ************************************************************************** */ @@ -22,7 +22,7 @@ Client::~Client() { void Client::connectToServer(const int serverSocket) { socklen_t addressSize = sizeof(this->_address); - this->_clientSocket = accept(serverSocket, + this->_clientSocket = accept(serverSocket, (struct sockaddr *)&this->_address, &addressSize); if (this->_clientSocket == -1) { throw std::runtime_error("Error connecting to the server"); @@ -34,6 +34,18 @@ int Client::getClientSocket(void) const { return this->_clientSocket; } +void Client::_setClientSocket(int socket) { + this->_clientSocket = socket; +} + +void Client::_setConnected(bool status) { + this->_connected = status; +} + +bool Client::_isConnected(void) const { + return this->_connected; +} + void Client::_createClientSocket(void) { this->_clientSocket = socket(AF_INET, SOCK_STREAM, 0); if (this->_clientSocket == -1) { @@ -53,3 +65,7 @@ void Client::_setNonBlock(void) { throw std::runtime_error("Error setting client to nonblock"); } } + +int Client::getPortClient(void) const{ + return this->_address.sin_port; +} \ No newline at end of file diff --git a/src/Server.cpp b/src/Server.cpp index 5b933b9..af10120 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -3,7 +3,7 @@ /* ::: :::::::: */ /* Server.cpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: bmoretti +#+ +:+ +#+ */ +/* By: lumedeir < lumedeir@student.42sp.org.br +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/27 10:40:35 by bmoretti #+# #+# */ /* Updated: 2024/07/16 15:02:35 by bmoretti ### ########.fr */ From 9dcfa101eeb68a7b35f292a4c8ec48c98e58d22f Mon Sep 17 00:00:00 2001 From: LuMedeir Date: Thu, 18 Jul 2024 16:28:26 -0300 Subject: [PATCH 4/4] fix rebase --- arquivo.conf | 60 ++++++++++++++++++ include/Client.hpp | 14 +---- include/Config.hpp | 42 +++++++++++++ include/Server.hpp | 2 +- include/common.hpp | 6 +- src/Client.cpp | 22 +------ src/Config.cpp | 147 +++++++++++++++++++++++++++++++++++++++++++++ src/Server.cpp | 2 +- src/main.cpp | 18 +++--- 9 files changed, 269 insertions(+), 44 deletions(-) create mode 100644 arquivo.conf create mode 100644 include/Config.hpp create mode 100644 src/Config.cpp diff --git a/arquivo.conf b/arquivo.conf new file mode 100644 index 0000000..d136441 --- /dev/null +++ b/arquivo.conf @@ -0,0 +1,60 @@ +server { + server_name server.com; + listen 127.0.0.1:4242; + error_page 403 error_pages/403.html; + error_page 404 error_pages/404.html; + error_page 405 error_pages/405.html; + error_page 413 error_pages/413.html; + error_page 500 error_pages/500.html; + client_max_body_size 100000; + + location / { + autoindex on; + allow_methods GET POST DELETE; + root web_root; + upload_dir web_root/uploads + index index.html index.php; + cgi .php cgi-bin/php-cgi; + } + + location /potato/ { + autoindex on; + root web_root; + allow_methods GET POST DELETE; + } + + location /redirect/ { + return 301 https://google.com; + } + +} +server { + server_name server2.com; + listen 127.0.0.1:4242; + error_page 403 error_pages/403.html; + error_page 404 error_pages/404.html; + error_page 405 error_pages/405.html; + error_page 413 error_pages/413.html; + error_page 500 error_pages/500.html; + client_max_body_size 100; + + location / { + autoindex off; + allow_methods GET POST; + root web_root; + upload_dir web_root/uploads + index index.html index.php; + cgi .php cgi-bin/php-cgi; + } + + location /potato2/ { + autoindex on; + root web_root; + allow_methods GET; + } + + location /redirect/ { + return 301 https://google.com; + } + +} \ No newline at end of file diff --git a/include/Client.hpp b/include/Client.hpp index 275d574..c717d75 100644 --- a/include/Client.hpp +++ b/include/Client.hpp @@ -3,10 +3,10 @@ /* ::: :::::::: */ /* Client.hpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: lumedeir < lumedeir@student.42sp.org.br +#+ +:+ +#+ */ +/* By: bmoretti +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/27 14:40:02 by bmoretti #+# #+# */ -/* Updated: 2024/07/06 16:09:27 by lumedeir ### ########.fr */ +/* Updated: 2024/07/01 13:47:27 by bmoretti ### ########.fr */ /* */ /* ************************************************************************** */ @@ -21,22 +21,14 @@ class Client Client(); ~Client(); void connectToServer(const int serverSocket); - void _setNonBlock(void); int getClientSocket(void) const; - int getPortClient(void) const; - bool _isConnected(void) const; - void _setConnected(bool status); - void _setClientSocket(int socket); - -protected: - bool _connected; private: int _clientSocket; struct sockaddr_in _address; void _createClientSocket(void); - + void _setNonBlock(void); }; diff --git a/include/Config.hpp b/include/Config.hpp new file mode 100644 index 0000000..83d45c3 --- /dev/null +++ b/include/Config.hpp @@ -0,0 +1,42 @@ +#ifndef CONFIG_HPP +#define CONFIG_HPP + +#include "common.hpp" + +struct LocationConfig { + std::string path; + bool autoindex; + std::vector allow_methods; + std::string root; + std::string upload_dir; + std::vector index; + std::string cgi_extension; + std::string cgi_path; + std::string redirect; +}; + +struct ServerConfig { + std::string server_name; + std::string listen; + std::map error_pages; + size_t client_max_body_size; + std::vector locations; +}; + +class Config { + public: + Config(const std::string &filePath); + const std::vector& getServers() const; + void printServers() const; + + private: + std::string filePath; + std::vector servers; + + void parseConfigFile(); + void parseServerBlock(const std::vector &lines, size_t &index); + void parseLocationBlock(const std::vector &lines, size_t &index, ServerConfig &server); + std::string trim(const std::string& str); +}; + +#endif diff --git a/include/Server.hpp b/include/Server.hpp index ddab2a7..ebce47e 100644 --- a/include/Server.hpp +++ b/include/Server.hpp @@ -3,7 +3,7 @@ /* ::: :::::::: */ /* Server.hpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: lumedeir < lumedeir@student.42sp.org.br +#+ +:+ +#+ */ +/* By: bmoretti +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/27 10:40:41 by bmoretti #+# #+# */ /* Updated: 2024/07/16 14:54:14 by bmoretti ### ########.fr */ diff --git a/include/common.hpp b/include/common.hpp index 77238bc..7675bda 100644 --- a/include/common.hpp +++ b/include/common.hpp @@ -3,7 +3,7 @@ /* ::: :::::::: */ /* common.hpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: lumedeir < lumedeir@student.42sp.org.br +#+ +:+ +#+ */ +/* By: bmoretti +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/27 11:24:48 by bmoretti #+# #+# */ /* Updated: 2024/07/13 15:19:10 by bmoretti ### ########.fr */ @@ -30,10 +30,6 @@ # include # include # include -# include -# include -# include -# include // C++ LIBS # include diff --git a/src/Client.cpp b/src/Client.cpp index 0969891..0125eac 100644 --- a/src/Client.cpp +++ b/src/Client.cpp @@ -3,10 +3,10 @@ /* ::: :::::::: */ /* Client.cpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: lumedeir < lumedeir@student.42sp.org.br +#+ +:+ +#+ */ +/* By: bmoretti +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/27 14:46:10 by bmoretti #+# #+# */ -/* Updated: 2024/07/06 17:26:24 by lumedeir ### ########.fr */ +/* Updated: 2024/07/01 14:10:31 by bmoretti ### ########.fr */ /* */ /* ************************************************************************** */ @@ -22,7 +22,7 @@ Client::~Client() { void Client::connectToServer(const int serverSocket) { socklen_t addressSize = sizeof(this->_address); - this->_clientSocket = accept(serverSocket, + this->_clientSocket = accept(serverSocket, (struct sockaddr *)&this->_address, &addressSize); if (this->_clientSocket == -1) { throw std::runtime_error("Error connecting to the server"); @@ -34,18 +34,6 @@ int Client::getClientSocket(void) const { return this->_clientSocket; } -void Client::_setClientSocket(int socket) { - this->_clientSocket = socket; -} - -void Client::_setConnected(bool status) { - this->_connected = status; -} - -bool Client::_isConnected(void) const { - return this->_connected; -} - void Client::_createClientSocket(void) { this->_clientSocket = socket(AF_INET, SOCK_STREAM, 0); if (this->_clientSocket == -1) { @@ -65,7 +53,3 @@ void Client::_setNonBlock(void) { throw std::runtime_error("Error setting client to nonblock"); } } - -int Client::getPortClient(void) const{ - return this->_address.sin_port; -} \ No newline at end of file diff --git a/src/Config.cpp b/src/Config.cpp new file mode 100644 index 0000000..89df398 --- /dev/null +++ b/src/Config.cpp @@ -0,0 +1,147 @@ +#include "Config.hpp" + +Config::Config(const std::string& filePath) : filePath(filePath) { + parseConfigFile(); +} + +void Config::parseConfigFile() { + std::ifstream configFile(filePath.c_str()); + if (!configFile.is_open()) { + std::cerr << "Error opening config file: " << filePath << std::endl; + return; + } + + std::string line; + std::vector lines; + while (std::getline(configFile, line)) + lines.push_back(line); + size_t index = 0; + while (index < lines.size()) { + std::string trimmedLine = trim(lines[index]); + if (trimmedLine == "server {") + parseServerBlock(lines, index); + ++index; + } +} + +void Config::parseServerBlock(const std::vector& lines, size_t& index) { + ServerConfig server; + + while (++index < lines.size()) { + std::string trimmedLine = trim(lines[index]); + if (trimmedLine == "}") + break; + else if (trimmedLine.find("server_name") == 0) + server.server_name = trimmedLine.substr(12); + else if (trimmedLine.find("listen") == 0) { + std::istringstream iss(trimmedLine.substr(7)); + iss >> server.listen; + } + else if (trimmedLine.find("client_max_body_size") == 0) { + std::istringstream iss(trimmedLine.substr(21)); + iss >> server.client_max_body_size; + } + else if (trimmedLine.find("error_page") == 0) { + size_t pos = trimmedLine.find(' ', 11); + int errorCode; + std::istringstream iss(trimmedLine.substr(11, pos - 11)); + iss >> errorCode; + std::string errorPage = trimmedLine.substr(pos + 1); + server.error_pages[errorCode] = errorPage; + } + else if (trimmedLine.find("location") == 0) + parseLocationBlock(lines, index, server); + } + + servers.push_back(server); +} + + +void Config::parseLocationBlock(const std::vector& lines, size_t& index, ServerConfig& server) { + LocationConfig location; + + size_t pos = lines[index].find(' '); + location.path = lines[index].substr(pos + 1); + + while (++index < lines.size()) { + std::string trimmedLine = trim(lines[index]); + if (trimmedLine == "}") + break; + else if (trimmedLine.find("autoindex") == 0) + location.autoindex = (trimmedLine.substr(10) == "on"); + else if (trimmedLine.find("root") == 0) + location.root = trimmedLine.substr(5); + else if (trimmedLine.find("upload_dir") == 0) + location.upload_dir = trimmedLine.substr(11); + else if (trimmedLine.find("index") == 0) { + std::istringstream iss(trimmedLine.substr(6)); + std::string idx; + while (iss >> idx) + location.index.push_back(idx); + } + else if (trimmedLine.find("allow_methods") == 0) { + std::istringstream iss(trimmedLine.substr(14)); + std::string method; + while (iss >> method) + location.allow_methods.push_back(method); + } + else if (trimmedLine.find("cgi_extension") == 0) + location.cgi_extension = trimmedLine.substr(14); + else if (trimmedLine.find("cgi_path") == 0) + location.cgi_path = trimmedLine.substr(9); + else if (trimmedLine.find("redirect") == 0) + location.redirect = trimmedLine.substr(9); + } + + server.locations.push_back(location); +} + +std::string Config::trim(const std::string& str) { + size_t first = 0; + size_t last = str.size() - 1; + + while (first <= last && std::isspace(str[first])) + ++first; + while (last >= first && std::isspace(str[last])) + --last; + if (first > last) + return ""; + return str.substr(first, last - first + 1); +} + +void Config::printServers() const { + std::cout << "Number of servers: " << servers.size() << "\n\n"; + for (size_t i = 0; i < servers.size(); ++i) { + const ServerConfig& server = servers[i]; + std::cout << "Server Name: " << server.server_name << "\n"; + std::cout << "Listen: " << server.listen << "\n"; + std::cout << "Client Max Body Size: " << server.client_max_body_size << "\n"; + + for (std::map::const_iterator it = server.error_pages.begin(); it != server.error_pages.end(); ++it) { + std::cout << "Error Page " << it->first << ": " << it->second << "\n"; + } + + for (size_t j = 0; j < server.locations.size(); ++j) { + const LocationConfig& location = server.locations[j]; + std::cout << "Location: " << location.path << "\n"; + std::cout << " Autoindex: " << (location.autoindex ? "on" : "off") << "\n"; + std::cout << " Root: " << location.root << "\n"; + std::cout << " Upload Dir: " << location.upload_dir << "\n"; + std::cout << " Index: "; + for (size_t k = 0; k < location.index.size(); ++k) + std::cout << location.index[k] << " "; + std::cout << "\n"; + std::cout << " Allow Methods: "; + for (size_t k = 0; k < location.allow_methods.size(); ++k) + std::cout << location.allow_methods[k] << " "; + std::cout << "\n"; + if (!location.cgi_extension.empty()) { + std::cout << " CGI Extension: " << location.cgi_extension << "\n"; + std::cout << " CGI Path: " << location.cgi_path << "\n"; + } + if (!location.redirect.empty()) + std::cout << " Redirect: " << location.redirect << "\n"; + } + std::cout << "\n"; + } +} diff --git a/src/Server.cpp b/src/Server.cpp index af10120..5b933b9 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -3,7 +3,7 @@ /* ::: :::::::: */ /* Server.cpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: lumedeir < lumedeir@student.42sp.org.br +#+ +:+ +#+ */ +/* By: bmoretti +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/06/27 10:40:35 by bmoretti #+# #+# */ /* Updated: 2024/07/16 15:02:35 by bmoretti ### ########.fr */ diff --git a/src/main.cpp b/src/main.cpp index c5a1b76..1055a26 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,11 +2,15 @@ int main(void) { - try { - Server server("127.0.0.1", PORT); - server.run(); - } catch (std::exception &e) { - std::cerr << RED("Error: ") << e.what() << std::endl; - } - return 0; + Config config("arquivo.conf"); + config.printServers(); + + + // try { + // Server server("127.0.0.1", PORT); + // server.run(); + // } catch (std::exception &e) { + // std::cerr << RED("Error: ") << e.what() << std::endl; + // } + // return 0; }