#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 &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) _locationSTR = _location->redirect[_code]; } 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::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); if (!_location->uploadDir.empty()) _upload_dir = _location->uploadDir + tmp; tmp = _location->root + tmp; } else { tmp = _request.getURI().substr(len); 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::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->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 (_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 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::iterator it; it = _errorCode.find(code); return (it->second); } std::string Response::getReasonPhrase(int code) { std::stringstream ss; std::string nbr; std::map::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 << "" << code <<" "<< getReasonPhrase(code) <<"" <<"

" << code <<" " << getReasonPhrase(code) <<"

" << "
poheck/1.0.0 (genereted)
"; Page = ss.str(); return (Page); } Response::~Response() { }