Browse Source

save22-11-17-1

master
nicolas-arnaud 2 years ago
parent
commit
8b22bc9b5e
  1. 18
      default.json
  2. 5
      includes/Client.hpp
  3. 2
      includes/Env.hpp
  4. 2
      includes/webserv.hpp
  5. 10
      public/testsite/LICENSE
  6. 46
      public/testsite/basique.html
  7. 21
      public/testsite/index.py
  8. 10
      srcs/debug.cpp
  9. 26
      srcs/load/Env.cpp
  10. 8
      srcs/load/Route.cpp
  11. 70
      srcs/sock/Client.cpp

18
default.json

@ -1,27 +1,21 @@
{ {
"root_folder": "./www", "root_folder": "./www",
"allowed_methods": ["GET", "POST", "PUT", "DELETE"],
"servers": [ "servers": [
{ {
"server_name": "localhost", "server_name": "localhost",
"listens": [ "listens": ["localhost:8080"],
"localhost:8080"
],
"root": "public/", "root": "public/",
"return": "301 https://$host$uri" "return": "301 https://$host$uri"
}, },
{ {
"server_name": "localhost", "server_name": "localhost",
"listens": [ "listens": ["192.168.62.61:8080", "localhost", "555"],
"192.168.62.61:8080",
"localhost",
"555"
],
"root": "public/testsite", "root": "public/testsite",
"indexs": [ "indexs": ["basique.html"],
"basique.html"
],
"cgi": { "cgi": {
".php": "/usr/bin/php-cgi" ".php": "/usr/bin/php",
".py": "/usr/bin/python"
}, },
"client_max_body_size": 10000, "client_max_body_size": 10000,
"locations": { "locations": {

5
includes/Client.hpp

@ -8,8 +8,9 @@ class Client {
ip_port_t _ip_port; ip_port_t _ip_port;
Master *_parent; Master *_parent;
Server *_server; Server *_server;
Env *_env;
Route *_route; Route *_route;
string _method, _uri, _host, _header, _body; string _method, _uri, _query, _host, _header, _body;
int _len; int _len;
bool _last_chunk; bool _last_chunk;
request_t _request; request_t _request;
@ -25,6 +26,8 @@ class Client {
void send_error(int error_code); void send_error(int error_code);
void send_answer(string msg); void send_answer(string msg);
void print_header(void);
public: public:
Client(int fd, ip_port_t ip_port, Master *parent); Client(int fd, ip_port_t ip_port, Master *parent);
~Client(void); ~Client(void);

2
includes/Env.hpp

@ -5,6 +5,8 @@ class Env {
public: public:
std::vector< Server * > _servers; std::vector< Server * > _servers;
std::vector< Master * > _masters; std::vector< Master * > _masters;
vec_string _allowed_methods;
Env(JSONNode *conf); Env(JSONNode *conf);
void cycle(void); void cycle(void);

2
includes/webserv.hpp

@ -1,6 +1,6 @@
#pragma once #pragma once
#define DEBUG 0 #define DEBUG 1
#include <arpa/inet.h> #include <arpa/inet.h>
#include <dirent.h> #include <dirent.h>

10
public/testsite/LICENSE

@ -0,0 +1,10 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>

46
public/testsite/basique.html

@ -12,22 +12,28 @@
<button class="first" <button class="first"
style="height: 50px; font-size: 20px; background-color: rgb(0, 255, 85); color: white;">CLIQUEZ ICI POUR VOIR style="height: 50px; font-size: 20px; background-color: rgb(0, 255, 85); color: white;">CLIQUEZ ICI POUR VOIR
VOTRE CADEAU</button> VOTRE CADEAU</button>
<script>
const button1 = document.querySelector('button.first');
button1.addEventListener('click', function () {
alert('PRANK hahaha, cliquez sur le bouton en bas de la page pour voir le vrai cadeau');
document.querySelector('body').innerHTML = '<button class ="second" style="position: fixed; bottom: 0; left: 0; width: 100%; height: 50px; font-size: 20px; background-color: red; color: white;">CLIQUEZ ICI POUR VOIR VOTRE VRAI CADEAU</button>';
const button2 = document.querySelector('button.second');
button2.addEventListener('click', function () {
document.querySelector('body').innerHTML = '<img src="./monkey.gif" style="width: 100%; height: 100%;">';
});
});
</script>
<ul> <ul>
<li><a href="/docs/">Documentss</a></li> <li><a href="/docs/">Documentss</a></li>
<li><a href="/img/">Images</a></li> <li><a href="/img/">Images</a></li>
<li><a href="/index.php">php-cgi test</a></li> <li><a href="/index.php">php-cgi test</a></li>
</ul> </ul>
<h1> Query and python cgi test </h1>
<form action = "/index.py" method = "get">
First Name: <input type = "text" name = "first_name"> <br />
Last Name: <input type = "text" name = "last_name" />
<input type = "submit" value = "Submit" />
</form>
<h1> File Creation test: </h1>
<form action="/" method="post" enctype="text/plain">
Filename: <input type="text" id="changeAction" />
Content: <input name="content" type="text">
<button type="submit">Create file</button>
</form>
<h1> Forms tests: </h1>
<form action="/" method="post" enctype="multipart/form-data"> <form action="/" method="post" enctype="multipart/form-data">
<input type="text" name="description" value="form-data" /> <input type="text" name="description" value="form-data" />
<input type="file" name="myFile" /> <input type="file" name="myFile" />
@ -37,6 +43,24 @@
<input type="text" name="description" value="UrlEncode" /> <input type="text" name="description" value="UrlEncode" />
<button type="submit">Submit</button> <button type="submit">Submit</button>
</form> </form>
<script>
const button1 = document.querySelector('button.first');
button1.addEventListener('click', function () {
alert('PRANK hahaha, cliquez sur le bouton en bas de la page pour voir le vrai cadeau');
document.querySelector('body').innerHTML = '<button class ="second" style="position: fixed; bottom: 0; left: 0; width: 100%; height: 50px; font-size: 20px; background-color: red; color: white;">CLIQUEZ ICI POUR VOIR VOTRE VRAI CADEAU</button>';
const button2 = document.querySelector('button.second');
button2.addEventListener('click', function () {
document.querySelector('body').innerHTML = '<img src="./monkey.gif" style="width: 100%; height: 100%;">';
});
});
const actionUpdater = document.querySelector("#changeAction");
actionUpdater.addEventListener("change", () => {
const parent = actionUpdater.parentElement;
parent.action = actionUpdater.value;
});
</script>
</body> </body>
</html> </html>

21
public/testsite/index.py

@ -0,0 +1,21 @@
#!/usr/bin/python
# Import modules for CGI handling
import cgi, cgitb
# Create instance of FieldStorage
form = cgi.FieldStorage()
# Get data from fields
first_name = form.getvalue('first_name')
last_name = form.getvalue('last_name')
print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>"
print "<title>Hello - Second CGI Program</title>"
print "</head>"
print "<body>"
print "<h2>Hello %s %s</h2>" % (first_name, last_name)
print "</body>"
print "</html>"

10
srcs/debug.cpp

@ -1,9 +1,19 @@
#include "webserv.hpp" #include "webserv.hpp"
void print_block(string name, string content) { void print_block(string name, string content) {
if (!DEBUG)
return ;
string separator = "|===================================================" string separator = "|==================================================="
"===========================|\n"; "===========================|\n";
cout << name << separator.substr(name.length(), string::npos) << content cout << name << separator.substr(name.length(), string::npos) << content
<< "\n" << "\n"
<< separator; << separator;
} }
void Client::print_header(void) {
cout << "Method: " << _method << "\n";
cout << "Uri: " << _uri << "\n";
cout << "Query: " << _query << "\n";
cout << "Host: " << _host << "\n";
cout << "Location: " << _route->getRoot() << "\n";
}

26
srcs/load/Env.cpp

@ -25,13 +25,25 @@ Env::~Env() {
*/ */
Env::Env(JSONNode *conf) { Env::Env(JSONNode *conf) {
try { try {
JSONList servers = conf->obj()["servers"]->lst(); JSONNode *node;
for (std::vector< JSONNode * >::iterator it = servers.begin(); JSONList lst;
it < servers.end(); it++) { if ((node = conf->obj()["servers"]))
Server *server = new Server(*it); {
_servers.push_back(server); lst = conf->obj()["servers"]->lst();
std::vector< Master * > tmp_s = server->get_sockets(*it); for (std::vector< JSONNode * >::iterator it = lst.begin();
_masters.insert(_masters.end(), tmp_s.begin(), tmp_s.end()); it < lst.end(); it++) {
Server *server = new Server(*it);
_servers.push_back(server);
std::vector< Master * > tmp_s = server->get_sockets(*it);
_masters.insert(_masters.end(), tmp_s.begin(), tmp_s.end());
}
}
if ((node = conf->obj()["allowed_methods"])) {
JSONList lst = node->lst();
for (JSONList::iterator it = lst.begin(); it < lst.end();
it++) {
_allowed_methods.push_back((*it)->str());
}
} }
} catch (std::exception &e) { } catch (std::exception &e) {
std::cerr << e.what() << "\n"; std::cerr << e.what() << "\n";

8
srcs/load/Route.cpp

@ -14,6 +14,8 @@ Route::Route(Server *server, string location, JSONNode *datas)
: _server(server), _location(location) { : _server(server), _location(location) {
JSONObject object = datas->obj(); JSONObject object = datas->obj();
JSONNode *tmp; JSONNode *tmp;
_autoindex = false;
_client_max_body_size = -1;
if ((tmp = object["root"])) if ((tmp = object["root"]))
_root = tmp->str(); _root = tmp->str();
if ((tmp = object["return"])) if ((tmp = object["return"]))
@ -70,7 +72,8 @@ string Route::getIndex(string uri, string path) {
if ((dir = opendir(path.c_str())) == NULL) { if ((dir = opendir(path.c_str())) == NULL) {
return ""; return "";
} else { } else {
// cout << "get index(): path=" << path << "\n"; if (DEBUG)
cout << "get index(): path=" << path << "\n";
body << "<h3 style=\"text-align: center;\">" << path body << "<h3 style=\"text-align: center;\">" << path
<< " files :</h3>\n<ul>\n"; << " files :</h3>\n<ul>\n";
while ((entry = readdir(dir)) != NULL) { while ((entry = readdir(dir)) != NULL) {
@ -91,7 +94,8 @@ string Route::getIndex(string uri, string path) {
} }
if (!_autoindex) if (!_autoindex)
return ""; return "";
// cout << "Getting autoindex\n"; if (DEBUG)
cout << "Getting autoindex\n";
ret << "Content-type: text/html \r\n"; ret << "Content-type: text/html \r\n";
ret << "Content-length: " << body.str().length() << "\r\n"; ret << "Content-length: " << body.str().length() << "\r\n";
ret << "\r\n" << body.str(); ret << "\r\n" << body.str();

70
srcs/sock/Client.cpp

@ -27,6 +27,7 @@ void Client::clean(void) {
bool Client::getHeader(Env *env, string paquet) { bool Client::getHeader(Env *env, string paquet) {
if (paquet.length() < 1) if (paquet.length() < 1)
send_error(403); send_error(403);
print_block("Paquet: ", paquet);
if (header_pick("Method:", 0) != "") if (header_pick("Method:", 0) != "")
return getBody(paquet); return getBody(paquet);
vec_string lines = split(paquet, "\r\n"); vec_string lines = split(paquet, "\r\n");
@ -40,7 +41,7 @@ bool Client::getHeader(Env *env, string paquet) {
if (_header.find("\r\n\r\n") != string::npos) if (_header.find("\r\n\r\n") != string::npos)
return !this->parseHeader(env) return !this->parseHeader(env)
? false ? false
: (paquet.length() > 0 ? getBody(paquet) : true); : (_len != 0 ? getBody(paquet) : true);
} }
return false; return false;
} }
@ -50,6 +51,8 @@ bool Client::getBody(string paquet) {
vec_string::iterator it; vec_string::iterator it;
for (it = lines.begin(); it < lines.end(); it++) { for (it = lines.begin(); it < lines.end(); it++) {
if (DEBUG)
cout << "Remaining length: " << _len << "\n";
if ((*it).length() && _len <= 0 && if ((*it).length() && _len <= 0 &&
header_pick("Transfer-Encoding:", 0) == "chunked") { header_pick("Transfer-Encoding:", 0) == "chunked") {
_len = std::strtol((*it).c_str(), 0, 16) + 2; _len = std::strtol((*it).c_str(), 0, 16) + 2;
@ -68,6 +71,8 @@ bool Client::getBody(string paquet) {
bool Client::parseHeader(Env *env) { bool Client::parseHeader(Env *env) {
vec_string lines, method, line; vec_string lines, method, line;
if (DEBUG)
cout << "Parsing header...\n";
lines = split(_header, "\r\n"); lines = split(_header, "\r\n");
method = split(lines.at(0), " "); method = split(lines.at(0), " ");
_request["Method:"] = method; _request["Method:"] = method;
@ -78,38 +83,44 @@ bool Client::parseHeader(Env *env) {
_request[line.at(0)] = vec_string(line.begin() + 1, line.end()); _request[line.at(0)] = vec_string(line.begin() + 1, line.end());
} }
} }
if ((method.at(0) == "POST" || method.at(0) == "PUT") &&
header_pick("Content-Length:", 0) == "" &&
header_pick("Transfer-Encoding:", 0) != "chunked") {
send_error(400);
return false;
}
_method = header_pick("Method:", 0); _method = header_pick("Method:", 0);
_uri = header_pick("Method:", 1); if ((_method == "POST" || _method == "PUT") &&
header_pick("Content-Length:", 0) == "" &&
header_pick("Transfer-Encoding:", 0) != "chunked")
return (send_error(400), false);
vec_string uri_split = split(header_pick("Method:", 1), "?");
_uri = uri_split.at(0);
if (uri_split.size() > 1)
_query = uri_split.at(1);
_host = header_pick("Host:", 0); _host = header_pick("Host:", 0);
_env = env;
_server = _parent->choose_server(env, _host); _server = _parent->choose_server(env, _host);
_route = _server->choose_route(_uri); _route = _server->choose_route(_uri);
if (DEBUG)
print_header();
string len = header_pick("Content-Length:", 0).c_str(); string len = header_pick("Content-Length:", 0).c_str();
if (len != "") { if (len != "") {
_len = std::atoi(len.c_str()); _len = std::atoi(len.c_str());
_last_chunk = true; _last_chunk = true;
if (_len > _route->_client_max_body_size) int max_len = _route->_client_max_body_size >= 0 ? _route->_client_max_body_size : _server->_client_max_body_size >= 0 ? _server->_client_max_body_size : INT_MAX;
if (_len > max_len)
return (send_error(413), false); return (send_error(413), false);
} } else
_len = 0;
return true; return true;
} }
bool Client::check_method(void) { bool Client::check_method(void) {
vec_string allowed; vec_string allowed;
if ((allowed = _route->_allowed_methods).size() > 0 || if ((_route && (allowed = _route->_allowed_methods).size() > 0) ||
(allowed = _server->_allowed_methods).size() > 0) (_server && (allowed = _server->_allowed_methods).size() > 0) ||
((allowed = _env->_allowed_methods).size() > 0))
return std::find(allowed.begin(), allowed.end(), _method) < return std::find(allowed.begin(), allowed.end(), _method) <
allowed.end() allowed.end()
? true ? true
: false; : false;
else if (_method == "GET" || _method == "POST" || _method != "DELETE" || else if (_method == "GET" || _method == "POST" || _method == "DELETE" ||
_method != "PUT") _method == "PUT")
return (true); return (true);
return (false); return (false);
} }
@ -126,20 +137,25 @@ void Client::answer(void) {
string cgi = _route->_cgi.size() ? _route->_cgi[get_extension(path)] string cgi = _route->_cgi.size() ? _route->_cgi[get_extension(path)]
: _server->_cgi.size() ? _server->_cgi[get_extension(path)] : _server->_cgi.size() ? _server->_cgi[get_extension(path)]
: ""; : "";
cout << "Path: " << path << "\n"; if (DEBUG)
if (_method == "PUT") cout << "Path: " << path << "\n";
create_file(path); if (!check_method())
if (cgi != "")
send_cgi(cgi, path);
else if (!check_method())
send_error(405); send_error(405);
else { else {
if ((ret = _route->getIndex(_uri, path)) == "") if ((ret = _route->getIndex(_uri, path)) == "")
ret = read_file(path); ret = read_file(path);
if (ret == "404") if (ret == "404") {
send_error(404); if (_method == "POST" || _method == "PUT")
create_file(path);
else
send_error(404);
}
else if (ret == "403") else if (ret == "403")
send_error(403); send_error(403);
else if (_method == "DELETE")
std::remove(path.c_str());
else if (cgi != "")
send_cgi(cgi, path);
else else
send_answer("HTTP/1.1 200 OK\r\n" + ret); send_answer("HTTP/1.1 200 OK\r\n" + ret);
} }
@ -170,10 +186,12 @@ void Client::send_cgi(string cgi, string path) {
args[0] = cgi.c_str(); args[0] = cgi.c_str();
args[1] = path.c_str(); args[1] = path.c_str();
args[2] = NULL; args[2] = NULL;
string path_info = "PATH_INFO=" + _route->getRoot(); string path_info = "PATH_INFO=" + _route->getRoot();
const char **env = new const char *[path_info.length() + 1]; string query = "QUERY_STRING=" + _query;
const char **env = new const char *[path_info.length() + query.length() + 2];
env[0] = path_info.c_str(); env[0] = path_info.c_str();
env[1] = NULL; env[1] = query.c_str();
env[2] = NULL;
dup2(fd[1], STDOUT_FILENO); dup2(fd[1], STDOUT_FILENO);
close(fd[1]); close(fd[1]);
close(fd[0]); close(fd[0]);

Loading…
Cancel
Save