Files
webserv/src/Client/Response.cpp
2022-02-20 20:00:03 +03:00

607 lines
14 KiB
C++

#include "Response.hpp"
//-------------------------------------------------Constructor---------------------------------------
Response::Response()
{
initErrorCode();
_Autoindex = true;
_body = NULL;
_header = NULL;
_code = 200;
}
//-------------------------------------------------GET/SET---------------------------------------
void Response::freeData(void)
{
if (_body != NULL)
{
delete _body;
_body = NULL;
}
else if (_header != NULL)
{
delete _header;
_header = NULL;
}
}
std::string Response::getHeader(void)
{
return (*_header);
}
std::string *Response::getBody(void)
{
return (_body);
}
void Response::setData(Request request, ServerConfig *config)
{
_request = request;
_code = request.getCode();
_config = config;
}
void Response::setData(Request &request, ServerConfig *config, std::vector<location *> &loc)
{
_request = request;
_code = request.getCode();
_config = config;
if (loc.empty())
_code = 404;
else
{
_location = loc[0];
if (loc.size() == 2)
_cgi_Pass = loc[1]->cgi_pass;
else
_cgi_Pass = _location->cgi_pass;
}
}
void Response::setHeaderBlocks(void)
{
setContentType();
setContentLength();
setServer();
setConnection();
setDate();
setCacheControl();
setLocation();
// setLanguage(void);
// setTransferEncoding(void);
}
void Response::setContentType(void)
{
if (_code == 204 || !_contentType.empty())
return ;
else if (_request.badCode(_code))
_contentType = "text/html";
else
_contentType = getContentType();
}
void Response::setContentLength()
{
if (_body != NULL)
_contentLength = _body->size();
else
_contentLength = 0;
}
void Response::setServer(void)
{
_server = "Poheck/1.0";
}
void Response::setConnection()
{
std::stringstream ss;
if (_request.getConnection() == "keep-alive")
{
ss << "timeout=" << _request.getLifeTime();
_keepAlive = ss.str();
}
}
void Response::setDate(void)
{
_date = getTime();
}
void Response::setCacheControl(void)
{
_cacheControl = "no-store, no-cache, must-revalidate";
}
void Response::setLocation(void)
{
if (_code == 301)
{
_redirect_location = _location->redirect[_code];
unsigned long pos = _redirect_location.rfind("$request_file");
if (pos != std::string::npos)
{
_redirect_location.erase(pos);
_redirect_location += _request_file;
}
_locationSTR = _redirect_location;
}
}
serverListen Response::getListen()
{
return (_listen);
}
std::string Response::getCgiPass(void)
{
return (_cgi_Pass);
}
ssize_t Response::getMaxBodySize(void)
{
return (_maxBodySize);
}
//-------------------------------------------------File---------------------------------------
void Response::OpenResponseFile(const char *path)
{
std::stringstream ss;
std::ifstream file(path, std::ifstream::in);
if (file.is_open())
{
ss << file.rdbuf();
*_body = ss.str();
file.close();
}
else
{
_code = 403;
OpenErrorFile(_code);
}
}
void Response::OpenErrorFile(int code)
{
std::map<int, std::string>::iterator it;
std::stringstream ss;
it = _errorPages.find(code);
if (it != _errorPages.end())
{
const char *path = it->second.c_str();
std::ifstream file(path, std::ifstream::in);
if (file.is_open())
{
ss << file.rdbuf();
*_body = ss.str();
file.close();
}
else
*_body = getErrorPage(code);
}
else
*_body = getErrorPage(code);
}
std::string Response::getContentType(void)
{
std::string path = _fullURI;
std::string type = path.substr(path.rfind(".") + 1, path.size() - path.rfind("."));
if (_request.isDir(path) == 0)
return ("text/html");
else if (type == "html")
return ("text/html");
else if (type == "css")
return ("text/css");
else if (type == "js")
return ("text/javascript");
else if (type == "json")
return ("application/json");
else if (type == "woff")
return ("application/x-font-woff");
else if (type == "mp4" || type == "m4v" || type == " f4v")
return ("video/mp4");
else if (type == "ico")
return ("image/x-icon");
else if (type == "jpeg" || type == "jpg")
return ("image/jpeg");
else if (type == "png")
return ("image/png");
else if (type == "bmp")
return ("image/bmp");
else if (type == "pdf")
return ("application/pdf");
else
return ("text/plain");
}
std::string Response::getTime(void)
{
char buff[1337] = {0};
struct timeval currTime;
struct tm *t;
gettimeofday(&currTime, NULL);
t = gmtime(&currTime.tv_sec);
strftime(buff, 1337, "%a, %d %b %Y %H:%M:%S GMT", t);
return (buff);
}
std::string Response::getFullURI(void)
{
std::string tmp;
std::string ret = "";
int len = _location->location.size();
if (_location->location[0] == '*')
{
int pos = 0;
pos = _request.getURI().rfind("/");
tmp = _request.getURI().substr(pos);
_request_file = tmp;
if (!_location->uploadDir.empty())
_upload_dir = _location->uploadDir + tmp;
tmp = _location->root + tmp;
}
else
{
tmp = _request.getURI().substr(len);
_request_file = tmp;
if (!_location->uploadDir.empty())
_upload_dir = _location->uploadDir + tmp;
tmp = _location->root + tmp;
}
if (_request.isDir(tmp) == 0)
{
if (_location->directoryFile.empty() || _Autoindex)
ret = tmp;
else
{
ret = tmp + "/" + _location->directoryFile;
}
}
else
ret = tmp;
if (_upload_dir.empty())
_upload_dir = ret;
DBOUT << PINK << "location " << _location->location << ENDL;
DBOUT << PINK << "fullURI " << ret << ENDL;
DBOUT << PINK << "upload dir " << _upload_dir << ENDL;
return (ret);
}
void Response::generateBody(void)
{
if (!_request.badCode(_code) && _request.isDir(_fullURI) == 0)
{
if (_Autoindex)
{
*_body = Autoindex::getPage(_request.getURI(), _fullURI, _request.getHost(), _listen.port);
if (_body->empty())
_code = 404;
}
else
_code = 403;
}
else if (!_request.badCode(_code) && _request.isFile(_fullURI) == 0)
OpenResponseFile(_fullURI.c_str());
else if (_request.isFile(_fullURI) == -1)
_code = 404;
if (_request.badCode(_code))
OpenErrorFile(_code);
}
bool Response::allowedMethod(std::string &method)
{
std::vector<std::string>::iterator it;
it = _location->methods.begin();
while (it != _location->methods.end())
{
if (*it == method)
return (true);
it++;
}
if (!_cgi_Pass.empty() && (method == "GET" || method == "POST"))
return (true);
_code = 405;
return (false);
}
void Response::generateHeader(void)
{
_header = new std::string;
std::stringstream ss;
std::string tmp;
ss << "HTTP/1.1" << " " << _code << " " << getReasonPhrase(_code) << "\r\n";
if (!_contentType.empty())
ss << "Content-Type: " << _contentType << "\r\n";
ss << "Content-Length: " << _contentLength << "\r\n";
ss << "Server: " << _server << "\r\n";
// if (!_keepAlive.empty())
// ss << "Keep-Alive: " <<_keepAlive << "\r\n";
ss << "Date: " << _date << "\r\n";
if (!_cacheControl.empty())
ss << "Cache-Control: " << _cacheControl << "\r\n";
if (!_locationSTR.empty())
ss << "Location: " << _locationSTR << "\r\n";
ss << "\r\n";
*_header = ss.str();
}
void Response::generate()
{
_fullURI = _request.getFullUri();
if (_request.badCode(_request.getCode()))
invalidClient();
else if (_request.getMethod() == "GET")
methodGet();
else if (_request.getMethod() == "DELETE")
methodDelete();
else
methodPost();
}
void Response::generate2(serverListen &l)
{
if (_config == NULL)
{
_code = 404;
}
else if (!_request.badCode(_code))
{
_listen = l;
_errorPages = _config->getErrorPages();
_Autoindex = _location->autoindex;
_code = _request.getCode();
_hostPort.ip = _config->getHost();
_hostPort.port = _config->getPort();
_fullURI = getFullURI();
_method = _request.getMethod();
_maxBodySize = (_location->clientBodySize > 0) ? _location->clientBodySize : _config->getClientBodySize();
if (_maxBodySize > 0 && _request.getBody() != NULL)
_code = (_request.getBody()->size() > (unsigned long)_maxBodySize) ? 413 : _code;
}
if (_request.badCode(_code) || !allowedMethod(_method) || isRedirect())
{
invalidClient();
return;
}
if (_method == "GET")
methodGet();
else if (_method == "POST")
methodPost();
else if (_method == "DELETE")
methodDelete();
else if (_method == "PUT")
methodPut();
}
bool Response::isRedirect()
{
if (_location == NULL)
return (false);
if (!_location->redirect.empty())
{
_code = 301;
return (true);
}
else
return (false);
}
//-------------------------------------------------HEADER/BODY---------------------------------------
void Response::invalidClient(void)
{
_body = new std::string;
if (!isRedirect())
OpenErrorFile(_code);
setHeaderBlocks();
generateHeader();
DBOUT << RED << "Error Method called" << ENDL;
}
void Response::methodGet(void)
{
_body = new std::string;
if (!_cgi_Pass.empty())
{
CgiHandle cgi(_request, *this);
*_body = cgi.executeCgi();
unsigned long pos = _body->find("\r\n\r\n");
if (pos != std::string::npos)
{
std::string tmp = _body->substr(0, pos);
unsigned long stat = tmp.find("Status: ");
unsigned long type = tmp.find("Content-type: ");
if (stat != std::string::npos)
_code = atoi(tmp.substr(stat + 8, 3).c_str());
if (type != std::string::npos)
_contentType = tmp.substr(type + 14, tmp.find("\r\n", type+14));
_body->erase(_body->begin(), _body->begin() + pos + 4);
}
}
else
generateBody();
setHeaderBlocks();
generateHeader();
DBOUT << GREEN << "GET method called\n" << ZERO_C;
}
void Response::methodPost(void)
{
if (!_cgi_Pass.empty())
{
_body = new std::string;
CgiHandle cgi(_request, *this);
*_body = cgi.executeCgi();
DBOUT << "CGI SIZE BODY " << _body->size() << ENDL;
unsigned long pos = _body->find("\r\n\r\n");
if (pos != std::string::npos)
{
std::string tmp = _body->substr(0, pos);
unsigned long stat = tmp.find("Status: ");
unsigned long type = tmp.find("Content-type: ");
if (stat != std::string::npos)
_code = atoi(tmp.substr(stat + 8, 3).c_str());
if (type != std::string::npos)
_contentType = tmp.substr(type + 14, tmp.find("\r\n", type+14));
_body->erase(_body->begin(), _body->begin() + pos + 4);
}
}
else
_code = 204;
setHeaderBlocks();
generateHeader();
DBOUT << GREEN << "POST method called" << ENDL;
}
void Response::methodPut(void)
{
_code = 201;
if (!_location->uploadAccept)
{
_code = 403;
invalidClient();
return;
}
if (_request.isFile(_upload_dir) == 0)
_code = 204;
std::ofstream file(_upload_dir.c_str(), std::ios::out | std::ios::binary);
if (!file.is_open())
_code = 403;
else
{
file.write(_request.getBody()->data(), _request.getBody()->size());
file.close();
}
setHeaderBlocks();
generateHeader();
DBOUT << GREEN << "PUT method called" << ENDL;
}
void Response::methodDelete(void)
{
if (_request.isFile(_fullURI) == 0)
{
if (remove(_fullURI.c_str()) == 0)
_code = 204;
else
_code = 403;
}
else
_code = 404;
if (_code == 404 || _code == 403)
OpenErrorFile(_code);
setHeaderBlocks();
generateHeader();
DBOUT << GREEN << "Delete method called" << ENDL;
}
//-------------------------------------------------GET/SET---------------------------------------
std::map<std::string, std::string> Response::_errorCode;
void Response::initErrorCode(void)
{
_errorCode["100"] = "Continue";
_errorCode["101"] = "Switching Protocols";
_errorCode["200"] = "OK";
_errorCode["201"] = "Created";
_errorCode["202"] = "Accepted";
_errorCode["203"] = "Non-Authoritative Information";
_errorCode["204"] = "No Content";
_errorCode["205"] = "Reset Content";
_errorCode["206"] = "Partial Content";
_errorCode["300"] = "Multiple Choices";
_errorCode["301"] = "Moved Permanently";
_errorCode["302"] = "Found";
_errorCode["303"] = "See Other";
_errorCode["304"] = "Not Modified";
_errorCode["305"] = "Use Proxy";
_errorCode["306"] = "(Unused)";
_errorCode["307"] = "Temporary Redirect";
_errorCode["400"] = "Bad Request";
_errorCode["401"] = "Unauthorized";
_errorCode["402"] = "Payment Required";
_errorCode["403"] = "Forbidden";
_errorCode["404"] = "Not Found";
_errorCode["405"] = "Method Not Allowed";
_errorCode["406"] = "Not Acceptable";
_errorCode["407"] = "Proxy Authentication Required";
_errorCode["408"] = "Request Timeout";
_errorCode["409"] = "Conflict";
_errorCode["410"] = "Gone";
_errorCode["411"] = "Length Required";
_errorCode["412"] = "Precondition Failed";
_errorCode["413"] = "Payload Too Large";
_errorCode["414"] = "Request-URI Too Long";
_errorCode["415"] = "Unsupported Media Type";
_errorCode["416"] = "Requested Range Not Satisfiable";
_errorCode["417"] = "Expectation Failed";
_errorCode["500"] = "Internal Server Error";
_errorCode["501"] = "Not Implemented";
_errorCode["502"] = "Bad Gateway";
_errorCode["503"] = "Service Unavailable";
_errorCode["504"] = "Gateway Timeout";
_errorCode["505"] = "HTTP Version Not Supported";
}
std::string Response::getReasonPhrase(std::string code)
{
std::map<std::string, std::string>::iterator it;
it = _errorCode.find(code);
return (it->second);
}
std::string Response::getReasonPhrase(int code)
{
std::stringstream ss;
std::string nbr;
std::map<std::string, std::string>::iterator it;
ss << code;
nbr = ss.str();
it = _errorCode.find(nbr);
return (it->second);
}
std::string Response::getErrorPage(int code)
{
std::stringstream ss;
std::string Page;
ss << "<html><head><title>" << code <<" "<< getReasonPhrase(code) <<"</title></head><body>"
<<"<center><h1>" << code <<" " << getReasonPhrase(code) <<"</h1></center> "
<< "<hr><center>poheck/1.0.0 (genereted)</center></body></html>";
Page = ss.str();
return (Page);
}
Response::~Response()
{
}