4 Commits
hugo ... hugo2

Author SHA1 Message Date
hugogogo
53a548e314 wip script output verification working
+ trim secure pos segfault
+ concat script message with server message
2022-08-09 14:57:05 +02:00
hugogogo
3dad938e3c add extern function for http message parsing
+ wip compare fields server and script
+ g tout cassey
2022-08-09 11:19:46 +02:00
hugogogo
ae9a9b37f1 added test form html in www 2022-08-08 18:22:54 +02:00
hugogogo
e1a68bc3e4 changes var in client 2022-08-08 18:06:41 +02:00
16 changed files with 344 additions and 126 deletions

View File

@@ -5,7 +5,7 @@ CXX = c++
CXXFLAGS = -Wall -Wextra #-Werror CXXFLAGS = -Wall -Wextra #-Werror
CXXFLAGS += $(HEADERS_D:%=-I%) CXXFLAGS += $(HEADERS_D:%=-I%)
CXXFLAGS += -std=c++98 CXXFLAGS += -std=c++98
CXXFLAGS += -g CXXFLAGS += -g3
CXXFLAGS += -MMD -MP #header dependencie CXXFLAGS += -MMD -MP #header dependencie
#CXXFLAGS += -O3 #CXXFLAGS += -O3
@@ -29,6 +29,7 @@ SRCS = main.cpp \
utils.cpp \ utils.cpp \
cgi_script.cpp \ cgi_script.cpp \
Client.cpp \ Client.cpp \
parsing_message_http.cpp \
OBJS_D = builds OBJS_D = builds
OBJS = $(SRCS:%.cpp=$(OBJS_D)/%.o) OBJS = $(SRCS:%.cpp=$(OBJS_D)/%.o)

View File

@@ -1,23 +1,33 @@
## work together ## work together
#### message
- err access line response.cpp:169
- g pas fini la gestion de sortie du cgi (comparaison des headers fields pour supprimer les doublons)
- g rendu independantes les fonctions qui parses un message http (requete ou response) dans `parsing_http_message.cpp`
- il y a une erreur importante dans la fonction qui parse les headers d'un message http : ca ne verifie pas si la premier ligne est un header ou la "first line"
#### TODO
- `_is_cgi()` and `_fill_cgi_path()`
- `_cgi_output()` change status in `client->status`
- two cgi tests :
? - a basic form with "name" and "something", that return a html page with that
? - for GET and POST
? - a script called by a file extension in URI
#### output cgi script : #### output cgi script :
! TODO : change all the '\n' by '\r\n' ! TODO : change all the '\n' by '\r\n'
! TODO : there is at least one header field followed by '\r\n\r\n' : ! TODO : there is at least one header field followed by '\r\n\r\n' :
- "Content-Type" - "Content-Type"
- "Location" - "Location"
- "Status" - "Status"
-> TODO : there is no field duplicate (resolve conflicts)
-> TODO : if status field, change server status for this one
! TODO : there is no space between filed name and ":" ! TODO : there is no space between filed name and ":"
! TODO : if no Location field && no Status field -> status code = 200
! TODO?: handle Location field, either : ! TODO?: handle Location field, either :
- local : start with '/' --> rerun the request with new uri - local : start with '/' --> rerun the request with new uri
- client : start with '<scheme>:' --> send back status code 302 - client : start with '<scheme>:' --> send back status code 302
-> TODO : there is no field duplicate (resolve conflicts)
#### what cgi ? -> TODO : if status field, change server status for this one
- a basic form with "name" and "something", that return a html page with that -> TODO : if no Location field && no Status field -> status code = 200
- a script called by a file extension in URI
#### questions #### questions
- in client.cpp i fill the port, is there a default one in case it's not in the request ? - in client.cpp i fill the port, is there a default one in case it's not in the request ?

View File

