|
|
@ -1,43 +1,58 @@ |
|
|
|
#include "webserv.hpp" |
|
|
|
|
|
|
|
Client::Client(int fd, listen_t listen, Master *parent) |
|
|
|
: _fd(fd), _listen(listen), _parent(parent) { |
|
|
|
cout << "New connection, socket fd is " << fd << ", ip is : " << _listen.ip |
|
|
|
<< ", port : " << _listen.port << "\n"; |
|
|
|
Client::Client(int fd, ip_port_t ip_port, Master *parent) |
|
|
|
: _fd(fd), _ip_port(ip_port), _parent(parent) { |
|
|
|
cout << "New connection, socket fd is " << fd << ", ip is : " << _ip_port.ip |
|
|
|
<< ", port : " << _ip_port.port << "\n"; |
|
|
|
} |
|
|
|
|
|
|
|
Client::~Client(void) { |
|
|
|
close(_fd); |
|
|
|
cout << "Host disconnected, ip " << _listen.ip << ", port " << _listen.port |
|
|
|
<< "\n"; |
|
|
|
cout << "Host disconnected, ip " << _ip_port.ip << ", port " |
|
|
|
<< _ip_port.port << "\n"; |
|
|
|
} |
|
|
|
|
|
|
|
void Client::clean(void) { |
|
|
|
_server = NULL; |
|
|
|
_route = NULL; |
|
|
|
|
|
|
|
_method = ""; |
|
|
|
_uri = ""; |
|
|
|
_host = ""; |
|
|
|
|
|
|
|
_header = ""; |
|
|
|
_content = ""; |
|
|
|
_request.clear(); |
|
|
|
} |
|
|
|
|
|
|
|
bool Client::getRequest(string paquet) { |
|
|
|
cout << "|===|paquet|===>" << paquet << "|===||\n"; |
|
|
|
bool Client::getRequest(Env *env, string paquet) { |
|
|
|
// cout << "|===|paquet|===>" << paquet << "|===||\n";
|
|
|
|
if (paquet.length() < 1) // HTTPS?
|
|
|
|
return false; |
|
|
|
std::vector< string > lines = split(paquet, "\n"); |
|
|
|
long chunk_len = |
|
|
|
(_content.length() > 0 && _request["Transfer-Encoding:"].size() && |
|
|
|
_request["Transfer-Encoding:"].at(0) == "chunked") |
|
|
|
? std::strtol(lines.at(0).substr(1).c_str(), 0, 16) |
|
|
|
: -1; |
|
|
|
long chunk_len; |
|
|
|
chunk_len = (_content.length() > 0 && |
|
|
|
header_pick("Transfer-Encoding:", 0) == "chunked") |
|
|
|
? std::strtol(lines.at(0).c_str(), 0, 16) |
|
|
|
: -1; |
|
|
|
cout << "Chunk length: " << chunk_len << "\n"; |
|
|
|
for (std::vector< string >::iterator it = lines.begin(); it < lines.end(); |
|
|
|
it++) { |
|
|
|
if (*it == "\r" && _content.length() == 0) |
|
|
|
this->parseHeader(); |
|
|
|
if (*it == "\r" && _content.length() == 0) { |
|
|
|
if (!this->parseHeader(env)) |
|
|
|
return false; |
|
|
|
} |
|
|
|
if (*it != "\r" && _content.length() == 0) |
|
|
|
_header += *it + "\n"; |
|
|
|
else if (chunk_len == -1 || it != lines.begin()) |
|
|
|
_content += *it + "\n"; |
|
|
|
} |
|
|
|
cout << "Header: \n-|" << _header << "|-\n"; |
|
|
|
cout << "Content: \n-|" << _content << "|-\n"; |
|
|
|
if (_content.length() > 0) { |
|
|
|
_content.resize(_content.length() - 1); |
|
|
|
if (_request["Method:"].at(0) == "GET" || |
|
|
|
if (header_pick("Method:", 0) == "GET" || |
|
|
|
(chunk_len == 0 || |
|
|
|
std::strtoul(_request["Content-Length:"].at(0).c_str(), 0, 10) <= |
|
|
|
std::strtoul(header_pick("Content-Length:", 0).c_str(), 0, 10) <= |
|
|
|
_content.length())) { |
|
|
|
cout << "Request received\n"; |
|
|
|
return true; |
|
|
@ -47,8 +62,12 @@ bool Client::getRequest(string paquet) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
bool Client::parseHeader() { |
|
|
|
bool Client::parseHeader(Env *env) { |
|
|
|
cout << "Header: \n-|" << _header << "|-\n"; |
|
|
|
std::vector< string > lines = split(_header, "\r\n"); |
|
|
|
std::vector< string > method = split(lines.at(0), " "); |
|
|
|
_request["Method:"] = method; |
|
|
|
|
|
|
|
std::vector< string > line; |
|
|
|
if (lines.size() > 0) { |
|
|
|
for (std::vector< string >::iterator it = lines.begin() + 1; |
|
|
@ -58,24 +77,34 @@ bool Client::parseHeader() { |
|
|
|
std::vector< string >(line.begin() + 1, line.end()); |
|
|
|
} |
|
|
|
} |
|
|
|
std::vector< string > method = split(lines.at(0), " "); |
|
|
|
if (method.at(0) == "POST" && |
|
|
|
_request.find("Content-Length:") == _request.end() && |
|
|
|
_request.find("Transfer-Encoding:") == _request.end()) |
|
|
|
if (method.at(0) == "POST" && header_pick("Content-Length:", 0) == "" && |
|
|
|
header_pick("Transfer-Encoding:", 0) != "chunked") { |
|
|
|
send_error(400); |
|
|
|
return false; |
|
|
|
_request["Method:"] = method; |
|
|
|
} |
|
|
|
|
|
|
|
_method = header_pick("Method:", 0); |
|
|
|
_uri = header_pick("Method:", 1); |
|
|
|
_host = header_pick("Host:", 0); |
|
|
|
_server = _parent->choose_server(env, _host); |
|
|
|
_route = _server->choose_route(_uri); |
|
|
|
_len = header_pick("Content-Length:", 0).c_str(); |
|
|
|
if (_len != "" && std::atoi(_len.c_str()) > _route->_client_max_body_size) { |
|
|
|
send_error(413); |
|
|
|
return false; |
|
|
|
} |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
bool Client::check_method(Server *server, Route *route, string method) { |
|
|
|
bool Client::check_method(string method) { |
|
|
|
std::vector< string > allowed; |
|
|
|
if (method != "GET" && method != "POST" && method != "DELETE") |
|
|
|
send_error(405); |
|
|
|
else if ((allowed = route->_headers).size() > 0 && |
|
|
|
else if ((allowed = _route->_headers).size() > 0 && |
|
|
|
std::find(allowed.begin(), allowed.end(), method) == |
|
|
|
allowed.end()) { |
|
|
|
send_error(405); |
|
|
|
} else if ((allowed = server->_headers).size() > 0 && |
|
|
|
} else if ((allowed = _server->_headers).size() > 0 && |
|
|
|
std::find(allowed.begin(), allowed.end(), method) == |
|
|
|
allowed.end()) { |
|
|
|
send_error(405); |
|
|
@ -84,31 +113,25 @@ bool Client::check_method(Server *server, Route *route, string method) { |
|
|
|
return (false); |
|
|
|
} |
|
|
|
|
|
|
|
string Client::header_pick(string key, int id) { |
|
|
|
if (_request[key].size() == 0) |
|
|
|
throw std::runtime_error("The key is not in request's header."); |
|
|
|
string ret = _request[key].at(id); |
|
|
|
return ret; |
|
|
|
string Client::header_pick(string key, size_t id) { |
|
|
|
if (_request[key].size() <= id) |
|
|
|
return ""; |
|
|
|
return _request[key].at(id); |
|
|
|
} |
|
|
|
|
|
|
|
inline string get_extension(string str) { return str.substr(str.rfind('.')); } |
|
|
|
|
|
|
|
void Client::answer(Env *env) { |
|
|
|
string method = header_pick("Method:", 0); |
|
|
|
string uri = header_pick("Method:", 1); |
|
|
|
string host = header_pick("Host:", 0); |
|
|
|
cout << "Method: " << method << "\n"; |
|
|
|
cout << "URI: " << uri << "\n"; |
|
|
|
cout << "Host: " << host << "\n"; |
|
|
|
void Client::answer() { |
|
|
|
cout << "Method: " << _method << "\n"; |
|
|
|
cout << "URI: " << _uri << "\n"; |
|
|
|
cout << "Host: " << _host << "\n"; |
|
|
|
string ret; |
|
|
|
|
|
|
|
Server *server = _parent->choose_server(env, host); |
|
|
|
Route *route = server->choose_route(uri); |
|
|
|
if (check_method(server, route, method)) { |
|
|
|
string path = route->correctUri(uri); |
|
|
|
string cgi = route->_cgi.size() ? route->_cgi[get_extension(path)] : ""; |
|
|
|
if (check_method(_method)) { |
|
|
|
string path = _route->correctUri(_uri); |
|
|
|
string cgi = |
|
|
|
_route->_cgi.size() ? _route->_cgi[get_extension(path)] : ""; |
|
|
|
if (cgi == "") { |
|
|
|
if ((ret = route->getIndex(uri, path)) == "" && |
|
|
|
if ((ret = _route->getIndex(_uri, path)) == "" && |
|
|
|
(ret = read_file(path)) == "") |
|
|
|
send_error(404); |
|
|
|
else |
|
|
@ -116,8 +139,6 @@ void Client::answer(Env *env) { |
|
|
|
} else |
|
|
|
send_cgi(cgi, path); |
|
|
|
} |
|
|
|
_content = ""; |
|
|
|
_header = ""; |
|
|
|
} |
|
|
|
|
|
|
|
void Client::send_cgi(string cgi, string path) { |
|
|
@ -145,7 +166,7 @@ void Client::send_cgi(string cgi, string path) { |
|
|
|
char buffer[10000]; |
|
|
|
buffer[read(fd[0], buffer, 10000)] = 0; |
|
|
|
ret = string(buffer); |
|
|
|
ss << "HTTP/1.1 200 OK\r\nContent-length: " |
|
|
|
ss << "HTTP/1.1 200 OK\r\nContent-Length: " |
|
|
|
<< ret.length() - ret.find("\r\n\r\n") - 4 << "\r\n" |
|
|
|
<< ret; |
|
|
|
send_answer(ss.str()); |
|
|
@ -153,19 +174,28 @@ void Client::send_cgi(string cgi, string path) { |
|
|
|
|
|
|
|
void Client::send_error(int error_code) { |
|
|
|
switch (error_code) { |
|
|
|
case 400: |
|
|
|
return send_answer( |
|
|
|
"HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n"); |
|
|
|
case 404: |
|
|
|
return send_answer( |
|
|
|
"HTTP/1.1 404 Not Found\r\nContent-length: 0\r\n\r\n"); |
|
|
|
"HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n"); |
|
|
|
case 405: |
|
|
|
return send_answer( |
|
|
|
"HTTP/1.1 405 Method Not Allowed\r\nContent-length: 0\r\n\r\n"); |
|
|
|
"HTTP/1.1 405 Method Not Allowed\r\nContent-Length: 0\r\n\r\n"); |
|
|
|
case 413: |
|
|
|
return send_answer( |
|
|
|
"HTTP/1.1 413 Payload Too " |
|
|
|
"Large\r\nConnection:close\r\nContent-Length: 0\r\n\r\n"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void Client::send_answer(string msg) { |
|
|
|
#ifdef __linux__ |
|
|
|
cout << "Answer: \n-|" << msg << "|-\n"; |
|
|
|
send(_fd, msg.c_str(), msg.length(), MSG_NOSIGNAL); |
|
|
|
#elif __APPLE__ |
|
|
|
send(_fd, msg.c_str(), msg.length(), 0); |
|
|
|
#endif |
|
|
|
clean(); |
|
|
|
} |
|
|
|