11 #include <string_view>
13 #include <unordered_map>
17 #include "crow/settings.h"
19 #if defined(CROW_CAN_USE_CPP17) && !defined(CROW_FILESYSTEM_IS_EXPERIMENTAL)
24 #if defined(__GNUG__) || defined(__clang__)
25 #define CROW_LIKELY(X) __builtin_expect(!!(X), 1)
26 #define CROW_UNLIKELY(X) __builtin_expect(!!(X), 0)
28 #define CROW_LIKELY(X) (X)
29 #define CROW_UNLIKELY(X) (X)
37 #ifndef CROW_MSVC_WORKAROUND
41 OutOfRange(
unsigned ,
unsigned ) {}
44 constexpr
unsigned requires_in_range(
unsigned i,
unsigned len)
46 return i >= len ?
throw OutOfRange(i, len) : i;
52 const char*
const begin_;
57 constexpr const_str(
const char (&arr)[N]):
58 begin_(arr), size_(N - 1)
60 static_assert(N >= 1,
"not a string literal");
62 constexpr
char operator[](
unsigned i)
const
64 return requires_in_range(i, size_), begin_[i];
67 constexpr
operator const char*()
const
72 constexpr
const char* begin()
const {
return begin_; }
73 constexpr
const char* end()
const {
return begin_ + size_; }
75 constexpr
unsigned size()
const
81 constexpr
unsigned find_closing_tag(const_str s,
unsigned p)
83 return s[p] ==
'>' ? p : find_closing_tag(s, p + 1);
87 constexpr
bool is_valid(const_str s,
unsigned i = 0,
int f = 0)
89 return i == s.size() ? f == 0 :
90 f < 0 || f >= 2 ? false :
91 s[i] ==
'<' ? is_valid(s, i + 1, f + 1) :
92 s[i] ==
'>' ? is_valid(s, i + 1, f - 1) :
93 is_valid(s, i + 1, f);
96 constexpr
bool is_equ_p(
const char* a,
const char* b,
unsigned n)
98 return *a == 0 && *b == 0 && n == 0 ? true :
99 (*a == 0 || *b == 0) ?
false :
102 is_equ_p(a + 1, b + 1, n - 1);
105 constexpr
bool is_equ_n(const_str a,
unsigned ai, const_str b,
unsigned bi,
unsigned n)
107 return ai + n > a.size() || bi + n > b.size() ? false :
109 a[ai] != b[bi] ? false :
110 is_equ_n(a, ai + 1, b, bi + 1, n - 1);
113 constexpr
bool is_int(const_str s,
unsigned i)
115 return is_equ_n(s, i,
"<int>", 0, 5);
118 constexpr
bool is_uint(const_str s,
unsigned i)
120 return is_equ_n(s, i,
"<uint>", 0, 6);
123 constexpr
bool is_float(const_str s,
unsigned i)
125 return is_equ_n(s, i,
"<float>", 0, 7) ||
126 is_equ_n(s, i,
"<double>", 0, 8);
129 constexpr
bool is_str(const_str s,
unsigned i)
131 return is_equ_n(s, i,
"<str>", 0, 5) ||
132 is_equ_n(s, i,
"<string>", 0, 8);
135 constexpr
bool is_path(const_str s,
unsigned i)
137 return is_equ_n(s, i,
"<path>", 0, 6);
143 static const int value = 0;
145 #define CROW_INTERNAL_PARAMETER_TAG(t, i) \
147 struct parameter_tag<t> \
149 static const int value = i; \
151 CROW_INTERNAL_PARAMETER_TAG(
int, 1);
152 CROW_INTERNAL_PARAMETER_TAG(
char, 1);
153 CROW_INTERNAL_PARAMETER_TAG(
short, 1);
154 CROW_INTERNAL_PARAMETER_TAG(
long, 1);
155 CROW_INTERNAL_PARAMETER_TAG(
long long, 1);
156 CROW_INTERNAL_PARAMETER_TAG(
unsigned int, 2);
157 CROW_INTERNAL_PARAMETER_TAG(
unsigned char, 2);
158 CROW_INTERNAL_PARAMETER_TAG(
unsigned short, 2);
159 CROW_INTERNAL_PARAMETER_TAG(
unsigned long, 2);
160 CROW_INTERNAL_PARAMETER_TAG(
unsigned long long, 2);
161 CROW_INTERNAL_PARAMETER_TAG(
double, 3);
162 CROW_INTERNAL_PARAMETER_TAG(std::string, 4);
163 #undef CROW_INTERNAL_PARAMETER_TAG
164 template<
typename... Args>
165 struct compute_parameter_tag_from_args_list;
168 struct compute_parameter_tag_from_args_list<>
170 static const int value = 0;
173 template<
typename Arg,
typename... Args>
174 struct compute_parameter_tag_from_args_list<Arg, Args...>
176 static const int sub_value =
177 compute_parameter_tag_from_args_list<Args...>::value;
178 static const int value =
179 parameter_tag<typename std::decay<Arg>::type>::value ? sub_value * 6 + parameter_tag<typename std::decay<Arg>::type>::value : sub_value;
182 static inline bool is_parameter_tag_compatible(uint64_t a, uint64_t b)
194 return is_parameter_tag_compatible(a / 6, b / 6);
197 static inline unsigned find_closing_tag_runtime(
const char* s,
unsigned p)
199 return s[p] == 0 ?
throw std::runtime_error(
"unmatched tag <") :
201 find_closing_tag_runtime(s, p + 1);
204 static inline uint64_t get_parameter_tag_runtime(
const char* s,
unsigned p = 0)
206 return s[p] == 0 ? 0 :
208 std::strncmp(s + p,
"<int>", 5) == 0 ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 1 :
209 std::strncmp(s + p,
"<uint>", 6) == 0 ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 2 :
210 (std::strncmp(s + p,
"<float>", 7) == 0 ||
211 std::strncmp(s + p,
"<double>", 8) == 0) ?
212 get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 3 :
213 (std::strncmp(s + p,
"<str>", 5) == 0 ||
214 std::strncmp(s + p,
"<string>", 8) == 0) ?
215 get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 4 :
216 std::strncmp(s + p,
"<path>", 6) == 0 ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 5 :
217 throw std::runtime_error(
"invalid parameter type")) :
218 get_parameter_tag_runtime(s, p + 1);
220 #ifndef CROW_MSVC_WORKAROUND
221 constexpr uint64_t get_parameter_tag(const_str s,
unsigned p = 0)
223 return p == s.size() ? 0 :
225 is_int(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 1 :
226 is_uint(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 2 :
227 is_float(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 3 :
228 is_str(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 4 :
229 is_path(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 5 :
230 throw std::runtime_error(
"invalid parameter type")) :
231 get_parameter_tag(s, p + 1);
235 template<
typename... T>
239 using push = S<U, T...>;
241 using push_back = S<T..., U>;
242 template<
template<
typename... Args>
class U>
243 using rebind = U<T...>;
247 template<
typename F,
typename Set>
249 template<
typename F,
typename... Args>
250 struct CallHelper<F, S<Args...>>
252 template<
typename F1,
typename... Args1,
typename = decltype(std::declval<F1>()(std::declval<Args1>()...))>
253 static char __test(
int);
255 template<
typename...>
256 static int __test(...);
258 static constexpr
bool value =
sizeof(__test<F, Args...>(0)) ==
sizeof(char);
262 template<
typename T,
typename Tuple>
266 struct has_type<T, std::tuple<>> : std::false_type
269 template<
typename T,
typename U,
typename... Ts>
270 struct has_type<T, std::tuple<U, Ts...>> : has_type<T, std::tuple<Ts...>>
273 template<
typename T,
typename... Ts>
274 struct has_type<T, std::tuple<T, Ts...>> : std::true_type
278 template<
class T,
class Tuple>
281 template<
class T,
class... Types>
282 struct tuple_index<T, std::tuple<T, Types...>>
284 static const int value = 0;
287 template<
class T,
class U,
class... Types>
288 struct tuple_index<T, std::tuple<U, Types...>>
290 static const int value = 1 + tuple_index<T, std::tuple<Types...>>::value;
294 #ifdef CROW_CAN_USE_CPP14
295 template<
typename T,
typename Tup>
296 typename std::enable_if<has_type<T&, Tup>::value,
typename std::decay<T>::type&&>::type
297 tuple_extract(Tup& tup)
299 return std::move(std::get<T&>(tup));
302 template<
typename T,
typename Tup>
303 typename std::enable_if<has_type<T&, Tup>::value, T&&>::type
304 tuple_extract(Tup& tup)
306 return std::move(std::get<tuple_index<T&, Tup>::value>(tup));
310 template<
typename T,
typename Tup>
311 typename std::enable_if<!has_type<T&, Tup>::value, T>::type
321 using all_true = std::is_same<bool_pack<bs...,
true>, bool_pack<
true, bs...>>;
324 struct single_tag_to_type
328 struct single_tag_to_type<1>
330 using type = int64_t;
334 struct single_tag_to_type<2>
336 using type = uint64_t;
340 struct single_tag_to_type<3>
346 struct single_tag_to_type<4>
348 using type = std::string;
352 struct single_tag_to_type<5>
354 using type = std::string;
358 template<u
int64_t Tag>
361 using subarguments =
typename arguments<Tag / 6>::type;
363 typename subarguments::template push<typename single_tag_to_type<Tag % 6>::type>;
372 template<
typename... T>
373 struct last_element_type
375 using type =
typename std::tuple_element<
sizeof...(T) - 1, std::tuple<T...>>::type;
380 struct last_element_type<>
386 using Invoke =
typename T::type;
388 template<
unsigned...>
394 template<
class S1,
class S2>
397 template<
unsigned... I1,
unsigned... I2>
398 struct concat<seq<I1...>, seq<I2...>> : seq<I1..., (sizeof...(I1) + I2)...>
401 template<
class S1,
class S2>
402 using Concat = Invoke<concat<S1, S2>>;
407 using GenSeq = Invoke<gen_seq<N>>;
410 struct gen_seq : Concat<GenSeq<N / 2>, GenSeq<N - N / 2>>
414 struct gen_seq<0> : seq<>
417 struct gen_seq<1> : seq<0>
420 template<
typename Seq,
typename Tuple>
421 struct pop_back_helper;
423 template<
unsigned... N,
typename Tuple>
424 struct pop_back_helper<seq<N...>, Tuple>
426 template<
template<
typename... Args>
class U>
427 using rebind = U<typename std::tuple_element<N, Tuple>::type...>;
430 template<
typename... T>
433 template<
template<
typename... Args>
class U>
434 using rebind =
typename pop_back_helper<
typename gen_seq<
sizeof...(T) - 1>::type, std::tuple<T...>>::
template rebind<U>;
440 template<
template<
typename... Args>
class U>
445 template<
typename Tp,
typename... List>
446 struct contains : std::true_type
449 template<
typename Tp,
typename Head,
typename... Rest>
450 struct contains<Tp, Head, Rest...> : std::conditional<std::is_same<Tp, Head>::value, std::true_type, contains<Tp, Rest...>>::type
453 template<
typename Tp>
454 struct contains<Tp> : std::false_type
467 #define CROW_INTERNAL_PROMOTE_TYPE(t1, t2) \
474 CROW_INTERNAL_PROMOTE_TYPE(
char, int64_t);
475 CROW_INTERNAL_PROMOTE_TYPE(
short, int64_t);
476 CROW_INTERNAL_PROMOTE_TYPE(
int, int64_t);
477 CROW_INTERNAL_PROMOTE_TYPE(
long, int64_t);
478 CROW_INTERNAL_PROMOTE_TYPE(
long long, int64_t);
479 CROW_INTERNAL_PROMOTE_TYPE(
unsigned char, uint64_t);
480 CROW_INTERNAL_PROMOTE_TYPE(
unsigned short, uint64_t);
481 CROW_INTERNAL_PROMOTE_TYPE(
unsigned int, uint64_t);
482 CROW_INTERNAL_PROMOTE_TYPE(
unsigned long, uint64_t);
483 CROW_INTERNAL_PROMOTE_TYPE(
unsigned long long, uint64_t);
484 CROW_INTERNAL_PROMOTE_TYPE(
float,
double);
485 #undef CROW_INTERNAL_PROMOTE_TYPE
488 using promote_t =
typename promote<T>::type;
495 template<
class T, std::size_t N,
class... Args>
496 struct get_index_of_element_from_tuple_by_type_impl
498 static constexpr
auto value = N;
501 template<
class T, std::size_t N,
class... Args>
502 struct get_index_of_element_from_tuple_by_type_impl<T, N, T, Args...>
504 static constexpr
auto value = N;
507 template<
class T, std::size_t N,
class U,
class... Args>
508 struct get_index_of_element_from_tuple_by_type_impl<T, N, U, Args...>
510 static constexpr
auto value = get_index_of_element_from_tuple_by_type_impl<T, N + 1, Args...>::value;
516 template<
class T,
class... Args>
517 T& get_element_by_type(std::tuple<Args...>& t)
519 return std::get<detail::get_index_of_element_from_tuple_by_type_impl<T, 0, Args...>::value>(t);
523 struct function_traits;
525 #ifndef CROW_MSVC_WORKAROUND
527 struct function_traits :
public function_traits<decltype(&T::operator())>
529 using parent_t = function_traits<decltype(&T::operator())>;
530 static const size_t arity = parent_t::arity;
531 using result_type =
typename parent_t::result_type;
533 using arg =
typename parent_t::template arg<i>;
537 template<
typename ClassType,
typename R,
typename... Args>
538 struct function_traits<R (ClassType::*)(Args...) const>
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 ClassType,
typename R,
typename... Args>
549 struct function_traits<R (ClassType::*)(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;
559 template<
typename R,
typename... Args>
560 struct function_traits<std::function<R(Args...)>>
562 static const size_t arity =
sizeof...(Args);
564 typedef R result_type;
567 using arg =
typename std::tuple_element<i, std::tuple<Args...>>::type;
571 inline static std::string base64encode(
const unsigned char* data,
size_t size,
const char* key =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")
574 ret.resize((size + 2) / 3 * 4);
575 auto it = ret.begin();
578 *it++ = key[(
static_cast<unsigned char>(*data) & 0xFC) >> 2];
579 unsigned char h = (
static_cast<unsigned char>(*data++) & 0x03) << 4;
580 *it++ = key[h | ((
static_cast<unsigned char>(*data) & 0xF0) >> 4)];
581 h = (
static_cast<unsigned char>(*data++) & 0x0F) << 2;
582 *it++ = key[h | ((
static_cast<unsigned char>(*data) & 0xC0) >> 6)];
583 *it++ = key[
static_cast<unsigned char>(*data++) & 0x3F];
589 *it++ = key[(
static_cast<unsigned char>(*data) & 0xFC) >> 2];
590 unsigned char h = (
static_cast<unsigned char>(*data++) & 0x03) << 4;
597 *it++ = key[(
static_cast<unsigned char>(*data) & 0xFC) >> 2];
598 unsigned char h = (
static_cast<unsigned char>(*data++) & 0x03) << 4;
599 *it++ = key[h | ((
static_cast<unsigned char>(*data) & 0xF0) >> 4)];
600 h = (
static_cast<unsigned char>(*data++) & 0x0F) << 2;
607 inline static std::string base64encode(std::string data,
size_t size,
const char* key =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")
609 return base64encode((
const unsigned char*)data.c_str(), size, key);
612 inline static std::string base64encode_urlsafe(
const unsigned char* data,
size_t size)
614 return base64encode(data, size,
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_");
617 inline static std::string base64encode_urlsafe(std::string data,
size_t size)
619 return base64encode((
const unsigned char*)data.c_str(), size,
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_");
622 inline static std::string base64decode(
const char* data,
size_t size)
628 auto key = [](
char c) ->
unsigned char {
629 if ((c >=
'A') && (c <=
'Z'))
return c -
'A';
630 if ((c >=
'a') && (c <=
'z'))
return c -
'a' + 26;
631 if ((c >=
'0') && (c <=
'9'))
return c -
'0' + 52;
632 if ((c ==
'+') || (c ==
'-'))
return 62;
633 if ((c ==
'/') || (c ==
'_'))
return 63;
639 size = (size / 4 * 3) + 1;
640 else if (size % 4 == 3)
641 size = (size / 4 * 3) + 2;
644 else if (size >= 2 && data[size - 2] ==
'=')
645 size = (size / 4 * 3) - 2;
646 else if (size >= 1 && data[size - 1] ==
'=')
647 size = (size / 4 * 3) - 1;
655 auto it = ret.begin();
667 *it++ = (odd << 2) | ((even & 0x30) >> 4);
670 *it++ = ((even & 0x0F) << 4) | ((odd & 0x3C) >> 2);
673 *it++ = ((odd & 0x03) << 6) | (even);
682 *it++ = (odd << 2) | ((even & 0x30) >> 4);
685 *it++ = ((even & 0x0F) << 4) | ((odd & 0x3C) >> 2);
692 *it++ = (odd << 2) | ((even & 0x30) >> 4);
697 inline static std::string base64decode(
const std::string& data,
size_t size)
699 return base64decode(data.data(), size);
702 inline static std::string base64decode(
const std::string& data)
704 return base64decode(data.data(), data.length());
707 inline static std::string normalize_path(
const std::string& directoryPath)
709 std::string normalizedPath = directoryPath;
710 std::replace(normalizedPath.begin(), normalizedPath.end(),
'\\',
'/');
711 if (!normalizedPath.empty() && normalizedPath.back() !=
'/')
712 normalizedPath +=
'/';
713 return normalizedPath;
716 inline static void sanitize_filename(std::string& data,
char replacement =
'_')
718 if (data.length() > 255)
721 static const auto toUpper = [](
char c) {
722 return ((c >=
'a') && (c <=
'z')) ? (c - (
'a' -
'A')) : c;
727 auto sanitizeSpecialFile = [](std::string& source,
unsigned ofs,
const char* pattern,
bool includeNumber,
char replacement_) {
729 size_t len = source.length();
730 const char* p = pattern;
733 if (i >= len)
return;
734 if (toUpper(source[i]) != *p)
return;
740 if ((i >= len) || (source[i] <
'1') || (source[i] >
'9'))
return;
743 if ((i >= len) || (source[i] ==
'.') || (source[i] ==
':') || (source[i] ==
'/') || (source[i] ==
'\\'))
745 source.erase(ofs + 1, (i - ofs) - 1);
746 source[ofs] = replacement_;
749 bool checkForSpecialEntries =
true;
750 for (
unsigned i = 0; i < data.length(); ++i)
753 if (checkForSpecialEntries)
755 checkForSpecialEntries =
false;
756 switch (toUpper(data[i]))
759 sanitizeSpecialFile(data, i,
"AUX",
false, replacement);
762 sanitizeSpecialFile(data, i,
"CON",
false, replacement);
763 sanitizeSpecialFile(data, i,
"COM",
true, replacement);
766 sanitizeSpecialFile(data, i,
"LPT",
true, replacement);
769 sanitizeSpecialFile(data, i,
"NUL",
false, replacement);
772 sanitizeSpecialFile(data, i,
"PRN",
false, replacement);
775 sanitizeSpecialFile(data, i,
"..",
false, replacement);
781 unsigned char c = data[i];
782 if ((c <
' ') || ((c >= 0x80) && (c <= 0x9F)) || (c ==
'?') || (c ==
'<') || (c ==
'>') || (c ==
':') || (c ==
'*') || (c ==
'|') || (c ==
'\"'))
784 data[i] = replacement;
786 else if ((c ==
'/') || (c ==
'\\'))
788 if (CROW_UNLIKELY(i == 0))
790 data[i] = replacement;
794 checkForSpecialEntries =
true;
800 inline static std::string random_alphanum(std::size_t size)
802 static const char alphabet[] =
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
803 std::random_device dev;
804 std::mt19937 rng(dev());
805 std::uniform_int_distribution<std::mt19937::result_type> dist(0,
sizeof(alphabet) - 2);
808 for (std::size_t i = 0; i < size; i++)
809 out.push_back(alphabet[dist(rng)]);
813 inline static std::string join_path(std::string path,
const std::string& fname)
815 #if defined(CROW_CAN_USE_CPP17) && !defined(CROW_FILESYSTEM_IS_EXPERIMENTAL)
816 return (std::filesystem::path(path) / fname).string();
818 if (!(path.back() ==
'/' || path.back() ==
'\\'))
830 inline static bool string_equals(
const std::string_view l,
const std::string_view r,
bool case_sensitive =
false)
832 if (l.length() != r.length())
835 for (
size_t i = 0; i < l.length(); i++)
844 if (std::toupper(l[i]) != std::toupper(r[i]))
852 template<
typename T,
typename U>
853 inline static T lexical_cast(
const U& v)
855 std::stringstream stream;
865 inline static T lexical_cast(
const char* v,
size_t count)
867 std::stringstream stream;
870 stream.write(v, count);
879 inline static std::string trim(
const std::string& v)
884 size_t begin = 0, end = v.length();
887 for (i = 0; i < v.length(); i++)
889 if (!std::isspace(v[i]))
899 for (i = v.length(); i > 0; i--)
901 if (!std::isspace(v[i - 1]))
908 return v.substr(begin, end - begin);
914 inline static std::vector<std::string> split(
const std::string& v,
const std::string& separator)
916 std::vector<std::string> result;
919 for (
size_t foundPos = v.find(separator); foundPos != std::string::npos; foundPos = v.find(separator, startPos))
921 result.push_back(v.substr(startPos, foundPos - startPos));
922 startPos = foundPos + separator.size();
925 result.push_back(v.substr(startPos));
937 template<
typename Iter1,
typename Iter2>
938 inline static Iter1 find_first_of(Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2)
940 for (; first1 != last1; ++first1)
942 if (std::find(first2, last2, *first1) != last2)
The main namespace of the library. In this namespace is defined the most important classes and functi...