@@ -16,6 +16,7 @@ server {
location /board { location /board {
allow_methods GET; allow_methods GET;
root ./www/html; root ./www/html;
cgi_ext php cgi
} }
location /board/content { location /board/content {

View File

@@ -36,10 +36,10 @@ Client::~Client() {
Client::Client( Client const & src ) Client::Client( Client const & src )
: body_size(0) : body_size(0)
, status(0) , status(0)
, _fd ( src.get_cl_fd() ) , _fd ( src._fd )
, _port ( src.get_cl_port() ) , _port ( src._port )
, _ip ( src.get_cl_ip() ) , _ip ( src._ip )
, _lsocket ( src.get_cl_lsocket() ) , _lsocket ( src._lsocket )
{ {
raw_request = src.raw_request; raw_request = src.raw_request;
response = src.response; response = src.response;
@@ -70,22 +70,15 @@ Client & Client::operator=( Client const & rhs )
// https://www.tutorialspoint.com/http/http_requests.htm // https://www.tutorialspoint.com/http/http_requests.htm
void Client::parse_request() void Client::parse_request()
{ {
std::string sub; std::map<std::string, std::string> headers;
std::vector<std::string> list; std::string body;
size_t pos;
// DEBUG // DEBUG
std::cout << "\nREQUEST _____________________\n" std::cout << "\nREQUEST ____________\n" << raw_request << "\n_____________\n";
<< raw_request
<< "\n\n";
pos = (raw_request).find(CRLF CRLF); _parse_request_line();
sub = (raw_request).substr(0, pos); _parse_request_headers();
list = split(sub, '\n'); _parse_request_body();
_parse_request_line(*list.begin());
list.erase(list.begin());
_parse_request_headers(list);
_parse_request_body(pos + 4);
_parse_port_hostname(this->get_rq_headers("Host")); _parse_port_hostname(this->get_rq_headers("Host"));
raw_request.clear(); raw_request.clear();
} }
@@ -143,10 +136,10 @@ void Client::clear_script()
*********************************************/ *********************************************/
// client side // client side
int Client::get_cl_fd() const { return _fd; } int Client::get_cl_fd() const { return _fd; }
const std::string &Client::get_cl_ip() const { return _ip; } const std::string & Client::get_cl_ip() const { return _ip; }
const std::string &Client::get_cl_port() const { return _port; } const std::string & Client::get_cl_port() const { return _port; }
const listen_socket *Client::get_cl_lsocket() const { return _lsocket; } const listen_socket * Client::get_cl_lsocket() const { return _lsocket; }
// requette // requette
http_method Client::get_rq_method() const { return _request.method; } http_method Client::get_rq_method() const { return _request.method; }
@@ -176,30 +169,24 @@ std::string Client::get_rq_headers(const std::string & key) const
* PRIVATE MEMBER FUNCTIONS * PRIVATE MEMBER FUNCTIONS
*********************************************/ *********************************************/
void Client::_parse_request_line( std::string rline ) void Client::_parse_request_line()
{ {
std::vector<std::string> sline; std::vector<std::string> line;
std::string tmp; int ret;
sline = split(rline, ' '); ret = ::parse_http_first_line(raw_request, line);
if (sline.size() != 3) if (ret != 3)
{ {
std::cerr << "err _parse_request_line(): "; std::cerr << "err _parse_first_line(): wrong number of elements (" << ret << " instead of 3)\n";
throw std::runtime_error("bad request-line header"); status = 400; // "bad request"
}
else
{
_request.method = str_to_http_method(line[0]);
_request.uri = line[1];
_parse_request_uri(line[1]);
_request.version = line[2];
} }
// method
tmp = ::trim(sline[0], ' ');
tmp = ::trim(tmp, '\r');
_request.method = str_to_http_method(tmp);
// uri
tmp = ::trim(sline[1], ' ');
tmp = ::trim(tmp, '\r');
_request.uri = tmp;
_parse_request_uri( tmp );
// http version
tmp = ::trim(sline[2], ' ');
tmp = ::trim(tmp, '\r');
_request.version = tmp;
} }
void Client::_parse_request_uri( std::string uri ) void Client::_parse_request_uri( std::string uri )
@@ -214,32 +201,16 @@ void Client::_parse_request_uri( std::string uri )
_request.abs_path = uri.substr(0, pos); _request.abs_path = uri.substr(0, pos);
} }
void Client::_parse_request_headers( std::vector<std::string> list ) void Client::_parse_request_headers()
{ {
std::string key; // TODO: check error and adjust status
std::string val; _request.headers = ::parse_http_headers(raw_request);
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');
key = ::str_tolower(key);
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 ) void Client::_parse_request_body()
{ {
std::string body = &raw_request[pos]; // TODO: check error and adjust status
_request.body = ::parse_http_body(raw_request);
_request.body = body;
} }
void Client::_parse_port_hostname(std::string host) void Client::_parse_port_hostname(std::string host)
@@ -247,10 +218,7 @@ void Client::_parse_port_hostname(std::string host)
size_t pos; size_t pos;
if (host == "") if (host == "")
{
std::cerr << "no host\n"; std::cerr << "no host\n";
throw std::runtime_error("no host in request");
}
pos = host.find(':'); pos = host.find(':');
// port : // port :

View File

@@ -7,9 +7,10 @@
# include <map> # include <map>
# include <vector> # include <vector>
# include <string.h> // strdup # include <string.h> // strdup
# include "utils.hpp"
# include <netinet/in.h> // sockaddr_in, struct in_addr # include <netinet/in.h> // sockaddr_in, struct in_addr
# include <arpa/inet.h> // htonl, htons, ntohl, ntohs, inet_addr, inet_ntoa # include <arpa/inet.h> // htonl, htons, ntohl, ntohs, inet_addr, inet_ntoa
# include "utils.hpp"
# include "parsing_message_http.hpp"
struct Script struct Script
{ {
@@ -74,16 +75,16 @@ class Client
bool fill_script_path(std::string script); bool fill_script_path(std::string script);
private: private:
const int _fd; int _fd;
const std::string _port; std::string _port;
const std::string _ip; std::string _ip;
const listen_socket * _lsocket; listen_socket * _lsocket;
struct Request _request; struct Request _request;
void _parse_request_line( std::string rline ); void _parse_request_line();
void _parse_request_headers();
void _parse_request_body();
void _parse_request_uri( std::string uri ); void _parse_request_uri( std::string uri );
void _parse_request_headers( std::vector<std::string> list );
void _parse_request_body( size_t pos );
void _parse_port_hostname(std::string host); void _parse_port_hostname(std::string host);
}; };

View File

@@ -1,9 +1,9 @@
#! /usr/bin/php #! /usr/bin/php
<?php <?php
echo "Status: 200\r\n";
echo "\r\n";
echo "BEGIN PHP-CGI\n-----------\n\n"; echo "BEGIN PHP-CGI\n-----------\n\n";
//phpinfo();
echo "AUTH_TYPE: " . getenv("AUTH_TYPE"); echo "AUTH_TYPE: " . getenv("AUTH_TYPE");
echo "\nCONTENT_LENGTH: " . getenv("CONTENT_LENGTH"); echo "\nCONTENT_LENGTH: " . getenv("CONTENT_LENGTH");
echo "\nCONTENT_TYPE: " . getenv("CONTENT_TYPE"); echo "\nCONTENT_TYPE: " . getenv("CONTENT_TYPE");

View File

@@ -15,8 +15,19 @@ std::vector<std::string> split(std::string input, char delimiter)
std::string trim(std::string str, char c) std::string trim(std::string str, char c)
{ {
str = str.substr(str.find_first_not_of(c)); size_t pos;
str = str.substr(0, str.find_last_not_of(c) + 1);
// delete leadings c
pos = str.find_first_not_of(c);
if (pos == std::string::npos)
return str;
str = str.substr(pos);
// delete endings c
pos = str.find_last_not_of(c);
if (pos == std::string::npos)
return str;
str = str.substr(0, pos + 1);
return str; return str;
} }
@@ -100,15 +111,37 @@ void replace_all_substr(std::string &str, const std::string &ori_substr, const s
} }
} }
bool operator==(const listen_socket& lhs, int fd)
{ return lhs.fd == fd; }
bool operator==(int fd, const listen_socket& rhs)
{ return fd == rhs.fd; }
std::string str_tolower(std::string str) std::string str_tolower(std::string str)
{ {
std::transform(str.begin(), str.end(), str.begin(), ::tolower); std::transform(str.begin(), str.end(), str.begin(), ::tolower);
return str; return str;
} }
void del_line_in_str(std::string * str, size_t pos, std::string delim)
{
size_t begin;
size_t end;
begin = (*str).rfind(delim, pos);
if (begin == std::string::npos)
begin = 0;
else
begin += delim.size();
end = (*str).find(delim, pos);
if (end == std::string::npos)
end = 0;
else
end += delim.size();
(*str).erase(begin, end - begin);
}
bool operator==(const listen_socket& lhs, int fd)
{ return lhs.fd == fd; }
bool operator==(int fd, const listen_socket& rhs)
{ return fd == rhs.fd; }

View File

@@ -49,5 +49,6 @@ http_method str_to_http_method(std::string &str);
std::string http_methods_to_str(unsigned int methods); std::string http_methods_to_str(unsigned int methods);
void replace_all_substr(std::string &str, const std::string &ori_substr, const std::string &new_substr); void replace_all_substr(std::string &str, const std::string &ori_substr, const std::string &new_substr);
std::string str_tolower(std::string str); std::string str_tolower(std::string str);
void del_line_in_str(std::string * str, size_t pos, std::string delim);
#endif #endif

View File

@@ -32,7 +32,7 @@
extern bool g_run; extern bool g_run;
extern int g_last_signal; extern int g_last_signal;
void signal_handler(int signum); void signal_handler(int signum);
// these might only be TMP // these might only be TMP
# define FAILURE -1 # define FAILURE -1
@@ -93,14 +93,16 @@ class Webserv
ServerConfig &_determine_process_server(Client *client); ServerConfig &_determine_process_server(Client *client);
LocationConfig &_determine_location(ServerConfig &server, std::string const &path); LocationConfig &_determine_location(ServerConfig &server, std::string const &path);
void _response_correction(Client *client);
// cgi_script.cpp // cgi_script.cpp
bool _is_cgi(Client *client); bool _is_cgi(Client *client);
void _exec_cgi(Client *client); std::string _exec_cgi(Client *client);
char** _set_env(Client *client); char** _set_env(Client *client);
char* _dup_env(std::string var, std::string val); char* _dup_env(std::string var, std::string val);
char* _dup_env(std::string var, int i); char* _dup_env(std::string var, int i);
void _exec_script(Client *client, char **env); std::string _exec_script(Client *client, char **env);
void _check_script_output(Client *client, std::string output);
void _check_script_status(Client *client, std::string output);
void _check_script_fields(Client *client, std::string output);
// epoll_update.cpp // epoll_update.cpp
int _epoll_update(int fd, uint32_t events, int op); int _epoll_update(int fd, uint32_t events, int op);
int _epoll_update(int fd, uint32_t events, int op, void *ptr); int _epoll_update(int fd, uint32_t events, int op, void *ptr);
@@ -115,6 +117,7 @@ class Webserv
void _listen(int socket_fd, unsigned int max_connections); void _listen(int socket_fd, unsigned int max_connections);
void _init_http_status_map(); void _init_http_status_map();
void _init_mime_types_map(); void _init_mime_types_map();
}; };
#endif #endif

