#include "Request.hpp" //-------------------------------------------------Constructors--------------------------------------- Request::Request() { _row = 0; _ret = 200; _contentLength = 0; _chunked = false; _head_ok = false; _body_ok = false; _received = 0; _headerSize = 0; _lifeTime = 5; _body = NULL; } Request::Request(char *str) { _row = 0; _ret = 200; _data = str; _head_ok = false; _body_ok = false; _received = 0; _chunked = false; _contentLength = 0; _headerSize = 0; _lifeTime = 5; _body = NULL; } //-------------------------------------------------Get/Set--------------------------------------- void Request::freeData(void) { if (_body != NULL) { delete _body; _body = NULL; } } std::string &Request::getURI(void) { return (_URI); } std::string *Request::getBody(void) { return (_body); } std::string &Request::getHost(void) { return (_host); } std::string &Request::getQuery(void) { return(_query); } std::string &Request::getMethod(void) { return (_method); } std::string &Request::getFullUri(void) { return (_fullURI); } std::string &Request::getVersion(void) { return (_version); } std::string &Request::getLocation(void) { return (_location); } std::string &Request::getConnection(void) { return (_connection); } ServerConfig *Request::getConfig(void) { return (_config); } int Request::getCode(void) { return (_ret); } int Request::getLifeTime(void) { return (_lifeTime); } std::map Request::getClientFields(void) { return (_headerField); } bool Request::getChunked(void) { return (_chunked); } ssize_t Request::getContentLength(void) const { return (_contentLength); } unsigned int Request::getHeaderSize(void) const { return (_headerSize); } ssize_t Request::getRecved(void) const { return (_received); } std::string &Request::getHeader(void) { return _head; } void Request::setData(char *str) { this->_data = str; } void Request::setData(std::string &str) { _stringBUF = str; } void Request::setData(char *str, ServerConfig *config) { _data = str; _config = config; } void Request::setConfig(ServerConfig *config) { this->_config = config; } //-------------------------------------------------Parsing--------------------------------------- void Request::increaseRecvCounter(unsigned int n) { _received += n; } std::string urlDecode(std::string &url) { std::string ret; char ch; size_t i, ii; for (i=0; i < url.length(); i++) { if (size_t(url[i])==37) { sscanf(url.substr(i+1,2).c_str(), "%lx", &ii); ch=static_cast(ii); ret+=ch; i=i+2; } else { ret+=url[i]; } } return (ret); } void Request::parseURI(std::string str) { std::string tmp; int pos; tmp = str; pos = str.find("?"); if (pos > 0) { _URI = tmp.substr(0, pos); _query = tmp.erase(0, pos + 1); } else _URI = str; std::string sIn = _URI; _URI = urlDecode(sIn); _fullURI = HOME + _URI; } int Request::parseStartLine(std::string str) { std::string tmp; _method = str.substr(0, str.find(" ")); str = str.erase(0 , str.find(" ") + 1); tmp = str.substr(0, str.find(" ")); str = str.erase(0 , str.find(" ") + 1); _version = str; _version.erase(_version.find_last_not_of(WHITESPACE) + 1); parseURI(tmp); if (_version != "HTTP/1.1") _ret = 505; return (_ret); } int checkEnd(const std::string& str, const std::string& end) { size_t i = str.size(); size_t j = end.size(); if (i == 0) return (1); while (j > 0) { i--; j--; if (str[i] != end[j]) return (1); } return (0); } void Request::splitData(std::string &data) { int pos; std::string str; str = std::string(data); if (!_head_ok) { _head.insert(_head.end(), str.begin(), str.end()); pos = _head.find("\r\n\r\n"); if (pos != -1) { std::string tmp; tmp = _head.substr(0, pos) + "\n"; _headerSize = tmp.size() + 3; str = _head.substr(_headerSize); _head = tmp; _head_ok = true; parseHeader(); if (_URI.size() > 100) _ret = 414; // else if (_row > 20) if ((_contentLength == 0 && !_chunked) || (_method == "GET" || _method == "DELETE" || _method == "HEAD")) _body_ok = true; else _body = new std::string; } } if (badCode(_ret)) { _body_ok = true; return ; } else if (_chunked && !_body_ok) { _body->insert(_body->end(), str.begin(), str.end()); if (checkEnd(*_body, "0\r\n\r\n") == 0) _body_ok = true; } else if (_head_ok && !_body_ok) { _body->insert(_body->end(), str.begin(), str.end()); if ((_received - _headerSize) == _contentLength) { _body_ok = true; } } if (_head_ok && _body_ok && _chunked) { std::string &tmp = *_body; std::string subchunk = tmp.substr(0, 100); std::string newBody = ""; int chunksize = strtol(subchunk.c_str(), NULL, 16); size_t i = 0; while (chunksize) { i = tmp.find("\r\n", i) + 2; newBody += tmp.substr(i, chunksize); i += chunksize + 2; subchunk = tmp.substr(i, 100); chunksize = strtol(subchunk.c_str(), NULL, 16); } *_body = newBody; } } int Request::parseClientfield(std::string str) { int distance; int sp; std::string key; std::string value; distance = str.find(":"); sp = str.find(" "); if (distance < 0 && str != "\r") return 200; if (sp < distance) return 400; key = str.substr(0, distance); std::transform(key.begin(), key.end(), key.begin(), ::tolower); value = str.erase(0, distance + 1); if (_headerField.find(key) != _headerField.end()) { DBOUT << WARNING << getDebugTime() << FAIL << "[Pars-error] : [double header-field: " << key << " ] [method: " << _method << " ]" << " [target: " << _URI << " ]" << ENDL; } else { value = value.erase(0, value.find_first_not_of(WHITESPACE)); value = value.substr(0, value.find_last_not_of(WHITESPACE) + 1); _headerField[key] = value; } return 200; } int Request::parseHeader(void) { std::string line; std::stringstream buffStream; buffStream << _head; _ret = 200; while (std::getline(buffStream, line, '\n') && !badCode(_ret)) { if (_row == 0) _ret = parseStartLine(line); else _ret = parseClientfield(line); _row++; } if (!badCode(_ret)) copyFromMap(); return (_ret); } int Request::parseRequest(void) { if (!_head_ok || !_body_ok) splitData(_stringBUF); return (_ret); } //-------------------------------------------------Utils--------------------------------------- void Request::copyFromMap() { std::map::iterator it; int pos = 0; //host it = _headerField.find("host"); if (it != _headerField.end()) { _host = it->second; pos = _host.find(":"); if (pos != -1) _host = _host.substr(0, pos); } pos = 0; //content-lenght it = _headerField.find("content-length"); if (it != _headerField.end()) _contentLength = atoi(it->second.c_str()); pos = 0; //chunked it = _headerField.find("transfer-encoding"); if (it != _headerField.end()) { pos = it->second.find("chunked"); if ( pos != -1) _chunked = true; } pos = 0; //connection it = _headerField.find("connection"); if (it != _headerField.end()) _connection = it->second; } bool Request::badCode(int code) { if (code == 200) return (false); return true; } bool Request::ok(void) { return (_head_ok && _body_ok); } int Request::isFile(std::string path) { struct stat s; if (stat(path.c_str(), &s) == 0) { if (s.st_mode & S_IFDIR) return (-1); else if (s.st_mode & S_IFREG) return (0); } else return (-1); return (-1); } int Request::isDir(std::string path) { struct stat s; if (stat(path.c_str(), &s) == 0) { if (s.st_mode & S_IFDIR) return (0); else if (s.st_mode & S_IFREG) return (-1); } else return (-1); return (-1); } void Request::clear(void) { _ret = 200; _row = 0; _URI = ""; _host = ""; _query = ""; _method = ""; _fullURI = ""; _version = ""; _location = ""; _head = ""; _head_ok = false; _body_ok = false; _headerField.clear(); _data = NULL; _config = NULL; } Request::~Request() { }