From e6ec3fe97bb31e80cc897be169256fe2dbe58df8 Mon Sep 17 00:00:00 2001 From: hugogogo Date: Thu, 28 Jul 2022 17:27:03 +0200 Subject: [PATCH] more tests on cgi --- Makefile | 16 ++-- README.md | 5 -- builds/Webserv.d | 3 + builds/main.d | 3 + headers/Webserv.hpp | 4 + headers_hugo/hugo_Webserv.hpp | 55 ------------ srcs/Webserv.cpp | 162 +++++++++++++++++---------------- srcs/cgi-bin/php-cgi | 6 +- srcs_hugo/hugo_Webserv.cpp | 164 ---------------------------------- srcs_hugo/hugo_main.cpp | 24 ----- 10 files changed, 104 insertions(+), 338 deletions(-) create mode 100644 builds/Webserv.d create mode 100644 builds/main.d delete mode 100644 headers_hugo/hugo_Webserv.hpp delete mode 100644 srcs_hugo/hugo_Webserv.cpp delete mode 100644 srcs_hugo/hugo_main.cpp diff --git a/Makefile b/Makefile index 5b93ef6..6ecb821 100644 --- a/Makefile +++ b/Makefile @@ -6,31 +6,27 @@ CXXFLAGS = -Wall -Wextra #-Werror CXXFLAGS += $(HEADERS) CXXFLAGS += -std=c++98 CXXFLAGS += -g +CXXFLAGS += -MMD -MP #header dependencie #CXXFLAGS += -O3 VPATH = $(SRCS_D) HEADERS = $(HEADERS_D:%=-I%) -HEADERS_D = headers \ - headers_hugo +HEADERS_D = headers -SRCS_D = srcs \ - srcs_hugo +SRCS_D = srcs SRCS = main.cpp \ Webserv.cpp -SRCS_HUGO = hugo_main.cpp \ - hugo_Webserv.cpp OBJS_D = builds OBJS = $(SRCS:%.cpp=$(OBJS_D)/%.o) -OBJS_HUGO = $(SRCS_HUGO:%.cpp=$(OBJS_D)/%.o) +DEPS = $(OBJS:.o=.d) #header dependencie # -------------------- # ------ RULES ------- # -------------------- all: $(NAME) -hugo: fclean hu_link $(OBJS_D)/%.o: %.cpp | $(OBJS_D) $(CXX) $(CXXFLAGS) -c $< -o $@ @@ -39,8 +35,6 @@ $(OBJS_D): mkdir $@ $(NAME): $(OBJS) -hu_link: $(OBJS_HUGO) -$(NAME) hu_link: $(CXX) $^ -o $(NAME) clean: @@ -53,3 +47,5 @@ re: fclean all .PHONY : all clean fclean re +-include $(DEPS) # header dependencie + diff --git a/README.md b/README.md index 56711d5..a9668a1 100644 --- a/README.md +++ b/README.md @@ -158,11 +158,6 @@ SERVER_SOFTWARE : the server software you're using (e.g. Apache 1.3) ``` REDIRECT_STATUS : for exemple, 200 ``` -#### cgi questions : -- when should we use the cgi ? - - execute cgi based on certain file extensions as defined in configuration file - - if the path lead to the cgi script ? - - for certain methods like POST GET or DELETE ? --- ## ressources diff --git a/builds/Webserv.d b/builds/Webserv.d new file mode 100644 index 0000000..b2c31be --- /dev/null +++ b/builds/Webserv.d @@ -0,0 +1,3 @@ +builds/Webserv.o: srcs/Webserv.cpp headers/Webserv.hpp + +headers/Webserv.hpp: diff --git a/builds/main.d b/builds/main.d new file mode 100644 index 0000000..4f088a7 --- /dev/null +++ b/builds/main.d @@ -0,0 +1,3 @@ +builds/main.o: srcs/main.cpp headers/Webserv.hpp + +headers/Webserv.hpp: diff --git a/headers/Webserv.hpp b/headers/Webserv.hpp index bef8f0e..d5ffc87 100644 --- a/headers/Webserv.hpp +++ b/headers/Webserv.hpp @@ -51,6 +51,10 @@ class Webserv void _accept_connection(int fd); void _read_request(int fd); void _send_response(int fd); + + // TMP HUGO TEST CGI + void _serve_file(int fd, std::string page); + void _exec_cgi_script(int fd); }; #endif diff --git a/headers_hugo/hugo_Webserv.hpp b/headers_hugo/hugo_Webserv.hpp deleted file mode 100644 index e61f2a4..0000000 --- a/headers_hugo/hugo_Webserv.hpp +++ /dev/null @@ -1,55 +0,0 @@ - -#ifndef WEBSERV_HPP -# define WEBSERV_HPP - -# include -# include -# include -# include -# include -# include // close -# include // exit -# include // cout, cin -# include // errno -# include // perror -# include // memset -# include // socket, accept, listen, send, recv, bind, connect, setsockopt, getsockname -# include // sockaddr_in -# include // inet_ntoa, inet_addr, htonl, htons, ntohl, ntohs -# include // poll -# include // fcntl -# include // ioctl - -# define TRUE 1 -# define FALSE 0 - -class Webserv -{ - public: - Webserv(); - // Webserv(Webserv const &src); - ~Webserv(); - // Webserv &operator=(Webserv const &rhs); - - void bind(in_port_t port); - void listen(unsigned int max_connections); - void start(int timeout, int bufsize); - - private: - int _socket_fd; - std::map _request; - std::map _response; - - void _add_fd(int sd, short event); - void _accept_connection(); - void _connect_socket(int it, int bufsize); - void _close_fd(int it); - - std::vector _fds; - std::vector::iterator _it; - std::vector::iterator _it_end; - -}; - -#endif - diff --git a/srcs/Webserv.cpp b/srcs/Webserv.cpp index 9c57479..fd5aee1 100644 --- a/srcs/Webserv.cpp +++ b/srcs/Webserv.cpp @@ -8,7 +8,7 @@ Webserv::Webserv() _epfd = ::epoll_create1(0); // (EPOLL_CLOEXEC) for CGI fork ? if (_epfd == -1) { - std::perror("err epoll_create1(): "); + std::perror("err epoll_create1()"); throw std::runtime_error("Epoll init"); } } @@ -38,9 +38,18 @@ void Webserv::init_virtual_servers() // ADD config param _socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); // (SOCK_CLOEXEC) for CGI fork ? if (_socket_fd == -1) { - std::perror("err socket(): "); + std::perror("err socket()"); throw std::runtime_error("Socket init"); } + // HUGO ADD + // allow socket descriptor to be reuseable + int on = 1; + if (setsockopt(_socket_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) + { + ::perror("setsockopt() failed"); + throw std::runtime_error("Socket init"); + } + // HUGO ADD END _bind(_socket_fd, 4040); _listen(_socket_fd, 512); // 512 arbitrary @@ -51,7 +60,7 @@ void Webserv::init_virtual_servers() // ADD config param ev.data.fd = _socket_fd; if (::epoll_ctl(_epfd, EPOLL_CTL_ADD, _socket_fd, &ev) == -1) { - std::perror("err epoll_ctl(): "); + std::perror("err epoll_ctl()"); throw std::runtime_error("Socket init"); } } @@ -88,7 +97,7 @@ void Webserv::start() if (nfds == -1) { - std::perror("err epoll_wait(): "); + std::perror("err epoll_wait()"); throw std::runtime_error("Epoll wait"); } } @@ -110,7 +119,7 @@ void Webserv::_bind(int socket_fd, in_port_t port) if (::bind(socket_fd, (const sockaddr*)&addr, sizeof addr) == -1) { - std::perror("err bind(): "); + std::perror("err bind()"); throw std::runtime_error("Socket bind"); } } @@ -119,7 +128,7 @@ void Webserv::_listen(int socket_fd, unsigned int max_connections) { if (::listen(socket_fd, max_connections) == -1) { - std::perror("err listen(): "); + std::perror("err listen()"); throw std::runtime_error("Socket listen"); } } @@ -135,7 +144,7 @@ void Webserv::_accept_connection(int fd) accepted_fd = ::accept(fd, (sockaddr*)&addr, &addr_len); if (accepted_fd == -1) { - std::perror("err accept(): "); + std::perror("err accept()"); return; } ::fcntl(accepted_fd, F_SETFL, O_NONBLOCK); @@ -145,7 +154,7 @@ void Webserv::_accept_connection(int fd) ev.events = EPOLLIN; ev.data.fd = accepted_fd; if (::epoll_ctl(_epfd, EPOLL_CTL_ADD, accepted_fd, &ev) == -1) - std::perror("err accept() epoll_ctl(): "); + std::perror("err accept() epoll_ctl()"); } void Webserv::_read_request(int fd) @@ -154,9 +163,9 @@ void Webserv::_read_request(int fd) _read_ret = ::recv(fd, _buf, BUFSIZE, 0); if (_read_ret == -1) { - std::perror("err recv(): "); + std::perror("err recv()"); if (::send(fd, MSG_BOUNCE, sizeof MSG_BOUNCE - 1, 0) == -1) - std::perror("err send(): "); + std::perror("err send()"); ::close(fd); return; @@ -175,79 +184,76 @@ void Webserv::_read_request(int fd) std::perror("err accept() epoll_ctl(): "); } +void Webserv::_serve_file(int fd, std::string page) +{ + int page_fd; + std::string to_send; + std::string end_header = "\r\n\r\n"; + std::string body; + std::stringstream strs; + char buffer[1]; + + to_send = "HTTP/1.1 200 OK\n"; + to_send += "Content-Type: text/html;\n"; + to_send += "Content-Length: "; + page_fd = open(page.c_str(), O_RDONLY); + for (int ret = 1; ret > 0;) + { + ret = read(page_fd, buffer, 1); + body += buffer; + } + strs << body.size(); + to_send += strs.str(); + to_send += end_header; + to_send += body; + if (::send(fd, to_send.c_str(), to_send.size(), 0) == -1) + std::perror("err send()"); +} +void Webserv::_exec_cgi_script(int fd) +{ + int save_stdout; + char** env = new char*[5]; + char * const * nll = NULL; + + // set env + env[0] = strdup("PATH_INFO=/no"); + env[1] = strdup("REQUEST_METHOD=POST"); + env[2] = strdup("SERVER_PROTOCOL=HTTP/1.1"); + env[3] = strdup("CONTENT_LENGTH=665"); + env[4] = NULL; + // save STDOUT + save_stdout = dup(STDOUT_FILENO); + // inside chil process + if (fork() == 0) + { + dup2(fd, STDOUT_FILENO); +// execve("./srcs/cgi-bin/cgi_cpp.cgi", nll, env); + execve("./srcs/cgi-bin/php-cgi", nll, env); + } + // inside parent process + else + waitpid(-1, NULL, 0); + // restore stdout + dup2(save_stdout, STDOUT_FILENO); +} + void Webserv::_send_response(int fd) { - - - // TMP test cgi - // find POST in _buf - std::string tmpstr = _buf; - std::size_t found; - found = tmpstr.find("POST"); - // if "POST" found, execve a cgi - if (found != std::string::npos) - { - int save_stdout; - char** env = new char*[4]; - char * const * nll = NULL; - - // set env - env[0] = strdup("PATH_INFO=/no"); - env[1] = strdup("REQUEST_METHOD=POST"); - env[2] = strdup("SERVER_PROTOCOL=HTTP/1.1"); - env[3] = NULL; - // save STDOUT - save_stdout = dup(STDOUT_FILENO); - // inside chil process - if (fork() == 0) - { - dup2(fd, STDOUT_FILENO); - execve("./srcs/cgi-bin/cgi_cpp.cgi", nll, env); - } - // inside parent process - else - waitpid(-1, NULL, 0); - // restore stdout - dup2(save_stdout, STDOUT_FILENO); - // don't send the rest - ::close(fd); - return; - } - else - found = tmpstr.find("index.html"); - // if "index.html" found, send the page - if (found != std::string::npos) - { - int index_fd; - std::string to_send; - std::string end_header = "\r\n\r\n"; - std::string body; - std::stringstream strs; - char buffer[1]; - - to_send = "HTTP/1.1 200 OK\nContent-Type: text/html; charset=UTF-8\nContent-Length: "; - index_fd = open("./index.html", O_RDONLY); - for (int ret = 1; ret > 0;) - { - ret = read(index_fd, buffer, 1); - body += buffer; - } - strs << body.size(); - to_send += strs.str(); - to_send += end_header; - to_send += body; - ::send(fd, to_send.c_str(), to_send.size(), 0); - // don't send the rest - ::close(fd); - return; - } - // TMP end test cgi - + // TMP HUGO test cgi + // if "POST" found in _buf, execve a cgi + if (std::string(_buf).find("POST") != std::string::npos) + _exec_cgi_script(fd); + // if "index.html" found in _buf, send the page + if (std::string(_buf).find("index.html") != std::string::npos) + _serve_file(fd, "index.html"); + // TMP HUGO end test cgi std::cout << "send()\n"; + std::cout << "buf size: " << strlen(_buf) << "\n"; + std::cout << "_buf: " << _buf << "\n"; if (::send(fd, _buf, _read_ret, 0) == -1) - std::perror("err send(): "); + std::perror("err send()"); if (::send(fd, MSG_TEST, sizeof MSG_TEST - 1, 0) == -1) - std::perror("err send(): "); + std::perror("err send()"); ::close(fd); } diff --git a/srcs/cgi-bin/php-cgi b/srcs/cgi-bin/php-cgi index bb78d68..0a1cadb 100755 --- a/srcs/cgi-bin/php-cgi +++ b/srcs/cgi-bin/php-cgi @@ -1,7 +1,9 @@ #! /usr/bin/php -# diff --git a/srcs_hugo/hugo_Webserv.cpp b/srcs_hugo/hugo_Webserv.cpp deleted file mode 100644 index 25dcbc8..0000000 --- a/srcs_hugo/hugo_Webserv.cpp +++ /dev/null @@ -1,164 +0,0 @@ - -#include "hugo_Webserv.hpp" - -Webserv::Webserv() -{ - int on = 1; - - std::cout << "Server init\n"; - - // create socket descriptor - _socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); - if (_socket_fd == -1) - { - ::perror("err socket()"); - throw std::runtime_error("Socket init"); - } - - // allow socket descriptor to be reuseable - if (setsockopt(_socket_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) - { - ::perror("setsockopt() failed"); - throw std::runtime_error("Socket init"); - } - -} - -Webserv::~Webserv() -{ - std::cout << "Server destroyed\n"; -} - -void Webserv::bind(in_port_t port) -{ - struct sockaddr_in addr; - - addr.sin_family = AF_INET; - addr.sin_port = ::htons(port); - addr.sin_addr.s_addr = ::htonl(INADDR_ANY); - if (::bind(_socket_fd, (const sockaddr*)&addr, sizeof addr) == -1) - { - ::perror("err bind()"); - throw std::runtime_error("Socket bind"); - } -} - -void Webserv::listen(unsigned int max_connections) -{ - if (::listen(_socket_fd, max_connections) == -1) - { - ::perror("err listen(): "); - throw std::runtime_error("Socket listen"); - } -} - -void Webserv::_add_fd(int sd, short event) -{ - struct pollfd new_poll_fd; - - new_poll_fd.fd = sd; - new_poll_fd.events = event; - new_poll_fd.revents = 0; - _fds.push_back(new_poll_fd); -} - -void Webserv::_close_fd(int i) -{ - close(_fds[i].fd); - _fds[i].fd = -1; - _fds.erase(_fds.begin() + i); -} - -void Webserv::_accept_connection() -{ - int new_sd = 0; - - printf(" Listening socket is readable\n"); - while (new_sd != -1) - { - new_sd = accept(_socket_fd, NULL, NULL); - if (new_sd < 0) - { - if (errno != EWOULDBLOCK && errno != EAGAIN) - { - ::perror("err accept()"); - throw std::runtime_error("Socket accept"); - } - break; - } - printf(" New incoming connection - %d\n", new_sd); - _add_fd(new_sd, POLLIN); - } -} - -void Webserv::_connect_socket(int i, int bufsize) -{ - int len; - int ret; - std::vector buffer(bufsize); - - printf(" Descriptor %d is readable\n", _fds[i].fd); - while (TRUE) - { - ret = recv(_fds[i].fd, &buffer[0], buffer.size(), 0); - if (ret < 0) - { - if (errno != EWOULDBLOCK) - { - ::perror(" recv() failed"); - _close_fd(i); - } - break; - } - - if (ret == 0) - { - printf(" Connection closed\n"); - _close_fd(i); - break; - } - - len = ret; - printf(" %d bytes received\n", len); - - ret = send(_fds[i].fd, &buffer[0], len, 0); - printf(" send\n"); - if (ret < 0) - { - ::perror(" send() failed"); - _close_fd(i); - break; - } - } -} - -void Webserv::start(int timeout, int bufsize) -{ - _add_fd(_socket_fd, POLLIN); - - std::cout << "Server started\n"; - while (TRUE) - { - printf("-----------\npoll\n"); - poll(&_fds[0], _fds.size(), timeout); - - for (unsigned int i = 0; i < _fds.size(); i++) - { - if(_fds[i].revents == 0) - continue; - - if(_fds[i].revents != POLLIN) - { - ::perror("err revents"); - throw std::runtime_error("Socket poll"); - } - - if (_fds[i].fd == _socket_fd) - _accept_connection(); - - else - _connect_socket(i, bufsize); - } - } -} - diff --git a/srcs_hugo/hugo_main.cpp b/srcs_hugo/hugo_main.cpp deleted file mode 100644 index 82a2397..0000000 --- a/srcs_hugo/hugo_main.cpp +++ /dev/null @@ -1,24 +0,0 @@ - -#include -#include -#include -#include "hugo_Webserv.hpp" - -int main(void) -{ - try - { - Webserv serv; - - // https://security.stackexchange.com/questions/169213/how-to-chose-a-port-to-run-an-application-on-localhost - serv.bind(4040); - serv.listen(20); - serv.start(3 * 60 * 1000, 8192); - } - catch (std::exception& e) - { - std::cout << e.what() << '\n'; - } - return (0); -} -