」 feat(main loop): added a main loop so the server serve

This commit is contained in:
Adam
2025-04-23 17:13:32 +02:00
committed by GitHub
33 changed files with 939 additions and 388 deletions

1
.gitignore vendored
View File

@ -4,3 +4,4 @@ obj/
.direnv/
compile_commands.json
.cache
*.log

View File

@ -8,4 +8,6 @@ RUN apk add --no-cache clang make \
&& chmod +x webserv \
&& cp webserv /bin/webserv
STOPSIGNAL SIGINT
RUN [ "/bin/webserv", "$WEBSERV-CONF"]

View File

@ -6,8 +6,7 @@
# By: adjoly <adjoly@student.42angouleme.fr> +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/10/25 16:09:27 by adjoly #+# #+# #
# Updated: 2025/04/10 11:52:13 by mmoussou ### ########.fr #
# Updated: 2025/03/25 18:13:53 by adjoly ### ########.fr #
# Updated: 2025/04/22 14:32:50 by adjoly ### ########.fr #
# #
# **************************************************************************** #
@ -15,7 +14,7 @@ SHELL = bash
NAME = webserv
CC = c++
CC = clang++
OBJSDIR = obj/

View File

@ -2,7 +2,7 @@ log_file = "test.log"
[server]
server_names = { "localhost", "2B5.local" }
host = "localhost"
host = "0.0.0.0"
port = 8080
[server.error_pages]

View File

