Files
webserv/src/server.cpp

160 lines
4.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* server.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: adjoly <adjoly@student.42angouleme.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/04/11 16:11:40 by adjoly #+# #+# */
/* Updated: 2025/04/17 12:37:45 by adjoly ### ########.fr */
/* */
/* ************************************************************************** */
#include <cmath>
#include <log.hpp>
#include <netinet/in.h>
#include <requests/default.hpp>
#include <server/default.hpp>
#include <sstream>
#include <stdexcept>
#include <sys/socket.h>
#include <webserv.hpp>
using namespace webserv;
std::string getMethod(std::string &data) {
return (data.substr(0, data.substr(0, 4).find_last_not_of(" ") + 1));
}
void Server::_handle_client(int fd) {
std::string received_data;
char buffer[BUFFER_SIZE];
ssize_t bytes_received;
do {
std::memset(buffer, 0, BUFFER_SIZE);
bytes_received = recv(fd, buffer, BUFFER_SIZE - 1, 0);
if (bytes_received == -1) {
_log->error("failed to receive request");
continue;
}
received_data += std::string(buffer, bytes_received);
} while (buffer[bytes_received]);
std::string response;
if (getMethod(received_data) == "GET") {
_log->info("get request received");
http::Get request(received_data);
response = request.execute().str();
} else if (getMethod(received_data) == "DELETE") {
_log->info("delete request received");
http::Delete request(received_data);
response = request.execute().str();
} else if (getMethod(received_data) == "POST") {
_log->info("post request received");
http::Post request(received_data);
response = request.execute().str();
} else {
response = "HTTP/1.1 501 Not Implemented\r\nContent-Type: "
"text/html\r\n\r\n<html><body><h1>501 Not "
"Implemented</h1></body></html>";
}
send(fd, response.c_str(), response.length(), 0);
}
int Server::_fillHostsPorts(std::vector<std::string> &hosts,
std::vector<int> &ports) {
std::vector<config::Server *> *config = _conf->getServers();
for (std::vector<config::Server *>::iterator it = config->begin();
it != config->end(); it++) {
hosts.push_back((*it)->getHost());
ports.push_back((*it)->getPort());
}
return config->size();
}
void Server::_setup(void) {
std::vector<std::string> hosts;
std::vector<int> ports;
int size = _fillHostsPorts(hosts, ports);
if (size < 1)
throw std::runtime_error("no server present in the config file");
std::vector<std::string>::iterator itH = hosts.begin();
for (std::vector<int>::iterator itP = ports.begin(); itP != ports.end(); itP++, itH++) {
try {
int fd = _createSocket(*itH, *itP);
_fds_server.push_back(fd);
} catch (std::exception &e) {
throw e;
}
}
}
void Server::_run(void) {
struct pollfd fd;
fd.fd = _fd_server;
fd.events = POLLIN;
_client_fds.clear();
_client_fds.push_back(fd);
int nbr_client = 0;
while (727) {
int ret = poll(_client_fds.data(), nbr_client + 1, -1);
if (ret < 0) {
close(_fd_server);
throw std::runtime_error("poll failed :(");
}
if (_client_fds[0].revents & POLLIN) {
struct sockaddr_in client_addr;
socklen_t addrlen = sizeof(client_addr);
int client_fd =
accept(_fd_server, (struct sockaddr *)&client_addr, &addrlen);
if (client_fd < 0) {
_log->error("accept failed");
continue;
}
struct pollfd client_pollfd;
client_pollfd.fd = client_fd;
client_pollfd.events = POLLIN;
_client_fds.push_back(client_pollfd);
++nbr_client;
// if (nbr_client) TODO do we need a max client probably not :D
}
for (int i = 1; i <= nbr_client;) {
if (_client_fds[i].revents & POLLIN) {
_handle_client(_client_fds[i].fd);
close(_client_fds[i].fd);
_client_fds[i] = _client_fds[nbr_client--];
_client_fds.pop_back();
} else
++i;
}
}
}
Server::Server(config::Config *conf) : _conf(conf) {
log("", "Server::Server", "config constructor called");
_log = conf->getLogger();
_setup();
_run();
}
Server::~Server(void) {
log("", "Server::Server", "destructor called");
for (std::vector<struct pollfd>::iterator it = _client_fds.begin();
it != _client_fds.end(); it++)
close(it->fd);
close(_fd_server);
}