client variables are made const
This commit is contained in:
119
srcs/webserv/Webserv.hpp
Normal file
119
srcs/webserv/Webserv.hpp
Normal file
@@ -0,0 +1,119 @@
|
||||
|
||||
#ifndef WEBSERV_HPP
|
||||
# define WEBSERV_HPP
|
||||
|
||||
# include <map>
|
||||
# include <vector>
|
||||
# include <exception> // exception, what
|
||||
# include <stdexcept> // runtime_error, invalid_argument
|
||||
# include <sys/epoll.h> // epoll
|
||||
# include <fcntl.h> // fcntl
|
||||
# include <sys/wait.h> // waitpid
|
||||
# include <csignal> // signal
|
||||
# include <fstream> // ifstream
|
||||
# include <sstream> // stringstream
|
||||
# include <cerrno> // errno
|
||||
# include <unistd.h> // close, access
|
||||
# include <iostream> // cout, cin
|
||||
# include <cstring> // memset
|
||||
# include <sys/socket.h> // socket, accept, listen, send, recv, bind, connect, setsockopt, getsockname
|
||||
# include <arpa/inet.h> // htonl, htons, ntohl, ntohs, inet_addr, inet_ntoa
|
||||
# include <netinet/in.h> // sockaddr_in, struct in_addr
|
||||
// # include <netinet/ip.h> // usefull for what ? -> 'man (7) ip' says it's a superset of 'netinet/in.h'
|
||||
# include <algorithm> // find
|
||||
# include <string> // string
|
||||
# include <cstdio> // perror, remove
|
||||
# include <cstdlib> // atoi (athough it's already cover by <string>)
|
||||
|
||||
# include "Client.hpp"
|
||||
# include "ServerConfig.hpp"
|
||||
# include "utils.hpp"
|
||||
# include "http_status.hpp"
|
||||
|
||||
extern bool g_run;
|
||||
extern int g_last_signal;
|
||||
void signal_handler(int signum);
|
||||
|
||||
// these might only be TMP
|
||||
# define FAILURE -1
|
||||
# define SUCCESS 1
|
||||
|
||||
class Webserv
|
||||
{
|
||||
public:
|
||||
// base.cpp
|
||||
Webserv();
|
||||
// Webserv(Webserv const &src);
|
||||
|
||||
// what should it take as arg, *, &, ?
|
||||
// Webserv(std::vector<ServerConfig>& servers);
|
||||
|
||||
~Webserv();
|
||||
// Webserv &operator=(Webserv const &rhs);
|
||||
|
||||
// init.cpp
|
||||
void init_virtual_servers(std::vector<ServerConfig>* servers);
|
||||
// run_loop.cpp
|
||||
void run();
|
||||
|
||||
private:
|
||||
int _epfd;
|
||||
std::vector<listen_socket> _listen_sockets;
|
||||
std::vector<ServerConfig> _servers;
|
||||
std::vector<Client> _clients;
|
||||
std::map<int, std::string> _http_status;
|
||||
std::map<std::string, std::string> _mime_types;
|
||||
|
||||
// accept.cpp
|
||||
void _accept_connection(listen_socket &lsocket);
|
||||
std::map<std::string, std::string>
|
||||
_extract_infos(struct sockaddr_in addr);
|
||||
// request.cpp
|
||||
void _request(Client *client);
|
||||
void _read_request(Client *client);
|
||||
// response.cpp
|
||||
void _response(Client *client);
|
||||
void _send_response(Client *client, ServerConfig &server);
|
||||
|
||||
void _append_base_headers(Client *client);
|
||||
void _construct_response(Client *client, ServerConfig &server);
|
||||
void _process_method(Client *client, ServerConfig &server, LocationConfig &location);
|
||||
void _insert_status_line(Client *client);
|
||||
void _error_html_response(Client *client, ServerConfig &server);
|
||||
void _append_body(Client *client, const char *body, size_t body_size, const std::string &file_extension = "");
|
||||
|
||||
void _get(Client *client, ServerConfig &server, LocationConfig &location);
|
||||
void _get_file(Client *client, const std::string &path);
|
||||
|
||||
void _post(Client *client, ServerConfig &server, LocationConfig &location);
|
||||
void _post_file(Client *client, const std::string &path);
|
||||
|
||||
void _delete(Client *client, ServerConfig &server, LocationConfig &location);
|
||||
void _delete_file(Client *client, const std::string &path);
|
||||
|
||||
ServerConfig &_determine_process_server(Client *client);
|
||||
LocationConfig &_determine_location(ServerConfig &server, std::string const &path);
|
||||
// cgi_script.cpp
|
||||
bool _is_cgi(Client *client);
|
||||
void _exec_cgi(Client *client);
|
||||
void _construct_client(Client *client);
|
||||
char** _set_env(Client *client);
|
||||
char* _dup_env(std::string var, std::string val);
|
||||
void _exec_script(Client *client, char **env);
|
||||
// epoll_update.cpp
|
||||
int _epoll_update(int fd, uint32_t events, int op);
|
||||
int _epoll_update(int fd, uint32_t events, int op, void *ptr);
|
||||
// signal.cpp
|
||||
void _handle_last_signal();
|
||||
// close.cpp
|
||||
void _close_client(int fd);
|
||||
void _close_all_clients();
|
||||
void _close_all_listen_sockets();
|
||||
// init.cpp
|
||||
void _bind(int socket_fd, in_port_t port, std::string host);
|
||||
void _listen(int socket_fd, unsigned int max_connections);
|
||||
void _init_http_status_map();
|
||||
void _init_mime_types_map();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,15 +1,16 @@
|
||||
|
||||
#include "Webserv.hpp"
|
||||
|
||||
void Webserv::_accept_connection(int fd)
|
||||
void Webserv::_accept_connection(listen_socket &lsocket)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
socklen_t addr_len;
|
||||
int accepted_fd;
|
||||
struct sockaddr_in addr;
|
||||
socklen_t addr_len;
|
||||
int accepted_fd;
|
||||
std::map<std::string, std::string> infos;
|
||||
|
||||
std::cerr << "accept()\n";
|
||||
addr_len = sizeof addr;
|
||||
accepted_fd = ::accept(fd, (sockaddr*)&addr, &addr_len);
|
||||
accepted_fd = ::accept(lsocket.fd, (sockaddr*)&addr, &addr_len);
|
||||
if (accepted_fd == -1)
|
||||
{
|
||||
std::perror("err accept()");
|
||||
@@ -19,22 +20,22 @@ void Webserv::_accept_connection(int fd)
|
||||
}
|
||||
::fcntl(accepted_fd, F_SETFL, O_NONBLOCK);
|
||||
|
||||
_clients.push_back(Client());
|
||||
_clients.back().fd = accepted_fd;
|
||||
|
||||
// HUGO WIP
|
||||
//
|
||||
_clients.back().port = ::itos(addr.sin_port);
|
||||
struct in_addr tmp = { addr.sin_addr.s_addr };
|
||||
_clients.back().ip = inet_ntoa( tmp );
|
||||
|
||||
std::cout
|
||||
<< "port:" << _clients.back().port
|
||||
<< " ip:" << _clients.back().ip
|
||||
<< "\n";
|
||||
//
|
||||
// HUGO END
|
||||
|
||||
infos = _extract_infos(addr);
|
||||
Client client(accepted_fd, &lsocket, infos["port"], infos["ip"]);
|
||||
_clients.push_back(client);
|
||||
_epoll_update(accepted_fd, EPOLLIN, EPOLL_CTL_ADD);
|
||||
}
|
||||
|
||||
std::map<std::string, std::string>
|
||||
Webserv::_extract_infos(struct sockaddr_in addr)
|
||||
{
|
||||
struct in_addr ip_conversion;
|
||||
std::map<std::string, std::string> infos;
|
||||
|
||||
infos["port"] = ::itos( addr.sin_port );
|
||||
ip_conversion.s_addr = addr.sin_addr.s_addr;
|
||||
infos["ip"] = inet_ntoa( ip_conversion );
|
||||
|
||||
return infos;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,9 @@ Webserv::Webserv()
|
||||
throw std::runtime_error("Epoll init");
|
||||
}
|
||||
|
||||
_init_http_status_map();
|
||||
_init_mime_types_map();
|
||||
|
||||
std::signal(SIGPIPE, signal_handler);
|
||||
std::signal(SIGINT, signal_handler);
|
||||
}
|
||||
@@ -42,10 +45,9 @@ Webserv::Webserv(std::vector<ServerConfig>* servers)
|
||||
|
||||
Webserv::~Webserv()
|
||||
{
|
||||
//close(_socket_fd);
|
||||
// TODO : CLOSE ALL _listen_sockets
|
||||
close(_epfd);
|
||||
_close_all_clients();
|
||||
_close_all_listen_sockets();
|
||||
std::cerr << "Server destroyed\n";
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
bool Webserv::_is_cgi(Client *client)
|
||||
{
|
||||
if (client->get_path().find("/cgi-bin/") != std::string::npos)
|
||||
if (client->get_rq_path().find("/cgi-bin/") != std::string::npos)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@@ -30,22 +30,22 @@ char** Webserv::_set_env(Client *client)
|
||||
char** env = new char*[19];
|
||||
|
||||
env[0] = _dup_env("AUTH_TYPE");
|
||||
env[1] = _dup_env("CONTENT_LENGTH", "665");
|
||||
env[1] = _dup_env("CONTENT_LENGTH" , "665");
|
||||
env[2] = _dup_env("CONTENT_TYPE");
|
||||
env[3] = _dup_env("GATEWAY_INTERFACE");
|
||||
env[4] = _dup_env("PATH_INFO");
|
||||
env[5] = _dup_env("PATH_TRANSLATED");
|
||||
env[6] = _dup_env("QUERY_STRING");
|
||||
env[7] = _dup_env("REMOTE_ADDR", client->ip);
|
||||
env[8] = _dup_env("REMOTE_HOST", client->get_headers("Host")); // just test
|
||||
env[9] = _dup_env("REMOTE_IDENT"); // TODO: implement if authentification
|
||||
env[10] = _dup_env("REMOTE_USER"); // TODO: implement if authentification
|
||||
env[11] = _dup_env("REQUEST_METHOD", client->get_method());
|
||||
env[7] = _dup_env("REMOTE_ADDR" , client->get_cl_ip());
|
||||
env[8] = _dup_env("REMOTE_HOST" , client->get_rq_headers("Host")); // just test
|
||||
env[9] = _dup_env("REMOTE_IDENT"); // authentification not supported
|
||||
env[10] = _dup_env("REMOTE_USER"); // authentification not supported
|
||||
env[11] = _dup_env("REQUEST_METHOD" , client->get_rq_method_str());
|
||||
env[12] = _dup_env("SCRIPT_NAME"); // TODO: define (https://www.rfc-editor.org/rfc/rfc3875#section-4.1.13
|
||||
// ,https://www.rfc-editor.org/rfc/rfc3875#section-8.2)
|
||||
env[13] = _dup_env("SERVER_NAME", client->get_hostname());
|
||||
env[14] = _dup_env("SERVER_PORT", client->get_port());
|
||||
env[15] = _dup_env("SERVER_PROTOCOL", client->get_version());
|
||||
env[13] = _dup_env("SERVER_NAME" , client->get_rq_hostname());
|
||||
env[14] = _dup_env("SERVER_PORT" , client->get_rq_port());
|
||||
env[15] = _dup_env("SERVER_PROTOCOL", client->get_rq_version());
|
||||
env[16] = _dup_env("SERVER_SOFTWARE", "webser/1.0");
|
||||
env[17] = _dup_env("REDIRECT_STATUS", "200");
|
||||
env[18] = NULL;
|
||||
@@ -63,7 +63,7 @@ void Webserv::_exec_script(Client *client, char **env)
|
||||
// inside child process
|
||||
if (fork() == 0)
|
||||
{
|
||||
dup2(client->fd, STDOUT_FILENO);
|
||||
dup2(client->get_cl_fd(), STDOUT_FILENO);
|
||||
// execve("./srcs/cgi-bin/cgi_cpp.cgi", nll, client->env);
|
||||
execve("./srcs/cgi-bin/php-cgi", nll, env);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ void Webserv::_close_client(int fd)
|
||||
std::vector<Client>::iterator it = _clients.begin();
|
||||
while (it != _clients.end())
|
||||
{
|
||||
if (it->fd == fd)
|
||||
if (*it == fd)
|
||||
{
|
||||
// _epoll_update(fd, 0, EPOLL_CTL_DEL); // normalement superflu, DEBUG
|
||||
if (::close(fd) == -1)
|
||||
@@ -25,10 +25,23 @@ void Webserv::_close_all_clients()
|
||||
while (!_clients.empty())
|
||||
{
|
||||
// _epoll_update(_clients.back().fd, 0, EPOLL_CTL_DEL); // normalement superflu, DEBUG
|
||||
if (::close(_clients.back().fd) == -1)
|
||||
if (::close(_clients.back().get_cl_fd()) == -1)
|
||||
std::perror("err close()");
|
||||
else
|
||||
std::cerr << "close fd " << _clients.back().fd << "\n";
|
||||
std::cerr << "close fd " << _clients.back().get_cl_fd() << "\n";
|
||||
_clients.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void Webserv::_close_all_listen_sockets()
|
||||
{
|
||||
while (!_listen_sockets.empty())
|
||||
{
|
||||
// _epoll_update(_listen_sockets.back().fd, 0, EPOLL_CTL_DEL); // normalement superflu, DEBUG
|
||||
if (::close(_listen_sockets.back().fd) == -1)
|
||||
std::perror("err close()");
|
||||
else
|
||||
std::cerr << "close fd " << _listen_sockets.back().fd << "\n";
|
||||
_listen_sockets.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
42
srcs/webserv/http_status.hpp
Normal file
42
srcs/webserv/http_status.hpp
Normal file
@@ -0,0 +1,42 @@
|
||||
|
||||
#ifndef HTTP_STATUS_HPP
|
||||
# define HTTP_STATUS_HPP
|
||||
|
||||
// https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
|
||||
|
||||
/*
|
||||
First version of macro HTML_ERROR(STATUS) dont work with call like this :
|
||||
client->response.append( HTML_ERROR( _http_status[client->status].c_str() ) );
|
||||
so I made the other version with dynamic replacement of STATUS .
|
||||
*/
|
||||
// # define HTML_ERROR(STATUS) "\r\n<!DOCTYPE html><html><head><title>"STATUS"</title></head><body><h1 style=\"text-align:center\">"STATUS"</h1><hr><p style=\"text-align:center\">Le Webserv/0.1</p></body></html>"
|
||||
|
||||
# define STATUS_PLACEHOLDER "$STATUS"
|
||||
# define HTML_ERROR \
|
||||
"<!DOCTYPE html>"\
|
||||
"<html>"\
|
||||
"<head>"\
|
||||
"<title>" STATUS_PLACEHOLDER "</title>"\
|
||||
"</head>"\
|
||||
"<body>"\
|
||||
"<h1 style=\"text-align:center\">" STATUS_PLACEHOLDER "</h1>"\
|
||||
"<hr>"\
|
||||
"<p style=\"text-align:center\">Le Webserv/0.1</p>"\
|
||||
"</body>"\
|
||||
"</html>"
|
||||
|
||||
// When new status added, need to update _init_http_status_map()
|
||||
# define S200 "200 OK"
|
||||
# define S201 "201 Created"
|
||||
# define S204 "204 No Content"
|
||||
|
||||
# define S400 "400 Bad Request"
|
||||
# define S403 "403 Forbidden"
|
||||
# define S404 "404 Not Found"
|
||||
# define S405 "405 Method Not Allowed"
|
||||
# define S413 "413 Content Too Large"
|
||||
|
||||
# define S500 "500 Internal Server Error"
|
||||
# define S501 "501 Not Implemented"
|
||||
|
||||
#endif
|
||||
@@ -4,7 +4,9 @@
|
||||
void Webserv::init_virtual_servers(std::vector<ServerConfig>* servers)
|
||||
{
|
||||
int ret;
|
||||
std::vector<int> _open_ports;
|
||||
std::vector<std::string> open_sockets;
|
||||
struct listen_socket new_socket;
|
||||
std::string host_port;
|
||||
|
||||
_servers = *servers;
|
||||
_listen_sockets.clear();
|
||||
@@ -12,7 +14,11 @@ void Webserv::init_virtual_servers(std::vector<ServerConfig>* servers)
|
||||
|
||||
while (it != _servers.end())
|
||||
{
|
||||
if ( std::find(_open_ports.begin(), _open_ports.end(), std::atoi(it->port.data()) ) != _open_ports.end() )
|
||||
host_port.clear();
|
||||
host_port.append(it->host);
|
||||
host_port.append(":");
|
||||
host_port.append(it->port);
|
||||
if ( std::find(open_sockets.begin(), open_sockets.end(), host_port) != open_sockets.end() )
|
||||
{
|
||||
++it;
|
||||
continue;
|
||||
@@ -24,13 +30,17 @@ void Webserv::init_virtual_servers(std::vector<ServerConfig>* servers)
|
||||
std::perror("err socket()");
|
||||
throw std::runtime_error("Socket init");
|
||||
}
|
||||
new_socket.fd = ret;
|
||||
new_socket.host = it->host;
|
||||
new_socket.port = it->port;
|
||||
_listen_sockets.push_back(new_socket);
|
||||
|
||||
// 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)
|
||||
if (setsockopt(new_socket.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
|
||||
{
|
||||
::perror("err setsockopt()");
|
||||
throw std::runtime_error("Socket init");
|
||||
@@ -38,15 +48,13 @@ void Webserv::init_virtual_servers(std::vector<ServerConfig>* servers)
|
||||
//
|
||||
// HUGO ADD END
|
||||
|
||||
_listen_sockets.push_back(ret);
|
||||
_bind(new_socket.fd, std::atoi(it->port.c_str()), it->host);
|
||||
_listen(new_socket.fd, 512); // 512 arbitrary
|
||||
|
||||
_bind(_listen_sockets.back(), std::atoi(it->port.data()), it->host);
|
||||
_listen(_listen_sockets.back(), 512); // 512 arbitrary
|
||||
|
||||
if (_epoll_update(_listen_sockets.back(), EPOLLIN, EPOLL_CTL_ADD) == -1)
|
||||
if (_epoll_update(new_socket.fd, EPOLLIN, EPOLL_CTL_ADD) == -1)
|
||||
throw std::runtime_error("Socket init");
|
||||
|
||||
_open_ports.push_back(std::atoi(it->port.data()));
|
||||
open_sockets.push_back(host_port);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
@@ -78,3 +86,136 @@ void Webserv::_listen(int socket_fd, unsigned int max_connections)
|
||||
throw std::runtime_error("Socket listen");
|
||||
}
|
||||
}
|
||||
|
||||
void Webserv::_init_http_status_map()
|
||||
{
|
||||
_http_status[200] = S200;
|
||||
_http_status[201] = S201;
|
||||
_http_status[204] = S204;
|
||||
|
||||
_http_status[400] = S400;
|
||||
_http_status[403] = S403;
|
||||
_http_status[404] = S404;
|
||||
_http_status[405] = S405;
|
||||
_http_status[413] = S413;
|
||||
|
||||
_http_status[500] = S500;
|
||||
_http_status[501] = S501;
|
||||
}
|
||||
|
||||
void Webserv::_init_mime_types_map()
|
||||
{
|
||||
_mime_types[""] = "application/octet-stream";
|
||||
|
||||
_mime_types["html"] = "text/html";
|
||||
_mime_types["htm"] = "text/html";
|
||||
_mime_types["shtml"] = "text/html";
|
||||
_mime_types["css"] = "text/css";
|
||||
_mime_types["xml"] = "text/xml";
|
||||
_mime_types["gif"] = "image/gif";
|
||||
_mime_types["jpeg"] = "image/jpeg";
|
||||
_mime_types["jpg"] = "image/jpeg";
|
||||
_mime_types["js"] = "application/javascript";
|
||||
_mime_types["atom"] = "application/atom+xml";
|
||||
_mime_types["rss"] = "application/rss+xml";
|
||||
|
||||
_mime_types["mml"] = "text/mathml";
|
||||
_mime_types["txt"] = "text/plain";
|
||||
_mime_types["jad"] = "text/vnd.sun.j2me.app-descriptor";
|
||||
_mime_types["wml"] = "text/vnd.wap.wml";
|
||||
_mime_types["htc"] = "text/x-component";
|
||||
|
||||
_mime_types["png"] = "image/png";
|
||||
_mime_types["tif"] = "image/tiff";
|
||||
_mime_types["tiff"] = "image/tiff";
|
||||
_mime_types["wbmp"] = "image/vnd.wap.wbmp";
|
||||
_mime_types["ico"] = "image/x-icon";
|
||||
_mime_types["jng"] = "image/x-jng";
|
||||
_mime_types["bmp"] = "image/x-ms-bmp";
|
||||
_mime_types["svg"] = "image/svg+xml";
|
||||
_mime_types["svgz"] = "image/svg+xml";
|
||||
_mime_types["webp"] = "image/webp";
|
||||
|
||||
_mime_types["woff"] = "application/font-woff";
|
||||
_mime_types["jar"] = "application/java-archive";
|
||||
_mime_types["war"] = "application/java-archive";
|
||||
_mime_types["ear"] = "application/java-archive";
|
||||
_mime_types["json"] = "application/json";
|
||||
_mime_types["hqx"] = "application/mac-binhex40";
|
||||
_mime_types["doc"] = "application/msword";
|
||||
_mime_types["pdf"] = "application/pdf";
|
||||
_mime_types["ps"] = "application/postscript";
|
||||
_mime_types["eps"] = "application/postscript";
|
||||
_mime_types["ai"] = "application/postscript";
|
||||
_mime_types["rtf"] = "application/rtf";
|
||||
_mime_types["m3u8"] = "application/vnd.apple.mpegurl";
|
||||
_mime_types["xls"] = "application/vnd.ms-excel";
|
||||
_mime_types["eot"] = "application/vnd.ms-fontobject";
|
||||
_mime_types["ppt"] = "application/vnd.ms-powerpoint";
|
||||
_mime_types["wmlc"] = "application/vnd.wap.wmlc";
|
||||
_mime_types["kml"] = "application/vnd.google-earth.kml+xml";
|
||||
_mime_types["kmz"] = "application/vnd.google-earth.kmz";
|
||||
_mime_types["7z"] = "application/x-7z-compressed";
|
||||
_mime_types["cco"] = "application/x-cocoa";
|
||||
_mime_types["jardiff"] = "application/x-java-archive-diff";
|
||||
_mime_types["jnlp"] = "application/x-java-jnlp-file";
|
||||
_mime_types["run"] = "application/x-makeself";
|
||||
_mime_types["pl"] = "application/x-perl";
|
||||
_mime_types["pm"] = "application/x-perl";
|
||||
_mime_types["prc"] = "application/x-pilot";
|
||||
_mime_types["pdb"] = "application/x-pilot";
|
||||
_mime_types["rar"] = "application/x-rar-compressed";
|
||||
_mime_types["rpm"] = "application/x-redhat-package-manager";
|
||||
_mime_types["sea"] = "application/x-sea";
|
||||
_mime_types["swf"] = "application/x-shockwave-flash";
|
||||
_mime_types["sit"] = "application/x-stuffit";
|
||||
_mime_types["tcl"] = "application/x-tcl";
|
||||
_mime_types["tk"] = "application/x-tcl";
|
||||
_mime_types["der"] = "application/x-x509-ca-cert";
|
||||
_mime_types["pem"] = "application/x-x509-ca-cert";
|
||||
_mime_types["crt"] = "application/x-x509-ca-cert";
|
||||
_mime_types["xpi"] = "application/x-xpinstall";
|
||||
_mime_types["xhtml"] = "application/xhtml+xml";
|
||||
_mime_types["xspf"] = "application/xspf+xml";
|
||||
_mime_types["zip"] = "application/zip";
|
||||
|
||||
_mime_types["bin"] = "application/octet-stream";
|
||||
_mime_types["exe"] = "application/octet-stream";
|
||||
_mime_types["dll"] = "application/octet-stream";
|
||||
_mime_types["deb"] = "application/octet-stream";
|
||||
_mime_types["dmg"] = "application/octet-stream";
|
||||
_mime_types["iso"] = "application/octet-stream";
|
||||
_mime_types["img"] = "application/octet-stream";
|
||||
_mime_types["msi"] = "application/octet-stream";
|
||||
_mime_types["msp"] = "application/octet-stream";
|
||||
_mime_types["msm"] = "application/octet-stream";
|
||||
|
||||
_mime_types["docx"] = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
|
||||
_mime_types["xlsx"] = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
||||
_mime_types["pptx"] = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
|
||||
|
||||
_mime_types["mid"] = "audio/midi";
|
||||
_mime_types["midi"] = "audio/midi";
|
||||
_mime_types["kar"] = "audio/midi";
|
||||
_mime_types["mp3"] = "audio/mpeg";
|
||||
_mime_types["ogg"] = "audio/ogg";
|
||||
_mime_types["m4a"] = "audio/x-m4a";
|
||||
_mime_types["ra"] = "audio/x-realaudio";
|
||||
|
||||
_mime_types["3gpp"] = "video/3gpp";
|
||||
_mime_types["3gp"] = "video/3gpp";
|
||||
_mime_types["ts"] = "video/mp2t";
|
||||
_mime_types["mp4"] = "video/mp4";
|
||||
_mime_types["mpeg"] = "video/mpeg";
|
||||
_mime_types["mpg"] = "video/mpeg";
|
||||
_mime_types["mov"] = "video/quicktime";
|
||||
_mime_types["webm"] = "video/webm";
|
||||
_mime_types["flv"] = "video/x-flv";
|
||||
_mime_types["m4v"] = "video/x-m4v";
|
||||
_mime_types["mng"] = "video/x-mng";
|
||||
_mime_types["asx"] = "video/x-ms-asf";
|
||||
_mime_types["asf"] = "video/x-ms-asf";
|
||||
_mime_types["wmv"] = "video/x-ms-wmv";
|
||||
_mime_types["avi"] = "video/x-msvideo";
|
||||
}
|
||||
|
||||
|
||||
@@ -15,19 +15,19 @@ void Webserv::_read_request(Client *client)
|
||||
char buf[BUFSIZE+1];
|
||||
ssize_t ret;
|
||||
|
||||
ret = ::recv(client->fd, buf, BUFSIZE, 0);
|
||||
std::cerr << "recv() on fd(" << client->fd << ") returned = " << ret << "\n" ;
|
||||
ret = ::recv(client->get_cl_fd(), buf, BUFSIZE, 0);
|
||||
std::cerr << "recv() on fd(" << client->get_cl_fd() << ") returned = " << ret << "\n" ;
|
||||
if (ret == -1)
|
||||
{
|
||||
std::perror("err recv()");
|
||||
std::cerr << "client ptr =" << client << "\n"; // DEBUG
|
||||
std::cerr << "client.fd =" << client->fd << "\n"; // DEBUG
|
||||
_close_client(client->fd);
|
||||
std::cerr << "client.get_cl_fd() =" << client->get_cl_fd() << "\n"; // DEBUG
|
||||
_close_client(client->get_cl_fd());
|
||||
return ;
|
||||
}
|
||||
if (ret == 0) // Not sure what to do in case of 0. Just close ?
|
||||
{
|
||||
_close_client(client->fd);
|
||||
_close_client(client->get_cl_fd());
|
||||
return ;
|
||||
}
|
||||
/*
|
||||
@@ -39,6 +39,6 @@ void Webserv::_read_request(Client *client)
|
||||
client->raw_request.append(buf);
|
||||
client->parse_request();
|
||||
|
||||
_epoll_update(client->fd, EPOLLOUT, EPOLL_CTL_MOD);
|
||||
_epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_MOD);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,95 +3,145 @@
|
||||
|
||||
void Webserv::_response(Client *client)
|
||||
{
|
||||
_send_response(client);
|
||||
client->status = 200; // default value
|
||||
|
||||
ServerConfig &server = _determine_process_server(client);
|
||||
_send_response(client, server);
|
||||
if (g_last_signal)
|
||||
_handle_last_signal();
|
||||
}
|
||||
|
||||
void Webserv::_send_response(Client *client)
|
||||
void Webserv::_send_response(Client *client, ServerConfig &server)
|
||||
{
|
||||
ssize_t ret;
|
||||
|
||||
std::cerr << "send()\n";
|
||||
std::cerr << "RAW_REQUEST\n|\n" << client->raw_request << "|\n"; // DEBUG
|
||||
|
||||
_construct_response(client);
|
||||
_append_base_headers(client);
|
||||
_construct_response(client, server);
|
||||
_insert_status_line(client);
|
||||
if (client->status >= 400)
|
||||
_error_html_response(client, server);
|
||||
|
||||
ret = ::send(client->fd, client->response.data(), client->response.size(), 0);
|
||||
ret = ::send(client->get_cl_fd(), client->response.c_str(), client->response.size(), 0);
|
||||
if (ret == -1)
|
||||
{
|
||||
std::perror("err send()");
|
||||
std::cerr << "client ptr =" << client << "\n"; // DEBUG
|
||||
std::cerr << "client.fd =" << client->fd << "\n"; // DEBUG
|
||||
_close_client(client->fd);
|
||||
std::cerr << "client.get_cl_fd() =" << client->get_cl_fd() << "\n"; // DEBUG
|
||||
_close_client(client->get_cl_fd());
|
||||
return ;
|
||||
}
|
||||
|
||||
if (client->raw_request.find("Connection: close") != std::string::npos)
|
||||
_close_client(client->fd);
|
||||
// Body send (WIP for working binary files)
|
||||
if (client->body_size)
|
||||
{
|
||||
ret = ::send(client->get_cl_fd(), client->buf, client->body_size, 0);
|
||||
if (ret == -1)
|
||||
{
|
||||
std::perror("err send()");
|
||||
std::cerr << "client.get_cl_fd() =" << client->get_cl_fd() << "\n"; // DEBUG
|
||||
_close_client(client->get_cl_fd());
|
||||
return ;
|
||||
}
|
||||
}
|
||||
|
||||
if (client->get_rq_headers("Connection") == "close")
|
||||
_close_client(client->get_cl_fd());
|
||||
else
|
||||
{
|
||||
_epoll_update(client->fd, EPOLLIN, EPOLL_CTL_MOD);
|
||||
client->raw_request.clear();
|
||||
client->response.clear();
|
||||
_epoll_update(client->get_cl_fd(), EPOLLIN, EPOLL_CTL_MOD);
|
||||
client->clear();
|
||||
}
|
||||
}
|
||||
|
||||
void Webserv::_construct_response(Client *client)
|
||||
void Webserv::_append_base_headers(Client *client)
|
||||
{
|
||||
client->status = 200;
|
||||
client->response.append("Server: Webserv/0.1\r\n");
|
||||
client->response.append("Server: Webserv/0.1" CRLF);
|
||||
|
||||
if (client->raw_request.find("Connection: close") != std::string::npos)
|
||||
client->response.append("Connection: close\r\n");
|
||||
if (client->get_rq_headers("Connection") == "close")
|
||||
client->response.append("Connection: close" CRLF);
|
||||
else
|
||||
client->response.append("Connection: keep-alive\r\n");
|
||||
|
||||
_get_ressource(client);
|
||||
|
||||
_insert_status_line(client);
|
||||
client->response.append("Connection: keep-alive" CRLF);
|
||||
}
|
||||
|
||||
void Webserv::_construct_response(Client *client, ServerConfig &server)
|
||||
{
|
||||
// TODO : Move this in read(), stop read if content too large
|
||||
if (client->get_rq_body().size() > server.client_body_limit)
|
||||
{
|
||||
client->status = 413;
|
||||
return;
|
||||
}
|
||||
LocationConfig &location = _determine_location(server, client->get_rq_path());
|
||||
_process_method(client, server, location);
|
||||
}
|
||||
|
||||
void Webserv::_process_method(Client *client, ServerConfig &server, LocationConfig &location)
|
||||
{
|
||||
unsigned int allow_methods = ANY_METHODS; // TEMP VARIABLE
|
||||
// after update in ConfigParser, use the "allow_methods" of location.
|
||||
// TODO in ConfigParser : by default if no field in config file, "allow_methods" must be set to ANY_METHODS
|
||||
|
||||
if (client->get_rq_method() == UNKNOWN)
|
||||
{
|
||||
client->status = 501;
|
||||
}
|
||||
else if (allow_methods & client->get_rq_method())
|
||||
{
|
||||
switch (client->get_rq_method())
|
||||
{
|
||||
case (GET):
|
||||
_get(client, server, location); break;
|
||||
case (POST):
|
||||
_post(client, server, location); break;
|
||||
case (DELETE):
|
||||
_delete(client, server, location); break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
client->status = 405;
|
||||
client->response.append("Allow: ");
|
||||
client->response.append(::http_methods_to_str(allow_methods));
|
||||
client->response.append(CRLF);
|
||||
}
|
||||
}
|
||||
|
||||
#define E400 "\r\n<!DOCTYPE html><html><head><title>400 Bad Request</title></head><body><h1 style=\"text-align:center\">400 Bad Request</h1><hr><p style=\"text-align:center\">Le Webserv/0.1</p></body></html>"
|
||||
#define E404 "\r\n<!DOCTYPE html><html><head><title>404 Not Found</title></head><body><h1 style=\"text-align:center\">404 Not Found</h1><hr><p style=\"text-align:center\">Le Webserv/0.1</p></body></html>"
|
||||
#define E500 "\r\n<!DOCTYPE html><html><head><title>500 Internal Server Error</title></head><body><h1 style=\"text-align:center\">500 Internal Server Error</h1><hr><p style=\"text-align:center\">Le Webserv/0.1</p></body></html>"
|
||||
void Webserv::_insert_status_line(Client *client)
|
||||
{
|
||||
std::string status_line;
|
||||
|
||||
status_line.append("HTTP/1.1 ");
|
||||
// WIP, maybe make a map for status response
|
||||
switch (client->status)
|
||||
{
|
||||
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);
|
||||
break;
|
||||
case (500):
|
||||
status_line.append("500 Internal Server Error");
|
||||
client->response.append(E500);
|
||||
break;
|
||||
}
|
||||
status_line.append("\r\n");
|
||||
|
||||
status_line.append(_http_status[client->status]);
|
||||
status_line.append(CRLF);
|
||||
client->response.insert(0, status_line);
|
||||
}
|
||||
|
||||
#define ROOT "website"
|
||||
#define INDEX "index.html"
|
||||
#define MAX_FILESIZE 1000000 // (1Mo)
|
||||
void Webserv::_get_ressource(Client *client)
|
||||
void Webserv::_error_html_response(Client *client, ServerConfig &server)
|
||||
{
|
||||
std::ifstream ifd; // For chunk, ifstream directly in struct CLient for multiples read without close() ?
|
||||
char buf[MAX_FILESIZE+1];
|
||||
std::string tmp;
|
||||
if (server.error_pages[client->status].empty())
|
||||
{
|
||||
std::string html_page = HTML_ERROR;
|
||||
::replace_all_substr(html_page, STATUS_PLACEHOLDER, _http_status[client->status]);
|
||||
_append_body(client, html_page.c_str(), html_page.size(), "html");
|
||||
}
|
||||
else
|
||||
_get_file(client, server.error_pages[client->status]);
|
||||
}
|
||||
|
||||
#define INDEX "index.html" // temp wip
|
||||
void Webserv::_get(Client *client, ServerConfig &server, LocationConfig &location)
|
||||
{
|
||||
(void)server; // To remove from arg if we determine its useless
|
||||
std::string path = client->get_rq_path();
|
||||
|
||||
if (path == "/") // TODO : index and autoindex
|
||||
path.append(INDEX);
|
||||
path.insert(0, location.root);
|
||||
|
||||
std::cerr << "path = " << path << "\n";
|
||||
|
||||
// TMP HUGO
|
||||
//
|
||||
@@ -103,41 +153,39 @@ void Webserv::_get_ressource(Client *client)
|
||||
//
|
||||
// END TMP HUGO
|
||||
|
||||
// Mini parsing à l'arrache du PATH
|
||||
std::string path;
|
||||
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 ;
|
||||
}
|
||||
_get_file(client, path);
|
||||
}
|
||||
|
||||
if (access(path.data(), R_OK) == -1)
|
||||
void Webserv::_get_file(Client *client, const std::string &path)
|
||||
{
|
||||
std::ifstream ifd; // For chunk, ifstream directly in struct CLient for multiples read without close() ?
|
||||
// char buf[MAX_FILESIZE+1];
|
||||
|
||||
if (access(path.c_str(), F_OK) == -1)
|
||||
{
|
||||
std::perror("err access()");
|
||||
client->status = 404;
|
||||
return ;
|
||||
}
|
||||
|
||||
ifd.open(path.data(), std::ios::binary | std::ios::ate); // std::ios::binary (binary for files like images ?)
|
||||
if (access(path.c_str(), R_OK) == -1)
|
||||
{
|
||||
std::perror("err access()");
|
||||
client->status = 403;
|
||||
return ;
|
||||
}
|
||||
|
||||
ifd.open(path.c_str(), std::ios::binary | std::ios::ate); // std::ios::binary (binary for files like images ?)
|
||||
if (!ifd)
|
||||
{
|
||||
std::cerr << path << ": open fail" << '\n';
|
||||
std::cerr << path << ": ifd.open fail" << '\n';
|
||||
client->status = 500;
|
||||
}
|
||||
else
|
||||
{
|
||||
// WIP : Chunk or not chunk (if filesize too big)
|
||||
std::streampos size = ifd.tellg();
|
||||
|
||||
// WIP : Chunk or not chunk (if filesize too big)
|
||||
if (size > MAX_FILESIZE)
|
||||
{
|
||||
// Then chunk
|
||||
@@ -148,22 +196,211 @@ void Webserv::_get_ressource(Client *client)
|
||||
}
|
||||
|
||||
ifd.seekg(0, std::ios::beg);
|
||||
ifd.read(buf, size);
|
||||
buf[ifd.gcount()] = '\0';
|
||||
ifd.read(client->buf, size);
|
||||
if (!ifd)
|
||||
{
|
||||
std::cerr << path << ": ifd.read fail" << '\n';
|
||||
client->status = 500;
|
||||
}
|
||||
else
|
||||
{
|
||||
client->status = 200;
|
||||
client->buf[ifd.gcount()] = '\0';
|
||||
|
||||
client->response.append("Content-Type: text/html; charset=UTF-8\r\n");
|
||||
std::string file_ext = "";
|
||||
size_t dot_pos = path.rfind(".");
|
||||
std::cerr << "dot_pos = " << dot_pos << "\n";
|
||||
if (dot_pos != std::string::npos && dot_pos + 1 < path.size())
|
||||
file_ext = path.substr(dot_pos + 1);
|
||||
std::cerr << "file_ext = " << file_ext << "\n";
|
||||
|
||||
client->response.append("Content-Length: ");
|
||||
|
||||
tmp = ::itos(ifd.gcount());
|
||||
client->response.append(tmp.c_str());
|
||||
client->response.append("\r\n");
|
||||
|
||||
// Body
|
||||
client->response.append("\r\n");
|
||||
client->response.append(buf);
|
||||
client->body_size = ifd.gcount();
|
||||
// WIP, pass empty body argument because append to string mess up binary file
|
||||
_append_body(client, "", client->body_size, file_ext);
|
||||
}
|
||||
|
||||
ifd.close();
|
||||
}
|
||||
}
|
||||
|
||||
void Webserv::_append_body(Client *client, const char *body, size_t body_size, const std::string &file_extension)
|
||||
{
|
||||
/*
|
||||
TODO : determine Content-Type
|
||||
how ? read the body ?
|
||||
or before in other way (like based and file extension) and pass here as argument ?
|
||||
http://nginx.org/en/docs/http/ngx_http_core_module.html#types
|
||||
Need to look "conf/mime.types" of nginx. Maybe make a map<> based on that.
|
||||
*/
|
||||
const std::string &mime_type = _mime_types[file_extension];
|
||||
client->response.append("Content-Type: ");
|
||||
client->response.append(mime_type);
|
||||
if (mime_type.find("text/") != std::string::npos)
|
||||
client->response.append("; charset=UTF-8");
|
||||
client->response.append(CRLF);
|
||||
|
||||
client->response.append("Content-Length: ");
|
||||
std::string tmp = ::itos(body_size);
|
||||
client->response.append(tmp);
|
||||
client->response.append(CRLF);
|
||||
|
||||
client->response.append(CRLF);
|
||||
client->response.append(body);
|
||||
}
|
||||
|
||||
void Webserv::_post(Client *client, ServerConfig &server, LocationConfig &location)
|
||||
{
|
||||
(void)server; // To remove from arg if we determine its useless
|
||||
/*
|
||||
WIP
|
||||
https://www.rfc-editor.org/rfc/rfc9110.html#name-post
|
||||
*/
|
||||
std::string path = client->get_rq_path();
|
||||
path.insert(0, location.root);
|
||||
|
||||
/* CGI Here ? */
|
||||
|
||||
_post_file(client, path);
|
||||
}
|
||||
|
||||
void Webserv::_post_file(Client *client, const std::string &path)
|
||||
{
|
||||
std::ofstream ofd;
|
||||
|
||||
bool file_existed;
|
||||
if (access(path.c_str(), F_OK) == -1)
|
||||
file_existed = false;
|
||||
else
|
||||
file_existed = true;
|
||||
|
||||
// How to determine status 403 for file that dont already exist ?
|
||||
if (file_existed && access(path.c_str(), W_OK) == -1)
|
||||
{
|
||||
std::perror("err access()");
|
||||
client->status = 403;
|
||||
return ;
|
||||
}
|
||||
|
||||
ofd.open(path.c_str(), std::ios::binary | std::ios::trunc);
|
||||
if (!ofd)
|
||||
{
|
||||
std::cerr << path << ": ofd.open fail" << '\n';
|
||||
client->status = 500;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Used body.size() so Content-Length useless at this point ?
|
||||
// Maybe usefull in _read_request() for rejecting too big content.
|
||||
// Need to _determine_process_server() as soon as possible,
|
||||
// like in _read_request() for stopping read if body is too big ?
|
||||
ofd.write(client->get_rq_body().c_str(), client->get_rq_body().size());
|
||||
if (!ofd)
|
||||
{
|
||||
std::cerr << path << ": ofd.write fail" << '\n';
|
||||
client->status = 500;
|
||||
}
|
||||
else if (file_existed)
|
||||
{
|
||||
client->status = 200;
|
||||
// WIP https://www.rfc-editor.org/rfc/rfc9110.html#name-200-ok
|
||||
}
|
||||
else
|
||||
{
|
||||
client->status = 201;
|
||||
// WIP https://www.rfc-editor.org/rfc/rfc9110.html#section-9.3.3-4
|
||||
}
|
||||
|
||||
ofd.close();
|
||||
}
|
||||
}
|
||||
|
||||
void Webserv::_delete(Client *client, ServerConfig &server, LocationConfig &location)
|
||||
{
|
||||
(void)server; // To remove from arg if we determine its useless
|
||||
/*
|
||||
WIP
|
||||
https://www.rfc-editor.org/rfc/rfc9110.html#name-delete
|
||||
*/
|
||||
std::string path = client->get_rq_path();
|
||||
path.insert(0, location.root);
|
||||
|
||||
/* CGI Here ? */
|
||||
|
||||
_delete_file(client, path);
|
||||
}
|
||||
|
||||
void Webserv::_delete_file(Client *client, const std::string &path)
|
||||
{
|
||||
if (access(path.c_str(), F_OK) == -1)
|
||||
{
|
||||
std::perror("err access()");
|
||||
client->status = 404;
|
||||
return ;
|
||||
}
|
||||
|
||||
if (access(path.c_str(), W_OK) == -1)
|
||||
{
|
||||
std::perror("err access()");
|
||||
client->status = 403;
|
||||
return ;
|
||||
}
|
||||
|
||||
if (remove(path.c_str()) == -1)
|
||||
{
|
||||
std::perror("err remove()");
|
||||
client->status = 500;
|
||||
return ;
|
||||
}
|
||||
}
|
||||
|
||||
ServerConfig &Webserv::_determine_process_server(Client *client)
|
||||
{
|
||||
/*
|
||||
http://nginx.org/en/docs/http/request_processing.html
|
||||
_determine_process_server() should be complete.
|
||||
TODO : test it
|
||||
*/
|
||||
|
||||
std::string const &server_name = client->get_rq_headers("Host");
|
||||
std::vector<ServerConfig>::iterator it = _servers.begin();
|
||||
std::vector<ServerConfig>::iterator default_server = _servers.end();
|
||||
|
||||
while (it != _servers.end())
|
||||
{
|
||||
if (it->host == client->get_cl_lsocket()->host
|
||||
&& it->port == client->get_cl_lsocket()->port)
|
||||
{
|
||||
if ( std::find(it->server_name.begin(), it->server_name.end(), server_name) != it->server_name.end() )
|
||||
break;
|
||||
else if (default_server == _servers.end())
|
||||
default_server = it;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
if (it != _servers.end())
|
||||
return (*it);
|
||||
else
|
||||
return (*default_server);
|
||||
}
|
||||
|
||||
LocationConfig &Webserv::_determine_location(ServerConfig &server, std::string const &path)
|
||||
{
|
||||
/*
|
||||
Assume there is at least one location in vector<LocationConfig> for path "/"
|
||||
TODO in ConfigParser :
|
||||
If no location block in config file, one need to be generated
|
||||
for path "/", and filled with fields "root" and "index" based on parent server block
|
||||
*/
|
||||
|
||||
std::vector<LocationConfig>::iterator it = server.locations.begin();
|
||||
while (it != server.locations.end())
|
||||
{
|
||||
if (it->path.compare(0, path.size(), path))
|
||||
break;
|
||||
++it;
|
||||
}
|
||||
if (it != server.locations.end())
|
||||
return (*it);
|
||||
else
|
||||
return (server.locations.front());
|
||||
}
|
||||
|
||||
@@ -4,14 +4,6 @@
|
||||
#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";
|
||||
@@ -19,6 +11,7 @@ void Webserv::run()
|
||||
int nfds;
|
||||
int i;
|
||||
int count_loop = 0;
|
||||
std::vector<listen_socket>::iterator it_socket;
|
||||
|
||||
g_run = true;
|
||||
while (g_run)
|
||||
@@ -42,9 +35,9 @@ void Webserv::run()
|
||||
while (i < nfds)
|
||||
{
|
||||
// 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);
|
||||
it_socket = std::find(_listen_sockets.begin(), _listen_sockets.end(), events[i].data.fd);
|
||||
if (it_socket != _listen_sockets.end() && events[i].events & EPOLLIN)
|
||||
_accept_connection(*it_socket);
|
||||
else if (events[i].events & EPOLLIN)
|
||||
_request( &(*std::find(_clients.begin(), _clients.end(), events[i].data.fd)) );
|
||||
else if (events[i].events & EPOLLOUT)
|
||||
|
||||
Reference in New Issue
Block a user