Browse Source

save 22-11-13-4

master
nicolas-arnaud 2 years ago
parent
commit
66beaba729
  1. 7
      includes/Route.hpp
  2. 1
      srcs/load/Env.cpp
  3. 57
      srcs/load/Route.cpp
  4. 49
      srcs/load/Server.cpp
  5. 78
      srcs/sock/Client.cpp
  6. 70
      srcs/sock/Master.cpp
  7. 61
      srcs/tools.cpp
  8. 7
      srcs/webserv.cpp

7
includes/Route.hpp

@ -4,14 +4,11 @@
class Route {
protected:
Server *_server;
string _location;
string _root;
string _ret;
string _location, _root, _ret;
bool _autoindex;
public:
vec_string _indexs;
vec_string _allowed_methods;
vec_string _indexs, _allowed_methods;
std::map< string, string > _cgi;
int _client_max_body_size;

1
srcs/load/Env.cpp

@ -25,7 +25,6 @@ Env::~Env() {
*/
Env::Env(JSONNode *conf) {
try {
JSONList servers = conf->obj()["servers"]->lst();
for (std::vector< JSONNode * >::iterator it = servers.begin();
it < servers.end(); it++) {

57
srcs/load/Route.cpp

@ -51,15 +51,17 @@ string Route::getLocation(void) { return _location; }
string Route::getRoot(void) { return _root; }
string Route::getReturn(void) { return _ret; }
/* |==========|
* Find either an autoindex or an index into the directory required by request
* Generate the autoindex of folder.
* If while generating it an index file is found, it return the opened file.
* Else it finish generating autoindex and return it finally if autoindex is
* enable on this route.
*
* Input: The uri client asked, the real local path to the directory
* Output: The file or the autoindex page to display
* Input: The uri client asked and the real local path to the directory
* Output: The index or the autoindex page to display
*/
string Route::getIndex(string uri, string path) {
std::stringstream content;
std::stringstream ret;
std::stringstream body, ret;
DIR *dir;
struct dirent *entry;
struct stat info;
@ -68,8 +70,8 @@ string Route::getIndex(string uri, string path) {
if ((dir = opendir(path.c_str())) == NULL) {
return "";
} else {
cout << "get index(): path=" << path << "\n";
content << "<h3 style=\"text-align: center;\">" << path
// cout << "get index(): path=" << path << "\n";
body << "<h3 style=\"text-align: center;\">" << path
<< " files :</h3>\n<ul>\n";
while ((entry = readdir(dir)) != NULL) {
if (entry->d_name[0] == '.')
@ -78,21 +80,21 @@ string Route::getIndex(string uri, string path) {
if (entry->d_name == *it)
return (read_file(path + "/" + *it));
}
content << "<li><a href=\"" << uri + "/" + entry->d_name << "\">"
body << "<li><a href=\"" << uri + "/" + entry->d_name << "\">"
<< entry->d_name << "</a></li>\n";
if (stat(path.c_str(), &info) != 0)
std::cerr << "stat() error on " << path << ": "
<< strerror(errno) << "\n";
}
content << "</ul>";
body << "</ul>";
closedir(dir);
}
if (!_autoindex)
return "";
cout << "Getting autoindex\n";
// cout << "Getting autoindex\n";
ret << "Content-type: text/html \r\n";
ret << "Content-length: " << content.str().length() << "\r\n";
ret << "\r\n" << content.str();
ret << "Content-length: " << body.str().length() << "\r\n";
ret << "\r\n" << body.str();
return ret.str();
}
/* |==========|
@ -104,24 +106,21 @@ string Route::getIndex(string uri, string path) {
string Route::correctUri(string uri) {
std::stringstream ret;
vec_string::iterator it;
vec_string::iterator it2;
ret << "./" << _root;
vec_string loc_split = split(_location, "/");
vec_string uri_split = split(uri, "/");
it2 = uri_split.begin();
for (it = loc_split.begin(); it < loc_split.end(); it++) {
while (it2 < uri_split.end() && *it2 == "")
it2++;
while (it < loc_split.end() && *it == "")
it++;
if (it != loc_split.end())
it2++;
}
vec_string::iterator loc_word, uri_word;
while (it2 < uri_split.end()) {
ret << "/" << *(it2++);
vec_string loc_words = split(_location, "/");
vec_string uri_words = split(uri, "/");
uri_word = uri_words.begin();
for (loc_word = loc_words.begin(); loc_word < loc_words.end(); loc_word++) {
while (uri_word < uri_words.end() && *uri_word == "")
uri_word++;
while (loc_word < loc_words.end() && *loc_word == "")
loc_word++;
if (loc_word != loc_words.end())
uri_word++;
}
ret << "./" << _root;
while (uri_word < uri_words.end())
ret << "/" << *(uri_word++);
return ret.str();
}

49
srcs/load/Server.cpp

@ -33,7 +33,6 @@ Server::Server(JSONNode *server) : Route(NULL, "/", server) {
}
}
}
/* Get the server name (_server_name)*/
string Server::getName(void) { return _name; }
@ -46,31 +45,31 @@ string Server::getName(void) { return _name; }
Master *Server::create_master(string str) {
ip_port_t listen = get_ip_port_t(str);
if (listen.ip.at(0) == '[') {
cout << "Listen: IPv6 isn't supported\n";
}
if (listen.ip.at(0) != '[') {
try {
_listens.push_back(listen);
Master *sock = new Master(listen);
return (sock);
} catch (std::exception &e) {
std::cerr << e.what() << '\n';
return NULL;
}
} else
cout << "Listen: IPv6 isn't supported\n";
return NULL;
}
/*|===========|
* Create server's defined sockets:
*
* Input: A server block node from JSONParser.
* Output: A vector containing all the succesfull created sockets using listens
* from the server block.
* Output: A vector containing all the succesfull created sockets using
* listens from the server block.
*/
std::vector< Master * > Server::get_sockets(JSONNode *server) {
JSONObject datas = server->obj();
std::vector< Master * > ret;
ip_port_t listen;
Master *tmp;
ip_port_t listen;
if (datas["listens"]) {
JSONList listens = datas["listens"]->lst();
for (JSONList::iterator it = listens.begin(); it != listens.end();
@ -86,27 +85,27 @@ std::vector< Master * > Server::get_sockets(JSONNode *server) {
* Choose the route an uri asked to the server must lead to.
*
* Intput: The uri asked by the client to the server.
* Output: The route object choosen or the server itself if no location block is
* adapted.
* Output: The route object choosen or the server itself if no location
* block is adapted.
*/
Route *Server::choose_route(string uri) {
vec_string req = split(uri, "/");
vec_string root;
for (std::map< string, Route * >::iterator rit = _routes.begin();
rit != _routes.end(); rit++) {
root = split((*rit).first, "/");
cout << "Route: " << (*rit).first << "\n";
vec_string::iterator root_it = root.begin();
for (vec_string::iterator it = req.begin(); it < req.end(); it++) {
while (it != req.end() && *it == "")
it++;
if (*it != *(root_it++))
vec_string uri_words, loc_words;
uri_words = split(uri, "/");
for (std::map< string, Route * >::iterator loc_it = _routes.begin();
loc_it != _routes.end(); loc_it++) {
loc_words = split((*loc_it).first, "/");
vec_string::iterator loc_word = loc_words.begin();
for (vec_string::iterator uri_word = uri_words.begin();
uri_word < uri_words.end(); uri_word++) {
while (uri_word != uri_words.end() && *uri_word == "")
uri_word++;
if (*uri_word != *(loc_word++))
break;
while (root_it != root.end() && *root_it == "")
root_it++;
if (root_it == root.end())
return ((*rit).second);
while (loc_word != loc_words.end() && *loc_word == "")
loc_word++;
if (loc_word == loc_words.end())
return ((*loc_it).second);
}
}
return this;

78
srcs/sock/Client.cpp

@ -37,14 +37,10 @@ bool Client::getHeader(Env *env, string paquet) {
else
paquet.clear();
_header += *it + (it + 1 != lines.end() ? "\r\n" : "");
if (_header.find("\r\n\r\n") != string::npos) {
print_block("HEADER: ", _header);
if (!this->parseHeader(env))
return false;
if (paquet.length() > 0)
return getBody(paquet);
return true;
}
if (_header.find("\r\n\r\n") != string::npos)
return !this->parseHeader(env)
? false
: (paquet.length() > 0 ? getBody(paquet) : true);
}
return false;
}
@ -54,25 +50,19 @@ bool Client::getBody(string paquet) {
vec_string::iterator it;
for (it = lines.begin(); it < lines.end(); it++) {
// cout << "line: " << *it << "\n";
if ((*it).length() && _len <= 0 &&
header_pick("Transfer-Encoding:", 0) == "chunked") {
_len = std::strtol((*it).c_str(), 0, 16) + 2;
_last_chunk = _len == 2 ? true : false;
// +2 for the final \r\n closing chunk
} else if (_len > 0 || it != lines.begin()) {
_body += *it + "\r\n";
_len -= ((*it).length() + 2);
}
}
if (_body.size())
// if (_body.size())
_body.resize(_body.length() - 2);
_len += 2;
if (_last_chunk && _len == 0) {
print_block("BODY: ", _body);
return true;
}
return false;
return (_last_chunk && _len == 0) ? true : false;
}
bool Client::parseHeader(Env *env) {
@ -104,55 +94,46 @@ bool Client::parseHeader(Env *env) {
if (len != "") {
_len = std::atoi(len.c_str());
_last_chunk = true;
if (_len > _route->_client_max_body_size) {
send_error(413);
return false;
}
if (_len > _route->_client_max_body_size)
return (send_error(413), false);
}
return true;
}
bool Client::check_method(void) {
vec_string allowed;
if (_method != "GET" && _method != "POST" && _method != "DELETE" &&
if ((allowed = _route->_allowed_methods).size() > 0 ||
(allowed = _server->_allowed_methods).size() > 0)
return std::find(allowed.begin(), allowed.end(), _method) <
allowed.end()
? true
: false;
else if (_method == "GET" || _method == "POST" || _method != "DELETE" ||
_method != "PUT")
send_error(405);
else if ((allowed = _route->_allowed_methods).size() > 0) {
if (std::find(allowed.begin(), allowed.end(), _method) == allowed.end())
send_error(405);
else
return true;
} else if ((allowed = _server->_allowed_methods).size() > 0) {
if (std::find(allowed.begin(), allowed.end(), _method) == allowed.end())
send_error(405);
else
return true;
} else
return (true);
return (false);
}
string Client::header_pick(string key, size_t id) {
if (_request[key].size() <= id)
return "";
return _request[key].at(id);
return _request[key].size() <= id ? "" : _request[key].at(id);
}
void Client::answer(void) {
cout << "Method: " << _method << "\n";
cout << "URI: " << _uri << "\n";
cout << "Host: " << _host << "\n";
print_block("Header: ", _header);
print_block("Body: ", _body);
string ret;
string path = _route->correctUri(_uri);
string cgi =
_route->_cgi.size()
? _route->_cgi[get_extension(path)]
: (_server->_cgi.size() ? _server->_cgi[get_extension(path)] : "");
string cgi = _route->_cgi.size() ? _route->_cgi[get_extension(path)]
: _server->_cgi.size() ? _server->_cgi[get_extension(path)]
: "";
cout << "Path: " << path << "\n";
if (_method == "PUT")
create_file(path);
if (cgi == "") {
if (check_method()) {
if (cgi != "")
send_cgi(cgi, path);
else if (!check_method())
send_error(405);
else {
if ((ret = _route->getIndex(_uri, path)) == "")
ret = read_file(path);
if (ret == "404")
@ -162,8 +143,6 @@ void Client::answer(void) {
else
send_answer("HTTP/1.1 200 OK\r\n" + ret);
}
} else
send_cgi(cgi, path);
}
void Client::create_file(string path) {
@ -186,8 +165,7 @@ void Client::send_cgi(string cgi, string path) {
if (!std::ifstream(cgi.c_str()).good())
return send_error(404);
pipe(fd);
int pid = fork();
if (pid == 0) {
if (fork() == 0) {
const char **args = new const char *[cgi.length() + path.length() + 2];
args[0] = cgi.c_str();
args[1] = path.c_str();
@ -202,7 +180,7 @@ void Client::send_cgi(string cgi, string path) {
execve(cgi.c_str(), (char **)args, (char **)env);
}
close(fd[1]);
waitpid(pid, &status, 0);
waitpid(-1, &status, 0);
char buffer[10000];
buffer[read(fd[0], buffer, 10000)] = 0;
ret = string(buffer);

70
srcs/sock/Master.cpp

@ -16,34 +16,27 @@ Master::~Master(void) {
*/
Master::Master(ip_port_t list) : _listen(list) {
int opt = 1;
int x = 1, port = _listen.port;
string ip = _listen.ip;
int port = _listen.port;
_fd = socket(AF_INET, SOCK_STREAM, 0);
if (_fd == 0)
throw std::runtime_error("socket() error" + string(strerror(errno)));
int opt_ret =
setsockopt(_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt));
if (opt_ret < 0) {
close(_fd);
if (setsockopt(_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&x, sizeof(x)) < 0 &&
close(_fd) <= 0)
throw std::runtime_error("setsockopt() error: " +
string(strerror(errno)));
}
_address.sin_family = AF_INET;
_address.sin_addr.s_addr = inet_addr(ip.c_str());
_address.sin_port = htons(port);
if (bind(_fd, (struct sockaddr *)&_address, sizeof(_address)) < 0) {
close(_fd);
if (bind(_fd, (struct sockaddr *)&_address, sizeof(_address)) &&
close(_fd) <= 0)
throw std::runtime_error("bind() error: " + string(strerror(errno)));
}
if (listen(_fd, 3) < 0) {
close(_fd);
if (listen(_fd, 3) < 0 && close(_fd) <= 0)
throw std::runtime_error("listen() error: " + string(strerror(errno)));
}
cout << "New master socket with fd " << _fd << " which listen " << ip << ":"
<< port << "\n";
if (_fd < _min_fd)
@ -54,14 +47,12 @@ Master::Master(ip_port_t list) : _listen(list) {
void Master::set_fds(void) {
FD_SET(_fd, &_readfds);
int child_fd;
for (std::vector< Client * >::iterator it = _childs.begin();
it < _childs.end(); it++) {
child_fd = (*it)->_fd;
FD_SET(child_fd, &_readfds);
if (child_fd > _max_fd)
_max_fd = child_fd;
for (std::vector< Client * >::iterator child = _childs.begin();
child < _childs.end(); child++) {
FD_SET((*child)->_fd, &_readfds);
if ((*child)->_fd > _max_fd)
_max_fd = (*child)->_fd;
}
}
/* |==========|
@ -101,13 +92,10 @@ void Master::refresh(Env *env) {
(socklen_t *)&addrlen);
delete (*it);
_childs.erase(it);
} else {
// print_block("Paquet: ", buffer);
if ((*it)->getHeader(env, buffer))
} else if ((*it)->getHeader(env, buffer))
(*it)->answer();
}
}
}
}
/* |==========|
* Choose the server which must handle a request
@ -126,21 +114,19 @@ void Master::refresh(Env *env) {
*/
Server *Master::choose_server(Env *env, string host) {
std::vector< Server * > exact;
std::vector< Server * > inrange;
vec_string ip_listen;
vec_string ip_required;
std::vector< Server * > exact, inrange;
vec_string ip_listen, ip_required;
ip_required = split(_listen.ip, ".");
for (std::vector< Server * >::iterator sit = env->_servers.begin();
sit < env->_servers.end(); sit++) {
std::vector< ip_port_t > serv_listens = (*sit)->_listens;
for (std::vector< Server * >::iterator server = env->_servers.begin();
server < env->_servers.end(); server++) {
std::vector< ip_port_t > serv_listens = (*server)->_listens;
for (std::vector< ip_port_t >::iterator it = serv_listens.begin();
it < serv_listens.end(); it++) {
if (_listen.port != (*it).port)
continue;
if (_listen.ip == (*it).ip) {
exact.push_back(*sit);
exact.push_back(*server);
continue;
}
bool is_inrange = true;
@ -151,22 +137,22 @@ Server *Master::choose_server(Env *env, string host) {
if (*l != *r && *l != "0")
is_inrange = false;
}
if (is_inrange == true)
inrange.push_back(*sit);
if (is_inrange)
inrange.push_back(*server);
}
}
if (exact.size() == 0) {
for (std::vector< Server * >::iterator sit = inrange.begin();
sit < inrange.end(); sit++) {
if (host == (*sit)->getName())
return *sit;
for (std::vector< Server * >::iterator server = inrange.begin();
server < inrange.end(); server++) {
if (host == (*server)->getName())
return *server;
}
return inrange.front();
} else {
for (std::vector< Server * >::iterator sit = exact.begin();
sit < exact.end(); sit++) {
if (host == (*sit)->getName())
return *sit;
for (std::vector< Server * >::iterator server = exact.begin();
server < exact.end(); server++) {
if (host == (*server)->getName())
return *server;
}
return exact.front();
}

61
srcs/tools.cpp

@ -1,14 +1,12 @@
#include "webserv.hpp"
void *ft_memset(void *b, int c, size_t len) {
size_t i;
unsigned char *b_cpy;
b_cpy = (unsigned char *)b;
i = 0;
while (i < len)
*(unsigned char *)(b_cpy + i++) = (unsigned char)c;
return ((void *)b);
for (size_t i = 0; i < len; i++)
*(unsigned char *)(b_cpy + i) = (unsigned char)c;
return (b);
}
bool isInt(string str) {
@ -22,7 +20,7 @@ vec_string split(string str, string delim) {
string temp(str);
string token;
size_t pos;
std::vector< std::string > tokens;
vec_string tokens;
while ((pos = temp.find(delim)) != string::npos) {
token = temp.substr(0, pos);
@ -51,6 +49,33 @@ ip_port_t get_ip_port_t(string ip, int port) {
return ret;
}
string read_file(string path) {
struct stat info;
if (stat(path.c_str(), &info) != 0) {
std::cerr << "stat() error on " << path << ": " << strerror(errno)
<< "\n";
return "404";
} else if (S_ISDIR(info.st_mode))
return "404";
std::ifstream file(path.c_str());
if (!file.good())
return "404";
string str, body;
while (file) {
std::getline(file, str);
body += str + "\n";
}
std::stringstream ret;
ret << "Content-type: " << getMime(path) << "\r\n"
<< "Content-length: " << body.length() << "\r\n"
<< "\r\n"
<< body;
return (ret.str());
}
string getMime(string path) {
size_t pos = path.rfind('.');
string extension = (pos == string::npos) ? "txt" : path.substr(pos + 1);
@ -221,27 +246,3 @@ string getMime(string path) {
else
return ("text/plain");
}
string read_file(string path) {
string str;
string content;
std::stringstream ret;
struct stat info;
if (stat(path.c_str(), &info) != 0) {
std::cerr << "stat() error on " << path << ": " << strerror(errno)
<< "\n";
return "404";
} else if (S_ISDIR(info.st_mode))
return "404";
std::ifstream file(path.c_str());
if (!file.good())
return "404";
while (file) {
std::getline(file, str);
content += str + "\n";
}
ret << "Content-type: " << getMime(path) << "\r\n";
ret << "Content-length: " << content.length() << "\r\n";
ret << "\r\n" << content;
return (ret.str());
}

7
srcs/webserv.cpp

@ -1,30 +1,35 @@
#include "webserv.hpp"
fd_set Master::_readfds;
int Master::_max_fd;
int Master::_min_fd = INT_MAX;
int Master::_max_fd = 0;
int Master::_amount = 0;
int main(int ac, char **av) {
try {
if (ac > 2)
throw std::runtime_error("Too many arguments");
std::string config_file = "default.json";
if (ac == 2)
config_file = av[1];
std::ifstream file(config_file.c_str());
if (!file.good())
throw std::runtime_error("File not found");
cout << "Parsing configuration file from JSON conf file.\n";
cout << "You must be sure the syntax is correct\n";
JSONParser parser(config_file);
JSONNode *conf = parser.parse();
cout << "Initialization of server...\n";
Env env(conf);
while (1)
env.cycle();
} catch (const std::exception &e) {
std::cerr << e.what() << '\n';
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

Loading…
Cancel
Save