diff --git a/Makefile b/Makefile index 066f47c..c5ff5e4 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ NAME = webserv CXX = c++ CXXFLAGS = -Wall -Wextra #-Werror -CXXFLAGS += -I$(HEADERS_D) +CXXFLAGS += $(HEADERS_I) CXXFLAGS += -std=c++98 CXXFLAGS += -g CXXFLAGS += -MMD -MP #header dependencie @@ -12,19 +12,20 @@ CXXFLAGS += -MMD -MP #header dependencie #SHELL = /bin/zsh VPATH = $(SRCS_D) -# HEADERS = $(HEADERS_D:%=-I%) -HEADERS_D = ./srcs -HEADERS = Webserv.hpp \ - ConfigParser.hpp \ - ServerConfig.hpp \ - LocationConfig.hpp \ - Client.hpp \ - MethodType.hpp \ - utils.hpp \ +HEADERS_I = $(HEADERS_D:%=-I%) +HEADERS_D = srcs \ + headers +HEADERS = Webserv.hpp \ + ConfigParser.hpp \ + ServerConfig.hpp \ + LocationConfig.hpp \ + Client.hpp \ + MethodType.hpp \ + utils.hpp \ -SRCS_D = srcs srcs/webserv +SRCS_D = srcs \ + srcs/webserv SRCS = main.cpp \ - ft_itoa.cpp \ base.cpp init.cpp close.cpp epoll_update.cpp signal.cpp \ accept.cpp request.cpp response.cpp \ run_loop.cpp \ diff --git a/srcs/Client.hpp b/srcs/Client.hpp index 2536012..ede81f3 100644 --- a/srcs/Client.hpp +++ b/srcs/Client.hpp @@ -6,19 +6,19 @@ # include # include -struct Client +class Client { - // public: + public: // Client(Placeholder); // Client(); // Client(Client const &src); // ~Client(); // Client &operator=(Client const &rhs); + // Client &operator=(int); int fd; std::string raw_request; std::map request; - // std::map response; std::string response; unsigned int status; @@ -26,4 +26,8 @@ struct Client }; -#endif \ No newline at end of file +bool operator==(const Client& lhs, const Client& rhs); +bool operator==(const Client& lhs, int fd); +bool operator==(int fd, const Client& rhs); + +#endif diff --git a/srcs/ConfigParser.cpp b/srcs/ConfigParser.cpp index 46df807..30f3014 100644 --- a/srcs/ConfigParser.cpp +++ b/srcs/ConfigParser.cpp @@ -6,7 +6,7 @@ /* By: lperrey +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/07/13 22:11:17 by me #+# #+# */ -/* Updated: 2022/07/30 23:07:42 by lperrey ### ########.fr */ +/* Updated: 2022/07/31 13:18:14 by simplonco ### ########.fr */ /* */ /* ************************************************************************** */ @@ -216,7 +216,7 @@ void ConfigParser::_set_server_values(ServerConfig *server, \ value = _pre_set_val_check(key, value); - std::vector tmp_val = split(value, ' '); + std::vector tmp_val = ::split(value, ' '); size_t size = tmp_val.size(); if (size < 1) @@ -239,7 +239,7 @@ void ConfigParser::_set_server_values(ServerConfig *server, \ } else { - std::vector tmp2 = split(tmp_val[0], ':'); + std::vector tmp2 = ::split(tmp_val[0], ':'); if (!(isNumeric(tmp2[1]))) throw std::invalid_argument("value not a number"); diff --git a/srcs/Webserv.hpp b/srcs/Webserv.hpp index 6ba2970..b5a7b8b 100644 --- a/srcs/Webserv.hpp +++ b/srcs/Webserv.hpp @@ -2,26 +2,28 @@ #ifndef WEBSERV_HPP # define WEBSERV_HPP -# include // cout, cin -# include # include # include -# include // errno -# include // perror -# include -# include -# include // close -# include // memset -# include -# include - -# include // socket, accept, listen, send, recv, bind, connect, setsockopt, getsockname -# include // sockaddr_in -// # include // usefull for what ? -# include // htonl, htons, ntohl, ntohs, inet_addr - -# include // epoll -# include // fcntl +# include // exception, what +# include // runtime_error, invalid_argument +# include // epoll +# include // fcntl +# include // waitpid +# include // signal +# include // ifstream +# include // stringstream +# include // errno +# include // close, access +# include // cout, cin +# include // memset +# include // socket, accept, listen, send, recv, bind, connect, setsockopt, getsockname +# include // htonl, htons, ntohl, ntohs, inet_addr +# include // sockaddr_in +// # include // usefull for what ? -> 'man (7) ip' says it's a superset of 'netinet/in.h' +# include // find +# include // string +# include // perror +# include // atoi (athough it's already cover by ) # include "Client.hpp" # include "ServerConfig.hpp" @@ -33,17 +35,6 @@ # include "utils.hpp" // TODO: A virer -# include // signal -# include -# include -# include -# include -# include // atoi, itoa -# include // ifstream -char *ft_itoa(int n); -# include // access -# include // find - extern bool g_run; extern int g_last_signal; void signal_handler(int signum); diff --git a/srcs/ft_itoa.cpp b/srcs/ft_itoa.cpp deleted file mode 100644 index 1e996a9..0000000 --- a/srcs/ft_itoa.cpp +++ /dev/null @@ -1,50 +0,0 @@ - -#include - -static int eval_is_negative(int *n) -{ - if (*n < 0) - { - *n = *n * -1; - return (1); - } - return (0); -} - -static int eval_digit_nbr(int n) -{ - int digit_nbr; - - if (n == 0) - return (1); - digit_nbr = 0; - while (n != 0) - { - digit_nbr++; - n = n / 10; - } - return (digit_nbr); -} - -char *ft_itoa(int n) -{ - int i; - char *str; - int is_negative; - - if (n == -2147483648) - return (strdup("-2147483648")); - is_negative = eval_is_negative(&n); - i = eval_digit_nbr(n) + is_negative; - str = new char[i+1]; - if (is_negative) - str[0] = '-'; - str[i] = '\0'; - while (i > 0 + is_negative) - { - i--; - str[i] = (n % 10) + '0'; - n = n / 10; - } - return (str); -} diff --git a/srcs/utils.cpp b/srcs/utils.cpp index 6cf4df0..112cedb 100644 --- a/srcs/utils.cpp +++ b/srcs/utils.cpp @@ -1,8 +1,5 @@ - -#include "Webserv.hpp" - - +#include "utils.hpp" std::vector split(std::string input, char delimiter) { @@ -34,10 +31,17 @@ bool isNumeric_btw(int low, int high, std::string str) if (std::isdigit(str[i]) == false) return false; } - int n = atoi(str.c_str()); + int n = std::atoi(str.c_str()); if (n < low || n > high) return false; return true; } +char* itoa(int n) +{ + std::stringstream strs; + strs << n; + // casts : https://stackoverflow.com/questions/332030/when-should-static-cast-dynamic-cast-const-cast-and-reinterpret-cast-be-used + return ( const_cast( strs.str().c_str() ) ); +} diff --git a/srcs/utils.hpp b/srcs/utils.hpp index 83ebee8..1730236 100644 --- a/srcs/utils.hpp +++ b/srcs/utils.hpp @@ -1,12 +1,14 @@ - - #ifndef UTILS_HPP # define UTILS_HPP +# include +# include +# include std::vector split(std::string input, char delimiter); -bool isNumeric(std::string str); -bool isNumeric_btw(int low, int high, std::string str); +bool isNumeric(std::string str); +bool isNumeric_btw(int low, int high, std::string str); +char* itoa(int n); #endif diff --git a/srcs/webserv/accept.cpp b/srcs/webserv/accept.cpp index cd67904..f6db17b 100644 --- a/srcs/webserv/accept.cpp +++ b/srcs/webserv/accept.cpp @@ -22,5 +22,5 @@ void Webserv::_accept_connection(int fd) _clients.push_back(Client()); _clients.back().fd = accepted_fd; - _epoll_update(accepted_fd, EPOLLIN, EPOLL_CTL_ADD, &_clients.back()); + _epoll_update(accepted_fd, EPOLLIN, EPOLL_CTL_ADD); } diff --git a/srcs/webserv/init.cpp b/srcs/webserv/init.cpp index b773964..4c5956e 100644 --- a/srcs/webserv/init.cpp +++ b/srcs/webserv/init.cpp @@ -24,6 +24,18 @@ void Webserv::init_virtual_servers(std::vector* servers) std::perror("err socket()"); throw std::runtime_error("Socket init"); } + // HUGO ADD + // + // allow socket descriptor to be reuseable + // I just copied it from https://www.ibm.com/docs/en/i/7.2?topic=designs-example-nonblocking-io-select + int on = 1; + if (setsockopt(ret, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) + { + ::perror("err setsockopt()"); + throw std::runtime_error("Socket init"); + } + // + // HUGO ADD END _listen_sockets.push_back(ret); _bind(_listen_sockets.back(), std::atoi(it->port.data()), it->host); diff --git a/srcs/webserv/request.cpp b/srcs/webserv/request.cpp index 17c372b..de761f5 100644 --- a/srcs/webserv/request.cpp +++ b/srcs/webserv/request.cpp @@ -15,8 +15,8 @@ void Webserv::_read_request(Client *client) char buf[BUFSIZE+1]; ssize_t ret; - std::cerr << "recv()\n"; ret = ::recv(client->fd, buf, BUFSIZE, 0); + std::cerr << "recv() on fd(" << client->fd << ") returned = " << ret << "\n" ; if (ret == -1) { std::perror("err recv()"); @@ -25,6 +25,11 @@ void Webserv::_read_request(Client *client) _close_client(client->fd); return ; } + if (ret == 0) // Not sure what to do in case of 0. Just close ? + { + _close_client(client->fd); + return ; + } /* if (ret == BUFSIZE) // send error like "request too long" to client @@ -33,5 +38,5 @@ void Webserv::_read_request(Client *client) buf[ret] = '\0'; client->raw_request.append(buf); - _epoll_update(client->fd, EPOLLOUT, EPOLL_CTL_MOD, client); + _epoll_update(client->fd, EPOLLOUT, EPOLL_CTL_MOD); } diff --git a/srcs/webserv/response.cpp b/srcs/webserv/response.cpp index ce785ed..800903d 100644 --- a/srcs/webserv/response.cpp +++ b/srcs/webserv/response.cpp @@ -27,15 +27,14 @@ void Webserv::_send_response(Client *client) return ; } - _close_client(client->fd); - /* if (client->raw_request.find("Connection: keep-alive") == std::string::npos) + if (client->raw_request.find("Connection: close") != std::string::npos) _close_client(client->fd); else { - _epoll_update(client->fd, EPOLLIN, EPOLL_CTL_MOD, client); + _epoll_update(client->fd, EPOLLIN, EPOLL_CTL_MOD); client->raw_request.clear(); client->response.clear(); - } */ + } } void Webserv::_construct_response(Client *client) @@ -43,13 +42,17 @@ void Webserv::_construct_response(Client *client) client->status = 200; client->response.append("Server: Webserv/0.1\r\n"); - client->response.append("Connection: close\r\n"); + if (client->raw_request.find("Connection: close") != std::string::npos) + client->response.append("Connection: close\r\n"); + else + client->response.append("Connection: keep-alive\r\n"); _get_ressource(client); _insert_status_line(client); } +#define E400 "\r\n400 Bad Request