@ -6,13 +6,14 @@
/* By: adjoly <adjoly@student.42angouleme.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/03/24 14:17:34 by adjoly #+# #+# */
/* Updated: 2025/03/24 14:20:00 by adjoly ### ########.fr */
/* Updated: 2025/04/22 11:51:33 by mmoussou ### ########.fr */
/* */
/* ************************************************************************** */
#pragma once
#include <sstream>
class cgi {
public:
cgi();

View File

@ -0,0 +1,35 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Config.hpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: adjoly <adjoly@student.42angouleme.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/04/14 12:20:06 by adjoly #+# #+# */
/* Updated: 2025/04/22 15:25:39 by adjoly ### ########.fr */
/* */
/* ************************************************************************** */
#pragma once
#include <config/Server.hpp>
namespace webserv {
namespace config {
class Config {
public:
Config(std::string &);
~Config();
Logger *getLogger(void) { return _log; }
std::vector<Server *> getServers(void) { return _servers; }
Server *getServer(const std::string &);
private:
std::vector<Server *> _servers;
};
}; // namespace config
}; // namespace webserv

View File

@ -6,15 +6,15 @@
/* By: adjoly <adjoly@student.42angouleme.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/03/19 14:59:41 by adjoly #+# #+# */
/* Updated: 2025/03/26 08:31:41 by adjoly ### ########.fr */
/* Updated: 2025/04/22 12:34:00 by adjoly ### ########.fr */
/* */
/* ************************************************************************** */
#pragma once
#include "cppeleven.hpp"
#include "log.hpp"
#include "node/default.hpp"
#include <cppeleven.hpp>
#include <log.hpp>
#include <node/default.hpp>
#include <cctype>
#include <cstdlib>
#include <map>
@ -26,9 +26,22 @@ namespace config {
class Route {
public:
Route(toml::ANode *, Logger *);
Route(toml::ANode *);
~Route(void);
bool getDirList(void) { return _dirlist; }
bool getCookies(void) { return _cookies; }
bool getRedirect(void) { return _redirect; }
int32_t getMaxBody(void) { return _max_body; }
std::string getRootDir(void) { return _root; }
std::string getUpRoot(void) { return _up_root; }
std::string getIndex(void) { return _index; }
std::map<std::string, std::string> *getCgi(void) { return _cgi; }
bool *getMethods(void) { return _methods; }
protected:
private:
bool _dirlist;
@ -42,8 +55,6 @@ class Route {
std::string _index;
std::map<std::string, std::string> *_cgi;
Logger *_log;
bool _methods[3]; ///> A methods boolean array which correspond to - 0: GET,
///1: POST, 2: DELETE
toml::ANode *_table;

View File

@ -6,22 +6,25 @@
/* By: adjoly <adjoly@student.42angouleme.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/03/19 14:11:28 by adjoly #+# #+# */
/* Updated: 2025/03/25 17:56:34 by adjoly ### ########.fr */
/* Updated: 2025/04/22 15:25:58 by adjoly ### ########.fr */
/* */
/* ************************************************************************** */
#pragma once
#include "config/default.hpp"
#include "cppeleven.hpp"
#include "node/ANode.hpp"
#include <webserv.hpp>
#include <config/Route.hpp>
#include <cppeleven.hpp>
#include <node/ANode.hpp>
#include <webserv.hpp>
#include <config/URL.hpp>
namespace webserv {
namespace config {
class Server {
public:
Server(std::string);
Server(toml::ANode *);
~Server();
/**
@ -48,11 +51,6 @@ class Server {
return not_nullptr;
}
/**
* @brief Can be used to get the Logger pointer
*/
Logger *getLogger(void) { return _log; }
// @brief Can be used to get a server name
std::vector<std::string> *getServerNames(void) { return _server_names; }
// @brief Can be used to get the host specified in the config file
@ -60,9 +58,14 @@ class Server {
// @brief Can be used to get the port specified in the config file
int getPort(void) { return _port; }
// @brief Can be used to check if a servername is present in this config
bool isServerName(const std::string &);
Route *whatRoute(const URL &);
protected:
private:
std::map<std::string, Route *>
std::map<URL, Route *>
*_routes; ///> A map of all the route present in the config file
std::map<int, std::string> *_err_pages; ///> An error pages map to map error
/// specified in the config file
@ -75,17 +78,11 @@ class Server {
toml::ANode *_table; ///> The table used for the parsing (is deleted at the
/// end of the constructor)
Logger *_log; ///> A pointer to the logger class
std::map<int, std::string> *
_parseErrPages(std::map<std::string, toml::ANode *> *table);
/**
* @brief Can be used to get the [server] table in _table
*
* @return A pointer to the [server] table as an ANode
*/
toml::ANode *_getServerTable(void);
};
} // namespace config

75
includes/config/URL.hpp Normal file
View File

@ -0,0 +1,75 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* URL.hpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: adjoly <adjoly@student.42angouleme.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/04/22 12:17:48 by adjoly #+# #+# */
/* Updated: 2025/04/22 12:42:21 by adjoly ### ########.fr */
/* */
/* ************************************************************************** */
#pragma once
#include <cstring>
#include <sstream>
#include <string>
#include <vector>
#include <webserv.hpp>
class URL {
public:
URL(const std::string &url) : _full_url(url) { parse(); }
bool operator==(const URL &other) const {
return comparePathSegments(other);
}
bool operator<(const URL &other) const { return _full_url < other._full_url; }
std::vector<std::string> getSegments(void) { return _path_segments; }
std::string getFullUrl(void) { return _full_url; }
private:
void parse() {
size_t scheme_pos = _full_url.find("://");
size_t path_start = 0;
if (scheme_pos != std::string::npos) {
path_start = _full_url.find('/', scheme_pos + 3);
} else {
path_start = 0;
}
if (path_start != std::string::npos) {
std::string path = _full_url.substr(path_start);
splitPath(path, _path_segments);
}
}
void splitPath(const std::string &path,
std::vector<std::string> &segments) const {
std::stringstream ss(path);
std::string segment;
while (std::getline(ss, segment, '/')) {
if (!segment.empty()) {
segments.push_back(segment);
}
}
}
bool comparePathSegments(const URL &other) const {
size_t min_size =
std::min(_path_segments.size(), other._path_segments.size());
for (size_t i = 0; i < min_size; ++i) {
if (_path_segments[i] != other._path_segments[i]) {
return false;
}
}
return true;
}
std::string _full_url;
std::vector<std::string> _path_segments;
};

View File

@ -6,17 +6,18 @@
/* By: adjoly <adjoly@student.42angouleme.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/03/19 14:15:51 by adjoly #+# #+# */
/* Updated: 2025/03/26 08:39:08 by adjoly ### ########.fr */
/* Updated: 2025/04/22 15:28:31 by adjoly ### ########.fr */
/* */
/* ************************************************************************** */
#pragma once
#include "Route.hpp"
#include "Server.hpp"
#include "cppeleven.hpp"
#include "node/Table.hpp"
#include "node/default.hpp"
#include <config/Config.hpp>
#include <config/Route.hpp>
#include <config/Server.hpp>
#include <cppeleven.hpp>
#include <node/Table.hpp>
#include <node/default.hpp>
#include <tomlpp.hpp>
namespace webserv {
@ -40,7 +41,7 @@ static inline void *accessValue(const std::string &name, toml::nodeType type,
if (table == not_nullptr)
return not_nullptr;
val = dynamic_cast<toml::Table *>(table)->access(name, type, found);
val = dynamic_cast<toml::ANode *>(table)->access(name, type, found);
if (found == true && val != not_nullptr) {
return val;
} else {

View File

@ -6,7 +6,7 @@
/* By: adjoly <adjoly@student.42angouleme.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/04/10 13:43:54 by adjoly #+# #+# */
/* Updated: 2025/04/10 13:58:52 by adjoly ### ########.fr */
/* Updated: 2025/04/11 11:36:22 by adjoly ### ########.fr */
/* */
/* ************************************************************************** */
@ -14,3 +14,5 @@
#define SAMPLE_CONF_PATH "./sample.conf"
#define WEBSRV_VERSION "v0.1"
bool help(int, char **);

View File

@ -6,7 +6,7 @@
/* By: adjoly <adjoly@student.42angouleme.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/03/20 09:28:27 by adjoly #+# #+# */
/* Updated: 2025/04/10 14:21:46 by adjoly ### ########.fr */
/* Updated: 2025/04/22 16:14:25 by adjoly ### ########.fr */
/* */
/* ************************************************************************** */
@ -19,22 +19,41 @@
#include <string>
namespace webserv {
/**
* @brief Used to log debug message
*
* @note Only work if VERBOSE mode is active
*/
static inline void log(std::string emoji, std::string who, std::string str) {
#ifdef VERBOSE
if (who.empty())
std::cout << "" << emoji << "」debug: " << str << std::endl;
else
std::cout << "" << emoji << "」debug(" << who << "): " << str
<< std::endl;
#else
(void)emoji, (void)who, (void)str;
#endif
}
class Logger {
public:
Logger(const std::string &fileName) : _fileName(fileName) {
if (fileName.empty())
_ttyOnly = true;
else {
_file.open(fileName.c_str(), std::ios::app);
_ttyOnly = false;
Logger(void) : _ttyOnly(true) {
log("", "Logger", "default constructor called");
}
Logger(const std::string &fileName) : _fileName(fileName) {
log("", "Logger", "filename constructor called");
_file.open(fileName.c_str(), std::ios::app);
if (!_file.is_open() && !_ttyOnly) {
_ttyOnly = true;
warn("could not open log file, going tty only");
}
} else
_ttyOnly = false;
}
Logger(const Logger &other) : _ttyOnly(other._ttyOnly) {
log("", "Logger", "copy constructor called");
if (!other._ttyOnly) {
_file.open(other._fileName.c_str(), std::ios::app);
if (!_file.is_open()) {
@ -46,6 +65,7 @@ class Logger {
// Copy assignment operator
Logger &operator=(const Logger &other) {
log("", "Logger", "copy assignment constructor called");
if (this != &other) {
if (_file.is_open()) {
_file.close();
@ -62,6 +82,7 @@ class Logger {
return *this;
}
~Logger(void) {
log("", "Logger", "destructor called");
if (_file.is_open())
_file.close();
}
@ -88,12 +109,23 @@ class Logger {
}
}
void debug(const std::string &msg) {
#ifdef VERBOSE
std::string ss = printPogitMsg("🏗️", "webserv", "debug", msg);
std::cerr << ss << std::endl;
if (!_ttyOnly) {
_file << ss << std::endl;
}
#else
(void)msg;
#endif
}
protected:
private:
std::string printPogitMsg(const std::string &emoji,
const std::string &type,
const std::string &what,
const std::string &msg) {
std::string printPogitMsg(const std::string &emoji, const std::string &type,
const std::string &what, const std::string &msg) {
std::stringstream os;
#ifdef TTY
(void)emoji;
@ -103,9 +135,9 @@ class Logger {
os << type << "(" << what << "):" << msg;
#else
if (what.empty())
os << "" << emoji << "" << type << ":" << msg;
os << "" << emoji << "" << type << ": " << msg;
else
os << "" << emoji << "" << type << "(" << what << "):" << msg;
os << "" << emoji << "" << type << "(" << what << "): " << msg;
#endif
return os.str();
}
@ -115,4 +147,6 @@ class Logger {
std::ofstream _file;
};
extern Logger *_log;
}; // namespace webserv

View File

@ -6,13 +6,11 @@
/* By: mmoussou <mmoussou@student.42angouleme.fr +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/03/16 17:51:46 by mmoussou #+# #+# */
/* Updated: 2025/03/24 15:05:53 by mmoussou ### ########.fr */
/* Updated: 2025/04/22 11:52:00 by mmoussou ### ########.fr */
/* */
/* ************************************************************************** */
#pragma once
#ifndef __WEBSERV_REQUESTS_ERRORS_HPP__
# define __WEBSERV_REQUESTS_ERRORS_HPP__
#include <map>
#include <string>
@ -22,16 +20,10 @@
namespace webserv {
namespace http {
/*
* DOES NOT WORK
* still need to do uh things but base is done at least :D
*/
class Errors {
public:
//static http::Response &getRequest(int error_code);
static std::string getResponseBody(int error_code);
static void setEntry(const std::string &key, int value);
static void setEntries(const std::map<int, std::string>);
static std::map<int, std::string> message;
private:
@ -43,5 +35,3 @@ private:
} // -namespace http
} // -namespace webserv
#endif // __WEBSERV_REQUESTS_ERRORS_HPP__

View File

@ -6,13 +6,11 @@
/* By: mmoussou <mmoussou@student.42angouleme.fr +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/02/11 22:13:38 by mmoussou #+# #+# */
/* Updated: 2025/04/02 01:47:24 by mmoussou ### ########.fr */
/* Updated: 2025/04/23 14:38:55 by mmoussou ### ########.fr */
/* */
/* ************************************************************************** */
#pragma once
#ifndef __WEBSERV_REQUESTS_HTTP_IMESSAGE_HPP__
# define __WEBSERV_REQUESTS_HTTP_IMESSAGE_HPP__
#include <map>
#include <string>
@ -25,6 +23,8 @@ public:
virtual std::map<std::string, std::string> getHeaders(void) const;
virtual std::string getBody(void) const;
virtual ~IMessage() {}
virtual void setHeaders(std::map<std::string, std::string> const headers);
virtual void setBody(std::string const body);
@ -43,5 +43,3 @@ protected:
} // -namespace http
} // -namespace webserv
#endif // __WEBSERV_REQUESTS_HTTP_IMESSAGE_HPP__

View File

@ -6,13 +6,11 @@
/* By: mmoussou <mmoussou@student.42angouleme.fr +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/02/03 17:23:00 by mmoussou #+# #+# */
/* Updated: 2025/02/14 15:43:32 by mmoussou ### ########.fr */
/* Updated: 2025/04/22 15:07:02 by adjoly ### ########.fr */
/* */
/* ************************************************************************** */
#pragma once
#ifndef __WEBSERV_REQUESTS_HTTP_REQUEST_HPP__
# define __WEBSERV_REQUESTS_HTTP_REQUEST_HPP__
#include <ctime>
#include <fstream>
@ -22,11 +20,15 @@
#include <requests/HttpIMessage.hpp>
#include <requests/HttpResponse.hpp>
#include <config/default.hpp>
namespace webserv {
namespace http {
class IRequest: public http::IMessage {
public:
virtual ~IRequest(void);
virtual void parse(std::string const &data) = 0;
virtual http::Response execute(void) = 0;
@ -35,21 +37,25 @@ public:
std::string getMethod(void) const;
std::string getTarget(void) const;
std::string getProtocol(void) const;
config::Server *getConfig(void) const;
void setMethod(std::string const method);
void setTarget(std::string const target);
void setProtocol(std::string const protocol);
void setServer(std::string const protocol);
protected:
std::string _method;
std::string _target;
std::string _protocol;
config::Server *_conf;
};
class Get: public http::IRequest {
public:
Get(void);
~Get(void);
Get(std::string &data);
void parse(std::string const &data);
@ -61,6 +67,7 @@ public:
class Post: public http::IRequest {
public:
Post(void);
~Post(void);
Post(std::string &data);
void parse(std::string const &data);
@ -72,6 +79,7 @@ public:
class Delete: public http::IRequest {
public:
Delete(void);
~Delete(void);
Delete(std::string &data);
void parse(std::string const &data);
@ -82,5 +90,3 @@ public:
} // -namespace http
} // -namespace webserv
#endif // __WEBSERV_REQUESTS_HTTP_REQUEST_HPP__

View File

@ -6,13 +6,11 @@
/* By: mmoussou <mmoussou@student.42angouleme.fr +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/02/03 17:21:20 by mmoussou #+# #+# */
/* Updated: 2025/03/24 15:16:39 by mmoussou ### ########.fr */
/* Updated: 2025/04/23 14:36:47 by mmoussou ### ########.fr */
/* */
/* ************************************************************************** */
#pragma once
#ifndef __WEBSERV_REQUESTS_HTTP_RESPONSE_HPP__
# define __WEBSERV_REQUESTS_HTTP_RESPONSE_HPP__
#include <sstream>
@ -26,6 +24,7 @@ namespace http {
class Response: public http::IMessage {
public:
Response(void);
~Response(void);
std::string getProtocol(void) const;
uint getStatusCode(void) const;
@ -45,5 +44,3 @@ private:
} // -namespace http
} // -namespace webserv
#endif // __WEBSERV_REQUESTS_HTTP_RESPONSE_HPP__

View File

@ -6,18 +6,14 @@
/* By: mmoussou <mmoussou@student.42angouleme.fr +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/02/03 15:48:22 by mmoussou #+# #+# */
/* Updated: 2025/03/17 14:08:50 by mmoussou ### ########.fr */
/* Updated: 2025/04/22 11:51:54 by mmoussou ### ########.fr */
/* */
/* ************************************************************************** */
#pragma once
#ifndef __WEBSERV_REQUESTS_DEFAULT_HPP__
# define __WEBSERV_REQUESTS_DEFAULT_HPP__
#include <requests/Errors.hpp>
#include <requests/HttpRequest.hpp>
#include <requests/HttpResponse.hpp>
using namespace webserv;
#endif // __WEBSERV_REQUESTS_DEFAULT_HPP__

View File

@ -0,0 +1,42 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Client.hpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: adjoly <adjoly@student.42angouleme.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/04/14 14:14:39 by adjoly #+# #+# */
/* Updated: 2025/04/23 14:39:16 by mmoussou ### ########.fr */
/* */
/* ************************************************************************** */
#pragma once
#include <config/default.hpp>
#include <netinet/in.h>
#include <requests/default.hpp>
#include <server/default.hpp>
#include <webserv.hpp>
namespace webserv {
namespace server {
class Client {
public:
Client(int, sockaddr_in, config::Config *);
virtual ~Client(void);
void answer(void);
private:
void _getRequest(std::string);
int _fd;
struct sockaddr_in _client_addr;
http::IRequest *_request;
//http::Response *_response;
config::Server *_conf;
};
} // namespace server
} // namespace webserv

View File

@ -0,0 +1,92 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Server.hpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: adjoly <adjoly@student.42angouleme.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/04/11 17:45:43 by adjoly #+# #+# */
/* Updated: 2025/04/22 11:51:27 by mmoussou ### ########.fr */
/* */
/* ************************************************************************** */
#pragma once
#include <log.hpp>
#include <config/default.hpp>
#include <fcntl.h>
#include <netinet/in.h>
#include <stdexcept>
#include <sys/poll.h>
#include <vector>
namespace webserv {
struct client_data {
sockaddr_in sock_data;
pollfd poll_fd;
};
class Server {
public:
Server(config::Config *);
~Server(void);
protected:
private:
/**
* @brief Used to setup the webserver (primarly socket)
*/
void _setup(void);
/**
* @brief Used to run the webserver
*/
void _run(void);
/**
* @brief Used to handle client request
*
* @param The fd of the client
*/
bool _handle_client(struct pollfd &, sockaddr_in *);
/**
* @brief Can be used to fill the vector passed as parameters with all the
* port and host in the config
* @param The vector of host
* @param The vector of port
*/
int _fillHostsPorts(std::vector<std::string> &, std::vector<int> &);
/**
* @brief Can be used to open a socket with a specific port and host
* @param The host
* @param The port
*/
int _createSocket(std::string, int);
/**
* @brief Can be used to check if an fd is one of the socket or not
*
* @param the fd to check
*/
bool _isServerSocket(int fd) {
for (std::vector<int>::iterator it = _fds_server.begin();
it != _fds_server.end(); it++) {
if (fd == *it) {
return true;
}
}
return false;
}
config::Config
*_conf; // Pointer to the configuration class (with all config in)
Logger *_log; // Pointer to the log class
std::vector<int> _fds_server; // The fds of the sockets
std::vector<struct pollfd> _client_fds; // A vector of all the poll fd
std::vector<sockaddr_in *>
_client_data; // vector of all the client sockaddr_in
};
}; // namespace webserv

View File

@ -6,20 +6,19 @@
/* By: mmoussou <mmoussou@student.42angouleme.fr +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/02/11 13:29:05 by mmoussou #+# #+# */
/* Updated: 2025/02/12 00:14:11 by mmoussou ### ########.fr */
/* Updated: 2025/04/22 12:04:53 by mmoussou ### ########.fr */
/* */
/* ************************************************************************** */
#pragma once
#ifndef __WEBSERV_SERVER_DEFAULT_HPP__
# define __WEBSERV_SERVER_DEFAULT_HPP__
#include <server/Server.hpp>
#include <server/Client.hpp>
namespace webserv {
namespace server {
} // -namespace server
} // -namespace webserv
using namespace webserv;
#endif // __WEBSERV_SERVER_DEFAULT_HPP__

View File

@ -6,26 +6,40 @@
/* By: mmoussou <mmoussou@student.42angouleme.fr +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/02/11 13:29:21 by mmoussou #+# #+# */
/* Updated: 2025/04/10 13:58:56 by adjoly ### ########.fr */
/* Updated: 2025/04/22 14:27:31 by adjoly ### ########.fr */
/* */
/* ************************************************************************** */
#pragma once
#ifndef __WEBSERV_WEBSERV_HPP__
# define __WEBSERV_WEBSERV_HPP__
#include <string>
#include <cstring>
#include <fstream>
#define auto __auto_type
#include <sys/types.h>
#include <csignal>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string>
#include <sys/socket.h>
#include <unistd.h>
#include <vector>
#include <sstream>
#define range(x) \
x.begin(); \
it != x.end(); \
it++
#define prange(x) \
x->begin(); \
it != x->end(); \
it++
#define BUFFER_SIZE 4096
namespace webserv {
} //-namespace webserv
} // namespace webserv
#endif // __WEBSERV_WEBSERV_HPP__

9
sample.conf Normal file
View File

@ -0,0 +1,9 @@
[server]
host = "localhost"
port = 8080
[server.location./]
methods = { "GET" }
root = "/var/www/html"
dirlist = true
client_max_body_size = "10M"

60
src/config/Config.cpp Normal file
View File

@ -0,0 +1,60 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Config.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: adjoly <adjoly@student.42angouleme.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/04/14 12:53:54 by adjoly #+# #+# */
/* Updated: 2025/04/22 15:35:52 by adjoly ### ########.fr */
/* */
/* ************************************************************************** */
#include "node/default.hpp"
#include "webserv.hpp"
#include "cppeleven.hpp"
#include "node/ANode.hpp"
#include <config/default.hpp>
using namespace webserv::config;
Config::Config(std::string &filename) {
toml::Toml *file = new toml::Toml(filename);
file->parse();
toml::ANode *table = file->getParsedFile();
bool found = false;
void *logFile = table->access("log_file", toml::STRING, found);
if (found == true && logFile != not_nullptr) {
_log = new Logger(*static_cast<std::string *>(logFile));
} else {
_log = new Logger();
}
std::map<std::string, toml::ANode *> *node = table->getTable();
for (auto it = prange(node)) {
if (it->second->type() == toml::TABLE) {
_log->info("taking server from table : " + it->first);
Server *srv = new Server(it->second);
_servers.push_back(srv);
}
}
delete table;
delete file;
}
Config::~Config(void) {
for (auto it = range(_servers)) {
delete *it;
}
}
Server *Config::getServer(const std::string &server_name) {
for (auto it = range(_servers)) {
if ((*it)->isServerName(server_name)) {
return (*it);
}
}
return (not_nullptr);
}

View File

@ -9,12 +9,13 @@
/* ************************************************************************** */
#include "cppeleven.hpp"
#include "log.hpp"
#include <log.hpp>
#include "node/default.hpp"
#include <config/default.hpp>
#include <map>
#include <string>
using namespace webserv::config;
std::map<std::string, std::string> *Route::_parseCGI(toml::ANode *table) {
@ -57,12 +58,11 @@ void Route::_parseMethods(std::vector<toml::ANode *> *table) {
}
}
Route::Route(toml::ANode *table, Logger *logger)
: _max_body(10485760), _log(logger) {
Route::Route(toml::ANode *table)
: _max_body(10485760) {
void *val;
bool found;
_log = logger;
_table = table;
if (_table->type() != toml::TABLE) {
_log->warn("location need to be a table and not a :" +

View File

@ -6,71 +6,37 @@
/* By: adjoly <adjoly@student.42angouleme.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/03/24 15:10:07 by adjoly #+# #+# */
/* Updated: 2025/03/26 08:47:50 by adjoly ### ########.fr */
/* Updated: 2025/04/22 15:36:30 by adjoly ### ########.fr */
/* */
/* ************************************************************************** */
#include "config/Server.hpp"
#include "config/Route.hpp"
#include "cppeleven.hpp"
#include "log.hpp"
#include "node/ANode.hpp"
#include "node/Table.hpp"
#include "node/default.hpp"
#include "tomlpp.hpp"
#include <config/default.hpp>
#include <stdexcept>
#include <string>
#include <sys/types.h>
#include <webserv.hpp>
using namespace webserv::config;
toml::ANode *Server::_getServerTable(void) {
toml::ANode *serverT;
std::map<std::string, toml::ANode *>::iterator table =
_table->getTable()->find("server");
if (table == _table->getTable()->end())
throw std::runtime_error(
"could not find any [server] table in config file :(");
else
serverT = table->second;
return serverT;
}
Server::Server(std::string file_name) {
toml::Toml *tomlFile = new toml::Toml(file_name);
try {
tomlFile->parse();
} catch (std::runtime_error &e) {
throw e;
}
Server::Server(toml::ANode *node) : _table(node) {
bool found;
std::map<std::string, toml::ANode *> *map;
_table = tomlFile->getParsedFile();
if (_table == not_nullptr)
return;
void *val = _table->access("log_file", toml::STRING, found);
std::string log_file = "";
if (found == true && val != not_nullptr) {
std::string log_file = *static_cast<std::string *>(val);
}
_log = new Logger(log_file);
_table = _getServerTable();
// host and port parsing
// host parsing
void *host = accessValue("host", toml::STRING, _table, _log);
if (host != not_nullptr) {
_host = *static_cast<std::string *>(host);
} else {
delete _table;
throw std::runtime_error(
"no host specified - please specify one in server.host");
}
// port parsing
void *port = accessValue("port", toml::INT, _table, _log);
if (host != not_nullptr) {
if (port != not_nullptr) {
_port = *static_cast<unsigned short *>(port);
} else {
delete _table;
throw std::runtime_error(
"no port specified - please specify one in server.port");
}
@ -86,12 +52,15 @@ Server::Server(std::string file_name) {
std::string str = *static_cast<std::string *>((*vecIt)->getValue());
_server_names->push_back(str);
}
} else
} else {
_log->warn(
"no server_names all request will be accepted from any hostname");
_server_names = not_nullptr;
}
// error_pages parsing
map = static_cast<std::map<std::string, toml::ANode *> *>(
std::map<std::string, toml::ANode *> *map =
static_cast<std::map<std::string, toml::ANode *> *>(
accessValue("error_pages", toml::TABLE, _table, _log));
if (map != not_nullptr) {
_err_pages = _parseErrPages(map);
@ -101,27 +70,26 @@ Server::Server(std::string file_name) {
// location parsing
it = _table->accessIt("location", toml::TABLE, found);
if (found == true && it != _table->getTable()->end()) {
_routes = new std::map<std::string, Route *>;
std::map<std::string, toml::ANode *> *location_table = it->second->getTable();
_routes = new std::map<URL, Route *>;
std::map<std::string, toml::ANode *> *location_table =
it->second->getTable();
for (it = location_table->begin(); it != location_table->end(); it++) {
if (_routes->find(it->first) != _routes->end())
if (_routes->find(URL(it->first)) != _routes->end())
continue;
(*_routes)[it->first] = new Route(it->second, _log);
(*_routes)[URL(it->first)] = new Route(it->second);
}
}
delete tomlFile->getParsedFile();
delete tomlFile;
//delete _table;
}
Server::~Server(void) {
std::map<std::string, Route *>::iterator it = _routes->begin();
for (; it != _routes->end(); it++) {
for (auto it = prange(_routes)) {
delete it->second;
}
delete _routes;
delete _err_pages;
if (_server_names != not_nullptr)
delete _server_names;
delete _log; // to see if nessecary
}
std::map<int, std::string> *
@ -143,3 +111,21 @@ Server::_parseErrPages(std::map<std::string, toml::ANode *> *table) {
}
return errPages;
}
bool Server::isServerName(const std::string &server_name) {
for (auto it = prange(_server_names)) {
if (*it == server_name) {
return true;
}
}
return false;
}
Route *Server::whatRoute(const URL &url) {
for (auto it = prange(_routes)) {
if (it->first == url) {
return it->second;
}
}
return not_nullptr;
}

View File

@ -6,11 +6,11 @@
/* By: adjoly <adjoly@student.42angouleme.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/04/10 13:08:36 by adjoly #+# #+# */
/* Updated: 2025/04/10 14:20:36 by adjoly ### ########.fr */
/* Updated: 2025/04/22 11:47:39 by mmoussou ### ########.fr */
/* */
/* ************************************************************************** */
#include "log.hpp"
#include <log.hpp>
#include <fstream>
#include <help.hpp>
#include <sys/stat.h>
@ -37,7 +37,7 @@ void _generateConf(void) {
file << "[server]\nhost = \"localhost\"\nport = "
"8080\n\n[server.location./]\nmethods = { \"GET\" }\nroot "
"= \"/var/www/html\"\ndirlist = true\nclient_max_body_size "
"= \"10M\"";
"= \"10M\"\n";
file.close();
_log.info("config file successfully generated");
} else {
@ -50,16 +50,24 @@ void _printVersion(void) {
std::cout << "You are running : Webserv " << WEBSRV_VERSION << std::endl;
}
void help(int ac, char **av) {
bool help(int ac, char **av) {
if (ac < 2) {
_printHelp();
return;
return true;
}
std::string option = av[1];
if (option == "--help" || option == "-v")
if (option == "--help" || option == "-v") {
_printHelp();
else if (option == "--generate" || option == "-g")
return true;
}
else if (option == "--generate" || option == "-g") {
_generateConf();
else if (option == "--version" || option == "-v")
return true;
}
else if (option == "--version" || option == "-v") {
_printVersion();
return true;
}
else
return false;
}

View File

@ -6,134 +6,65 @@
/* By: mmoussou <mmoussou@student.42angouleme.fr +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/02/03 15:45:07 by mmoussou #+# #+# */
/* Updated: 2025/04/10 12:18:39 by mmoussou ### ########.fr */
/* Updated: 2025/03/25 17:10:29 by adjoly ### ########.fr */
/* Updated: 2025/04/22 15:43:21 by adjoly ### ########.fr */
/* */
/* ************************************************************************** */
#include <config/Server.hpp>
#include <tomlpp.hpp>
#include <webserv.hpp>
#include <config/default.hpp>
#include <csignal>
#include <server/default.hpp>
#include <config/Config.hpp>
#include <cstdlib>
#include <exception>
#include <help.hpp>
#include <requests/default.hpp>
#include <sstream>
#include <tomlpp.hpp>
#include <unistd.h>
#include <log.hpp>
#include <webserv.hpp>
#define PORT 8080
#define BUFFER_SIZE 4096
int server_socket;
int client_socket;
void close_socket(int signal)
{
std::cerr << std::endl << "closing..." << std::endl;
close(client_socket);
close(server_socket);
exit(signal);
namespace webserv {
Logger *_log = not_nullptr;
}
std::string getMethod(std::string &data)
{
return (data.substr(0, data.substr(0, 4).find_last_not_of(" ") + 1));
int _sig = 0;
void ft_sig(int sig) {
_sig = sig;
std::stringstream str;
str << "sig hitted = ";
str << sig;
_log->info(str.str());
}
int main()
{
// handle ctrl-C to close server socket
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR || signal(SIGINT, close_socket) == SIG_ERR || signal(SIGQUIT, close_socket) == SIG_ERR)
{
std::cerr << "Error registering signal handlers!" << std::endl;
int main(int ac, char **av) {
if (help(ac, av)) {
return EXIT_SUCCESS;
}
std::cout << "Starting server..." << std::endl;
if (access(av[1], F_OK) < 0) {
std::cout << "File : " << av[1] << " could not be opened" << std::endl;
return EXIT_FAILURE;
}
config::Config *conf;
try {
std::string str = av[1];
conf = new config::Config(str);
} catch (std::exception &e) {
std::cout << e.what() << std::endl;
return 1;
}
// create a socket
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket == -1)
{
std::cerr << "Failed to create socket" << std::endl;
return 1;
if (signal(SIGINT, &ft_sig) == SIG_ERR) {
conf->getLogger()->error("could not bind sigint :(");
return EXIT_FAILURE;
}
// prepare the server address
sockaddr_in server_address;
std::memset(&server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = INADDR_ANY;
server_address.sin_port = htons(PORT);
webserv::Server *serv = new webserv::Server(conf);
if (bind(server_socket, (sockaddr*)&server_address, sizeof(server_address)) == -1)
{
std::cerr << "Failed to bind socket" << std::endl;
return 1;
}
if (listen(server_socket, 5) == -1)
{
std::cerr << "Failed to listen on socket" << std::endl;
return 1;
}
std::cout << "Server is listening on port " << PORT << std::endl;
while (true)
{
// accept an incoming connection
sockaddr_in client_address;
socklen_t client_address_len = sizeof(client_address);
//int client_socket = accept(server_socket, (sockaddr*)&client_address, &client_address_len);
client_socket = accept(server_socket, (sockaddr*)&client_address, &client_address_len);
if (client_socket == -1) {
std::cerr << "Failed to accept connection" << std::endl;
continue;
}
// receive the HTTP request
std::string received_data;
char buffer[BUFFER_SIZE];
ssize_t bytes_received;
do
{
std::memset(buffer, 0, BUFFER_SIZE);
bytes_received = recv(client_socket, buffer, BUFFER_SIZE - 1, 0);
if (bytes_received == -1)
{
std::cerr << "Failed to receive request" << std::endl;
close(client_socket);
continue;
}
received_data += std::string(buffer, bytes_received);
}
while (buffer[bytes_received]);
// parse the request
// handle the request
std::string response;
//std::cout << received_data << std::endl;
std::cout << getMethod(received_data) << std::endl;
if (getMethod(received_data) == "GET")
{
std::cout << "------------ GET REQUEST ------------" << std::endl;
http::Get request(received_data);
response = request.execute().str();
}
else if (getMethod(received_data) == "POST")
{
std::cout << "------------ POST REQUEST ------------" << std::endl;
http::Post request(received_data);
response = request.execute().str();
//std::cout << "worked" << std::endl;
}
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(client_socket, response.c_str(), response.length(), 0);
//close(client_socket);
}
close(server_socket);
return 0;
delete serv;
delete _log;
delete conf;
}

View File

@ -6,7 +6,7 @@
/* By: mmoussou <mmoussou@student.42angouleme.fr +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/02/03 16:07:01 by mmoussou #+# #+# */
/* Updated: 2025/04/10 11:50:48 by mmoussou ### ########.fr */
/* Updated: 2025/04/22 15:03:46 by adjoly ### ########.fr */
/* */
/* ************************************************************************** */
@ -20,6 +20,10 @@
using namespace webserv;
http::IRequest::~IRequest(void) {
}
std::string http::IRequest::str(void) const
{
std::ostringstream response;
@ -75,6 +79,10 @@ http::Get::Get(void)
{
}
http::Get::~Get(void)
{
}
http::Get::Get(std::string &data)
{
this->parse(data);
@ -218,6 +226,10 @@ http::Delete::Delete(void)
{
}
http::Delete::~Delete(void)
{
}
http::Delete::Delete(std::string &data)
{
this->parse(data);
@ -297,6 +309,10 @@ http::Post::Post(void)
{
}
http::Post::~Post(void)
{
}
http::Post::Post(std::string &data)
{
this->parse(data);

View File

@ -6,7 +6,7 @@
/* By: mmoussou <mmoussou@student.42angouleme.fr +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/02/03 17:28:31 by mmoussou #+# #+# */
/* Updated: 2025/04/08 01:11:40 by mmoussou ### ########.fr */
/* Updated: 2025/04/23 14:30:28 by mmoussou ### ########.fr */
/* */
/* ************************************************************************** */
@ -27,6 +27,10 @@ http::Response::Response(void)
{
}
http::Response::~Response(void)
{
}
std::string http::Response::str(void) const
{
std::ostringstream response;

76
src/server/Client.cpp Normal file
View File

@ -0,0 +1,76 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Client.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: mmoussou <mmoussou@student.42angouleme.fr +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/04/17 11:12:41 by mmoussou #+# #+# */
/* Updated: 2025/04/23 14:40:06 by mmoussou ### ########.fr */
/* */
/* ************************************************************************** */
#include <log.hpp>
#include <server/Client.hpp>
using namespace server;
Client::Client(int fd, sockaddr_in socket, config::Config *conf)
: _fd(fd), _client_addr(socket) {
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");
throw std::runtime_error("failed to receive request");
}
received_data += std::string(buffer, bytes_received);
} while (buffer[bytes_received]);
this->_getRequest(received_data);
this->_conf = conf->getServer(this->_request->getHeaders()["Host"]);
// if (received_data.length > (get max_body_size from Route corresponding) )
// throw error
}
void Client::_getRequest(std::string request_str) {
std::string method = request_str.substr(
0, request_str.substr(0, 4).find_last_not_of(" ") + 1);
if (method == "GET") {
_log->info("get request received");
this->_request = new http::Get(request_str);
} else if (method == "DELETE") {
_log->info("delete request received");
this->_request = new http::Delete(request_str);
} else if (method == "POST") {
_log->info("post request received");
this->_request = new http::Post(request_str);
} else {
_log->info("unsupported request received");
this->_request = new http::Get();
this->_request->setMethod("501");
}
}
void Client::answer(void) {
(void) _client_addr;
std::string response;
if (this->_request->getMethod() == "GET" ||
this->_request->getMethod() == "DELETE" ||
this->_request->getMethod() == "POST")
response = this->_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(this->_fd, response.c_str(), response.length(), 0);
}
Client::~Client(void) {
delete (http::Get *)(this->_request);
}

166
src/server/Server.cpp Normal file
View File

@ -0,0 +1,166 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Server.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: adjoly <adjoly@student.42angouleme.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/04/11 16:11:40 by adjoly #+# #+# */
/* Updated: 2025/04/23 16:22:22 by adjoly ### ########.fr */
/* */
/* ************************************************************************** */
#include <cerrno>
#include <cmath>
#include <cstring>
#include <exception>
#include <fcntl.h>
#include <iterator>
#include <log.hpp>
#include <netinet/in.h>
#include <poll.h>
#include <requests/default.hpp>
#include <server/default.hpp>
#include <sstream>
#include <stdexcept>
#include <string>
#include <sys/poll.h>
#include <sys/socket.h>
#include <webserv.hpp>
using namespace webserv;
extern int _sig;
std::string convertIPToString(const struct in_addr *addr) {
unsigned int ip = ntohl(addr->s_addr);
std::stringstream ss;
ss << ((ip >> 24) & 0xFF) << "." << ((ip >> 16) & 0xFF) << "."
<< ((ip >> 8) & 0xFF) << "." << (ip & 0xFF);
return ss.str();
}
std::string convertPortToString(const struct sockaddr_in *sa) {
int port = ntohs(sa->sin_port);
std::stringstream ss;
ss << port;
return ss.str();
}
std::string getMethod(std::string &data) {
return (data.substr(0, data.substr(0, 4).find_last_not_of(" ") + 1));
}
int Server::_fillHostsPorts(std::vector<std::string> &hosts,
std::vector<int> &ports) {
std::vector<config::Server *> config = _conf->getServers();
for (auto it = range(config)) {
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");
auto itH = hosts.begin();
for (auto it = range(ports), itH++) {
int fd = _createSocket(*itH, *it);
_fds_server.push_back(fd);
}
}
short sigHandling(void) {
if (_sig == SIGINT) {
return 727;
}
return 0;
}
void Server::_run(void) {
struct pollfd fd;
for (std::vector<int>::iterator it = _fds_server.begin();
it != _fds_server.end(); it++) {
fd.fd = *it;
fd.events = POLLIN;
_client_fds.push_back(fd);
_client_data.push_back(NULL);
_log->debug("new socket in poll");
}
// to add signal instead of 727
while (727 - sigHandling()) {
if (poll(_client_fds.data(), _client_fds.size(), -1) < 0) {
std::stringstream str;
str << "poll failed : ";
str << strerror(errno);
_log->error(str.str());
continue;
}
for (auto it = range(_fds_server)) {
struct sockaddr_in client_addr;
socklen_t addrlen = sizeof(client_addr);
int client_fd =
accept((*it), (struct sockaddr *)&client_addr, &addrlen);
if (client_fd < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK)
continue;
std::stringstream str;
str << "Accept failed: ";
str << strerror(errno);
_log->error(str.str());
continue;
}
pollfd pfd;
pfd.fd = client_fd;
pfd.events = POLLIN | POLLOUT;
pfd.revents = 0;
_client_fds.push_back(pfd);
struct sockaddr_in *new_client_sock = new sockaddr_in();
std::memmove(new_client_sock, &client_addr,
sizeof(struct sockaddr_in));
_client_data.push_back(new_client_sock);
}
for (size_t i = _fds_server.size(); i < _client_fds.size(); ++i) {
if (_client_fds[i].revents & POLLIN) {
if (_handle_client(_client_fds[i], _client_data[i])) {
close(_client_fds[i].fd);
_client_fds.erase(_client_fds.begin() + i);
delete _client_data[i];
_client_data.erase(_client_data.begin() + i);
i--;
}
}
}
}
}
Server::Server(config::Config *conf) : _conf(conf) {
log("", "Server::Server", "config constructor called");
_log = conf->getLogger();
try {
_setup();
_run();
} catch (std::exception &e) {
_log->error(e.what());
}
}
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);
}

View File

@ -0,0 +1,93 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* ServerUtils.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: adjoly <adjoly@student.42angouleme.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/04/17 11:58:42 by adjoly #+# #+# */
/* Updated: 2025/04/23 16:00:14 by adjoly ### ########.fr */
/* */
/* ************************************************************************** */
#include <server/Client.hpp>
#include <netinet/in.h>
#include <server/default.hpp>
#include <sstream>
#include <stdexcept>
#include <string>
#include <sys/socket.h>
using namespace webserv::server;
bool convertStringToIP(const char *ip_str, struct in_addr *addr) {
// Split the IP string into four octets
unsigned int a, b, c, d;
if (sscanf(ip_str, "%u.%u.%u.%u", &a, &b, &c, &d) != 4) {
return false;
}
// Check if each octet is within the valid range
if (a > 255 || b > 255 || c > 255 || d > 255) {
return false;
}
// Combine the octets into a single 32-bit address
addr->s_addr = htonl((a << 24) | (b << 16) | (c << 8) | d);
return true;
}
int Server::_createSocket(std::string host, int port) {
int fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
if (fd == -1) {
std::ostringstream str;
str << port;
throw std::runtime_error("socket binding failed for : " + host + ":" +
str.str());
return -1;
}
int opt = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
close(fd);
throw std::runtime_error("setsockopt failed");
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
if (!convertStringToIP(host.c_str(), &addr.sin_addr)) {
throw std::runtime_error("ip is not of the valid format : " + host);
}
std::stringstream str;
str << port;
_log->debug("port : " + str.str());
addr.sin_port = htons(port);
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
close(fd);
std::ostringstream str;
str << port;
throw std::runtime_error("bind failed for : " + host + ":" + str.str());
}
if (listen(fd, SOMAXCONN) < 0) {
close(fd);
std::ostringstream str;
str << port;
throw std::runtime_error("listen failed for : " + host + ":" + str.str());
}
return (fd);
}
bool Server::_handle_client(struct pollfd &pollfd, sockaddr_in *sock_data) {
try {
Client client(pollfd.fd, *sock_data, _conf);
client.answer();
} catch (std::runtime_error &e) {
_log->error(e.what());
return false;
}
return true;
}

View File

@ -1,90 +0,0 @@
<meta charset="utf-8">
<html>
<head>
<title>upload</title>
</head>
<body>
<!-- j'ai pas volé le code (c'est faux) -->
<!-- putain les pubs spotify c'est chiant -->
<!-- je m'en fous de leur bière -->
<form id="upload_form" enctype="multipart/form-data" method="post">
<input type="file" name="file1" id="file1" onchange="uploadFile()"><br>
<progress id="progressBar" value="0" max="100" style="width:300px;"></progress>
<h3 id="status"></h3>
<p id="loaded_n_total"></p>
</form>
<button id="abort" hidden>annuler le tranfert</button>
<script>
function _(el) {
return document.getElementById(el);
}
function uploadFile() {
bouton = document.getElementById("abort")
var file = _("file1").files[0];
// alert(file.name+" | "+file.size+" | "+file.type);
var formdata = new FormData();
formdata.append("file1", file);
var ajax = new XMLHttpRequest();
bouton.onclick = function(){
ajax.abort()
}
bouton.removeAttribute("hidden")
ajax.upload.addEventListener("progress", progressHandler, false);
ajax.addEventListener("load", completeHandler, false);
ajax.addEventListener("error", errorHandler, false);
ajax.addEventListener("abort", abortHandler, false);
ajax.open("POST", "/upload.html");
ajax.send(formdata);
startmillis = Date.now()
}
function copy(){
window.getSelection().removeAllRanges()
range = document.createRange()
range.selectNodeContents(_("addr"))
window.getSelection().addRange(range)
document.execCommand('copy')
window.getSelection().removeAllRanges()
temp = _("addr").innerHTML
_("addr").innerHTML = "copié !"
setTimeout(()=>{_("addr").innerHTML = temp},500)
}
function progressHandler(event) {
// console.log(Math.round((event.loaded/1024/1024)*100)/100)
// console.log((Date.now()-startmillis)/1000+'s')
//console.log((event.loaded/1024/1024) /((Date.now()-startmillis)*1000)+"Mo/s")
// console.log((event.loaded/1024/1024))
console.log(`${(event.loaded/1024/1024)} / ${(Date.now()-startmillis)} / 1000`)
console.log((event.loaded/1024/1024)/((Date.now()-startmillis)/1000))
_("loaded_n_total").innerHTML = Math.round((event.loaded/1024/1024)*100)/100 + "Mo / " + Math.round((event.total/1024/1024)*100)/100+"Mo envoyé<br/>"+Math.round((event.loaded/1024/1024)/((Date.now()-startmillis)/1000)*100)/100+"Mo/s en moyenne";
var percent = (event.loaded / event.total) * 100;
_("progressBar").value = Math.round(percent);
_("status").innerHTML = Math.round(percent * 100) / 100 + "% envoyé... veuillez patienter";
}
function completeHandler(event) {
_("status").innerHTML = event.target.responseText;
_("progressBar").value = 0; //wil clear progress bar after successful upload
console.log("fin de l'envoi")
_("abort").setAttribute("hidden",true)
}
function errorHandler(event) {
_("status").innerHTML = "Upload Failed";
}
function abortHandler(event) {
_("status").innerHTML = "envoi annulé";
}
</script>
</body>
</html>