View File

@@ -11,16 +11,19 @@ bool Webserv::_is_cgi(Client *client)
return false; return false;
} }
void Webserv::_exec_cgi(Client *client) std::string Webserv::_exec_cgi(Client *client)
{ {
char** env; char** env;
std::string script_output;
env = _set_env(client); env = _set_env(client);
_exec_script(client, env); script_output = _exec_script(client, env);
for (int i = 0; env[i]; i++) for (int i = 0; env[i]; i++)
delete[] env[i]; delete[] env[i];
delete[] env; delete[] env;
return script_output;
} }
char* Webserv::_dup_env(std::string var, std::string val = "") char* Webserv::_dup_env(std::string var, std::string val = "")
@@ -49,7 +52,7 @@ char** Webserv::_set_env(Client *client)
env[0] = _dup_env("AUTH_TYPE"); // authentification not supported env[0] = _dup_env("AUTH_TYPE"); // authentification not supported
env[1] = _dup_env("CONTENT_LENGTH" , client->get_rq_body().size()); env[1] = _dup_env("CONTENT_LENGTH" , client->get_rq_body().size());
env[2] = _dup_env("CONTENT_TYPE" , client->get_rq_headers("Content-Type")); env[2] = _dup_env("CONTENT_TYPE" , client->get_rq_headers("Content-Type"));
env[3] = _dup_env("GATEWAY_INTERFACE" , "CGI/1.0"); env[3] = _dup_env("GATEWAY_INTERFACE" , "CGI/1.1"); // https://www.rfc-editor.org/rfc/rfc3875
env[4] = _dup_env("PATH_INFO" , client->get_rq_script_info()); env[4] = _dup_env("PATH_INFO" , client->get_rq_script_info());
env[5] = _dup_env("PATH_TRANSLATED"); // not supported env[5] = _dup_env("PATH_TRANSLATED"); // not supported
env[6] = _dup_env("QUERY_STRING" , client->get_rq_query()); env[6] = _dup_env("QUERY_STRING" , client->get_rq_query());
@@ -69,7 +72,7 @@ char** Webserv::_set_env(Client *client)
return env; return env;
} }
void Webserv::_exec_script(Client *client, char **env) std::string Webserv::_exec_script(Client *client, char **env)
{ {
#define RD 0 #define RD 0
#define WR 1 #define WR 1
@@ -82,7 +85,7 @@ void Webserv::_exec_script(Client *client, char **env)
pid_t pid; pid_t pid;
char buf[CGI_BUF_SIZE]; // WIP define buffer char buf[CGI_BUF_SIZE]; // WIP define buffer
char * const * nll = NULL; char * const * nll = NULL;
std::string response; std::string script_output;
std::string body = client->get_rq_body(); std::string body = client->get_rq_body();
int fd_in[2]; int fd_in[2];
int fd_out[2]; int fd_out[2];
@@ -99,7 +102,11 @@ void Webserv::_exec_script(Client *client, char **env)
close(FD_RD_FR_CHLD); close(FD_RD_FR_CHLD);
dup2(FD_RD_FR_PRNT, STDIN_FILENO); dup2(FD_RD_FR_PRNT, STDIN_FILENO);
dup2(FD_WR_TO_PRNT, STDOUT_FILENO); dup2(FD_WR_TO_PRNT, STDOUT_FILENO);
// DEBUG
std::cerr << "execve:\n";
execve(client->get_rq_script_path().c_str(), nll, env); execve(client->get_rq_script_path().c_str(), nll, env);
// for tests execve crash :
//execve("wrong", nll, env);
std::cerr << "execve crashed.\n"; std::cerr << "execve crashed.\n";
} }
else else
@@ -113,19 +120,59 @@ void Webserv::_exec_script(Client *client, char **env)
memset(buf, '\0', CGI_BUF_SIZE); memset(buf, '\0', CGI_BUF_SIZE);
while (read(FD_RD_FR_CHLD, buf, CGI_BUF_SIZE - 1) > 0) while (read(FD_RD_FR_CHLD, buf, CGI_BUF_SIZE - 1) > 0)
{ {
response += buf; script_output += buf;
memset(buf, '\0', CGI_BUF_SIZE); memset(buf, '\0', CGI_BUF_SIZE);
} }
close(FD_RD_FR_CHLD);
}
if (script_output.empty())
script_output = "Status: 500\r\n\r\n";
return script_output;
}
void Webserv::_check_script_output(Client *client, std::string output)
{
// TODO: it doesn't work with execve error, i don't know why yet ?
_check_script_status(client, output);
_check_script_fields(client, output);
}
void Webserv::_check_script_status(Client *client, std::string output)
{
size_t pos;
int status_pos;
pos = output.find("Status:");
if (pos != std::string::npos)
{
status_pos = pos + std::string("Status:").size();
client->status = atoi(output.c_str() + status_pos);
::del_line_in_str(&output, pos, CRLF);
}
client->status = 200;
}
void Webserv::_check_script_fields(Client *client, std::string output)
{
std::map<std::string, std::string> srv_fld; // server_field
std::map<std::string, std::string> scr_fld; // script_field
std::map<std::string, std::string>::iterator it_srv;
std::map<std::string, std::string>::iterator it_scr;
size_t pos;
srv_fld = parse_http_headers(client->response);
scr_fld = parse_http_headers(output);
// wip: compare both map to supress duplicates
for (it_srv = srv_fld.begin(); it_srv != srv_fld.end(); it_srv++)
{
for (it_scr = scr_fld.begin(); it_scr != scr_fld.end(); it_scr++)
{
if (it_srv->first == it_scr->first)
{
pos = client->response.find(it_srv->first);
::del_line_in_str(&client->response, pos, CRLF);
}
}
} }
if (response.empty())
response = "Status: 500\r\n\r\n";
// DEBUG
std::cout << "\n_______response_______\n"
<< response
<< "\n_____end response_____\n";
// TODO: see how this must be handled
client->response += response;
} }

