xref: /aosp_15_r20/external/ot-br-posix/third_party/Simple-web-server/repo/utility.hpp (revision 4a64e381480ef79f0532b2421e44e6ee336b8e0d)
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