#include "ehs/io/socket/Response.h" namespace ehs { Response::Response(const UInt_32 code, const Str_8& server) : code(code), server(server), cType(ContentType::NONE) { } Response::Response(const char* data, const UInt_64 size) : code(0), cType(ContentType::NONE) { ReadData(Str_8(data, size)); } Response::Response(const Str_8& data) : code(0), cType(ContentType::NONE) { ReadData(data); } Response::Response() : code(0), cType(ContentType::NONE) { } Response& Response::operator=(const Response& res) { if (this == &res) return *this; code = res.code; server = res.server; cType = res.cType; header = res.header; body = res.body; return *this; } void Response::SetCode(const UInt_32 code) { this->code = code; } UInt_32 Response::GetCode() const { return code; } void Response::SetServer(const Str_8& server) { this->server = server; } Str_8 Response::GetServer() const { return server; } void Response::SetContentType(const ContentType cType) { this->cType = cType; } ContentType Response::GetContentType() const { return cType; } void Response::AddToHeader(const Str_8& var, const Str_8& value) { header.Push(var + ": " + value); } Str_8 Response::GetHeader(const Str_8& var) const { Str_8 lIdentity = var.GetLower(); for (UInt_64 i = 0; i < header.Size(); ++i) { Vector data = header[i].Split(": "); if (data[0].GetLower() == lIdentity) return data[1]; } return ""; } Vector Response::GetHeader() const { return header; } void Response::AddToBody(const Str_8& var, const Str_8& value) { if (body.Size()) { if (cType == ContentType::APP_FORMURLENCODED) body.Push('&'); } body += var; if (cType == ContentType::APP_FORMURLENCODED) body += "="; body += value; } void Response::AddToBody(const Str_8& data) { if (body.Size()) { if (cType == ContentType::APP_FORMURLENCODED) body.Push('&'); } body += data; } void Response::SetBody(const Str_8& body) { this->body = body; } Str_8 Response::GetVar(const Str_8& var) const { Vector vars; if (cType == ContentType::APP_FORMURLENCODED) vars = body.Split("&"); for (UInt_64 i = 0; i < vars.Size(); ++i) { Vector data = vars[i].Split("="); if (data[0] == var) return data[1]; } return ""; } Str_8 Response::GetBody() const { return body; } Json Response::GetJson() const { return {body, 5}; } Str_8 Response::FormResult() const { Str_8 result = "HTTP/1.1 " + Str_8::FromNum(code) + " " + CodeToStr(code) + "\r\nServer: " + server + "\r\n"; for (UInt_64 i = 0; i < header.Size(); ++i) { if (header[i].Find("Content-Length", nullptr, SearchPattern::LEFT_RIGHT, IndexResult::ENDING)) continue; else if (header[i].Find("Server", nullptr, SearchPattern::LEFT_RIGHT, IndexResult::ENDING)) continue; else if (header[i].Find("Content-Type", nullptr, SearchPattern::LEFT_RIGHT, IndexResult::ENDING)) continue; result += header[i] + "\r\n"; } result += "Content-Type: " + ContentTypeToStr(cType) + "\r\nContent-Length: " + Str_8::FromNum(body.Size()) + "\r\n\r\n" + body; return result; } bool Response::IsValid() const { return server.Size() || header.Size() || body.Size(); } Str_8 Response::CodeToStr(const UInt_32 code) { if (code == 100) return "Continue"; else if (code == 101) return "Switching Protocols"; else if (code == 102) return "Processing (WebDAV)"; else if (code == 200) return "OK"; else if (code == 201) return "Created"; else if (code == 202) return "Accepted"; else if (code == 203) return "Non-Authoritative Information"; else if (code == 204) return "No Content"; else if (code == 205) return "Reset Content"; else if (code == 206) return "Partial Content"; else if (code == 207) return "Multi-Status (WebDAV)"; else if (code == 208) return "Already Reported (WebDAV)"; else if (code == 226) return "IM Used"; else if (code == 300) return "Multiple Choices"; else if (code == 301) return "Moved Permanently"; else if (code == 302) return "Found"; else if (code == 303) return "See Others"; else if (code == 304) return "Not Modified"; else if (code == 305) return "Use Proxy"; else if (code == 306) return "(Unused)"; else if (code == 307) return "Temporary Redirect"; else if (code == 308) return "Permanent Redirect (experimental)"; else if (code == 400) return "Bad Request"; else if (code == 401) return "Unauthorized"; else if (code == 402) return "Payment Required"; else if (code == 403) return "Forbidden"; else if (code == 404) return "Not Found"; else if (code == 405) return "Method Not Allowed"; else if (code == 406) return "Not Acceptable"; else if (code == 407) return "Proxy Authentication Required"; else if (code == 408) return "Request Timeout"; else if (code == 409) return "Conflict"; else if (code == 410) return "Gone"; else if (code == 411) return "Length Required"; else if (code == 412) return "Precondition Failed"; else if (code == 413) return "Request Entity Too Large"; else if (code == 414) return "Request-URI Too Long"; else if (code == 415) return "Unsupported Media Type"; else if (code == 416) return "Requested Range Not Satisfiable"; else if (code == 417) return "Expectation Failed"; else if (code == 418) return "I'm a teapot (RFC 2324)"; else if (code == 420) return "Enhance Your Calm (Twitter)"; else if (code == 422) return "Unprocessable Entity (WebDAV)"; else if (code == 423) return "Locked (WebDAV)"; else if (code == 424) return "Failed Dependency (Nginx)"; else if (code == 425) return "Reserved for WebDAV"; else if (code == 426) return "Upgrade Required"; else if (code == 428) return "Precondition Required"; else if (code == 429) return "Too Many Requests"; else if (code == 431) return "Request Header Fields Too Large"; else if (code == 444) return "No Response (Nginx)"; else if (code == 449) return "Retry With (Microsoft)"; else if (code == 450) return "Blocked by Windows Parental Controls (Microsoft)"; else if (code == 451) return "Unavailable For Legal Reasons"; else if (code == 499) return "Client Closed Request (Nginx)"; else if (code == 500) return "Internal Server Error"; else if (code == 501) return "Not Implemented"; else if (code == 502) return "Bad Gateway"; else if (code == 503) return "Service Unavailable"; else if (code == 504) return "Gateway Timeout"; else if (code == 505) return "HTTP Version Not Supported"; else if (code == 506) return "Variant Also Negotiates (Experimental)"; else if (code == 507) return "Insufficient Storage (WebDAV)"; else if (code == 508) return "Loop Detected (WebDAV)"; else if (code == 509) return "Bandwidth Limit Exceeded (Apache)"; else if (code == 510) return "Not Extended"; else if (code == 511) return "Network Authentication Required"; else if (code == 598) return "Network read timeout error"; else if (code == 599) return "Network connect timeout error"; else return "Unused Status Code"; } Str_8 Response::ContentTypeToStr(const ContentType cType) { switch (cType) { case ContentType::APP_MULTIPART_FORMDATA: return "multipart/form-data"; case ContentType::APP_FORMURLENCODED: return "application/x-www-form-urlencoded"; case ContentType::APP_JAVASCRIPT: return "application/javascript"; case ContentType::APP_JSON: return "application/json"; case ContentType::APP_XML: return "application/xml"; case ContentType::TEXT_PLAIN: return "text/plain"; case ContentType::TEXT_HTML: return "text/html"; case ContentType::TEXT_XML: return "text/xml"; default: return ""; } } ContentType Response::StrToContentType(const Str_8& value) { if (value == "multipart/form-data") return ContentType::APP_MULTIPART_FORMDATA; else if (value == "application/x-www-form-urlencoded") return ContentType::APP_FORMURLENCODED; else if (value == "application/javascript") return ContentType::APP_JAVASCRIPT; else if (value == "application/json") return ContentType::APP_JSON; else if (value == "application/xml") return ContentType::APP_XML; else if (value == "text/plain") return ContentType::TEXT_PLAIN; else if (value == "text/html") return ContentType::TEXT_HTML; else if (value == "text/xml") return ContentType::TEXT_XML; else return ContentType::NONE; } void Response::ReadData(const Str_8& data) { Vector lines = data.Split("\r\n"); Vector meta = lines[0].Split(" "); code = meta[1].ToDecimal(); for (UInt_64 i = 1; i < lines.Size(); ++i) { if (!lines[i].Size()) break; Vector var = lines[i].Split(": "); if (var[0].GetLower() == "server") { server = var[1]; continue; } else if (var[0].GetLower() == "content-type") { Vector ctData = var[1].Split(";"); cType = StrToContentType(ctData[0].GetLower()); continue; } header.Push(lines[i]); } } }