400 Bad Request


Le Webserv/0.1

" #define E404 "\r\n404 Not Found

404 Not Found


Le Webserv/0.1

" #define E500 "\r\n500 Internal Server Error

500 Internal Server Error


Le Webserv/0.1

" void Webserv::_insert_status_line(Client *client) @@ -63,6 +66,10 @@ void Webserv::_insert_status_line(Client *client) case (200): status_line.append("200 OK"); break; + case (400): + status_line.append("400 Not Found"); + client->response.append(E400); + break; case (404): status_line.append("404 Not Found"); client->response.append(E404); @@ -88,12 +95,21 @@ void Webserv::_get_ressource(Client *client) // Mini parsing à l'arrache du PATH std::string path; - path = client->raw_request.substr(0, client->raw_request.find("\r\n")); - path = path.substr(0, path.rfind(" ")); - path = path.substr(path.find("/")); - if (path == "/") - path.append(INDEX); - path.insert(0, ROOT); + try + { + path = client->raw_request.substr(0, client->raw_request.find("\r\n")); + path = path.substr(0, path.rfind(" ")); + path = path.substr(path.find("/")); + if (path == "/") + path.append(INDEX); + path.insert(0, ROOT); + } + catch (std::out_of_range& e) + { + std::cout << e.what() << '\n'; + client->status = 400; + return ; + } if (access(path.data(), R_OK) == -1) { @@ -128,9 +144,8 @@ void Webserv::_get_ressource(Client *client) client->response.append("Content-Type: text/html; charset=UTF-8\r\n"); client->response.append("Content-Length: "); - tmp = ::ft_itoa(ifd.gcount()); + tmp = ::itoa(ifd.gcount()); client->response.append(tmp); - delete tmp; client->response.append("\r\n"); // Body diff --git a/srcs/webserv/run_loop.cpp b/srcs/webserv/run_loop.cpp index f8ce7cb..215e4f9 100644 --- a/srcs/webserv/run_loop.cpp +++ b/srcs/webserv/run_loop.cpp @@ -4,6 +4,14 @@ #define MAX_EVENTS 42 // arbitrary #define TIMEOUT 3000 +// Temp. To move in other file +bool operator==(const Client& lhs, const Client& rhs) + { return lhs.fd == rhs.fd; } +bool operator==(const Client& lhs, int fd) + { return lhs.fd == fd; } +bool operator==(int fd, const Client& rhs) + { return fd == rhs.fd; } + void Webserv::run() { std::cerr << "Server started\n"; @@ -33,15 +41,14 @@ void Webserv::run() i = 0; while (i < nfds) { - // if ((events[i].data.u32 == SERVER_FD) && (events[i].events & EPOLLIN)) // Dont work, see "SERVER_FD" define - // if ((events[i].data.fd == _socket_fd) && (events[i].events & EPOLLIN)) + // TODO : handle EPOLLERR and EPOLLHUP if ((std::find(_listen_sockets.begin(), _listen_sockets.end(), events[i].data.fd) != _listen_sockets.end()) && (events[i].events & EPOLLIN)) _accept_connection(events[i].data.fd); else if (events[i].events & EPOLLIN) - _request(static_cast(events[i].data.ptr)); + _request( &(*std::find(_clients.begin(), _clients.end(), events[i].data.fd)) ); else if (events[i].events & EPOLLOUT) - _response(static_cast(events[i].data.ptr)); + _response( &(*std::find(_clients.begin(), _clients.end(), events[i].data.fd)) ); ++i; if (!g_run) break;