merge from hugo, add parsing requests and wip cgi
This commit is contained in:
BIN
42_testers/cgi_tester
Executable file
BIN
42_testers/cgi_tester
Executable file
Binary file not shown.
BIN
42_testers/tester
Executable file
BIN
42_testers/tester
Executable file
Binary file not shown.
16
Makefile
16
Makefile
@@ -3,25 +3,15 @@ NAME = webserv
|
||||
CXX = c++
|
||||
|
||||
CXXFLAGS = -Wall -Wextra #-Werror
|
||||
CXXFLAGS += $(HEADERS_I)
|
||||
CXXFLAGS += $(HEADERS_D:%=-I%)
|
||||
CXXFLAGS += -std=c++98
|
||||
CXXFLAGS += -g
|
||||
CXXFLAGS += -MMD -MP #header dependencie
|
||||
#CXXFLAGS += -O3
|
||||
|
||||
#SHELL = /bin/zsh
|
||||
VPATH = $(SRCS_D)
|
||||
|
||||
HEADERS_I = $(HEADERS_D:%=-I%)
|
||||
HEADERS_D = srcs \
|
||||
headers
|
||||
HEADERS = Webserv.hpp \
|
||||
ConfigParser.hpp \
|
||||
ServerConfig.hpp \
|
||||
LocationConfig.hpp \
|
||||
Client.hpp \
|
||||
MethodType.hpp \
|
||||
utils.hpp \
|
||||
HEADERS_D = srcs
|
||||
|
||||
SRCS_D = srcs \
|
||||
srcs/webserv
|
||||
@@ -33,6 +23,8 @@ SRCS = main.cpp \
|
||||
ConfigParserUtils.cpp \
|
||||
ConfigParserPost.cpp \
|
||||
utils.cpp \
|
||||
cgi_script.cpp \
|
||||
Client.cpp \
|
||||
|
||||
OBJS_D = builds
|
||||
OBJS = $(SRCS:%.cpp=$(OBJS_D)/%.o)
|
||||
|
||||
136
README.md
Normal file
136
README.md
Normal file
@@ -0,0 +1,136 @@
|
||||
|
||||
---
|
||||
## questions
|
||||
- mettre les fonctions specifiques a la requete, dans la class client ?
|
||||
- où est-ce que j'inclus le cgi ?
|
||||
- est-ce que le cgi est appellé par `/cgi-bin` ?
|
||||
- non
|
||||
- g rajouté `char ** env` dans client.cpp
|
||||
- non
|
||||
- ajouter un champ "message body" dans client ?
|
||||
- non
|
||||
- comment organiser la creation du message reponse (cgi ou pas) et des headers ?
|
||||
- comment je gere le path `/cgi-bin/` avec la suite ?
|
||||
- qu'est-ce que le cgi renvoit comme headers ? comment c'est géré ?
|
||||
- https://www.rfc-editor.org/rfc/rfc3875
|
||||
|
||||
---
|
||||
## man
|
||||
|
||||
- **htons, htonl, ntohs, ntohl :** converts the unsigned short or integer argument between host byte order and network byte order
|
||||
- **poll :** waits for one of a set of file descriptors to become ready to perform I/O
|
||||
- alternatives : select, epoll (epoll_create, epoll_ctl, epoll_wait), kqueue (kqueue, kevent)
|
||||
- **socket :** creates an endpoint for communication and returns a file descriptor that refers to that endpoint
|
||||
- **listen :** marks a socket as a passive socket, that is, as a socket that will be used to accept incoming connection requests using accept()
|
||||
- **accept :** used with connection-based socket types. It extracts the first connection request on the queue of pending connections for the listening socket, creates a new connected socket, and returns a new file descriptor referring to that socket. The newly created socket is not in the listening state. The original socket is unaffected by this call
|
||||
- **send :** (~write) used to transmit a message to another socket. May be used only when the socket is in a connected state (so that the intended recipient is known). The only difference between send() and write() is the presence of flags. With a zero flags argument, send() is equivalent to write()
|
||||
- **recv :** (~read) used to receive messages from a socket. May be used to receive data on both connectionless and connection-oriented sockets. The only difference between recv() and read() is the presence of flags. With a zero flags argument, recv() is generally equivalent to read()
|
||||
- **bind :** associate a socket fd to a local address. When a socket is created with socket(), it exists in a name space (address family) but has no address assigned to it. It is normally necessary to assign a local address using bind() before a socket may receive connections (see accept())
|
||||
- **connect :** connects a socket fd to a remote address
|
||||
- **inet_addr :** converts the Internet host address cp from IPv4 numbers-and-dots notation into binary data in network byte order. Use of this function is problematic because in case of error it returns -1, wich is a valid address (255.255.255.255). Avoid its use in favor of inet_aton(), inet_pton(), or getaddrinfo()
|
||||
- **setsockopt :** manipulate options for a socket fd. Options may exist at multiple protocol levels; they are always present at the uppermost socket level
|
||||
- **getsockname :** returns the current address to which a socket fd is bound
|
||||
- **fcntl :** manipulate an open fd, by performing some actions, like duplicate it or changing its flags
|
||||
|
||||
---
|
||||
## todo
|
||||
|
||||
- [ ] read the RFC and do some tests with telnet and NGINX
|
||||
#### parsing config
|
||||
- [ ] Your program has to take a configuration file as argument, or use a default path.
|
||||
- [ ] Choose the port and host of each ’server’.
|
||||
- [ ] Setup the server_names or not.
|
||||
- [ ] The first server for a host:port will be the default for this host:port (that means it will answer to all the requests that don’t belong to an other server).
|
||||
- [ ] Setup default error pages.
|
||||
- [ ] Limit client body size.
|
||||
- [ ] Setup routes with one or multiple of the following rules/configuration (routes wont be using regexp):
|
||||
- [ ] Define a list of accepted HTTP methods for the route.
|
||||
- [ ] Define a HTTP redirection.
|
||||
- [ ] Define a directory or a file from where the file should be searched (for example, if url /kapouet is rooted to /tmp/www, url /kapouet/pouic/toto/pouet is /tmp/www/pouic/toto/pouet).
|
||||
- [ ] Turn on or off directory listing.
|
||||
- [ ] Set a default file to answer if the request is a directory.
|
||||
- [ ] Execute CGI based on certain file extension (for example .php).
|
||||
- [ ] Make the route able to accept uploaded files and configure where they should be saved.
|
||||
#### connection basic
|
||||
- [ ] You can’t execve another web server.
|
||||
- [ ] Your server must never block and the client can be bounced properly if necessary.
|
||||
- [ ] It must be non-blocking and use only 1 poll() (or equivalent) for all the I/O operations between the client and the server (listen included).
|
||||
- [ ] poll() (or equivalent) must check read and write at the same time.
|
||||
- [ ] You must never do a read or a write operation without going through poll() (or equivalent).
|
||||
- [ ] Checking the value of errno is strictly forbidden after a read or a write operation.
|
||||
- [ ] You don’t need to use poll() (or equivalent) before reading your configuration file. Because you have to use non-blocking file descriptors, it is possible to use read/recv or write/send functions with no poll() (or equivalent), and your server wouldn’t be blocking. But it would consume more system resources. Thus, if you try to read/recv or write/send in any file descriptor without using poll() (or equivalent), your grade will be 0.
|
||||
- [ ] You can use every macro and define like FD_SET, FD_CLR, FD_ISSET, FD_ZERO (understanding what and how they do it is very useful).
|
||||
- [ ] A request to your server should never hang forever.
|
||||
- [ ] Your server must be compatible with the web browser of your choice.
|
||||
#### parsing request HTTP (fields, ...)
|
||||
- [ ] We will consider that NGINX is HTTP 1.1 compliant and may be used to compare headers and answer behaviors.
|
||||
#### response HTTP (fields, ...)
|
||||
- [ ] Your HTTP response status codes must be accurate.
|
||||
- [ ] You server must have default error pages if none are provided.
|
||||
- [ ] You can’t use fork for something else than CGI (like PHP, or Python, and so forth).
|
||||
- [ ] You must be able to serve a fully static website.
|
||||
#### upload files
|
||||
- [ ] Clients must be able to upload files.
|
||||
#### CGI
|
||||
- [ ] You need at least GET, POST, and DELETE methods.
|
||||
- [ ] Do you wonder what a CGI is?
|
||||
- [ ] Because you won’t call the CGI directly, use the full path as PATH_INFO.
|
||||
- [ ] Just remember that, for chunked request, your server needs to unchunked it and the CGI will expect EOF as end of the body.
|
||||
- [ ] Same things for the output of the CGI. If no content_length is returned from the CGI, EOF will mark the end of the returned data.
|
||||
- [ ] Your program should call the CGI with the file requested as first argument.
|
||||
- [ ] The CGI should be run in the correct directory for relative path file access.
|
||||
- [ ] Your server should work with one CGI (php-CGI, Python, and so forth).
|
||||
#### write tests
|
||||
- [ ] Stress tests your server. It must stay available at all cost.
|
||||
- [ ] Do not test with only one program.
|
||||
- [ ] Write your tests with a more convenient language such as Python or Golang, and so forth. Even in C or C++ if you want to
|
||||
#### persistent connexion
|
||||
- [ ] Your server must be able to listen to multiple ports (see Configuration file)
|
||||
- [ ] Your server should never die.
|
||||
|
||||
|
||||
---
|
||||
## cgi env variables
|
||||
[cgi env variables](http://www.faqs.org/rfcs/rfc3875.html)
|
||||
[wikipedia variables environnements cgi](https://fr.wikipedia.org/wiki/Variables_d%27environnement_CGI)
|
||||
[cgi server variables on adobe](https://helpx.adobe.com/coldfusion/cfml-reference/reserved-words-and-variables/cgi-environment-cgi-scope-variables/cgi-server-variables.html)
|
||||
```
|
||||
AUTH_TYPE : if the srcipt is protected, the authentification method used to validate the user
|
||||
CONTENT_LENGTH : length of the request content
|
||||
CONTENT_TYPE : if there is attached information, as with method POST or PUT, this is the content type of the data (e.g. "text/plain", it is set by the attribute "enctype" in html <form> as three values : "application/x-www-form-urlencoded", "multipart/form-data", "text/plain")
|
||||
GATEWAY_INTERFACE : CGI version (e.g. CGI/1.1)
|
||||
PATH_INFO : if any, path of the resquest in addition to the cgi script path (e.g. for cgi script path = "/usr/web/cgi-bin/script.cgi", and the url = "http://server.org/cgi-bin/script.cgi/house", the PATH-INFO would be "house")
|
||||
PATH_TRANSLATED : full path of the request, like path-to-cgi/PATH_INFO, null if PATH_INFO is null (e.g. for "http://server.org/cgi-bin/prog/the/path", PATH_INFO would be : "/the/path" and PATH_TRANSLATED would be : "/usr/web/cgi-bin/prog/the/path")
|
||||
QUERY_STRING : everything following the ? in the url sent by client (e.g. for url "http://server.org/query?var1=val2&var2=val2", it would be : "var1=val2&var2=val2")
|
||||
REMOTE_ADDR : ip address of the client
|
||||
REMOTE_HOST : host name of the client, empty if not known, or equal to REMOTE_ADDR
|
||||
REMOTE_IDENT : if known, username of the client, otherwise empty, use for logging only
|
||||
REMOTE_USER : username of client, if script is protected and the server support user authentification
|
||||
REQUEST_METHOD : method used for the request (for http, usually POST or GET)
|
||||
SCRIPT_NAME : path to the cgi, relative to the root, used for self-referencing URLs (e.g. "/cgi-bin/script.cgi")
|
||||
SERVER_NAME : name of the server, as hostname, IP address, or DNS (e.g. dns : "www.server.org")
|
||||
SERVER_PORT : the port number your server is listening on (e.g. 80)
|
||||
SERVER_PROTOCOL : protocol used for the request (e.g. HTTP/1.1)
|
||||
SERVER_SOFTWARE : the server software you're using (e.g. Apache 1.3)
|
||||
```
|
||||
[redirect status for php-cgi](https://woozle.org/papers/php-cgi.html)
|
||||
```
|
||||
REDIRECT_STATUS : for exemple, 200
|
||||
```
|
||||
|
||||
---
|
||||
## ressources
|
||||
|
||||
- [correction](https://github.com/AliMaskar96/42-Correction-Sheets/blob/master/ng_5_webserv.pdf)
|
||||
- [create an http server](https://medium.com/from-the-scratch/http-server-what-do-you-need-to-know-to-build-a-simple-http-server-from-scratch-d1ef8945e4fa)
|
||||
- [guide to network programming](https://beej.us/guide/bgnet/)
|
||||
- [same, translated in french](http://vidalc.chez.com/lf/socket.html)
|
||||
- [bind() vs connect()](https://stackoverflow.com/questions/27014955/socket-connect-vs-bind)
|
||||
- [INADDR_ANY for bind](https://stackoverflow.com/questions/16508685/understanding-inaddr-any-for-socket-programming)
|
||||
- [hack with CGI](https://www.youtube.com/watch?v=ph6-AKByBU4)
|
||||
- [http headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers)
|
||||
- [list of http headers fields](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields)
|
||||
- [http request ibm](https://www.ibm.com/docs/en/cics-ts/5.3?topic=protocol-http-requests)
|
||||
- [http request other](https://www.tutorialspoint.com/http/http_requests.htm)
|
||||
- [request line uri](https://stackoverflow.com/questions/40311306/when-is-absoluteuri-used-from-the-http-request-specs)
|
||||
|
||||
0
YoupiBanane/Yeah/not_happy.bad_extension
Normal file
0
YoupiBanane/Yeah/not_happy.bad_extension
Normal file
0
YoupiBanane/nop/other.pouic
Normal file
0
YoupiBanane/nop/other.pouic
Normal file
0
YoupiBanane/nop/youpi.bad_extension
Normal file
0
YoupiBanane/nop/youpi.bad_extension
Normal file
0
YoupiBanane/youpi.bad_extension
Normal file
0
YoupiBanane/youpi.bad_extension
Normal file
0
YoupiBanane/youpi.bla
Normal file
0
YoupiBanane/youpi.bla
Normal file
BIN
docs/webserv_correction.pdf
Normal file
BIN
docs/webserv_correction.pdf
Normal file
Binary file not shown.
116
srcs/Client.cpp
Normal file
116
srcs/Client.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
|
||||
#include "Client.hpp"
|
||||
|
||||
/*********************************************
|
||||
* COPLIENS
|
||||
*********************************************/
|
||||
|
||||
Client::Client( ) {
|
||||
return;
|
||||
}
|
||||
|
||||
Client::~Client() {
|
||||
return;
|
||||
}
|
||||
|
||||
// copy constructor :
|
||||
// Client::Client( Client const & src ) {}
|
||||
|
||||
// assignement operator :
|
||||
// Client & Client::operator=( Client const & rhs ) {}
|
||||
|
||||
|
||||
|
||||
/*********************************************
|
||||
* PUBLIC MEMBER FUNCTIONS
|
||||
*********************************************/
|
||||
|
||||
// http headers :
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers
|
||||
// https://www.ibm.com/docs/en/cics-ts/5.3?topic=protocol-http-requests
|
||||
// https://www.tutorialspoint.com/http/http_requests.htm
|
||||
void Client::parse_request()
|
||||
{
|
||||
std::string sub;
|
||||
std::vector<std::string> list;
|
||||
size_t pos;
|
||||
|
||||
pos = (raw_request).find("\r\n\r\n");
|
||||
sub = (raw_request).substr(0, pos);
|
||||
list = split(sub, '\n');
|
||||
// request_line
|
||||
_parse_request_line(*list.begin());
|
||||
list.erase(list.begin());
|
||||
// headers
|
||||
_parse_request_headers(list);
|
||||
//body- message
|
||||
_parse_request_body(pos + 4);
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string Client::get_method() { return _request.method; }
|
||||
std::string Client::get_path() { return _request.path; }
|
||||
std::string Client::get_version() { return _request.version; }
|
||||
std::string Client::get_body() { return _request.body; }
|
||||
std::string Client::get_headers(std::string key) { return _request.headers[key]; }
|
||||
|
||||
/*********************************************
|
||||
* PRIVATE MEMBER FUNCTIONS
|
||||
*********************************************/
|
||||
|
||||
void Client::_parse_request_line( std::string rline )
|
||||
{
|
||||
std::vector<std::string> sline;
|
||||
std::string tmp;
|
||||
|
||||
sline = split(rline, ' ');
|
||||
if (sline.size() != 3)
|
||||
{
|
||||
std::cerr << "err _parse_request_line(): ";
|
||||
throw std::runtime_error("bad request-line header");
|
||||
}
|
||||
// method
|
||||
tmp = ::trim(sline[0], ' ');
|
||||
tmp = ::trim(tmp, '\r');
|
||||
_request.method = tmp;
|
||||
// TODO uri in request_line
|
||||
// https://www.rfc-editor.org/rfc/rfc7230#section-5.3
|
||||
// https://stackoverflow.com/questions/40311306/when-is-absoluteuri-used-from-the-http-request-specs
|
||||
tmp = ::trim(sline[1], ' ');
|
||||
tmp = ::trim(tmp, '\r');
|
||||
_request.path = tmp;
|
||||
// http version
|
||||
tmp = ::trim(sline[2], ' ');
|
||||
tmp = ::trim(tmp, '\r');
|
||||
_request.version = tmp;
|
||||
}
|
||||
|
||||
void Client::_parse_request_headers( std::vector<std::string> list )
|
||||
{
|
||||
std::string key;
|
||||
std::string val;
|
||||
std::vector<std::string>::iterator it;
|
||||
size_t pos;
|
||||
|
||||
for (it = list.begin(); it != list.end(); it++)
|
||||
{
|
||||
pos = (*it).find(':');
|
||||
key = (*it).substr( 0, pos );
|
||||
key = ::trim(key, ' ');
|
||||
key = ::trim(key, '\r');
|
||||
val = (*it).substr( pos + 1 );
|
||||
val = ::trim(val, ' ');
|
||||
val = ::trim(val, '\r');
|
||||
_request.headers.insert( std::pair<std::string, std::string>(key, val) );
|
||||
}
|
||||
}
|
||||
|
||||
void Client::_parse_request_body( size_t pos )
|
||||
{
|
||||
std::string body = &raw_request[pos];
|
||||
|
||||
_request.body = body;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,24 +5,45 @@
|
||||
# include <iostream>
|
||||
# include <string>
|
||||
# include <map>
|
||||
# include <vector>
|
||||
# include "utils.hpp"
|
||||
|
||||
struct Request
|
||||
{
|
||||
std::map<std::string, std::string> headers;
|
||||
std::string method;
|
||||
std::string path;
|
||||
std::string version;
|
||||
std::string body;
|
||||
};
|
||||
|
||||
class Client
|
||||
{
|
||||
public:
|
||||
// Client(Placeholder);
|
||||
// Client();
|
||||
// Client(Client const &src);
|
||||
// ~Client();
|
||||
// Client &operator=(Client const &rhs);
|
||||
// Client &operator=(int);
|
||||
Client();
|
||||
~Client();
|
||||
//Client(Client const &src);
|
||||
//Client &operator=(Client const &rhs);
|
||||
|
||||
int fd;
|
||||
std::string raw_request;
|
||||
std::map<std::string, std::string> request;
|
||||
int fd;
|
||||
std::string raw_request;
|
||||
std::string response;
|
||||
unsigned int status;
|
||||
|
||||
// private:
|
||||
std::string get_method();
|
||||
std::string get_path();
|
||||
std::string get_version();
|
||||
std::string get_body();
|
||||
std::string get_headers(std::string key);
|
||||
|
||||
void parse_request();
|
||||
|
||||
private:
|
||||
struct Request _request;
|
||||
|
||||
void _parse_request_line( std::string rline );
|
||||
void _parse_request_headers( std::vector<std::string> list );
|
||||
void _parse_request_body( size_t pos );
|
||||
|
||||
};
|
||||
|
||||
|
||||
21
srcs/Server.hpp
Normal file
21
srcs/Server.hpp
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
#ifndef SERVER_HPP
|
||||
# define SERVER_HPP
|
||||
|
||||
# include <iostream>
|
||||
# include <string>
|
||||
|
||||
class Server
|
||||
{
|
||||
public:
|
||||
// Server(Placeholder);
|
||||
// Server();
|
||||
// Server(Server const &src);
|
||||
// ~Server();
|
||||
// Server &operator=(Server const &rhs);
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,14 +1,3 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* ServerConfig.hpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: me <erlazo@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/07/23 15:55:16 by me #+# #+# */
|
||||
/* Updated: 2022/07/23 16:19:43 by me ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef SERVERCONFIG_HPP
|
||||
# define SERVERCONFIG_HPP
|
||||
@@ -68,8 +57,6 @@ public:
|
||||
// int redirect_status;
|
||||
// std::string redirect_uri;
|
||||
|
||||
|
||||
|
||||
void print_all()
|
||||
{
|
||||
std::cout << "PRINTING A FULL SERVER CONFIG\n\n";
|
||||
@@ -100,18 +87,7 @@ public:
|
||||
|
||||
std::cout << "\n----------\n";
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -77,9 +77,9 @@ class Webserv
|
||||
|
||||
private:
|
||||
int _epfd;
|
||||
std::vector<int> _listen_sockets;
|
||||
std::vector<int> _listen_sockets;
|
||||
std::vector<ServerConfig> _servers;
|
||||
std::vector<Client> _clients;
|
||||
std::vector<Client> _clients;
|
||||
|
||||
// accept.cpp
|
||||
void _accept_connection(int fd);
|
||||
@@ -92,6 +92,13 @@ class Webserv
|
||||
void _construct_response(Client *client);
|
||||
void _insert_status_line(Client *client);
|
||||
void _get_ressource(Client *client);
|
||||
// cgi_script.cpp
|
||||
bool _is_cgi(Client *client);
|
||||
void _exec_cgi(Client *client);
|
||||
void _construct_client(Client *client);
|
||||
char** _set_env(Client *client);
|
||||
char* _dup_env(std::string var, std::string val);
|
||||
void _exec_script(Client *client, char **env);
|
||||
// epoll_update.cpp
|
||||
int _epoll_update(int fd, uint32_t events, int op);
|
||||
int _epoll_update(int fd, uint32_t events, int op, void *ptr);
|
||||
|
||||
447
srcs/Webserv_hugo.cpp
Normal file
447
srcs/Webserv_hugo.cpp
Normal file
@@ -0,0 +1,447 @@
|
||||
|
||||
#include "Webserv.hpp"
|
||||
|
||||
int g_last_signal;
|
||||
bool g_run;
|
||||
void signal_handler(int signum)
|
||||
{
|
||||
g_last_signal = signum;
|
||||
}
|
||||
|
||||
Webserv::Webserv()
|
||||
{
|
||||
std::cerr << "Server init\n";
|
||||
|
||||
_epfd = ::epoll_create1(0); // (EPOLL_CLOEXEC) for CGI fork ?
|
||||
if (_epfd == -1)
|
||||
{
|
||||
std::perror("err epoll_create1()");
|
||||
throw std::runtime_error("Epoll init");
|
||||
}
|
||||
|
||||
std::signal(SIGPIPE, signal_handler);
|
||||
std::signal(SIGINT, signal_handler);
|
||||
}
|
||||
|
||||
/* Webserv::Webserv(Webserv const &src)
|
||||
{
|
||||
|
||||
} */
|
||||
|
||||
Webserv::~Webserv()
|
||||
{
|
||||
close(_socket_fd);
|
||||
close(_epfd);
|
||||
_close_all_clients();
|
||||
std::cerr << "Server destroyed\n";
|
||||
}
|
||||
|
||||
/* Webserv & Webserv::operator=(Webserv const &rhs)
|
||||
{
|
||||
|
||||
} */
|
||||
|
||||
///////////////
|
||||
// Functions //
|
||||
|
||||
void Webserv::init_virtual_servers() // ADD config param
|
||||
{
|
||||
_socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); // (SOCK_CLOEXEC) for CGI fork ?
|
||||
if (_socket_fd == -1)
|
||||
{
|
||||
std::perror("err socket()");
|
||||
throw std::runtime_error("Socket init");
|
||||
}
|
||||
// HUGO ADD
|
||||
// allow socket descriptor to be reuseable
|
||||
int on = 1;
|
||||
if (setsockopt(_socket_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
|
||||
{
|
||||
::perror("setsockopt() failed");
|
||||
throw std::runtime_error("Socket init");
|
||||
}
|
||||
// HUGO ADD END
|
||||
|
||||
_bind(_socket_fd, 4040);
|
||||
_listen(_socket_fd, 512); // 512 arbitrary
|
||||
|
||||
if (_epoll_update(_socket_fd, EPOLLIN, EPOLL_CTL_ADD) == -1)
|
||||
throw std::runtime_error("Socket init");
|
||||
}
|
||||
|
||||
void Webserv::start()
|
||||
{
|
||||
std::cerr << "Server started\n";
|
||||
struct epoll_event events[MAX_EVENTS];
|
||||
int nfds;
|
||||
int i;
|
||||
int count_loop = 0;
|
||||
|
||||
g_run = true;
|
||||
while (g_run)
|
||||
{
|
||||
std::cerr << ++count_loop << "----loop epoll()\n";
|
||||
nfds = ::epoll_wait(_epfd, events, MAX_EVENTS, TIMEOUT);
|
||||
if (nfds == -1)
|
||||
{
|
||||
std::perror("err epoll_wait(): ");
|
||||
throw std::runtime_error("Epoll wait");
|
||||
}
|
||||
else if (nfds == 0)
|
||||
{
|
||||
if (!_clients.empty())
|
||||
{
|
||||
std::cerr << "Timeout " << TIMEOUT << "ms\n";
|
||||
_close_all_clients();
|
||||
}
|
||||
}
|
||||
i = 0;
|
||||
while (i < nfds)
|
||||
{
|
||||
// if ((events[i].data.u32 == SERVER_FD) && (events[i].events & EPOLLIN)) // Dont work, see "SERVER_FD" define
|
||||
if ((events[i].data.fd == _socket_fd) && (events[i].events & EPOLLIN))
|
||||
_accept_connection(events[i].data.fd);
|
||||
else if (events[i].events & EPOLLIN)
|
||||
_read_request(static_cast<Client*>(events[i].data.ptr));
|
||||
else if (events[i].events & EPOLLOUT)
|
||||
_send_response(static_cast<Client*>(events[i].data.ptr));
|
||||
++i;
|
||||
_actual_client = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////
|
||||
// Private Functions //
|
||||
|
||||
void Webserv::_accept_connection(int fd)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
socklen_t addr_len;
|
||||
int accepted_fd;
|
||||
|
||||
std::cerr << "accept()\n";
|
||||
addr_len = sizeof addr;
|
||||
accepted_fd = ::accept(fd, (sockaddr*)&addr, &addr_len);
|
||||
if (accepted_fd == -1)
|
||||
{
|
||||
std::perror("err accept(): ");
|
||||
return ;
|
||||
}
|
||||
::fcntl(accepted_fd, F_SETFL, O_NONBLOCK);
|
||||
|
||||
_clients.push_back(Client());
|
||||
_clients.back().fd = accepted_fd;
|
||||
|
||||
_epoll_update(accepted_fd, EPOLLIN, EPOLL_CTL_ADD, &_clients.back());
|
||||
}
|
||||
|
||||
//////////
|
||||
// READ //
|
||||
void Webserv::_read_request(Client *client)
|
||||
{
|
||||
char buf[BUFSIZE+1];
|
||||
ssize_t ret;
|
||||
_actual_client = client;
|
||||
|
||||
std::cerr << "recv()\n";
|
||||
ret = ::recv(client->fd, buf, BUFSIZE, 0);
|
||||
if (ret == -1)
|
||||
{
|
||||
std::perror("err recv(): ");
|
||||
// if (g_last_signal)
|
||||
// _handle_last_signal();
|
||||
// else
|
||||
// _close_client(client->fd);
|
||||
|
||||
std::cerr << "client ptr =" << client << "\n"; // DEBUG
|
||||
std::cerr << "client.fd =" << client->fd << "\n"; // DEBUG
|
||||
return ;
|
||||
}
|
||||
/*
|
||||
if (ret == BUFSIZE)
|
||||
// send error like "request too long" to client
|
||||
*/
|
||||
|
||||
buf[ret] = '\0';
|
||||
client->raw_request.append(buf);
|
||||
|
||||
// HUGO TMP
|
||||
//
|
||||
_parse_request(client);
|
||||
//
|
||||
// HUGO TMP END
|
||||
|
||||
_epoll_update(client->fd, EPOLLOUT, EPOLL_CTL_MOD, client);
|
||||
}
|
||||
|
||||
///////////
|
||||
// WRITE //
|
||||
void Webserv::_send_response(Client *client)
|
||||
{
|
||||
ssize_t ret;
|
||||
_actual_client = client;
|
||||
|
||||
std::cerr << "send()\n";
|
||||
std::cerr << "RAW_REQUEST\n|\n" << client->raw_request << "|\n";
|
||||
|
||||
|
||||
// TMP HUGO test cgi
|
||||
//
|
||||
// if "POST" found in _buf, execve a cgi
|
||||
if (client->raw_request.find("POST") != std::string::npos)
|
||||
_exec_cgi_script(client);
|
||||
// if "index.html" found in _buf, send the page
|
||||
if (client->raw_request.find("index.html") != std::string::npos)
|
||||
_serve_file(client, "index.html");
|
||||
//
|
||||
// TMP HUGO end test cgi
|
||||
|
||||
|
||||
ret = ::send(client->fd, MSG_TEST, sizeof MSG_TEST - 1, 0);
|
||||
if (ret == -1)
|
||||
{
|
||||
std::perror("err send(): ");
|
||||
if (g_last_signal)
|
||||
_handle_last_signal();
|
||||
// else
|
||||
// _close_client(client->fd);
|
||||
return ;
|
||||
}
|
||||
|
||||
_close_client(client->fd);
|
||||
// if (client->raw_request.find("Connection: keep-alive") == std::string::npos)
|
||||
// _close_client(client->fd);
|
||||
// else
|
||||
// _epoll_update(client->fd, EPOLLIN, EPOLL_CTL_MOD, client);
|
||||
|
||||
client->raw_request.clear();
|
||||
}
|
||||
|
||||
|
||||
////////////////////
|
||||
// Misc functions //
|
||||
|
||||
int Webserv::_epoll_update(int fd, uint32_t events, int op)
|
||||
{
|
||||
struct epoll_event ev;
|
||||
std::memset(&ev, 0, sizeof ev);
|
||||
ev.events = events;
|
||||
ev.data.fd = fd;
|
||||
if (::epoll_ctl(_epfd, op, fd, &ev) == -1)
|
||||
{
|
||||
std::perror("err _epoll_update(): ");
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
// TMP HUGO
|
||||
//
|
||||
void _parse_request(Client *client)
|
||||
{
|
||||
std::string request = client->raw_request;
|
||||
std::map<std::string, std::string> field = client->request;
|
||||
// size_t size = request.size();
|
||||
size_t begin = 0;
|
||||
size_t end;
|
||||
size_t len;
|
||||
|
||||
// std::string str ("test un: deux\ntest deux: trois quatre\ntest :trois quatre cinq");
|
||||
// std::string sub;
|
||||
|
||||
std::cout << str << "\n\n";
|
||||
|
||||
int i = 0;
|
||||
while (end != std::string::npos)
|
||||
{
|
||||
// find first portion, before ':'
|
||||
end = str.find(':', begin);
|
||||
len = end - begin;
|
||||
if (end == std::string::npos)
|
||||
len = end;
|
||||
sub = str.substr(begin, len);
|
||||
std::cout << i << "|" << sub << "\n";
|
||||
// std::cout << "[begin:" << begin << " - end:" << end << " - len:" << len << "] " << sub << "\n";
|
||||
begin = end + 1;
|
||||
|
||||
// find second portion, until '\n'
|
||||
end = str.find('\n', begin);
|
||||
len = end - begin;
|
||||
if (end == std::string::npos)
|
||||
len = end;
|
||||
sub = str.substr(begin, len);
|
||||
std::cout << i << "|" << sub << "\n";
|
||||
begin = end + 1;
|
||||
i++;
|
||||
}
|
||||
|
||||
// for (size_t i = 0; i < size; i++)
|
||||
// {
|
||||
// field.insert(request);
|
||||
// }
|
||||
|
||||
// GET /home.html HTTP/1.1
|
||||
// Host: developer.mozilla.org
|
||||
// User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:50.0) Gecko/20100101 Firefox/50.0
|
||||
// Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
|
||||
// Accept-Language: en-US,en;q=0.5
|
||||
// Accept-Encoding: gzip, deflate, br
|
||||
// Referer: https://developer.mozilla.org/testpage.html
|
||||
// Connection: keep-alive
|
||||
// Upgrade-Insecure-Requests: 1
|
||||
// If-Modified-Since: Mon, 18 Jul 2016 02:36:04 GMT
|
||||
// If-None-Match: "c561c68d0ba92bbeb8b0fff2a9199f722e3a621a"
|
||||
// Cache-Control: max-age=0
|
||||
|
||||
}
|
||||
void Webserv::_serve_file(Client *client, std::string page)
|
||||
{
|
||||
int page_fd;
|
||||
std::string to_send;
|
||||
std::string end_header = "\r\n\r\n";
|
||||
std::string body;
|
||||
std::stringstream strs;
|
||||
char buffer[1];
|
||||
|
||||
to_send = "HTTP/1.1 200 OK\n";
|
||||
to_send += "Content-Type: text/html;\n";
|
||||
to_send += "Content-Length: ";
|
||||
page_fd = open(page.c_str(), O_RDONLY);
|
||||
for (int ret = 1; ret > 0;)
|
||||
{
|
||||
ret = read(page_fd, buffer, 1);
|
||||
body += buffer;
|
||||
}
|
||||
strs << body.size();
|
||||
to_send += strs.str();
|
||||
to_send += end_header;
|
||||
to_send += body;
|
||||
if (::send(client->fd, to_send.c_str(), to_send.size(), 0) == -1)
|
||||
std::perror("err send()");
|
||||
}
|
||||
void Webserv::_exec_cgi_script(Client *client)
|
||||
{
|
||||
int save_stdout;
|
||||
char** env = new char*[5];
|
||||
char * const * nll = NULL;
|
||||
|
||||
// set env
|
||||
env[0] = strdup("PATH_INFO=/no");
|
||||
env[1] = strdup("REQUEST_METHOD=POST");
|
||||
env[2] = strdup("SERVER_PROTOCOL=HTTP/1.1");
|
||||
env[3] = strdup("CONTENT_LENGTH=665");
|
||||
env[4] = NULL;
|
||||
// save STDOUT
|
||||
save_stdout = dup(STDOUT_FILENO);
|
||||
// inside child process
|
||||
if (fork() == 0)
|
||||
{
|
||||
dup2(client->fd, STDOUT_FILENO);
|
||||
// execve("./srcs/cgi-bin/cgi_cpp.cgi", nll, env);
|
||||
execve("./srcs/cgi-bin/php-cgi", nll, env);
|
||||
}
|
||||
// inside parent process
|
||||
else
|
||||
waitpid(-1, NULL, 0);
|
||||
// restore stdout
|
||||
dup2(save_stdout, STDOUT_FILENO);
|
||||
}
|
||||
//
|
||||
// END TMP HUGO
|
||||
|
||||
int Webserv::_epoll_update(int fd, uint32_t events, int op, void *ptr)
|
||||
{
|
||||
struct epoll_event ev;
|
||||
std::memset(&ev, 0, sizeof ev);
|
||||
ev.events = events;
|
||||
ev.data.ptr = ptr;
|
||||
if (::epoll_ctl(_epfd, op, fd, &ev) == -1)
|
||||
{
|
||||
std::perror("err _epoll_update(): ");
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
void Webserv::_handle_last_signal()
|
||||
{
|
||||
if (g_last_signal == SIGPIPE)
|
||||
{
|
||||
std::cerr << "SIGPIPE\n";
|
||||
if (_actual_client)
|
||||
{
|
||||
_close_client(_actual_client->fd);
|
||||
_actual_client = NULL;
|
||||
}
|
||||
}
|
||||
else if (g_last_signal == SIGINT)
|
||||
{
|
||||
g_run = false;
|
||||
}
|
||||
g_last_signal = 0;
|
||||
}
|
||||
|
||||
void Webserv::_close_client(int fd)
|
||||
{
|
||||
std::vector<Client>::iterator it = _clients.begin();
|
||||
while (it != _clients.end())
|
||||
{
|
||||
if (it->fd == fd)
|
||||
{
|
||||
// _epoll_update(fd, 0, EPOLL_CTL_DEL); // normalement superflu, DEBUG
|
||||
if (::close(fd) == -1)
|
||||
std::perror("err close(): ");
|
||||
else
|
||||
std::cerr << "close fd " << fd << "\n";
|
||||
_clients.erase(it);
|
||||
break;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void Webserv::_close_all_clients()
|
||||
{
|
||||
while (!_clients.empty())
|
||||
{
|
||||
// _epoll_update(_clients.back().fd, 0, EPOLL_CTL_DEL); // normalement superflu, DEBUG
|
||||
if (::close(_clients.back().fd) == -1)
|
||||
std::perror("err close(): ");
|
||||
else
|
||||
std::cerr << "close fd " << _clients.back().fd << "\n";
|
||||
_clients.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////
|
||||
// Init functions //
|
||||
|
||||
void Webserv::_bind(int socket_fd, in_port_t port)
|
||||
{
|
||||
// cast invalid ? how to ?
|
||||
// const struct sockaddr* cast_test = static_cast<const struct sockaddr*>(addr);
|
||||
|
||||
struct sockaddr_in addr;
|
||||
std::memset(&addr, 0, sizeof addr);
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = ::htons(port);
|
||||
addr.sin_addr.s_addr = ::htonl(INADDR_ANY); // htonl useless with 0 value (INADDR_ANY) ?
|
||||
|
||||
if (::bind(socket_fd, (const sockaddr*)&addr, sizeof addr) == -1)
|
||||
{
|
||||
std::perror("err bind(): ");
|
||||
throw std::runtime_error("Socket bind");
|
||||
}
|
||||
}
|
||||
|
||||
void Webserv::_listen(int socket_fd, unsigned int max_connections)
|
||||
{
|
||||
if (::listen(socket_fd, max_connections) == -1)
|
||||
{
|
||||
std::perror("err listen(): ");
|
||||
throw std::runtime_error("Socket listen");
|
||||
}
|
||||
}
|
||||
41
srcs/cgi-bin/cgi.cpp
Normal file
41
srcs/cgi-bin/cgi.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
# include <iostream>
|
||||
# include <string>
|
||||
# include <sstream>
|
||||
|
||||
int main (int ac, char **av) {
|
||||
std::string to_send;
|
||||
std::string header;
|
||||
std::string end_header = "\r\n\r\n";
|
||||
std::string response;
|
||||
std::stringstream strs;
|
||||
|
||||
header = "HTTP/1.1 200 OK\n";
|
||||
header += "Content-Type: text/html; charset=UTF-8\n";
|
||||
header += "Content-Length: ";
|
||||
|
||||
response = "<!DOCTYPE html>\n";
|
||||
response += "<html>\n";
|
||||
response += "<head>\n";
|
||||
response += "<title>CGI</title>\n";
|
||||
response += "</head>\n";
|
||||
response += "<body>\n";
|
||||
response += "<h2>CGI request :</h2>\n";
|
||||
for (int i = 1; i < ac; i++)
|
||||
{
|
||||
response += "<p>";
|
||||
response += av[i];
|
||||
response += "</p>\n";
|
||||
}
|
||||
response += "</body>\n";
|
||||
response += "</html>\n";
|
||||
|
||||
strs << response.size();
|
||||
header += strs.str();
|
||||
header += end_header;
|
||||
to_send = header;
|
||||
to_send += response;
|
||||
|
||||
std::cout << to_send;
|
||||
|
||||
return 0;
|
||||
}
|
||||
BIN
srcs/cgi-bin/cgi_cpp.cgi
Executable file
BIN
srcs/cgi-bin/cgi_cpp.cgi
Executable file
Binary file not shown.
29
srcs/cgi-bin/php-cgi
Executable file
29
srcs/cgi-bin/php-cgi
Executable file
@@ -0,0 +1,29 @@
|
||||
#! /usr/bin/php
|
||||
|
||||
<?php
|
||||
echo "BEGIN PHP-CGI\n-----------\n\n";
|
||||
//phpinfo();
|
||||
|
||||
echo "AUTH_TYPE: " . getenv("AUTH_TYPE");
|
||||
echo "\nCONTENT_LENGTH: " . getenv("CONTENT_LENGTH");
|
||||
echo "\nCONTENT_TYPE: " . getenv("CONTENT_TYPE");
|
||||
echo "\nGATEWAY_INTERFACE: " . getenv("GATEWAY_INTERFACE");
|
||||
echo "\nPATH_INFO: " . getenv("PATH_INFO");
|
||||
echo "\nPATH_TRANSLATED: " . getenv("PATH_TRANSLATED");
|
||||
echo "\nQUERY_STRING: " . getenv("QUERY_STRING");
|
||||
echo "\nREMOTE_ADDR: " . getenv("REMOTE_ADDR");
|
||||
echo "\nREMOTE_HOST: " . getenv("REMOTE_HOST");
|
||||
echo "\nREMOTE_IDENT: " . getenv("REMOTE_IDENT");
|
||||
echo "\nREMOTE_USER: " . getenv("REMOTE_USER");
|
||||
echo "\nREQUEST_METHOD: " . getenv("REQUEST_METHOD");
|
||||
echo "\nSCRIPT_NAME: " . getenv("SCRIPT_NAME");
|
||||
echo "\nSERVER_NAME: " . getenv("SERVER_NAME");
|
||||
echo "\nSERVER_PORT: " . getenv("SERVER_PORT");
|
||||
echo "\nSERVER_PROTOCOL: " . getenv("SERVER_PROTOCOL");
|
||||
echo "\nSERVER_SOFTWARE: " . getenv("SERVER_SOFTWARE");
|
||||
echo "\nREDIRECT_STATUS: " . getenv("REDIRECT_STATUS");
|
||||
|
||||
// echo $_POST['REQUEST_METHOD'];
|
||||
echo "\n\n-----------\nEND PHP-CGI\n\n";
|
||||
?>
|
||||
|
||||
13
srcs/ft_itoa.cpp
Normal file
13
srcs/ft_itoa.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
# include <sstream>
|
||||
# include <string.h>
|
||||
|
||||
char* itoa(int n)
|
||||
{
|
||||
std::stringstream strs;
|
||||
char * str;
|
||||
|
||||
strs << n;
|
||||
str = (char*)(strs.str().c_str());
|
||||
return (str);
|
||||
}
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
std::vector<std::string> split(std::string input, char delimiter)
|
||||
{
|
||||
std::vector<std::string> answer;
|
||||
std::stringstream ss(input);
|
||||
std::string temp;
|
||||
std::vector<std::string> answer;
|
||||
std::stringstream ss(input);
|
||||
std::string temp;
|
||||
|
||||
while (getline(ss, temp, delimiter))
|
||||
answer.push_back(temp);
|
||||
@@ -13,6 +13,22 @@ std::vector<std::string> split(std::string input, char delimiter)
|
||||
return answer;
|
||||
}
|
||||
|
||||
std::string trim(std::string str, char c)
|
||||
{
|
||||
str = str.substr(str.find_first_not_of(c));
|
||||
str = str.substr(0, str.find_last_not_of(c) + 1);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string itos(int n)
|
||||
{
|
||||
std::stringstream strs;
|
||||
|
||||
strs << n;
|
||||
return ( strs.str() );
|
||||
}
|
||||
|
||||
bool isNumeric(std::string str)
|
||||
{
|
||||
for (size_t i = 0; i < str.length(); i++)
|
||||
@@ -23,7 +39,6 @@ bool isNumeric(std::string str)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool isNumeric_btw(int low, int high, std::string str)
|
||||
{
|
||||
for (size_t i = 0; i < str.length(); i++)
|
||||
@@ -37,11 +52,3 @@ bool isNumeric_btw(int low, int high, std::string str)
|
||||
return true;
|
||||
}
|
||||
|
||||
char* itoa(int n)
|
||||
{
|
||||
std::stringstream strs;
|
||||
|
||||
strs << n;
|
||||
// casts : https://stackoverflow.com/questions/332030/when-should-static-cast-dynamic-cast-const-cast-and-reinterpret-cast-be-used
|
||||
return ( const_cast<char*>( strs.str().c_str() ) );
|
||||
}
|
||||
|
||||
@@ -5,11 +5,12 @@
|
||||
# include <vector>
|
||||
# include <string>
|
||||
# include <sstream>
|
||||
# include <cstdlib> // atoi (athough it's already cover by <string>)
|
||||
# include <cstdlib> // atoi
|
||||
|
||||
std::vector<std::string> split(std::string input, char delimiter);
|
||||
bool isNumeric(std::string str);
|
||||
bool isNumeric_btw(int low, int high, std::string str);
|
||||
char* itoa(int n);
|
||||
std::string itos(int n);
|
||||
std::string trim(std::string str, char c);
|
||||
|
||||
#endif
|
||||
|
||||
80
srcs/webserv/cgi_script.cpp
Normal file
80
srcs/webserv/cgi_script.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
|
||||
#include "Webserv.hpp"
|
||||
|
||||
bool Webserv::_is_cgi(Client *client)
|
||||
{
|
||||
if (client->get_path().find("/cgi-bin/") != std::string::npos)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void Webserv::_exec_cgi(Client *client)
|
||||
{
|
||||
char** env;
|
||||
|
||||
env = _set_env(client);
|
||||
_exec_script(client, env);
|
||||
// _construct_response(client);
|
||||
}
|
||||
|
||||
char* Webserv::_dup_env(std::string var, std::string val = "")
|
||||
{
|
||||
std::string str;
|
||||
|
||||
str = var + "=" + val;
|
||||
return ( strdup(str.c_str()) );
|
||||
}
|
||||
|
||||
char** Webserv::_set_env(Client *client)
|
||||
{
|
||||
char** env = new char*[19];
|
||||
|
||||
env[0] = _dup_env("AUTH_TYPE");
|
||||
env[1] = _dup_env("CONTENT_LENGTH", "665");
|
||||
env[2] = _dup_env("CONTENT_TYPE");
|
||||
env[3] = _dup_env("GATEWAY_INTERFACE");
|
||||
env[4] = _dup_env("PATH_INFO");
|
||||
env[5] = _dup_env("PATH_TRANSLATED");
|
||||
env[6] = _dup_env("QUERY_STRING");
|
||||
env[7] = _dup_env("REMOTE_ADDR");
|
||||
env[8] = _dup_env("REMOTE_HOST", client->get_headers("Host")); // just test
|
||||
env[9] = _dup_env("REMOTE_IDENT");
|
||||
env[10] = _dup_env("REMOTE_USER");
|
||||
env[11] = _dup_env("REQUEST_METHOD", client->get_method());
|
||||
env[12] = _dup_env("SCRIPT_NAME");
|
||||
env[13] = _dup_env("SERVER_NAME");
|
||||
env[14] = _dup_env("SERVER_PORT");
|
||||
env[15] = _dup_env("SERVER_PROTOCOL", client->get_version());
|
||||
env[16] = _dup_env("SERVER_SOFTWARE");
|
||||
env[17] = _dup_env("REDIRECT_STATUS");
|
||||
env[18] = NULL;
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
void Webserv::_exec_script(Client *client, char **env)
|
||||
{
|
||||
int save_stdout;
|
||||
char * const * nll = NULL;
|
||||
|
||||
// save STDOUT
|
||||
save_stdout = dup(STDOUT_FILENO);
|
||||
// inside child process
|
||||
if (fork() == 0)
|
||||
{
|
||||
dup2(client->fd, STDOUT_FILENO);
|
||||
// execve("./srcs/cgi-bin/cgi_cpp.cgi", nll, client->env);
|
||||
execve("./srcs/cgi-bin/php-cgi", nll, env);
|
||||
}
|
||||
// inside parent process
|
||||
else
|
||||
waitpid(-1, NULL, 0);
|
||||
// restore stdout
|
||||
dup2(save_stdout, STDOUT_FILENO);
|
||||
}
|
||||
|
||||
void Webserv::_construct_client(Client *client)
|
||||
{
|
||||
(void)client;
|
||||
}
|
||||
|
||||
@@ -37,6 +37,8 @@ void Webserv::_read_request(Client *client)
|
||||
|
||||
buf[ret] = '\0';
|
||||
client->raw_request.append(buf);
|
||||
client->parse_request();
|
||||
|
||||
_epoll_update(client->fd, EPOLLOUT, EPOLL_CTL_MOD);
|
||||
}
|
||||
|
||||
|
||||
@@ -86,12 +86,22 @@ void Webserv::_insert_status_line(Client *client)
|
||||
|
||||
#define ROOT "website"
|
||||
#define INDEX "index.html"
|
||||
#define MAX_FILESIZE 1000000 // (1Mo)
|
||||
#define MAX_FILESIZE 1000000 // (1Mo)
|
||||
void Webserv::_get_ressource(Client *client)
|
||||
{
|
||||
std::ifstream ifd; // For chunk, ifstream directly in struct CLient for multiples read without close() ?
|
||||
char buf[MAX_FILESIZE+1];
|
||||
char *tmp;
|
||||
std::ifstream ifd; // For chunk, ifstream directly in struct CLient for multiples read without close() ?
|
||||
char buf[MAX_FILESIZE+1];
|
||||
std::string tmp;
|
||||
|
||||
// TMP HUGO
|
||||
//
|
||||
if (_is_cgi(client))
|
||||
{
|
||||
_exec_cgi(client);
|
||||
return;
|
||||
}
|
||||
//
|
||||
// END TMP HUGO
|
||||
|
||||
// Mini parsing à l'arrache du PATH
|
||||
std::string path;
|
||||
@@ -144,15 +154,16 @@ void Webserv::_get_ressource(Client *client)
|
||||
client->response.append("Content-Type: text/html; charset=UTF-8\r\n");
|
||||
|
||||
client->response.append("Content-Length: ");
|
||||
tmp = ::itoa(ifd.gcount());
|
||||
client->response.append(tmp);
|
||||
|
||||
tmp = ::itos(ifd.gcount());
|
||||
client->response.append(tmp.c_str());
|
||||
client->response.append("\r\n");
|
||||
|
||||
// Body
|
||||
client->response.append("\r\n");
|
||||
client->response.append(buf);
|
||||
|
||||
client->response.append(buf);
|
||||
|
||||
ifd.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -309,4 +309,4 @@ Full stop should appear outside the parentheses in the last sentence.
|
||||
|
||||
|
||||
|
||||
</pre></body></html>
|
||||
</pre></body></html>
|
||||
|
||||
Reference in New Issue
Block a user