From 8b22bc9b5e8df0df4b3b4dd7c861cb9a0bd47238 Mon Sep 17 00:00:00 2001 From: nicolas-arnaud Date: Thu, 17 Nov 2022 15:21:28 +0100 Subject: [PATCH] save22-11-17-1 --- default.json | 18 ++++------ includes/Client.hpp | 5 ++- includes/Env.hpp | 2 ++ includes/webserv.hpp | 2 +- public/testsite/LICENSE | 10 ++++++ public/testsite/basique.html | 46 ++++++++++++++++++------ public/testsite/index.py | 21 +++++++++++ srcs/debug.cpp | 10 ++++++ srcs/load/Env.cpp | 26 ++++++++++---- srcs/load/Route.cpp | 8 +++-- srcs/sock/Client.cpp | 70 ++++++++++++++++++++++-------------- 11 files changed, 158 insertions(+), 60 deletions(-) create mode 100644 public/testsite/LICENSE create mode 100644 public/testsite/index.py diff --git a/default.json b/default.json index 4fe61a4..ccbc27e 100644 --- a/default.json +++ b/default.json @@ -1,27 +1,21 @@ { "root_folder": "./www", + "allowed_methods": ["GET", "POST", "PUT", "DELETE"], "servers": [ { "server_name": "localhost", - "listens": [ - "localhost:8080" - ], + "listens": ["localhost:8080"], "root": "public/", "return": "301 https://$host$uri" }, { "server_name": "localhost", - "listens": [ - "192.168.62.61:8080", - "localhost", - "555" - ], + "listens": ["192.168.62.61:8080", "localhost", "555"], "root": "public/testsite", - "indexs": [ - "basique.html" - ], + "indexs": ["basique.html"], "cgi": { - ".php": "/usr/bin/php-cgi" + ".php": "/usr/bin/php", + ".py": "/usr/bin/python" }, "client_max_body_size": 10000, "locations": { diff --git a/includes/Client.hpp b/includes/Client.hpp index c8f9240..13666ed 100644 --- a/includes/Client.hpp +++ b/includes/Client.hpp @@ -8,8 +8,9 @@ class Client { ip_port_t _ip_port; Master *_parent; Server *_server; + Env *_env; Route *_route; - string _method, _uri, _host, _header, _body; + string _method, _uri, _query, _host, _header, _body; int _len; bool _last_chunk; request_t _request; @@ -25,6 +26,8 @@ class Client { void send_error(int error_code); void send_answer(string msg); + void print_header(void); + public: Client(int fd, ip_port_t ip_port, Master *parent); ~Client(void); diff --git a/includes/Env.hpp b/includes/Env.hpp index b9be2ee..6487b10 100644 --- a/includes/Env.hpp +++ b/includes/Env.hpp @@ -5,6 +5,8 @@ class Env { public: std::vector< Server * > _servers; std::vector< Master * > _masters; + vec_string _allowed_methods; + Env(JSONNode *conf); void cycle(void); diff --git a/includes/webserv.hpp b/includes/webserv.hpp index 03cde84..9ba212d 100644 --- a/includes/webserv.hpp +++ b/includes/webserv.hpp @@ -1,6 +1,6 @@ #pragma once -#define DEBUG 0 +#define DEBUG 1 #include #include diff --git a/public/testsite/LICENSE b/public/testsite/LICENSE new file mode 100644 index 0000000..cde4ac6 --- /dev/null +++ b/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 diff --git a/public/testsite/basique.html b/public/testsite/basique.html index 01c7c94..e31e0ae 100644 --- a/public/testsite/basique.html +++ b/public/testsite/basique.html @@ -12,22 +12,28 @@ - + +

Query and python cgi test

+
+ First Name:
+ + Last Name: + +
+ +

File Creation test:

+
+ Filename: + Content: + +
+ +

Forms tests:

@@ -37,6 +43,24 @@
+ + diff --git a/public/testsite/index.py b/public/testsite/index.py new file mode 100644 index 0000000..50e81b2 --- /dev/null +++ b/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 "" +print "" +print "Hello - Second CGI Program" +print "" +print "" +print "

Hello %s %s

" % (first_name, last_name) +print "" +print "" diff --git a/srcs/debug.cpp b/srcs/debug.cpp index 021250e..69533ea 100644 --- a/srcs/debug.cpp +++ b/srcs/debug.cpp @@ -1,9 +1,19 @@ #include "webserv.hpp" void print_block(string name, string content) { + if (!DEBUG) + return ; string separator = "|===================================================" "===========================|\n"; cout << name << separator.substr(name.length(), string::npos) << content << "\n" << 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"; +} diff --git a/srcs/load/Env.cpp b/srcs/load/Env.cpp index 8a17d8e..449c20c 100644 --- a/srcs/load/Env.cpp +++ b/srcs/load/Env.cpp @@ -25,13 +25,25 @@ 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++) { - 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()); + JSONNode *node; + JSONList lst; + if ((node = conf->obj()["servers"])) + { + lst = conf->obj()["servers"]->lst(); + for (std::vector< JSONNode * >::iterator it = lst.begin(); + 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) { std::cerr << e.what() << "\n"; diff --git a/srcs/load/Route.cpp b/srcs/load/Route.cpp index 4efdb21..6bbfadb 100644 --- a/srcs/load/Route.cpp +++ b/srcs/load/Route.cpp @@ -14,6 +14,8 @@ Route::Route(Server *server, string location, JSONNode *datas) : _server(server), _location(location) { JSONObject object = datas->obj(); JSONNode *tmp; + _autoindex = false; + _client_max_body_size = -1; if ((tmp = object["root"])) _root = tmp->str(); if ((tmp = object["return"])) @@ -70,7 +72,8 @@ string Route::getIndex(string uri, string path) { if ((dir = opendir(path.c_str())) == NULL) { return ""; } else { - // cout << "get index(): path=" << path << "\n"; + if (DEBUG) + cout << "get index(): path=" << path << "\n"; body << "

" << path << " files :

\n
    \n"; while ((entry = readdir(dir)) != NULL) { @@ -91,7 +94,8 @@ string Route::getIndex(string uri, string path) { } if (!_autoindex) return ""; - // cout << "Getting autoindex\n"; + if (DEBUG) + cout << "Getting autoindex\n"; ret << "Content-type: text/html \r\n"; ret << "Content-length: " << body.str().length() << "\r\n"; ret << "\r\n" << body.str(); diff --git a/srcs/sock/Client.cpp b/srcs/sock/Client.cpp index 3d9e7b4..8e68d1c 100644 --- a/srcs/sock/Client.cpp +++ b/srcs/sock/Client.cpp @@ -27,6 +27,7 @@ void Client::clean(void) { bool Client::getHeader(Env *env, string paquet) { if (paquet.length() < 1) send_error(403); + print_block("Paquet: ", paquet); if (header_pick("Method:", 0) != "") return getBody(paquet); 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) return !this->parseHeader(env) ? false - : (paquet.length() > 0 ? getBody(paquet) : true); + : (_len != 0 ? getBody(paquet) : true); } return false; } @@ -50,6 +51,8 @@ bool Client::getBody(string paquet) { vec_string::iterator it; for (it = lines.begin(); it < lines.end(); it++) { + if (DEBUG) + cout << "Remaining length: " << _len << "\n"; if ((*it).length() && _len <= 0 && header_pick("Transfer-Encoding:", 0) == "chunked") { _len = std::strtol((*it).c_str(), 0, 16) + 2; @@ -68,6 +71,8 @@ bool Client::getBody(string paquet) { bool Client::parseHeader(Env *env) { vec_string lines, method, line; + if (DEBUG) + cout << "Parsing header...\n"; lines = split(_header, "\r\n"); method = split(lines.at(0), " "); _request["Method:"] = method; @@ -78,38 +83,44 @@ bool Client::parseHeader(Env *env) { _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); - _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); + _env = env; _server = _parent->choose_server(env, _host); _route = _server->choose_route(_uri); + if (DEBUG) + print_header(); string len = header_pick("Content-Length:", 0).c_str(); if (len != "") { _len = std::atoi(len.c_str()); _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); - } + } else + _len = 0; return true; } bool Client::check_method(void) { vec_string allowed; - if ((allowed = _route->_allowed_methods).size() > 0 || - (allowed = _server->_allowed_methods).size() > 0) + if ((_route && (allowed = _route->_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) < allowed.end() ? true : false; - else if (_method == "GET" || _method == "POST" || _method != "DELETE" || - _method != "PUT") + else if (_method == "GET" || _method == "POST" || _method == "DELETE" || + _method == "PUT") return (true); return (false); } @@ -126,20 +137,25 @@ void Client::answer(void) { 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 != "") - send_cgi(cgi, path); - else if (!check_method()) + if (DEBUG) + cout << "Path: " << path << "\n"; + if (!check_method()) send_error(405); else { if ((ret = _route->getIndex(_uri, path)) == "") ret = read_file(path); - if (ret == "404") - send_error(404); + if (ret == "404") { + if (_method == "POST" || _method == "PUT") + create_file(path); + else + send_error(404); + } else if (ret == "403") send_error(403); + else if (_method == "DELETE") + std::remove(path.c_str()); + else if (cgi != "") + send_cgi(cgi, path); else 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[1] = path.c_str(); args[2] = NULL; - string path_info = "PATH_INFO=" + _route->getRoot(); - const char **env = new const char *[path_info.length() + 1]; + string path_info = "PATH_INFO=" + _route->getRoot(); + string query = "QUERY_STRING=" + _query; + const char **env = new const char *[path_info.length() + query.length() + 2]; env[0] = path_info.c_str(); - env[1] = NULL; + env[1] = query.c_str(); + env[2] = NULL; dup2(fd[1], STDOUT_FILENO); close(fd[1]); close(fd[0]);