1. Util module
2. Implement ideas
(1) Management
- Implement some tool interfaces
- Read file contents
- Write content to file
- URL encoding
- URL decoding
- Get description information through HTTP status code
- Get mime by file extension
- Determine whether a file is a directory
- Determine whether a file is an ordinary file
- HTTP resource path validity judgment
(2) Meaning
In the protocol support module, it is easy to use when you need some fragmentary functions!
(3) Functional design
class Util {<!-- --> public: //String splitting function size_t Spilt(); //Read file content static bool ReadFile() {<!-- --> } //Write content to file static bool WriteFile(); //URL encoding static bool UrlEncode(); //URL decoding static bool UrlDecode(); // Get description information through HTTP status code static std::string StatusDesc(); // Get the file MINE based on the file extension name static std::string ExtMine(); // Determine whether a file is a directory static bool IsDirectory(); //Determine whether a file is an ordinary file static bool IsRegular(); //Judge the validity of HTTP resource path static bool VaildPath(); };
3. Code
class Util {<!-- --> public: //String splitting function, split the src string according to sep characters, put each obtained string into arry, and finally return the number of strings static size_t Split(const std::string & amp;src, const std::string & amp;sep, std::vector<std::string> *arry) {<!-- --> size_t offset = 0; // There are 10 characters. Offset is the starting position of the search. The range should be 0~9. Offset==10 means it has crossed the boundary. while(offset < src.size()) {<!-- --> size_t pos = src.find(sep, offset);//At the src string offset offset, start searching backward for the sep character/string and return to the found position if (pos == std::string::npos) {<!-- -->//No specific character found //Treat the remaining part as a string and put it into arry if(pos == src.size()) break; arry->push_back(src.substr(offset)); return arry->size(); } if (pos == offset) {<!-- --> offset = pos + sep.size(); continue;//The current string is empty and has no content } arry->push_back(src.substr(offset, pos - offset)); offset = pos + sep.size(); } return arry->size(); } //Read all the contents of the file and put the read contents into a Buffer static bool ReadFile(const std::string & amp;filename, std::string *buf) {<!-- --> std::ifstream ifs(filename, std::ios::binary); if (ifs.is_open() == false) {<!-- --> printf("OPEN %s FILE FAILED!!", filename.c_str()); return false; } size_t fsize = 0; ifs.seekg(0, ifs.end);//Jump the reading and writing position to the end fsize = ifs.tellg(); //Get the offset of the current read and write position relative to the starting position. The offset from the end is exactly the file size ifs.seekg(0, ifs.beg);//Jump to the starting position buf->resize(fsize); //Open up space of file size ifs.read( & amp;(*buf)[0], fsize); if (ifs.good() == false) {<!-- --> printf("READ %s FILE FAILED!!", filename.c_str()); ifs.close(); return false; } ifs.close(); return true; } //Write data to the file static bool WriteFile(const std::string & amp;filename, const std::string & amp;buf) {<!-- --> std::ofstream ofs(filename, std::ios::binary | std::ios::trunc); if (ofs.is_open() == false) {<!-- --> printf("OPEN %s FILE FAILED!!", filename.c_str()); return false; } ofs.write(buf.c_str(), buf.size()); if (ofs.good() == false) {<!-- --> ERR_LOG("WRITE %s FILE FAILED!", filename.c_str()); ofs.close(); return false; } ofs.close(); return true; } //URL encoding to avoid ambiguity between special characters in the resource path and query string in the URL and special characters in the HTTP request //Encoding format: Convert the ascii value of special characters into two hexadecimal characters, prefixed % C++ -> C++ //Unencoded special characters: RFC3986 document stipulates . - _ ~ Letters and numbers are absolutely unencoded characters //RFC3986 document stipulates that the encoding format is %HH //The W3C standard stipulates that spaces in the query string need to be encoded as + and decoded as + converted to spaces. static std::string UrlEncode(const std::string url, bool convert_space_to_plus) {<!-- --> std::string res; for (auto & amp;c : url) {<!-- --> if (c == '.' || c == '-' || c == '_' || c == '~' || isalnum(c)) {<!-- --> res + = c; continue; } if (c == ' ' & amp; & amp; convert_space_to_plus == true) {<!-- --> res + = ' + '; continue; } //The remaining characters need to be encoded into %HH format char tmp[4] = {<!-- -->0}; //snprintf is similar to printf. They are both formatted strings, except that one is printed and the other is placed in a space. snprintf(tmp, 4, "%% X", c); res + = tmp; } return res; } static char HEXTOI(char c) {<!-- --> if (c >= '0' & amp; & amp; c <= '9') {<!-- --> return c - '0'; }else if (c >= 'a' & amp; & amp; c <= 'z') {<!-- --> return c - 'a' + 10; }else if (c >= 'A' & amp; & amp; c <= 'Z') {<!-- --> return c - 'A' + 10; } return -1; } static std::string UrlDecode(const std::string url, bool convert_plus_to_space) {<!-- --> //When % is encountered, convert the following 2 characters into numbers, shift the first number to the left by 4 bits, and then add the second number + -> 2b +->2 << 4 + 11 std::string res; for (int i = 0; i < url.size(); i + + ) {<!-- --> if (url[i] == ' + ' & amp; & amp; convert_plus_to_space == true) {<!-- --> res + = ' '; continue; } if (url[i] == '%' & amp; & amp; (i + 2) < url.size()) {<!-- --> char v1 = HEXTOI(url[i + 1]); char v2 = HEXTOI(url[i + 2]); char v = v1 * 16 + v2; res + = v; i + = 2; continue; } res + = url[i]; } return res; } //Get description information of response status code static std::string StatuDesc(int statu) {<!-- --> auto it = _statu_msg.find(statu); if (it != _statu_msg.end()) {<!-- --> return it->second; } return "Unknow"; } //Get the file mime based on the file suffix name static std::string ExtMime(const std::string & amp;filename) {<!-- --> // a.b.txt gets the file extension first size_t pos = filename.find_last_of('.'); if (pos == std::string::npos) {<!-- --> return "application/octet-stream"; } //According to the extension, get the mime std::string ext = filename.substr(pos); auto it = _mime_msg.find(ext); if (it == _mime_msg.end()) {<!-- --> return "application/octet-stream"; } return it->second; } //Determine whether a file is a directory static bool IsDirectory(const std::string & amp;filename) {<!-- --> struct stat st; int ret = stat(filename.c_str(), & amp;st); if (ret < 0) {<!-- --> return false; } return S_ISDIR(st.st_mode); } //Determine whether a file is an ordinary file static bool IsRegular(const std::string & amp;filename) {<!-- --> struct stat st; int ret = stat(filename.c_str(), & amp;st); if (ret < 0) {<!-- --> return false; } return S_ISREG(st.st_mode); } //Judge the validity of the resource path of http request // /index.html --- The / in front is called the relative root directory, which maps a subdirectory on a certain server. // What I want to express is that the client can only request resources in the relative root directory, and resources in other places will be ignored. // /../login, the .. in this path will cause the path search to go outside the relative root directory, which is unreasonable and unsafe. static bool ValidPath(const std::string & amp;path) {<!-- --> //Idea: Split the path according to /, calculate the directory depth based on how many subdirectories there are, how many layers there are, and the depth cannot be less than 0 std::vector<std::string> subdir; Split(path, "/", & amp;subdir); int level = 0; for (auto & amp;dir : subdir) {<!-- --> if (dir == "..") {<!-- --> level--; //When any level leaves the relative root directory, it is considered a problem. if (level < 0) return false; continue; } level + + ; } return true; } };
status code:
std::unordered_map<int, std::string> _statu_msg = {<!-- --> {<!-- -->100, "Continue"}, {<!-- -->101, "Switching Protocol"}, {<!-- -->102, "Processing"}, {<!-- -->103, "Early Hints"}, {<!-- -->200, "OK"}, {<!-- -->201, "Created"}, {<!-- -->202, "Accepted"}, {<!-- -->203, "Non-Authoritative Information"}, {<!-- -->204, "No Content"}, {<!-- -->205, "Reset Content"}, {<!-- -->206, "Partial Content"}, {<!-- -->207, "Multi-Status"}, {<!-- -->208, "Already Reported"}, {<!-- -->226, "IM Used"}, {<!-- -->300, "Multiple Choice"}, {<!-- -->301, "Moved Permanently"}, {<!-- -->302, "Found"}, {<!-- -->303, "See Other"}, {<!-- -->304, "Not Modified"}, {<!-- -->305, "Use Proxy"}, {<!-- -->306, "unused"}, {<!-- -->307, "Temporary Redirect"}, {<!-- -->308, "Permanent Redirect"}, {<!-- -->400, "Bad Request"}, {<!-- -->401, "Unauthorized"}, {<!-- -->402, "Payment Required"}, {<!-- -->403, "Forbidden"}, {<!-- -->404, "Not Found"}, {<!-- -->405, "Method Not Allowed"}, {<!-- -->406, "Not Acceptable"}, {<!-- -->407, "Proxy Authentication Required"}, {<!-- -->408, "Request Timeout"}, {<!-- -->409, "Conflict"}, {<!-- -->410, "Gone"}, {<!-- -->411, "Length Required"}, {<!-- -->412, "Precondition Failed"}, {<!-- -->413, "Payload Too Large"}, {<!-- -->414, "URI Too Long"}, {<!-- -->415, "Unsupported Media Type"}, {<!-- -->416, "Range Not Satisfiable"}, {<!-- -->417, "Expectation Failed"}, {<!-- -->418, "I'm a teapot"}, {<!-- -->421, "Misdirected Request"}, {<!-- -->422, "Unprocessable Entity"}, {<!-- -->423, "Locked"}, {<!-- -->424, "Failed Dependency"}, {<!-- -->425, "Too Early"}, {<!-- -->426, "Upgrade Required"}, {<!-- -->428, "Precondition Required"}, {<!-- -->429, "Too Many Requests"}, {<!-- -->431, "Request Header Fields Too Large"}, {<!-- -->451, "Unavailable For Legal Reasons"}, {<!-- -->501, "Not Implemented"}, {<!-- -->502, "Bad Gateway"}, {<!-- -->503, "Service Unavailable"}, {<!-- -->504, "Gateway Timeout"}, {<!-- -->505, "HTTP Version Not Supported"}, {<!-- -->506, "Variant Also Negotiates"}, {<!-- -->507, "Insufficient Storage"}, {<!-- -->508, "Loop Detected"}, {<!-- -->510, "Not Extended"}, {<!-- -->511, "Network Authentication Required"} }; std::unordered_map<std::string, std::string> _mime_msg = {<!-- --> {<!-- -->".aac", "audio/aac"}, {<!-- -->".abw", "application/x-abiword"}, {<!-- -->".arc", "application/x-freearc"}, {<!-- -->".avi", "video/x-msvideo"}, {<!-- -->".azw", "application/vnd.amazon.ebook"}, {<!-- -->".bin", "application/octet-stream"}, {<!-- -->".bmp", "image/bmp"}, {<!-- -->".bz", "application/x-bzip"}, {<!-- -->".bz2", "application/x-bzip2"}, {<!-- -->".csh", "application/x-csh"}, {<!-- -->".css", "text/css"}, {<!-- -->".csv", "text/csv"}, {<!-- -->".doc", "application/msword"}, {<!-- -->".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}, {<!-- -->".eot", "application/vnd.ms-fontobject"}, {<!-- -->".epub", "application/epub + zip"}, {<!-- -->".gif", "image/gif"}, {<!-- -->".htm", "text/html"}, {<!-- -->".html", "text/html"}, {<!-- -->".ico", "image/vnd.microsoft.icon"}, {<!-- -->".ics", "text/calendar"}, {<!-- -->".jar", "application/java-archive"}, {<!-- -->".jpeg", "image/jpeg"}, {<!-- -->".jpg", "image/jpeg"}, {<!-- -->".js", "text/javascript"}, {<!-- -->".json", "application/json"}, {<!-- -->".jsonld", "application/ld + json"}, {<!-- -->".mid", "audio/midi"}, {<!-- -->".midi", "audio/x-midi"}, {<!-- -->".mjs", "text/javascript"}, {<!-- -->".mp3", "audio/mpeg"}, {<!-- -->".mpeg", "video/mpeg"}, {<!-- -->".mpkg", "application/vnd.apple.installer + xml"}, {<!-- -->".odp", "application/vnd.oasis.opendocument.presentation"}, {<!-- -->".ods", "application/vnd.oasis.opendocument.spreadsheet"}, {<!-- -->".odt", "application/vnd.oasis.opendocument.text"}, {<!-- -->".oga", "audio/ogg"}, {<!-- -->".ogv", "video/ogg"}, {<!-- -->".ogx", "application/ogg"}, {<!-- -->".otf", "font/otf"}, {<!-- -->".png", "image/png"}, {<!-- -->".pdf", "application/pdf"}, {<!-- -->".ppt", "application/vnd.ms-powerpoint"}, {<!-- -->".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"}, {<!-- -->".rar", "application/x-rar-compressed"}, {<!-- -->".rtf", "application/rtf"}, {<!-- -->".sh", "application/x-sh"}, {<!-- -->".svg", "image/svg + xml"}, {<!-- -->".swf", "application/x-shockwave-flash"}, {<!-- -->".tar", "application/x-tar"}, {<!-- -->".tif", "image/tiff"}, {<!-- -->".tiff", "image/tiff"}, {<!-- -->".ttf", "font/ttf"}, {<!-- -->".txt", "text/plain"}, {<!-- -->".vsd", "application/vnd.visio"}, {<!-- -->".wav", "audio/wav"}, {<!-- -->".weba", "audio/webm"}, {<!-- -->".webm", "video/webm"}, {<!-- -->".webp", "image/webp"}, {<!-- -->".woff", "font/woff"}, {<!-- -->".woff2", "font/woff2"}, {<!-- -->".xhtml", "application/xhtml + xml"}, {<!-- -->".xls", "application/vnd.ms-excel"}, {<!-- -->".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}, {<!-- -->".xml", "application/xml"}, {<!-- -->".xul", "application/vnd.mozilla.xul + xml"}, {<!-- -->".zip", "application/zip"}, {<!-- -->".3gp", "video/3gpp"}, {<!-- -->".3g2", "video/3gpp2"}, {<!-- -->".7z", "application/x-7z-compressed"} };