View File

@@ -0,0 +1,90 @@
#include "parsing_message_http.hpp"
size_t
parse_http_first_line(std::string message, std::vector<std::string> &line)
{
std::vector<std::string> sline;
std::string sub;
std::string tmp;
size_t pos;
size_t ret;
// TODO: check for err in substr
pos = message.find(CRLF);
sub = message.substr(0, pos);
sline = ::split(sub, ' ');
ret = sline.size();
if (ret != 3)
return ret;
for (int i = 0; i < 3; i++)
{
tmp = ::trim(sline[i], ' ');
tmp = ::trim(tmp, '\r');
line.push_back(tmp);
}
return ret;
}
std::map<std::string, std::string>
parse_http_headers(std::string message)
{
std::map<std::string, std::string> headers;
std::vector<std::string> list;
std::vector<std::string>::iterator it;
std::string sub;
std::string key;
std::string val;
size_t pos;
pos = (message).find(CRLF CRLF);
sub = (message).substr(0, pos);
list = ::split(sub, '\n');
if ( maybe_http_first_line( *list.begin() ) )
list.erase(list.begin());
for (it = list.begin(); it != list.end(); it++)
{
// TODO: if pattern is not "NAME: value" return error
pos = (*it).find(':');
key = (*it).substr( 0, pos );
key = ::trim(key, ' ');
key = ::trim(key, '\r');
key = ::str_tolower(key);
val = (*it).substr( pos + 1 );
val = ::trim(val, ' ');
val = ::trim(val, '\r');
headers.insert( std::pair<std::string, std::string>(key, val) );
}
return headers;
}
std::string
parse_http_body(std::string message)
{
std::string body;
size_t pos;
pos = message.find(CRLF CRLF);
pos += std::string(CRLF CRLF).size();
// TODO: copying just like that might fail in case of binary or images
body = message.substr(pos);
return body;
}
bool maybe_http_first_line(std::string str)
{
// method SP target SP version https://www.rfc-editor.org/rfc/rfc7230.html#section-3.1.1
// version SP status SP reason https://www.rfc-editor.org/rfc/rfc7230.html#section-3.1.2
std::vector<std::string> sline;
sline = ::split(str, ' ');
if (sline.size() != 3)
return false;
if (sline[0].find(':') != std::string::npos)
return false;
return true;
}

