#include "utils.hpp" // notice : the use of getline make it such as // it doesn't identify multiple delim as one : // " something \n else " -> 1 - something // 2 - else // is not the same as : // " something \n\n else " -> 1 - something // 2 - // 3 - else std::vector split(std::string input, char delimiter) { std::vector answer; std::stringstream ss(input); std::string temp; while (getline(ss, temp, delimiter)) answer.push_back(temp); return answer; } std::vector split_trim(std::string input, std::string delim, char ctrim) { std::vector split_str; std::string tmp; size_t start = 0; size_t end = 0; size_t len = 0; while (end != NPOS) { end = input.find(delim, start); len = end - start; if (end == NPOS) len = end; tmp = input.substr(start, len); if (ctrim != '\0') tmp = trim(tmp, ctrim); if (tmp.size() != 0) split_str.push_back( tmp ); start = end + delim.size(); } return split_str; } std::string trim(std::string str, char del) { size_t pos; // delete leadings del pos = str.find_first_not_of(del); if (pos == NPOS) pos = str.size(); str = str.substr(pos); // delete trailing del pos = str.find_last_not_of(del); if (pos != NPOS) str = str.substr(0, pos + 1); return str; } std::string itos(int n) { std::stringstream strs; strs << n; return ( strs.str() ); } bool is_numeric(std::string str) { for (size_t i = 0; i < str.length(); i++) { if (std::isdigit(str[i]) == false) return false; } return true; } bool is_numeric_btw(int low, int high, std::string str) { for (size_t i = 0; i < str.length(); i++) { if (std::isdigit(str[i]) == false) return false; } int n = std::strtol(str.c_str(), NULL, 10); if (n < low || n > high) return false; return true; } http_method str_to_http_method(std::string &str) { if (str == "GET") return GET; else if (str == "POST") return POST; else if (str == "DELETE") return DELETE; return UNKNOWN; } std::string http_methods_to_str(unsigned int methods) { std::string str; if (methods & GET) str.append("GET"); if (methods & POST) { if (!str.empty()) str.append(", "); str.append("POST"); } if (methods & DELETE) { if (!str.empty()) str.append(", "); str.append("DELETE"); } return (str); } # include file_type eval_file_type(const std::string &path) { struct stat s; if (::stat(path.c_str(), &s) != -1) { if (S_ISREG(s.st_mode)) return (IS_FILE); else if (S_ISDIR(s.st_mode)) return (IS_DIR); } else { std::perror("err stat()"); } return (IS_OTHER); } size_t eval_file_access(const std::string &path, int mode) { if (::access(path.c_str(), F_OK) == -1) { std::perror("err access()"); return 404; // NOT_FOUND, file doesn't exist } if (::access(path.c_str(), mode) == -1) { std::perror("err access()"); return 403; // FORBIDDEN, file doesn't have access permission } return 0; } void replace_all_substr( std::string &str, const std::string &ori_substr, const std::string &new_substr) { if (ori_substr.empty()) return; size_t pos = 0; while (1) { pos = str.find(ori_substr, pos); if (pos == NPOS) break; str.replace(pos, ori_substr.size(), new_substr); pos += new_substr.size(); } } std::string str_tolower(std::string str) { std::transform(str.begin(), str.end(), str.begin(), ::tolower); return str; } // identify a line in a string, by delim (ex. '\n') // delete this line from the string (and the following nl sequence characters) // and return the deleted line (without the followinf nl sequence characters) std::string extract_line(std::string & str, size_t pos, std::string delim) { std::string del_str; size_t begin; size_t end; size_t len; begin = str.rfind(delim, pos); if (begin == NPOS) begin = 0; else if (begin < pos) begin += delim.size(); end = str.find(delim, pos); len = end; if (end != NPOS) len = end - begin; del_str = str.substr(begin, len); str.erase(begin, len + delim.size()); return del_str; } // get a line in a string, by delim // same as extract, except it doesn't delete it std::string get_line(std::string str, size_t pos, std::string delim) { std::string ret; ret = ::extract_line(str, pos, delim); return ret; } size_t parse_http_headers ( std::string headers, std::map & fields ) { std::vector list; std::vector::iterator it; std::vector::iterator it_end; size_t err_count = 0; size_t pos; std::string key; std::string val; list = ::split_trim(headers, CRLF, ' '); it_end = list.end(); for (it = list.begin(); it != it_end; it++) { pos = (*it).find(':'); if (pos == NPOS) { err_count++; continue; } key = (*it).substr(0, pos); if ( key.find(' ') != NPOS ) { err_count++; continue; } // bad idea, in cgi we need to have the original value // key = ::str_tolower(key); // to make "key" case_insensitive val = (*it).substr(pos + 1); val = ::trim(val, ' '); fields.insert( std::pair(key, val) ); } return err_count; } void str_map_key_tolower(std::map & mp) { std::map new_mp; std::map::iterator it; std::string key; std::string value; for (it = mp.begin(); it != mp.end(); it++) { key = it->first; value = it->second; key = ::str_tolower(key); new_mp.insert( std::pair(key, value) ); } mp.swap(new_mp); } // DEBUG void throw_test() { static int i = 0; ++i; if (i % 8 == 0) throw std::bad_alloc(); } void print_special(std::string str) { char c; for (size_t i = 0; i < str.size(); i++) { c = str[i]; if (c == '\r') std::cout << YELLOW << "\\r" << RESET; else if (c == '\n') std::cout << YELLOW << "\\n" << RESET << "\n"; else std::cout << c; std::fflush(stdout); } } // OVERLOADS bool operator==(const listen_socket& lhs, int fd) { return lhs.fd == fd; } bool operator==(int fd, const listen_socket& rhs) { return fd == rhs.fd; }