13#include <unordered_map>
17#include "crow/settings.h"
22#if defined(__GNUG__) || defined(__clang__)
23#define CROW_LIKELY(X) __builtin_expect(!!(X), 1)
24#define CROW_UNLIKELY(X) __builtin_expect(!!(X), 0)
26#define CROW_LIKELY(X) (X)
27#define CROW_UNLIKELY(X) (X)
35#ifndef CROW_MSVC_WORKAROUND
39 OutOfRange(
unsigned ,
unsigned ) {}
42 constexpr unsigned requires_in_range(
unsigned i,
unsigned len)
44 return i >= len ?
throw OutOfRange(i, len) : i;
50 const char*
const begin_;
55 constexpr const_str(
const char (&arr)[N]):
56 begin_(arr), size_(N - 1)
58 static_assert(N >= 1,
"not a string literal");
60 constexpr char operator[](
unsigned i)
const
62 return requires_in_range(i, size_), begin_[i];
65 constexpr operator const char*()
const
70 constexpr const char* begin()
const {
return begin_; }
71 constexpr const char* end()
const {
return begin_ + size_; }
73 constexpr unsigned size()
const
79 constexpr unsigned find_closing_tag(const_str s,
unsigned p)
81 return s[p] ==
'>' ? p : find_closing_tag(s, p + 1);
85 constexpr bool is_valid(const_str s,
unsigned i = 0,
int f = 0)
87 return i == s.size() ? f == 0 :
88 f < 0 || f >= 2 ? false :
89 s[i] ==
'<' ? is_valid(s, i + 1, f + 1) :
90 s[i] ==
'>' ? is_valid(s, i + 1, f - 1) :
91 is_valid(s, i + 1, f);
94 constexpr bool is_equ_p(
const char* a,
const char* b,
unsigned n)
96 return *a == 0 && *b == 0 && n == 0 ? true :
97 (*a == 0 || *b == 0) ?
false :
100 is_equ_p(a + 1, b + 1, n - 1);
103 constexpr bool is_equ_n(const_str a,
unsigned ai, const_str b,
unsigned bi,
unsigned n)
105 return ai + n > a.size() || bi + n > b.size() ? false :
107 a[ai] != b[bi] ? false :
108 is_equ_n(a, ai + 1, b, bi + 1, n - 1);
111 constexpr bool is_int(const_str s,
unsigned i)
113 return is_equ_n(s, i,
"<int>", 0, 5);
116 constexpr bool is_uint(const_str s,
unsigned i)
118 return is_equ_n(s, i,
"<uint>", 0, 6);
121 constexpr bool is_float(const_str s,
unsigned i)
123 return is_equ_n(s, i,
"<float>", 0, 7) ||
124 is_equ_n(s, i,
"<double>", 0, 8);
127 constexpr bool is_str(const_str s,
unsigned i)
129 return is_equ_n(s, i,
"<str>", 0, 5) ||
130 is_equ_n(s, i,
"<string>", 0, 8);
133 constexpr bool is_path(const_str s,
unsigned i)
135 return is_equ_n(s, i,
"<path>", 0, 6);
141 static const int value = 0;
143#define CROW_INTERNAL_PARAMETER_TAG(t, i) \
145 struct parameter_tag<t> \
147 static const int value = i; \
149 CROW_INTERNAL_PARAMETER_TAG(
int, 1);
150 CROW_INTERNAL_PARAMETER_TAG(
char, 1);
151 CROW_INTERNAL_PARAMETER_TAG(
short, 1);
152 CROW_INTERNAL_PARAMETER_TAG(
long, 1);
153 CROW_INTERNAL_PARAMETER_TAG(
long long, 1);
154 CROW_INTERNAL_PARAMETER_TAG(
unsigned int, 2);
155 CROW_INTERNAL_PARAMETER_TAG(
unsigned char, 2);
156 CROW_INTERNAL_PARAMETER_TAG(
unsigned short, 2);
157 CROW_INTERNAL_PARAMETER_TAG(
unsigned long, 2);
158 CROW_INTERNAL_PARAMETER_TAG(
unsigned long long, 2);
159 CROW_INTERNAL_PARAMETER_TAG(
double, 3);
160 CROW_INTERNAL_PARAMETER_TAG(std::string, 4);
161#undef CROW_INTERNAL_PARAMETER_TAG
162 template<
typename... Args>
163 struct compute_parameter_tag_from_args_list;
166 struct compute_parameter_tag_from_args_list<>
168 static const int value = 0;
171 template<
typename Arg,
typename... Args>
172 struct compute_parameter_tag_from_args_list<Arg, Args...>
174 static const int sub_value =
175 compute_parameter_tag_from_args_list<Args...>::value;
176 static const int value =
177 parameter_tag<typename std::decay<Arg>::type>::value ? sub_value * 6 + parameter_tag<typename std::decay<Arg>::type>::value : sub_value;
180 static inline bool is_parameter_tag_compatible(uint64_t a, uint64_t b)
192 return is_parameter_tag_compatible(a / 6, b / 6);
195 static inline unsigned find_closing_tag_runtime(
const char* s,
unsigned p)
197 return s[p] == 0 ?
throw std::runtime_error(
"unmatched tag <") :
199 find_closing_tag_runtime(s, p + 1);
202 static inline uint64_t get_parameter_tag_runtime(
const char* s,
unsigned p = 0)
204 return s[p] == 0 ? 0 :
206 std::strncmp(s + p,
"<int>", 5) == 0 ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 1 :
207 std::strncmp(s + p,
"<uint>", 6) == 0 ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 2 :
208 (std::strncmp(s + p,
"<float>", 7) == 0 ||
209 std::strncmp(s + p,
"<double>", 8) == 0) ?
210 get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 3 :
211 (std::strncmp(s + p,
"<str>", 5) == 0 ||
212 std::strncmp(s + p,
"<string>", 8) == 0) ?
213 get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 4 :
214 std::strncmp(s + p,
"<path>", 6) == 0 ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 5 :
215 throw std::runtime_error(
"invalid parameter type")) :
216 get_parameter_tag_runtime(s, p + 1);
218#ifndef CROW_MSVC_WORKAROUND
219 constexpr uint64_t get_parameter_tag(const_str s,
unsigned p = 0)
221 return p == s.size() ? 0 :
223 is_int(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 1 :
224 is_uint(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 2 :
225 is_float(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 3 :
226 is_str(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 4 :
227 is_path(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 5 :
228 throw std::runtime_error(
"invalid parameter type")) :
229 get_parameter_tag(s, p + 1);
233 template<
typename... T>
237 using push = S<U, T...>;
239 using push_back = S<T..., U>;
240 template<
template<
typename... Args>
class U>
241 using rebind = U<T...>;
245 template<
typename F,
typename Set>
247 template<
typename F,
typename... Args>
248 struct CallHelper<F, S<Args...>>
250 template<
typename F1,
typename... Args1,
typename =
decltype(std::declval<F1>()(std::declval<Args1>()...))>
251 static char __test(
int);
253 template<
typename...>
254 static int __test(...);
256 static constexpr bool value =
sizeof(__test<F, Args...>(0)) ==
sizeof(char);
260 template<
typename T,
typename Tuple>
264 struct has_type<T, std::tuple<>> : std::false_type
267 template<
typename T,
typename U,
typename... Ts>
268 struct has_type<T, std::tuple<U, Ts...>> : has_type<T, std::tuple<Ts...>>
271 template<
typename T,
typename... Ts>
272 struct has_type<T, std::tuple<T, Ts...>> : std::true_type
276 template<
class T,
class Tuple>
279 template<
class T,
class... Types>
280 struct tuple_index<T, std::tuple<T, Types...>>
282 static const int value = 0;
285 template<
class T,
class U,
class... Types>
286 struct tuple_index<T, std::tuple<U, Types...>>
288 static const int value = 1 + tuple_index<T, std::tuple<Types...>>::value;
292 template<
typename T,
typename Tup>
293 typename std::enable_if<has_type<T&, Tup>::value,
typename std::decay<T>::type&&>::type
294 tuple_extract(Tup& tup)
296 return std::move(std::get<T&>(tup));
299 template<
typename T,
typename Tup>
300 typename std::enable_if<!has_type<T&, Tup>::value, T>::type
310 using all_true = std::is_same<bool_pack<bs...,
true>, bool_pack<
true, bs...>>;
313 struct single_tag_to_type
317 struct single_tag_to_type<1>
319 using type = int64_t;
323 struct single_tag_to_type<2>
325 using type = uint64_t;
329 struct single_tag_to_type<3>
335 struct single_tag_to_type<4>
337 using type = std::string;
341 struct single_tag_to_type<5>
343 using type = std::string;
347 template<u
int64_t Tag>
350 using subarguments =
typename arguments<Tag / 6>::type;
352 typename subarguments::template push<typename single_tag_to_type<Tag % 6>::type>;
361 template<
typename... T>
362 struct last_element_type
364 using type =
typename std::tuple_element<
sizeof...(T) - 1, std::tuple<T...>>::type;
369 struct last_element_type<>
375 using Invoke =
typename T::type;
377 template<
unsigned...>
383 template<
class S1,
class S2>
386 template<
unsigned... I1,
unsigned... I2>
387 struct concat<seq<I1...>, seq<I2...>> : seq<I1..., (sizeof...(I1) + I2)...>
390 template<
class S1,
class S2>
391 using Concat = Invoke<concat<S1, S2>>;
396 using GenSeq = Invoke<gen_seq<N>>;
399 struct gen_seq : Concat<GenSeq<N / 2>, GenSeq<N - N / 2>>
403 struct gen_seq<0> : seq<>
406 struct gen_seq<1> : seq<0>
409 template<
typename Seq,
typename Tuple>
410 struct pop_back_helper;
412 template<
unsigned... N,
typename Tuple>
413 struct pop_back_helper<seq<N...>, Tuple>
415 template<
template<
typename... Args>
class U>
416 using rebind = U<typename std::tuple_element<N, Tuple>::type...>;
419 template<
typename... T>
422 template<
template<
typename... Args>
class U>
423 using rebind =
typename pop_back_helper<
typename gen_seq<
sizeof...(T) - 1>::type, std::tuple<T...>>::template rebind<U>;
429 template<
template<
typename... Args>
class U>
434 template<
typename Tp,
typename... List>
435 struct contains : std::true_type
438 template<
typename Tp,
typename Head,
typename... Rest>
439 struct contains<Tp, Head, Rest...> : std::conditional<std::is_same<Tp, Head>::value, std::true_type, contains<Tp, Rest...>>::type
442 template<
typename Tp>
443 struct contains<Tp> : std::false_type
456#define CROW_INTERNAL_PROMOTE_TYPE(t1, t2) \
463 CROW_INTERNAL_PROMOTE_TYPE(
char, int64_t);
464 CROW_INTERNAL_PROMOTE_TYPE(
short, int64_t);
465 CROW_INTERNAL_PROMOTE_TYPE(
int, int64_t);
466 CROW_INTERNAL_PROMOTE_TYPE(
long, int64_t);
467 CROW_INTERNAL_PROMOTE_TYPE(
long long, int64_t);
468 CROW_INTERNAL_PROMOTE_TYPE(
unsigned char, uint64_t);
469 CROW_INTERNAL_PROMOTE_TYPE(
unsigned short, uint64_t);
470 CROW_INTERNAL_PROMOTE_TYPE(
unsigned int, uint64_t);
471 CROW_INTERNAL_PROMOTE_TYPE(
unsigned long, uint64_t);
472 CROW_INTERNAL_PROMOTE_TYPE(
unsigned long long, uint64_t);
473 CROW_INTERNAL_PROMOTE_TYPE(
float,
double);
474#undef CROW_INTERNAL_PROMOTE_TYPE
477 using promote_t =
typename promote<T>::type;
484 template<
class T, std::size_t N,
class... Args>
485 struct get_index_of_element_from_tuple_by_type_impl
487 static constexpr auto value = N;
490 template<
class T, std::size_t N,
class... Args>
491 struct get_index_of_element_from_tuple_by_type_impl<T, N, T, Args...>
493 static constexpr auto value = N;
496 template<
class T, std::size_t N,
class U,
class... Args>
497 struct get_index_of_element_from_tuple_by_type_impl<T, N, U, Args...>
499 static constexpr auto value = get_index_of_element_from_tuple_by_type_impl<T, N + 1, Args...>::value;
505 template<
class T,
class... Args>
506 T& get_element_by_type(std::tuple<Args...>& t)
508 return std::get<detail::get_index_of_element_from_tuple_by_type_impl<T, 0, Args...>::value>(t);
512 struct function_traits;
514#ifndef CROW_MSVC_WORKAROUND
516 struct function_traits :
public function_traits<decltype(&T::operator())>
518 using parent_t = function_traits<
decltype(&T::operator())>;
519 static const size_t arity = parent_t::arity;
520 using result_type =
typename parent_t::result_type;
522 using arg =
typename parent_t::template arg<i>;
526 template<
typename ClassType,
typename R,
typename... Args>
527 struct function_traits<R (ClassType::*)(Args...) const>
529 static const size_t arity =
sizeof...(Args);
531 typedef R result_type;
534 using arg =
typename std::tuple_element<i, std::tuple<Args...>>::type;
537 template<
typename ClassType,
typename R,
typename... Args>
538 struct function_traits<R (ClassType::*)(Args...)>
540 static const size_t arity =
sizeof...(Args);
542 typedef R result_type;
545 using arg =
typename std::tuple_element<i, std::tuple<Args...>>::type;
548 template<
typename R,
typename... Args>
549 struct function_traits<std::function<R(Args...)>>
551 static const size_t arity =
sizeof...(Args);
553 typedef R result_type;
556 using arg =
typename std::tuple_element<i, std::tuple<Args...>>::type;
560 inline static std::string base64encode(
const unsigned char* data,
size_t size,
const char* key =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")
563 ret.resize((size + 2) / 3 * 4);
564 auto it = ret.begin();
567 *it++ = key[(
static_cast<unsigned char>(*data) & 0xFC) >> 2];
568 unsigned char h = (
static_cast<unsigned char>(*data++) & 0x03) << 4;
569 *it++ = key[h | ((
static_cast<unsigned char>(*data) & 0xF0) >> 4)];
570 h = (
static_cast<unsigned char>(*data++) & 0x0F) << 2;
571 *it++ = key[h | ((
static_cast<unsigned char>(*data) & 0xC0) >> 6)];
572 *it++ = key[
static_cast<unsigned char>(*data++) & 0x3F];
578 *it++ = key[(
static_cast<unsigned char>(*data) & 0xFC) >> 2];
579 unsigned char h = (
static_cast<unsigned char>(*data++) & 0x03) << 4;
586 *it++ = key[(
static_cast<unsigned char>(*data) & 0xFC) >> 2];
587 unsigned char h = (
static_cast<unsigned char>(*data++) & 0x03) << 4;
588 *it++ = key[h | ((
static_cast<unsigned char>(*data) & 0xF0) >> 4)];
589 h = (
static_cast<unsigned char>(*data++) & 0x0F) << 2;
596 inline static std::string base64encode(std::string data,
size_t size,
const char* key =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")
598 return base64encode((
const unsigned char*)data.c_str(), size, key);
601 inline static std::string base64encode_urlsafe(
const unsigned char* data,
size_t size)
603 return base64encode(data, size,
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_");
606 inline static std::string base64encode_urlsafe(std::string data,
size_t size)
608 return base64encode((
const unsigned char*)data.c_str(), size,
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_");
611 inline static std::string base64decode(
const char* data,
size_t size)
617 auto key = [](
char c) ->
unsigned char {
618 if ((c >=
'A') && (c <=
'Z'))
return c -
'A';
619 if ((c >=
'a') && (c <=
'z'))
return c -
'a' + 26;
620 if ((c >=
'0') && (c <=
'9'))
return c -
'0' + 52;
621 if ((c ==
'+') || (c ==
'-'))
return 62;
622 if ((c ==
'/') || (c ==
'_'))
return 63;
628 size = (size / 4 * 3) + 1;
629 else if (size % 4 == 3)
630 size = (size / 4 * 3) + 2;
633 else if (size >= 2 && data[size - 2] ==
'=')
634 size = (size / 4 * 3) - 2;
635 else if (size >= 1 && data[size - 1] ==
'=')
636 size = (size / 4 * 3) - 1;
644 auto it = ret.begin();
656 *it++ = (odd << 2) | ((even & 0x30) >> 4);
659 *it++ = ((even & 0x0F) << 4) | ((odd & 0x3C) >> 2);
662 *it++ = ((odd & 0x03) << 6) | (even);
671 *it++ = (odd << 2) | ((even & 0x30) >> 4);
674 *it++ = ((even & 0x0F) << 4) | ((odd & 0x3C) >> 2);
681 *it++ = (odd << 2) | ((even & 0x30) >> 4);
686 inline static std::string base64decode(
const std::string& data,
size_t size)
688 return base64decode(data.data(), size);
691 inline static std::string base64decode(
const std::string& data)
693 return base64decode(data.data(), data.length());
696 inline static std::string normalize_path(
const std::string& directoryPath)
698 std::string normalizedPath = directoryPath;
699 std::replace(normalizedPath.begin(), normalizedPath.end(),
'\\',
'/');
700 if (!normalizedPath.empty() && normalizedPath.back() !=
'/')
701 normalizedPath +=
'/';
702 return normalizedPath;
705 inline static void sanitize_filename(std::string& data,
char replacement =
'_')
707 if (data.length() > 255)
710 static const auto toUpper = [](
char c) {
711 return ((c >=
'a') && (c <=
'z')) ? (c - (
'a' -
'A')) : c;
716 auto sanitizeSpecialFile = [](std::string& source,
unsigned ofs,
const char* pattern,
bool includeNumber,
char replacement_) {
718 size_t len = source.length();
719 const char* p = pattern;
722 if (i >= len)
return;
723 if (toUpper(source[i]) != *p)
return;
729 if ((i >= len) || (source[i] <
'1') || (source[i] >
'9'))
return;
732 if ((i >= len) || (source[i] ==
'.') || (source[i] ==
':') || (source[i] ==
'/') || (source[i] ==
'\\'))
734 source.erase(ofs + 1, (i - ofs) - 1);
735 source[ofs] = replacement_;
738 bool checkForSpecialEntries =
true;
739 for (
unsigned i = 0; i < data.length(); ++i)
742 if (checkForSpecialEntries)
744 checkForSpecialEntries =
false;
745 switch (toUpper(data[i]))
748 sanitizeSpecialFile(data, i,
"AUX",
false, replacement);
751 sanitizeSpecialFile(data, i,
"CON",
false, replacement);
752 sanitizeSpecialFile(data, i,
"COM",
true, replacement);
755 sanitizeSpecialFile(data, i,
"LPT",
true, replacement);
758 sanitizeSpecialFile(data, i,
"NUL",
false, replacement);
761 sanitizeSpecialFile(data, i,
"PRN",
false, replacement);
764 sanitizeSpecialFile(data, i,
"..",
false, replacement);
770 unsigned char c = data[i];
771 if ((c <
' ') || ((c >= 0x80) && (c <= 0x9F)) || (c ==
'?') || (c ==
'<') || (c ==
'>') || (c ==
':') || (c ==
'*') || (c ==
'|') || (c ==
'\"'))
773 data[i] = replacement;
775 else if ((c ==
'/') || (c ==
'\\'))
777 if (CROW_UNLIKELY(i == 0))
779 data[i] = replacement;
783 checkForSpecialEntries =
true;
789 inline static std::string random_alphanum(std::size_t size)
791 static const char alphabet[] =
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
792 std::random_device dev;
793 std::mt19937 rng(dev());
794 std::uniform_int_distribution<std::mt19937::result_type> dist(0,
sizeof(alphabet) - 2);
797 for (std::size_t i = 0; i < size; i++)
798 out.push_back(alphabet[dist(rng)]);
802 inline static std::string join_path(std::string path,
const std::string& fname)
804 return (std::filesystem::path(path) / fname).string();
812 inline static bool string_equals(
const std::string_view l,
const std::string_view r,
bool case_sensitive =
false)
814 if (l.length() != r.length())
817 for (
size_t i = 0; i < l.length(); i++)
826 if (std::toupper(l[i]) != std::toupper(r[i]))
834 template<
typename T,
typename U>
835 inline static T lexical_cast(
const U& v)
837 std::stringstream stream;
847 inline static T lexical_cast(
const char* v,
size_t count)
849 std::stringstream stream;
852 stream.write(v, count);
861 inline static std::string trim(
const std::string& v)
866 size_t begin = 0, end = v.length();
869 for (i = 0; i < v.length(); i++)
871 if (!std::isspace(v[i]))
881 for (i = v.length(); i > 0; i--)
883 if (!std::isspace(v[i - 1]))
890 return v.substr(begin, end - begin);
896 inline static std::vector<std::string> split(
const std::string& v,
const std::string& separator)
898 std::vector<std::string> result;
901 for (
size_t foundPos = v.find(separator); foundPos != std::string::npos; foundPos = v.find(separator, startPos))
903 result.push_back(v.substr(startPos, foundPos - startPos));
904 startPos = foundPos + separator.size();
907 result.push_back(v.substr(startPos));
919 template<
typename Iter1,
typename Iter2>
920 inline static Iter1 find_first_of(Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2)
922 for (; first1 != last1; ++first1)
924 if (std::find(first2, last2, *first1) != last2)
The main namespace of the library. In this namespace is defined the most important classes and functi...