1*4a64e381SAndroid Build Coastguard Worker #ifndef SIMPLE_WEB_UTILITY_HPP 2*4a64e381SAndroid Build Coastguard Worker #define SIMPLE_WEB_UTILITY_HPP 3*4a64e381SAndroid Build Coastguard Worker 4*4a64e381SAndroid Build Coastguard Worker #include "status_code.hpp" 5*4a64e381SAndroid Build Coastguard Worker #include <atomic> 6*4a64e381SAndroid Build Coastguard Worker #include <chrono> 7*4a64e381SAndroid Build Coastguard Worker #include <cstdlib> 8*4a64e381SAndroid Build Coastguard Worker #include <ctime> 9*4a64e381SAndroid Build Coastguard Worker #include <iostream> 10*4a64e381SAndroid Build Coastguard Worker #include <memory> 11*4a64e381SAndroid Build Coastguard Worker #include <mutex> 12*4a64e381SAndroid Build Coastguard Worker #include <string> 13*4a64e381SAndroid Build Coastguard Worker #include <unordered_map> 14*4a64e381SAndroid Build Coastguard Worker 15*4a64e381SAndroid Build Coastguard Worker #ifndef SW_DEPRECATED 16*4a64e381SAndroid Build Coastguard Worker #if defined(__GNUC__) || defined(__clang__) 17*4a64e381SAndroid Build Coastguard Worker #define SW_DEPRECATED __attribute__((deprecated)) 18*4a64e381SAndroid Build Coastguard Worker #elif defined(_MSC_VER) 19*4a64e381SAndroid Build Coastguard Worker #define SW_DEPRECATED __declspec(deprecated) 20*4a64e381SAndroid Build Coastguard Worker #else 21*4a64e381SAndroid Build Coastguard Worker #define SW_DEPRECATED 22*4a64e381SAndroid Build Coastguard Worker #endif 23*4a64e381SAndroid Build Coastguard Worker #endif 24*4a64e381SAndroid Build Coastguard Worker 25*4a64e381SAndroid Build Coastguard Worker #if __cplusplus > 201402L || _MSVC_LANG > 201402L 26*4a64e381SAndroid Build Coastguard Worker #include <string_view> 27*4a64e381SAndroid Build Coastguard Worker namespace SimpleWeb { 28*4a64e381SAndroid Build Coastguard Worker using string_view = std::string_view; 29*4a64e381SAndroid Build Coastguard Worker } 30*4a64e381SAndroid Build Coastguard Worker #elif !defined(ASIO_STANDALONE) 31*4a64e381SAndroid Build Coastguard Worker #include <boost/utility/string_ref.hpp> 32*4a64e381SAndroid Build Coastguard Worker namespace SimpleWeb { 33*4a64e381SAndroid Build Coastguard Worker using string_view = boost::string_ref; 34*4a64e381SAndroid Build Coastguard Worker } 35*4a64e381SAndroid Build Coastguard Worker #else 36*4a64e381SAndroid Build Coastguard Worker namespace SimpleWeb { 37*4a64e381SAndroid Build Coastguard Worker using string_view = const std::string &; 38*4a64e381SAndroid Build Coastguard Worker } 39*4a64e381SAndroid Build Coastguard Worker #endif 40*4a64e381SAndroid Build Coastguard Worker 41*4a64e381SAndroid Build Coastguard Worker namespace SimpleWeb { case_insensitive_equal(const std::string & str1,const std::string & str2)42*4a64e381SAndroid Build Coastguard Worker inline bool case_insensitive_equal(const std::string &str1, const std::string &str2) noexcept { 43*4a64e381SAndroid Build Coastguard Worker return str1.size() == str2.size() && 44*4a64e381SAndroid Build Coastguard Worker std::equal(str1.begin(), str1.end(), str2.begin(), [](char a, char b) { 45*4a64e381SAndroid Build Coastguard Worker return tolower(a) == tolower(b); 46*4a64e381SAndroid Build Coastguard Worker }); 47*4a64e381SAndroid Build Coastguard Worker } 48*4a64e381SAndroid Build Coastguard Worker class CaseInsensitiveEqual { 49*4a64e381SAndroid Build Coastguard Worker public: operator ()(const std::string & str1,const std::string & str2) const50*4a64e381SAndroid Build Coastguard Worker bool operator()(const std::string &str1, const std::string &str2) const noexcept { 51*4a64e381SAndroid Build Coastguard Worker return case_insensitive_equal(str1, str2); 52*4a64e381SAndroid Build Coastguard Worker } 53*4a64e381SAndroid Build Coastguard Worker }; 54*4a64e381SAndroid Build Coastguard Worker // Based on https://stackoverflow.com/questions/2590677/how-do-i-combine-hash-values-in-c0x/2595226#2595226 55*4a64e381SAndroid Build Coastguard Worker class CaseInsensitiveHash { 56*4a64e381SAndroid Build Coastguard Worker public: operator ()(const std::string & str) const57*4a64e381SAndroid Build Coastguard Worker std::size_t operator()(const std::string &str) const noexcept { 58*4a64e381SAndroid Build Coastguard Worker std::size_t h = 0; 59*4a64e381SAndroid Build Coastguard Worker std::hash<int> hash; 60*4a64e381SAndroid Build Coastguard Worker for(auto c : str) 61*4a64e381SAndroid Build Coastguard Worker h ^= hash(tolower(c)) + 0x9e3779b9 + (h << 6) + (h >> 2); 62*4a64e381SAndroid Build Coastguard Worker return h; 63*4a64e381SAndroid Build Coastguard Worker } 64*4a64e381SAndroid Build Coastguard Worker }; 65*4a64e381SAndroid Build Coastguard Worker 66*4a64e381SAndroid Build Coastguard Worker using CaseInsensitiveMultimap = std::unordered_multimap<std::string, std::string, CaseInsensitiveHash, CaseInsensitiveEqual>; 67*4a64e381SAndroid Build Coastguard Worker 68*4a64e381SAndroid Build Coastguard Worker /// Percent encoding and decoding 69*4a64e381SAndroid Build Coastguard Worker class Percent { 70*4a64e381SAndroid Build Coastguard Worker public: 71*4a64e381SAndroid Build Coastguard Worker /// Returns percent-encoded string encode(const std::string & value)72*4a64e381SAndroid Build Coastguard Worker static std::string encode(const std::string &value) noexcept { 73*4a64e381SAndroid Build Coastguard Worker static auto hex_chars = "0123456789ABCDEF"; 74*4a64e381SAndroid Build Coastguard Worker 75*4a64e381SAndroid Build Coastguard Worker std::string result; 76*4a64e381SAndroid Build Coastguard Worker result.reserve(value.size()); // Minimum size of result 77*4a64e381SAndroid Build Coastguard Worker 78*4a64e381SAndroid Build Coastguard Worker for(auto &chr : value) { 79*4a64e381SAndroid Build Coastguard Worker if(!((chr >= '0' && chr <= '9') || (chr >= 'A' && chr <= 'Z') || (chr >= 'a' && chr <= 'z') || chr == '-' || chr == '.' || chr == '_' || chr == '~')) 80*4a64e381SAndroid Build Coastguard Worker result += std::string("%") + hex_chars[static_cast<unsigned char>(chr) >> 4] + hex_chars[static_cast<unsigned char>(chr) & 15]; 81*4a64e381SAndroid Build Coastguard Worker else 82*4a64e381SAndroid Build Coastguard Worker result += chr; 83*4a64e381SAndroid Build Coastguard Worker } 84*4a64e381SAndroid Build Coastguard Worker 85*4a64e381SAndroid Build Coastguard Worker return result; 86*4a64e381SAndroid Build Coastguard Worker } 87*4a64e381SAndroid Build Coastguard Worker 88*4a64e381SAndroid Build Coastguard Worker /// Returns percent-decoded string decode(const std::string & value)89*4a64e381SAndroid Build Coastguard Worker static std::string decode(const std::string &value) noexcept { 90*4a64e381SAndroid Build Coastguard Worker std::string result; 91*4a64e381SAndroid Build Coastguard Worker result.reserve(value.size() / 3 + (value.size() % 3)); // Minimum size of result 92*4a64e381SAndroid Build Coastguard Worker 93*4a64e381SAndroid Build Coastguard Worker for(std::size_t i = 0; i < value.size(); ++i) { 94*4a64e381SAndroid Build Coastguard Worker auto &chr = value[i]; 95*4a64e381SAndroid Build Coastguard Worker if(chr == '%' && i + 2 < value.size()) { 96*4a64e381SAndroid Build Coastguard Worker auto hex = value.substr(i + 1, 2); 97*4a64e381SAndroid Build Coastguard Worker auto decoded_chr = static_cast<char>(std::strtol(hex.c_str(), nullptr, 16)); 98*4a64e381SAndroid Build Coastguard Worker result += decoded_chr; 99*4a64e381SAndroid Build Coastguard Worker i += 2; 100*4a64e381SAndroid Build Coastguard Worker } 101*4a64e381SAndroid Build Coastguard Worker else if(chr == '+') 102*4a64e381SAndroid Build Coastguard Worker result += ' '; 103*4a64e381SAndroid Build Coastguard Worker else 104*4a64e381SAndroid Build Coastguard Worker result += chr; 105*4a64e381SAndroid Build Coastguard Worker } 106*4a64e381SAndroid Build Coastguard Worker 107*4a64e381SAndroid Build Coastguard Worker return result; 108*4a64e381SAndroid Build Coastguard Worker } 109*4a64e381SAndroid Build Coastguard Worker }; 110*4a64e381SAndroid Build Coastguard Worker 111*4a64e381SAndroid Build Coastguard Worker /// Query string creation and parsing 112*4a64e381SAndroid Build Coastguard Worker class QueryString { 113*4a64e381SAndroid Build Coastguard Worker public: 114*4a64e381SAndroid Build Coastguard Worker /// Returns query string created from given field names and values create(const CaseInsensitiveMultimap & fields)115*4a64e381SAndroid Build Coastguard Worker static std::string create(const CaseInsensitiveMultimap &fields) noexcept { 116*4a64e381SAndroid Build Coastguard Worker std::string result; 117*4a64e381SAndroid Build Coastguard Worker 118*4a64e381SAndroid Build Coastguard Worker bool first = true; 119*4a64e381SAndroid Build Coastguard Worker for(auto &field : fields) { 120*4a64e381SAndroid Build Coastguard Worker result += (!first ? "&" : "") + field.first + '=' + Percent::encode(field.second); 121*4a64e381SAndroid Build Coastguard Worker first = false; 122*4a64e381SAndroid Build Coastguard Worker } 123*4a64e381SAndroid Build Coastguard Worker 124*4a64e381SAndroid Build Coastguard Worker return result; 125*4a64e381SAndroid Build Coastguard Worker } 126*4a64e381SAndroid Build Coastguard Worker 127*4a64e381SAndroid Build Coastguard Worker /// Returns query keys with percent-decoded values. parse(const std::string & query_string)128*4a64e381SAndroid Build Coastguard Worker static CaseInsensitiveMultimap parse(const std::string &query_string) noexcept { 129*4a64e381SAndroid Build Coastguard Worker CaseInsensitiveMultimap result; 130*4a64e381SAndroid Build Coastguard Worker 131*4a64e381SAndroid Build Coastguard Worker if(query_string.empty()) 132*4a64e381SAndroid Build Coastguard Worker return result; 133*4a64e381SAndroid Build Coastguard Worker 134*4a64e381SAndroid Build Coastguard Worker std::size_t name_pos = 0; 135*4a64e381SAndroid Build Coastguard Worker auto name_end_pos = std::string::npos; 136*4a64e381SAndroid Build Coastguard Worker auto value_pos = std::string::npos; 137*4a64e381SAndroid Build Coastguard Worker for(std::size_t c = 0; c < query_string.size(); ++c) { 138*4a64e381SAndroid Build Coastguard Worker if(query_string[c] == '&') { 139*4a64e381SAndroid Build Coastguard Worker auto name = query_string.substr(name_pos, (name_end_pos == std::string::npos ? c : name_end_pos) - name_pos); 140*4a64e381SAndroid Build Coastguard Worker if(!name.empty()) { 141*4a64e381SAndroid Build Coastguard Worker auto value = value_pos == std::string::npos ? std::string() : query_string.substr(value_pos, c - value_pos); 142*4a64e381SAndroid Build Coastguard Worker result.emplace(std::move(name), Percent::decode(value)); 143*4a64e381SAndroid Build Coastguard Worker } 144*4a64e381SAndroid Build Coastguard Worker name_pos = c + 1; 145*4a64e381SAndroid Build Coastguard Worker name_end_pos = std::string::npos; 146*4a64e381SAndroid Build Coastguard Worker value_pos = std::string::npos; 147*4a64e381SAndroid Build Coastguard Worker } 148*4a64e381SAndroid Build Coastguard Worker else if(query_string[c] == '=' && name_end_pos == std::string::npos) { 149*4a64e381SAndroid Build Coastguard Worker name_end_pos = c; 150*4a64e381SAndroid Build Coastguard Worker value_pos = c + 1; 151*4a64e381SAndroid Build Coastguard Worker } 152*4a64e381SAndroid Build Coastguard Worker } 153*4a64e381SAndroid Build Coastguard Worker if(name_pos < query_string.size()) { 154*4a64e381SAndroid Build Coastguard Worker auto name = query_string.substr(name_pos, (name_end_pos == std::string::npos ? std::string::npos : name_end_pos - name_pos)); 155*4a64e381SAndroid Build Coastguard Worker if(!name.empty()) { 156*4a64e381SAndroid Build Coastguard Worker auto value = value_pos >= query_string.size() ? std::string() : query_string.substr(value_pos); 157*4a64e381SAndroid Build Coastguard Worker result.emplace(std::move(name), Percent::decode(value)); 158*4a64e381SAndroid Build Coastguard Worker } 159*4a64e381SAndroid Build Coastguard Worker } 160*4a64e381SAndroid Build Coastguard Worker 161*4a64e381SAndroid Build Coastguard Worker return result; 162*4a64e381SAndroid Build Coastguard Worker } 163*4a64e381SAndroid Build Coastguard Worker }; 164*4a64e381SAndroid Build Coastguard Worker 165*4a64e381SAndroid Build Coastguard Worker class HttpHeader { 166*4a64e381SAndroid Build Coastguard Worker public: 167*4a64e381SAndroid Build Coastguard Worker /// Parse header fields from stream parse(std::istream & stream)168*4a64e381SAndroid Build Coastguard Worker static CaseInsensitiveMultimap parse(std::istream &stream) noexcept { 169*4a64e381SAndroid Build Coastguard Worker CaseInsensitiveMultimap result; 170*4a64e381SAndroid Build Coastguard Worker std::string line; 171*4a64e381SAndroid Build Coastguard Worker std::size_t param_end; 172*4a64e381SAndroid Build Coastguard Worker while(getline(stream, line) && (param_end = line.find(':')) != std::string::npos) { 173*4a64e381SAndroid Build Coastguard Worker std::size_t value_start = param_end + 1; 174*4a64e381SAndroid Build Coastguard Worker while(value_start + 1 < line.size() && line[value_start] == ' ') 175*4a64e381SAndroid Build Coastguard Worker ++value_start; 176*4a64e381SAndroid Build Coastguard Worker if(value_start < line.size()) 177*4a64e381SAndroid Build Coastguard Worker result.emplace(line.substr(0, param_end), line.substr(value_start, line.size() - value_start - (line.back() == '\r' ? 1 : 0))); 178*4a64e381SAndroid Build Coastguard Worker } 179*4a64e381SAndroid Build Coastguard Worker return result; 180*4a64e381SAndroid Build Coastguard Worker } 181*4a64e381SAndroid Build Coastguard Worker 182*4a64e381SAndroid Build Coastguard Worker class FieldValue { 183*4a64e381SAndroid Build Coastguard Worker public: 184*4a64e381SAndroid Build Coastguard Worker class SemicolonSeparatedAttributes { 185*4a64e381SAndroid Build Coastguard Worker public: 186*4a64e381SAndroid Build Coastguard Worker /// Parse Set-Cookie or Content-Disposition from given header field value. 187*4a64e381SAndroid Build Coastguard Worker /// Attribute values are percent-decoded. parse(const std::string & value)188*4a64e381SAndroid Build Coastguard Worker static CaseInsensitiveMultimap parse(const std::string &value) { 189*4a64e381SAndroid Build Coastguard Worker CaseInsensitiveMultimap result; 190*4a64e381SAndroid Build Coastguard Worker 191*4a64e381SAndroid Build Coastguard Worker std::size_t name_start_pos = std::string::npos; 192*4a64e381SAndroid Build Coastguard Worker std::size_t name_end_pos = std::string::npos; 193*4a64e381SAndroid Build Coastguard Worker std::size_t value_start_pos = std::string::npos; 194*4a64e381SAndroid Build Coastguard Worker for(std::size_t c = 0; c < value.size(); ++c) { 195*4a64e381SAndroid Build Coastguard Worker if(name_start_pos == std::string::npos) { 196*4a64e381SAndroid Build Coastguard Worker if(value[c] != ' ' && value[c] != ';') 197*4a64e381SAndroid Build Coastguard Worker name_start_pos = c; 198*4a64e381SAndroid Build Coastguard Worker } 199*4a64e381SAndroid Build Coastguard Worker else { 200*4a64e381SAndroid Build Coastguard Worker if(name_end_pos == std::string::npos) { 201*4a64e381SAndroid Build Coastguard Worker if(value[c] == ';') { 202*4a64e381SAndroid Build Coastguard Worker result.emplace(value.substr(name_start_pos, c - name_start_pos), std::string()); 203*4a64e381SAndroid Build Coastguard Worker name_start_pos = std::string::npos; 204*4a64e381SAndroid Build Coastguard Worker } 205*4a64e381SAndroid Build Coastguard Worker else if(value[c] == '=') 206*4a64e381SAndroid Build Coastguard Worker name_end_pos = c; 207*4a64e381SAndroid Build Coastguard Worker } 208*4a64e381SAndroid Build Coastguard Worker else { 209*4a64e381SAndroid Build Coastguard Worker if(value_start_pos == std::string::npos) { 210*4a64e381SAndroid Build Coastguard Worker if(value[c] == '"' && c + 1 < value.size()) 211*4a64e381SAndroid Build Coastguard Worker value_start_pos = c + 1; 212*4a64e381SAndroid Build Coastguard Worker else 213*4a64e381SAndroid Build Coastguard Worker value_start_pos = c; 214*4a64e381SAndroid Build Coastguard Worker } 215*4a64e381SAndroid Build Coastguard Worker else if(value[c] == '"' || value[c] == ';') { 216*4a64e381SAndroid Build Coastguard Worker result.emplace(value.substr(name_start_pos, name_end_pos - name_start_pos), Percent::decode(value.substr(value_start_pos, c - value_start_pos))); 217*4a64e381SAndroid Build Coastguard Worker name_start_pos = std::string::npos; 218*4a64e381SAndroid Build Coastguard Worker name_end_pos = std::string::npos; 219*4a64e381SAndroid Build Coastguard Worker value_start_pos = std::string::npos; 220*4a64e381SAndroid Build Coastguard Worker } 221*4a64e381SAndroid Build Coastguard Worker } 222*4a64e381SAndroid Build Coastguard Worker } 223*4a64e381SAndroid Build Coastguard Worker } 224*4a64e381SAndroid Build Coastguard Worker if(name_start_pos != std::string::npos) { 225*4a64e381SAndroid Build Coastguard Worker if(name_end_pos == std::string::npos) 226*4a64e381SAndroid Build Coastguard Worker result.emplace(value.substr(name_start_pos), std::string()); 227*4a64e381SAndroid Build Coastguard Worker else if(value_start_pos != std::string::npos) { 228*4a64e381SAndroid Build Coastguard Worker if(value.back() == '"') 229*4a64e381SAndroid Build Coastguard Worker result.emplace(value.substr(name_start_pos, name_end_pos - name_start_pos), Percent::decode(value.substr(value_start_pos, value.size() - 1))); 230*4a64e381SAndroid Build Coastguard Worker else 231*4a64e381SAndroid Build Coastguard Worker result.emplace(value.substr(name_start_pos, name_end_pos - name_start_pos), Percent::decode(value.substr(value_start_pos))); 232*4a64e381SAndroid Build Coastguard Worker } 233*4a64e381SAndroid Build Coastguard Worker } 234*4a64e381SAndroid Build Coastguard Worker 235*4a64e381SAndroid Build Coastguard Worker return result; 236*4a64e381SAndroid Build Coastguard Worker } 237*4a64e381SAndroid Build Coastguard Worker }; 238*4a64e381SAndroid Build Coastguard Worker }; 239*4a64e381SAndroid Build Coastguard Worker }; 240*4a64e381SAndroid Build Coastguard Worker 241*4a64e381SAndroid Build Coastguard Worker class RequestMessage { 242*4a64e381SAndroid Build Coastguard Worker public: 243*4a64e381SAndroid Build Coastguard Worker /** Parse request line and header fields from a request stream. 244*4a64e381SAndroid Build Coastguard Worker * 245*4a64e381SAndroid Build Coastguard Worker * @param[in] stream Stream to parse. 246*4a64e381SAndroid Build Coastguard Worker * @param[out] method HTTP method. 247*4a64e381SAndroid Build Coastguard Worker * @param[out] path Path from request URI. 248*4a64e381SAndroid Build Coastguard Worker * @param[out] query_string Query string from request URI. 249*4a64e381SAndroid Build Coastguard Worker * @param[out] version HTTP version. 250*4a64e381SAndroid Build Coastguard Worker * @param[out] header Header fields. 251*4a64e381SAndroid Build Coastguard Worker * 252*4a64e381SAndroid Build Coastguard Worker * @return True if stream is parsed successfully, false if not. 253*4a64e381SAndroid Build Coastguard Worker */ parse(std::istream & stream,std::string & method,std::string & path,std::string & query_string,std::string & version,CaseInsensitiveMultimap & header)254*4a64e381SAndroid Build Coastguard Worker static bool parse(std::istream &stream, std::string &method, std::string &path, std::string &query_string, std::string &version, CaseInsensitiveMultimap &header) noexcept { 255*4a64e381SAndroid Build Coastguard Worker std::string line; 256*4a64e381SAndroid Build Coastguard Worker std::size_t method_end; 257*4a64e381SAndroid Build Coastguard Worker if(getline(stream, line) && (method_end = line.find(' ')) != std::string::npos) { 258*4a64e381SAndroid Build Coastguard Worker method = line.substr(0, method_end); 259*4a64e381SAndroid Build Coastguard Worker 260*4a64e381SAndroid Build Coastguard Worker std::size_t query_start = std::string::npos; 261*4a64e381SAndroid Build Coastguard Worker std::size_t path_and_query_string_end = std::string::npos; 262*4a64e381SAndroid Build Coastguard Worker for(std::size_t i = method_end + 1; i < line.size(); ++i) { 263*4a64e381SAndroid Build Coastguard Worker if(line[i] == '?' && (i + 1) < line.size() && query_start == std::string::npos) 264*4a64e381SAndroid Build Coastguard Worker query_start = i + 1; 265*4a64e381SAndroid Build Coastguard Worker else if(line[i] == ' ') { 266*4a64e381SAndroid Build Coastguard Worker path_and_query_string_end = i; 267*4a64e381SAndroid Build Coastguard Worker break; 268*4a64e381SAndroid Build Coastguard Worker } 269*4a64e381SAndroid Build Coastguard Worker } 270*4a64e381SAndroid Build Coastguard Worker if(path_and_query_string_end != std::string::npos) { 271*4a64e381SAndroid Build Coastguard Worker if(query_start != std::string::npos) { 272*4a64e381SAndroid Build Coastguard Worker path = line.substr(method_end + 1, query_start - method_end - 2); 273*4a64e381SAndroid Build Coastguard Worker query_string = line.substr(query_start, path_and_query_string_end - query_start); 274*4a64e381SAndroid Build Coastguard Worker } 275*4a64e381SAndroid Build Coastguard Worker else 276*4a64e381SAndroid Build Coastguard Worker path = line.substr(method_end + 1, path_and_query_string_end - method_end - 1); 277*4a64e381SAndroid Build Coastguard Worker 278*4a64e381SAndroid Build Coastguard Worker std::size_t protocol_end; 279*4a64e381SAndroid Build Coastguard Worker if((protocol_end = line.find('/', path_and_query_string_end + 1)) != std::string::npos) { 280*4a64e381SAndroid Build Coastguard Worker if(line.compare(path_and_query_string_end + 1, protocol_end - path_and_query_string_end - 1, "HTTP") != 0) 281*4a64e381SAndroid Build Coastguard Worker return false; 282*4a64e381SAndroid Build Coastguard Worker version = line.substr(protocol_end + 1, line.size() - protocol_end - 2); 283*4a64e381SAndroid Build Coastguard Worker } 284*4a64e381SAndroid Build Coastguard Worker else 285*4a64e381SAndroid Build Coastguard Worker return false; 286*4a64e381SAndroid Build Coastguard Worker 287*4a64e381SAndroid Build Coastguard Worker header = HttpHeader::parse(stream); 288*4a64e381SAndroid Build Coastguard Worker } 289*4a64e381SAndroid Build Coastguard Worker else 290*4a64e381SAndroid Build Coastguard Worker return false; 291*4a64e381SAndroid Build Coastguard Worker } 292*4a64e381SAndroid Build Coastguard Worker else 293*4a64e381SAndroid Build Coastguard Worker return false; 294*4a64e381SAndroid Build Coastguard Worker return true; 295*4a64e381SAndroid Build Coastguard Worker } 296*4a64e381SAndroid Build Coastguard Worker }; 297*4a64e381SAndroid Build Coastguard Worker 298*4a64e381SAndroid Build Coastguard Worker class ResponseMessage { 299*4a64e381SAndroid Build Coastguard Worker public: 300*4a64e381SAndroid Build Coastguard Worker /** Parse status line and header fields from a response stream. 301*4a64e381SAndroid Build Coastguard Worker * 302*4a64e381SAndroid Build Coastguard Worker * @param[in] stream Stream to parse. 303*4a64e381SAndroid Build Coastguard Worker * @param[out] version HTTP version. 304*4a64e381SAndroid Build Coastguard Worker * @param[out] status_code HTTP status code. 305*4a64e381SAndroid Build Coastguard Worker * @param[out] header Header fields. 306*4a64e381SAndroid Build Coastguard Worker * 307*4a64e381SAndroid Build Coastguard Worker * @return True if stream is parsed successfully, false if not. 308*4a64e381SAndroid Build Coastguard Worker */ parse(std::istream & stream,std::string & version,std::string & status_code,CaseInsensitiveMultimap & header)309*4a64e381SAndroid Build Coastguard Worker static bool parse(std::istream &stream, std::string &version, std::string &status_code, CaseInsensitiveMultimap &header) noexcept { 310*4a64e381SAndroid Build Coastguard Worker std::string line; 311*4a64e381SAndroid Build Coastguard Worker std::size_t version_end; 312*4a64e381SAndroid Build Coastguard Worker if(getline(stream, line) && (version_end = line.find(' ')) != std::string::npos) { 313*4a64e381SAndroid Build Coastguard Worker if(5 < line.size()) 314*4a64e381SAndroid Build Coastguard Worker version = line.substr(5, version_end - 5); 315*4a64e381SAndroid Build Coastguard Worker else 316*4a64e381SAndroid Build Coastguard Worker return false; 317*4a64e381SAndroid Build Coastguard Worker if((version_end + 1) < line.size()) 318*4a64e381SAndroid Build Coastguard Worker status_code = line.substr(version_end + 1, line.size() - (version_end + 1) - (line.back() == '\r' ? 1 : 0)); 319*4a64e381SAndroid Build Coastguard Worker else 320*4a64e381SAndroid Build Coastguard Worker return false; 321*4a64e381SAndroid Build Coastguard Worker 322*4a64e381SAndroid Build Coastguard Worker header = HttpHeader::parse(stream); 323*4a64e381SAndroid Build Coastguard Worker } 324*4a64e381SAndroid Build Coastguard Worker else 325*4a64e381SAndroid Build Coastguard Worker return false; 326*4a64e381SAndroid Build Coastguard Worker return true; 327*4a64e381SAndroid Build Coastguard Worker } 328*4a64e381SAndroid Build Coastguard Worker }; 329*4a64e381SAndroid Build Coastguard Worker 330*4a64e381SAndroid Build Coastguard Worker /// Date class working with formats specified in RFC 7231 Date/Time Formats 331*4a64e381SAndroid Build Coastguard Worker class Date { 332*4a64e381SAndroid Build Coastguard Worker public: 333*4a64e381SAndroid Build Coastguard Worker /// Returns the given std::chrono::system_clock::time_point as a string with the following format: Wed, 31 Jul 2019 11:34:23 GMT. to_string(const std::chrono::system_clock::time_point time_point)334*4a64e381SAndroid Build Coastguard Worker static std::string to_string(const std::chrono::system_clock::time_point time_point) noexcept { 335*4a64e381SAndroid Build Coastguard Worker static std::string result_cache; 336*4a64e381SAndroid Build Coastguard Worker static std::chrono::system_clock::time_point last_time_point; 337*4a64e381SAndroid Build Coastguard Worker 338*4a64e381SAndroid Build Coastguard Worker static std::mutex mutex; 339*4a64e381SAndroid Build Coastguard Worker std::lock_guard<std::mutex> lock(mutex); 340*4a64e381SAndroid Build Coastguard Worker 341*4a64e381SAndroid Build Coastguard Worker if(std::chrono::duration_cast<std::chrono::seconds>(time_point - last_time_point).count() == 0 && !result_cache.empty()) 342*4a64e381SAndroid Build Coastguard Worker return result_cache; 343*4a64e381SAndroid Build Coastguard Worker 344*4a64e381SAndroid Build Coastguard Worker last_time_point = time_point; 345*4a64e381SAndroid Build Coastguard Worker 346*4a64e381SAndroid Build Coastguard Worker std::string result; 347*4a64e381SAndroid Build Coastguard Worker result.reserve(29); 348*4a64e381SAndroid Build Coastguard Worker 349*4a64e381SAndroid Build Coastguard Worker auto time = std::chrono::system_clock::to_time_t(time_point); 350*4a64e381SAndroid Build Coastguard Worker tm tm; 351*4a64e381SAndroid Build Coastguard Worker #if defined(_MSC_VER) || defined(__MINGW32__) 352*4a64e381SAndroid Build Coastguard Worker if(gmtime_s(&tm, &time) != 0) 353*4a64e381SAndroid Build Coastguard Worker return {}; 354*4a64e381SAndroid Build Coastguard Worker auto gmtime = &tm; 355*4a64e381SAndroid Build Coastguard Worker #else 356*4a64e381SAndroid Build Coastguard Worker auto gmtime = gmtime_r(&time, &tm); 357*4a64e381SAndroid Build Coastguard Worker if(!gmtime) 358*4a64e381SAndroid Build Coastguard Worker return {}; 359*4a64e381SAndroid Build Coastguard Worker #endif 360*4a64e381SAndroid Build Coastguard Worker 361*4a64e381SAndroid Build Coastguard Worker switch(gmtime->tm_wday) { 362*4a64e381SAndroid Build Coastguard Worker case 0: result += "Sun, "; break; 363*4a64e381SAndroid Build Coastguard Worker case 1: result += "Mon, "; break; 364*4a64e381SAndroid Build Coastguard Worker case 2: result += "Tue, "; break; 365*4a64e381SAndroid Build Coastguard Worker case 3: result += "Wed, "; break; 366*4a64e381SAndroid Build Coastguard Worker case 4: result += "Thu, "; break; 367*4a64e381SAndroid Build Coastguard Worker case 5: result += "Fri, "; break; 368*4a64e381SAndroid Build Coastguard Worker case 6: result += "Sat, "; break; 369*4a64e381SAndroid Build Coastguard Worker } 370*4a64e381SAndroid Build Coastguard Worker 371*4a64e381SAndroid Build Coastguard Worker result += gmtime->tm_mday < 10 ? '0' : static_cast<char>(gmtime->tm_mday / 10 + 48); 372*4a64e381SAndroid Build Coastguard Worker result += static_cast<char>(gmtime->tm_mday % 10 + 48); 373*4a64e381SAndroid Build Coastguard Worker 374*4a64e381SAndroid Build Coastguard Worker switch(gmtime->tm_mon) { 375*4a64e381SAndroid Build Coastguard Worker case 0: result += " Jan "; break; 376*4a64e381SAndroid Build Coastguard Worker case 1: result += " Feb "; break; 377*4a64e381SAndroid Build Coastguard Worker case 2: result += " Mar "; break; 378*4a64e381SAndroid Build Coastguard Worker case 3: result += " Apr "; break; 379*4a64e381SAndroid Build Coastguard Worker case 4: result += " May "; break; 380*4a64e381SAndroid Build Coastguard Worker case 5: result += " Jun "; break; 381*4a64e381SAndroid Build Coastguard Worker case 6: result += " Jul "; break; 382*4a64e381SAndroid Build Coastguard Worker case 7: result += " Aug "; break; 383*4a64e381SAndroid Build Coastguard Worker case 8: result += " Sep "; break; 384*4a64e381SAndroid Build Coastguard Worker case 9: result += " Oct "; break; 385*4a64e381SAndroid Build Coastguard Worker case 10: result += " Nov "; break; 386*4a64e381SAndroid Build Coastguard Worker case 11: result += " Dec "; break; 387*4a64e381SAndroid Build Coastguard Worker } 388*4a64e381SAndroid Build Coastguard Worker 389*4a64e381SAndroid Build Coastguard Worker auto year = gmtime->tm_year + 1900; 390*4a64e381SAndroid Build Coastguard Worker result += static_cast<char>(year / 1000 + 48); 391*4a64e381SAndroid Build Coastguard Worker result += static_cast<char>((year / 100) % 10 + 48); 392*4a64e381SAndroid Build Coastguard Worker result += static_cast<char>((year / 10) % 10 + 48); 393*4a64e381SAndroid Build Coastguard Worker result += static_cast<char>(year % 10 + 48); 394*4a64e381SAndroid Build Coastguard Worker result += ' '; 395*4a64e381SAndroid Build Coastguard Worker 396*4a64e381SAndroid Build Coastguard Worker result += gmtime->tm_hour < 10 ? '0' : static_cast<char>(gmtime->tm_hour / 10 + 48); 397*4a64e381SAndroid Build Coastguard Worker result += static_cast<char>(gmtime->tm_hour % 10 + 48); 398*4a64e381SAndroid Build Coastguard Worker result += ':'; 399*4a64e381SAndroid Build Coastguard Worker 400*4a64e381SAndroid Build Coastguard Worker result += gmtime->tm_min < 10 ? '0' : static_cast<char>(gmtime->tm_min / 10 + 48); 401*4a64e381SAndroid Build Coastguard Worker result += static_cast<char>(gmtime->tm_min % 10 + 48); 402*4a64e381SAndroid Build Coastguard Worker result += ':'; 403*4a64e381SAndroid Build Coastguard Worker 404*4a64e381SAndroid Build Coastguard Worker result += gmtime->tm_sec < 10 ? '0' : static_cast<char>(gmtime->tm_sec / 10 + 48); 405*4a64e381SAndroid Build Coastguard Worker result += static_cast<char>(gmtime->tm_sec % 10 + 48); 406*4a64e381SAndroid Build Coastguard Worker 407*4a64e381SAndroid Build Coastguard Worker result += " GMT"; 408*4a64e381SAndroid Build Coastguard Worker 409*4a64e381SAndroid Build Coastguard Worker result_cache = result; 410*4a64e381SAndroid Build Coastguard Worker return result; 411*4a64e381SAndroid Build Coastguard Worker } 412*4a64e381SAndroid Build Coastguard Worker }; 413*4a64e381SAndroid Build Coastguard Worker } // namespace SimpleWeb 414*4a64e381SAndroid Build Coastguard Worker 415*4a64e381SAndroid Build Coastguard Worker #ifdef __SSE2__ 416*4a64e381SAndroid Build Coastguard Worker #include <emmintrin.h> 417*4a64e381SAndroid Build Coastguard Worker namespace SimpleWeb { spin_loop_pause()418*4a64e381SAndroid Build Coastguard Worker inline void spin_loop_pause() noexcept { _mm_pause(); } 419*4a64e381SAndroid Build Coastguard Worker } // namespace SimpleWeb 420*4a64e381SAndroid Build Coastguard Worker // TODO: need verification that the following checks are correct: 421*4a64e381SAndroid Build Coastguard Worker #elif defined(_MSC_VER) && _MSC_VER >= 1800 && (defined(_M_X64) || defined(_M_IX86)) 422*4a64e381SAndroid Build Coastguard Worker #include <intrin.h> 423*4a64e381SAndroid Build Coastguard Worker namespace SimpleWeb { spin_loop_pause()424*4a64e381SAndroid Build Coastguard Worker inline void spin_loop_pause() noexcept { _mm_pause(); } 425*4a64e381SAndroid Build Coastguard Worker } // namespace SimpleWeb 426*4a64e381SAndroid Build Coastguard Worker #else 427*4a64e381SAndroid Build Coastguard Worker namespace SimpleWeb { spin_loop_pause()428*4a64e381SAndroid Build Coastguard Worker inline void spin_loop_pause() noexcept {} 429*4a64e381SAndroid Build Coastguard Worker } // namespace SimpleWeb 430*4a64e381SAndroid Build Coastguard Worker #endif 431*4a64e381SAndroid Build Coastguard Worker 432*4a64e381SAndroid Build Coastguard Worker namespace SimpleWeb { 433*4a64e381SAndroid Build Coastguard Worker /// Makes it possible to for instance cancel Asio handlers without stopping asio::io_service. 434*4a64e381SAndroid Build Coastguard Worker class ScopeRunner { 435*4a64e381SAndroid Build Coastguard Worker /// Scope count that is set to -1 if scopes are to be canceled. 436*4a64e381SAndroid Build Coastguard Worker std::atomic<long> count; 437*4a64e381SAndroid Build Coastguard Worker 438*4a64e381SAndroid Build Coastguard Worker public: 439*4a64e381SAndroid Build Coastguard Worker class SharedLock { 440*4a64e381SAndroid Build Coastguard Worker friend class ScopeRunner; 441*4a64e381SAndroid Build Coastguard Worker std::atomic<long> &count; SharedLock(std::atomic<long> & count)442*4a64e381SAndroid Build Coastguard Worker SharedLock(std::atomic<long> &count) noexcept : count(count) {} 443*4a64e381SAndroid Build Coastguard Worker SharedLock &operator=(const SharedLock &) = delete; 444*4a64e381SAndroid Build Coastguard Worker SharedLock(const SharedLock &) = delete; 445*4a64e381SAndroid Build Coastguard Worker 446*4a64e381SAndroid Build Coastguard Worker public: ~SharedLock()447*4a64e381SAndroid Build Coastguard Worker ~SharedLock() noexcept { 448*4a64e381SAndroid Build Coastguard Worker count.fetch_sub(1); 449*4a64e381SAndroid Build Coastguard Worker } 450*4a64e381SAndroid Build Coastguard Worker }; 451*4a64e381SAndroid Build Coastguard Worker ScopeRunner()452*4a64e381SAndroid Build Coastguard Worker ScopeRunner() noexcept : count(0) {} 453*4a64e381SAndroid Build Coastguard Worker 454*4a64e381SAndroid Build Coastguard Worker /// Returns nullptr if scope should be exited, or a shared lock otherwise. 455*4a64e381SAndroid Build Coastguard Worker /// The shared lock ensures that a potential destructor call is delayed until all locks are released. continue_lock()456*4a64e381SAndroid Build Coastguard Worker std::unique_ptr<SharedLock> continue_lock() noexcept { 457*4a64e381SAndroid Build Coastguard Worker long expected = count; 458*4a64e381SAndroid Build Coastguard Worker while(expected >= 0 && !count.compare_exchange_weak(expected, expected + 1)) 459*4a64e381SAndroid Build Coastguard Worker spin_loop_pause(); 460*4a64e381SAndroid Build Coastguard Worker 461*4a64e381SAndroid Build Coastguard Worker if(expected < 0) 462*4a64e381SAndroid Build Coastguard Worker return nullptr; 463*4a64e381SAndroid Build Coastguard Worker else 464*4a64e381SAndroid Build Coastguard Worker return std::unique_ptr<SharedLock>(new SharedLock(count)); 465*4a64e381SAndroid Build Coastguard Worker } 466*4a64e381SAndroid Build Coastguard Worker 467*4a64e381SAndroid Build Coastguard Worker /// Blocks until all shared locks are released, then prevents future shared locks. stop()468*4a64e381SAndroid Build Coastguard Worker void stop() noexcept { 469*4a64e381SAndroid Build Coastguard Worker long expected = 0; 470*4a64e381SAndroid Build Coastguard Worker while(!count.compare_exchange_weak(expected, -1)) { 471*4a64e381SAndroid Build Coastguard Worker if(expected < 0) 472*4a64e381SAndroid Build Coastguard Worker return; 473*4a64e381SAndroid Build Coastguard Worker expected = 0; 474*4a64e381SAndroid Build Coastguard Worker spin_loop_pause(); 475*4a64e381SAndroid Build Coastguard Worker } 476*4a64e381SAndroid Build Coastguard Worker } 477*4a64e381SAndroid Build Coastguard Worker }; 478*4a64e381SAndroid Build Coastguard Worker } // namespace SimpleWeb 479*4a64e381SAndroid Build Coastguard Worker 480*4a64e381SAndroid Build Coastguard Worker #endif // SIMPLE_WEB_UTILITY_HPP 481