View File

@@ -0,0 +1,36 @@
#ifndef PARSING_MESSAGE_HTTP_HPP
# define PARSING_MESSAGE_HTTP_HPP
# include <iostream>
# include <string>
# include <vector>
# include <map>
# include "utils.hpp"
size_t
parse_http_first_line(std::string message, std::vector<std::string> &line);
std::map<std::string, std::string>
parse_http_headers(std::string message);
std::string
parse_http_body(std::string message);
bool
maybe_http_first_line(std::string);
// http message structure :
//
// start-line
// request-line
// method SP target SP version
// response-line
// version SP status SP reason
// header-fields
// name ":" SP value
// CRLF
// body
#endif

View File

@@ -0,0 +1,2 @@
#include "parsing_request.hpp"

View File

@@ -145,10 +145,15 @@ void Webserv::_get(Client *client, ServerConfig &server, LocationConfig &locatio
// TMP HUGO // TMP HUGO
// //
std::string script_output;
if (_is_cgi(client)) if (_is_cgi(client))
{ {
_exec_cgi(client); script_output = _exec_cgi(client);
_response_correction(client); // DEBUG
std::cout << "\n____script_output____\n" << script_output << "\n_______________\n";
// wip check output of script
_check_script_output(client, script_output);
client->response += script_output;
return; return;
} }
// //
@@ -224,12 +229,6 @@ void Webserv::_get_file(Client *client, const std::string &path)
} }
} }
// WIP HUGO
void Webserv::_response_correction(Client *client)
{
(void)client;
}
void Webserv::_append_body(Client *client, const char *body, size_t body_size, const std::string &file_extension) void Webserv::_append_body(Client *client, const char *body, size_t body_size, const std::string &file_extension)
{ {
/* /*

13
www/form_get.html Normal file
View File

@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<form method="get">
<input type="submit" value="submit">
</form>
</body>
</html>

13
www/form_post.html Normal file
View File

@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<form method="post">
<input type="submit" value="submit">
</form>
</body>
</html>