drogon
C++14/17-based HTTP application framework
Loading...
Searching...
No Matches
Utilities.h
Go to the documentation of this file.
1
14
15#pragma once
16
17#include <drogon/exports.h>
18#include <trantor/utils/Date.h>
19#include <trantor/utils/Funcs.h>
20#include <trantor/utils/Utilities.h>
21#include <trantor/utils/LogStream.h>
22#include <memory>
23#include <string>
24#include <vector>
25#include <set>
26#include <limits>
27#include <sstream>
28#include <algorithm>
29#include <filesystem>
30#include <string_view>
31#include <unordered_map>
32#include <type_traits>
33#ifdef _WIN32
34#include <time.h>
35DROGON_EXPORT char *strptime(const char *s, const char *f, struct tm *tm);
36DROGON_EXPORT time_t timegm(struct tm *tm);
37#endif
38namespace drogon
39{
40namespace internal
41{
42template <typename T, typename = void>
43struct CanConvertFromStringStream : std::false_type
44{
45};
46
47template <typename T>
49 T,
50 std::void_t<decltype(std::declval<std::stringstream &>() >>
51 std::declval<T &>())>> : std::true_type
52{
53};
54
55template <typename T>
56struct CanConstructFromString : std::is_constructible<T, std::string>
57{
58};
59
60template <typename T>
61struct CanConvertFromString : std::is_assignable<T &, std::string>
62{
63};
64
65} // namespace internal
66
74DROGON_EXPORT const std::string_view &statusCodeToString(int code);
75
76namespace utils
77{
79DROGON_EXPORT bool isInteger(std::string_view str);
80
82DROGON_EXPORT bool isBase64(std::string_view str);
83
85
89DROGON_EXPORT std::string genRandomString(int length);
90
92DROGON_EXPORT std::string binaryStringToHex(const unsigned char *ptr,
93 size_t length,
94 bool lowerCase = false);
95
97DROGON_EXPORT std::string hexToBinaryString(const char *ptr, size_t length);
98
100DROGON_EXPORT std::vector<char> hexToBinaryVector(const char *ptr,
101 size_t length);
102
103DROGON_EXPORT void binaryStringToHex(const char *ptr,
104 size_t length,
105 char *out,
106 bool lowerCase = false);
107
109
116inline std::vector<std::string> splitString(const std::string &str,
117 const std::string &separator,
118 bool acceptEmptyString = false)
119{
120 return trantor::splitString(str, separator, acceptEmptyString);
121}
122
123DROGON_EXPORT std::set<std::string> splitStringToSet(
124 const std::string &str,
125 const std::string &separator);
126
133inline bool ci_equals(std::string_view str1, std::string_view str2)
134{
135 if (str1.size() != str2.size())
136 return false;
137 return std::equal(str1.begin(),
138 str1.end(),
139 str2.begin(),
140 [](unsigned char a, unsigned char b) {
141 return std::tolower(a) == std::tolower(b);
142 });
143}
144
150inline std::string_view &trim_inplace(std::string_view &str)
151{
152 auto pos = str.find_first_not_of(" \t");
153 // defeat Windows macro "min"
154 str.remove_prefix((std::min)(pos, str.size()));
155 if (str.empty())
156 return str;
157 pos = str.find_last_not_of(" \t");
158 str.remove_suffix(str.size() - pos - 1);
159 return str;
160}
161
166inline std::string_view trim(std::string_view str)
167{
168 return trim_inplace(str);
169}
170
175inline std::string trim(std::string &&str)
176{
177 auto pos = str.find_last_not_of(" \t");
178 if (pos == std::string::npos)
179 return {};
180 str.resize(pos + 1);
181 pos = str.find_first_not_of(" \t");
182 if (pos > 0)
183 str.erase(0, pos);
184 return str;
185}
186
196inline std::vector<std::string_view> splitStringView(
197 std::string_view str,
198 std::string_view separator,
199 bool trimValues = true,
200 bool acceptEmptyString = false)
201{
202 std::vector<std::string_view> result;
203 if (separator.empty())
204 {
205 if (trimValues)
206 trim_inplace(str);
207 if (acceptEmptyString || !str.empty())
208 result.push_back(str);
209 return result;
210 }
211 size_t start = 0;
212 size_t end = 0;
213 while ((end = str.find(separator, start)) != std::string_view::npos)
214 {
215 auto token = str.substr(start, end - start);
216 if (trimValues)
217 trim_inplace(token);
218 if (acceptEmptyString || !token.empty())
219 result.push_back(token);
220 start = end + separator.size();
221 }
222 auto token = str.substr(start);
223 if (trimValues)
224 trim_inplace(token);
225 if (acceptEmptyString || !token.empty())
226 {
227 result.push_back(token);
228 }
229 return result;
230}
231
239inline std::set<std::string_view> splitStringViewToSet(
240 std::string_view str,
241 std::string_view separator,
242 bool trimValues = true,
243 bool acceptEmptyString = false)
244{
245 auto v = splitStringView(str, separator, trimValues, acceptEmptyString);
246 return std::set<std::string_view>(v.begin(), v.end());
247}
248
256inline std::string joinStringViews(const std::vector<std::string_view> &strs,
257 std::string_view separator)
258{
259 std::string result;
260 for (std::string_view str : strs)
261 {
262 if (trim_inplace(str).empty())
263 continue;
264 if (!result.empty())
265 result.append(separator);
266 result.append(str);
267 }
268 return result;
269}
270
278inline std::string joinStringViews(const std::set<std::string_view> &strs,
279 std::string_view separator)
280{
281 return joinStringViews(std::vector<std::string_view>{strs.begin(),
282 strs.end()},
283 separator);
284}
285
287DROGON_EXPORT std::string getUuid(bool lowercase = true);
288
290constexpr size_t base64EncodedLength(size_t in_len, bool padded = true)
291{
292 return padded ? ((in_len + 3 - 1) / 3) * 4 : (in_len * 8 + 6 - 1) / 6;
293}
294
296DROGON_EXPORT void base64Encode(const unsigned char *bytesToEncode,
297 size_t inLen,
298 unsigned char *outputBuffer,
299 bool urlSafe = false,
300 bool padded = true);
301
303inline std::string base64Encode(const unsigned char *bytesToEncode,
304 size_t inLen,
305 bool urlSafe = false,
306 bool padded = true)
307{
308 std::string ret;
309 ret.resize(base64EncodedLength(inLen, padded));
311 bytesToEncode, inLen, (unsigned char *)ret.data(), urlSafe, padded);
312 return ret;
313}
314
316inline std::string base64Encode(std::string_view data,
317 bool urlSafe = false,
318 bool padded = true)
319{
320 return base64Encode((unsigned char *)data.data(),
321 data.size(),
322 urlSafe,
323 padded);
324}
325
327inline void base64EncodeUnpadded(const unsigned char *bytesToEncode,
328 size_t inLen,
329 unsigned char *outputBuffer,
330 bool urlSafe = false)
331{
332 base64Encode(bytesToEncode, inLen, outputBuffer, urlSafe, false);
333}
334
336inline std::string base64EncodeUnpadded(const unsigned char *bytesToEncode,
337 size_t inLen,
338 bool urlSafe = false)
339{
340 return base64Encode(bytesToEncode, inLen, urlSafe, false);
341}
342
344inline std::string base64EncodeUnpadded(std::string_view data,
345 bool urlSafe = false)
346{
347 return base64Encode(data, urlSafe, false);
348}
349
351constexpr size_t base64DecodedLength(size_t inLen)
352{
353 return (inLen * 3) / 4;
354}
355
358DROGON_EXPORT size_t base64Decode(const char *encodedString,
359 size_t inLen,
360 unsigned char *outputBuffer);
361
363inline std::string base64Decode(std::string_view encodedString)
364{
365 auto inLen = encodedString.size();
366 std::string ret;
367 ret.resize(base64DecodedLength(inLen));
368 ret.resize(
369 base64Decode(encodedString.data(), inLen, (unsigned char *)ret.data()));
370 return ret;
371}
372
373DROGON_EXPORT std::vector<char> base64DecodeToVector(
374 std::string_view encodedString);
375
377DROGON_EXPORT bool needUrlDecoding(const char *begin, const char *end);
378
380DROGON_EXPORT std::string urlDecode(const char *begin, const char *end);
381
382inline std::string urlDecode(const std::string &szToDecode)
383{
384 auto begin = szToDecode.data();
385 return urlDecode(begin, begin + szToDecode.length());
386}
387
388inline std::string urlDecode(const std::string_view &szToDecode)
389{
390 auto begin = szToDecode.data();
391 return urlDecode(begin, begin + szToDecode.length());
392}
393
394DROGON_EXPORT std::string urlEncode(const std::string &);
395DROGON_EXPORT std::string urlEncodeComponent(const std::string &);
396
398DROGON_EXPORT std::string getMd5(const char *data, const size_t dataLen);
399
400inline std::string getMd5(const std::string &originalString)
401{
402 return getMd5(originalString.data(), originalString.length());
403}
404
405DROGON_EXPORT std::string getSha1(const char *data, const size_t dataLen);
406
407inline std::string getSha1(const std::string &originalString)
408{
409 return getSha1(originalString.data(), originalString.length());
410}
411
412DROGON_EXPORT std::string getSha256(const char *data, const size_t dataLen);
413
414inline std::string getSha256(const std::string &originalString)
415{
416 return getSha256(originalString.data(), originalString.length());
417}
418
419DROGON_EXPORT std::string getSha3(const char *data, const size_t dataLen);
420
421inline std::string getSha3(const std::string &originalString)
422{
423 return getSha3(originalString.data(), originalString.length());
424}
425
426DROGON_EXPORT std::string getBlake2b(const char *data, const size_t dataLen);
427
428inline std::string getBlake2b(const std::string &originalString)
429{
430 return getBlake2b(originalString.data(), originalString.length());
431}
432
434
438DROGON_EXPORT std::string gzipCompress(const char *data, const size_t ndata);
439DROGON_EXPORT std::string gzipDecompress(const char *data, const size_t ndata);
440
442
446DROGON_EXPORT std::string brotliCompress(const char *data, const size_t ndata);
447DROGON_EXPORT std::string brotliDecompress(const char *data,
448 const size_t ndata);
449
451
460DROGON_EXPORT char *getHttpFullDate(
461 const trantor::Date &date = trantor::Date::now());
462
463DROGON_EXPORT const std::string &getHttpFullDateStr(
464 const trantor::Date &date = trantor::Date::now());
465
466DROGON_EXPORT void dateToCustomFormattedString(const std::string &fmtStr,
467 std::string &str,
468 const trantor::Date &date);
470
473DROGON_EXPORT trantor::Date getHttpDate(const std::string &httpFullDateString);
474
476DROGON_EXPORT std::string formattedString(const char *format, ...);
477
479
482DROGON_EXPORT int createPath(const std::string &path);
483
500inline std::string fromWidePath(const std::wstring &strPath)
501{
502 return trantor::utils::fromWidePath(strPath);
503}
504
524inline std::wstring toWidePath(const std::string &strUtf8Path)
525{
526 return trantor::utils::toWidePath(strUtf8Path);
527}
528
543#if defined(_WIN32) && !defined(__MINGW32__)
544inline std::wstring toNativePath(const std::string &strPath)
545{
546 return trantor::utils::toNativePath(strPath);
547}
548
549inline const std::wstring &toNativePath(const std::wstring &strPath)
550{
551 return trantor::utils::toNativePath(strPath);
552}
553#else // __WIN32
554inline const std::string &toNativePath(const std::string &strPath)
555{
556 return trantor::utils::toNativePath(strPath);
557}
558
559inline std::string toNativePath(const std::wstring &strPath)
560{
561 return trantor::utils::toNativePath(strPath);
562}
563#endif // _WIN32
581inline const std::string &fromNativePath(const std::string &strPath)
582{
583 return trantor::utils::fromNativePath(strPath);
584}
585
586// Convert on all systems
587inline std::string fromNativePath(const std::wstring &strPath)
588{
589 return trantor::utils::fromNativePath(strPath);
590}
591
593
598DROGON_EXPORT void replaceAll(std::string &s,
599 const std::string &from,
600 const std::string &to);
601
610DROGON_EXPORT bool secureRandomBytes(void *ptr, size_t size);
611
619DROGON_EXPORT std::string secureRandomString(size_t size);
620
621template <typename T>
622T fromString(const std::string &p) noexcept(false)
623{
624 if constexpr (std::is_integral<T>::value && std::is_signed<T>::value)
625 {
626 std::size_t pos;
627 auto v = std::stoll(p, &pos);
628 // throw if the whole string could not be parsed
629 // ("1a" should not return 1)
630 if (pos != p.size())
631 throw std::invalid_argument("Invalid value");
632 if ((v < static_cast<long long>((std::numeric_limits<T>::min)())) ||
633 (v > static_cast<long long>((std::numeric_limits<T>::max)())))
634 throw std::out_of_range("Value out of range");
635 return static_cast<T>(v);
636 }
637 else if constexpr (std::is_integral<T>::value &&
638 (!std::is_signed<T>::value))
639 {
640 std::size_t pos;
641 auto v = std::stoull(p, &pos);
642 // throw if the whole string could not be parsed
643 // ("1a" should not return 1)
644 if (pos != p.size())
645 throw std::invalid_argument("Invalid value");
646 if (v >
647 static_cast<unsigned long long>((std::numeric_limits<T>::max)()))
648 throw std::out_of_range("Value out of range");
649 return static_cast<T>(v);
650 }
651 else if constexpr (std::is_floating_point<T>::value)
652 {
653 std::size_t pos;
654 auto v = std::stold(p, &pos);
655 // throw if the whole string could not be parsed
656 // ("1a" should not return 1)
657 if (pos != p.size())
658 throw std::invalid_argument("Invalid value");
659 if ((v <
660 static_cast<long double>((std::numeric_limits<T>::lowest)())) ||
661 (v > static_cast<long double>((std::numeric_limits<T>::max)())))
662 throw std::out_of_range("Value out of range");
663 return static_cast<T>(v);
664 }
665 else if constexpr (internal::CanConvertFromStringStream<T>::value)
666 {
667 T value{};
668 if (!p.empty())
669 {
670 std::stringstream ss(p);
671 // must except in case of invalid value, not return a default value
672 // (else it returns 0 for integers if the string is empty or
673 // non-numeric)
674 ss.exceptions(std::ios_base::failbit);
675 ss >> value;
676 // throw if the whole string could not be parsed
677 // ("1a" should not return 1)
678 if (!ss.eof())
679 throw std::runtime_error("Bad type conversion");
680 }
681 return value;
682 }
683 else
684 {
685 throw std::runtime_error("Bad type conversion");
686 }
687}
688
689template <>
690inline std::string fromString<std::string>(const std::string &p) noexcept(false)
691{
692 return p;
693}
694
695template <>
696inline bool fromString<bool>(const std::string &p) noexcept(false)
697{
698 if (!p.empty() && std::all_of(p.begin(), p.end(), [](unsigned char c) {
699 return std::isdigit(c);
700 }))
701 return (std::stoll(p) != 0);
702 std::string l{p};
703 std::transform(p.begin(), p.end(), l.begin(), [](unsigned char c) {
704 return (char)tolower(c);
705 });
706 if (l == "true")
707 {
708 return true;
709 }
710 else if (l == "false")
711 {
712 return false;
713 }
714 throw std::runtime_error("Can't convert from string '" + p + "' to bool");
715}
716
717DROGON_EXPORT bool supportsTls() noexcept;
718
719namespace internal
720{
721DROGON_EXPORT extern const size_t fixedRandomNumber;
722
724{
725 size_t operator()(const std::string &str) const
726 {
727 const size_t A = 6665339;
728 const size_t B = 2534641;
729 size_t h = fixedRandomNumber;
730 for (char ch : str)
731 h = (h * A) ^ (ch * B);
732 return h;
733 }
734};
735} // namespace internal
736} // namespace utils
737
738template <typename T>
739using SafeStringMap =
740 std::unordered_map<std::string, T, utils::internal::SafeStringHash>;
741} // namespace drogon
742
743namespace trantor
744{
745inline LogStream &operator<<(LogStream &ls, const std::string_view &v)
746{
747 if (!v.empty())
748 ls.append(v.data(), v.length());
749 return ls;
750}
751
752inline LogStream &operator<<(LogStream &ls, const std::filesystem::path &p)
753{
754 return ls << p.string();
755}
756} // namespace trantor
std::wstring toWidePath(const std::string &strUtf8Path)
Definition Utilities.h:524
DROGON_EXPORT std::string genRandomString(int length)
Generate random a string.
void base64EncodeUnpadded(const unsigned char *bytesToEncode, size_t inLen, unsigned char *outputBuffer, bool urlSafe=false)
Encode the string to base64 format with no padding.
Definition Utilities.h:327
DROGON_EXPORT bool isInteger(std::string_view str)
Determine if the string is an integer.
std::string_view & trim_inplace(std::string_view &str)
Definition Utilities.h:150
DROGON_EXPORT void base64Encode(const unsigned char *bytesToEncode, size_t inLen, unsigned char *outputBuffer, bool urlSafe=false, bool padded=true)
Encode the string to base64 format.
std::string joinStringViews(const std::vector< std::string_view > &strs, std::string_view separator)
Join a vector of string_view into a string.
Definition Utilities.h:256
const std::string & fromNativePath(const std::string &strPath)
Convert a OS native path (wide string on Windows) to a generic UTF-8 path.
Definition Utilities.h:581
DROGON_EXPORT trantor::Date getHttpDate(const std::string &httpFullDateString)
Get the trantor::Date object according to the http full date string.
DROGON_EXPORT std::string brotliCompress(const char *data, const size_t ndata)
Compress or decompress data using brotli lib.
bool ci_equals(std::string_view str1, std::string_view str2)
Compare two string_views for equality, ignoring case.
Definition Utilities.h:133
constexpr size_t base64EncodedLength(size_t in_len, bool padded=true)
Get the encoded length of base64.
Definition Utilities.h:290
DROGON_EXPORT std::string binaryStringToHex(const unsigned char *ptr, size_t length, bool lowerCase=false)
Convert a binary string to hex format.
std::vector< std::string_view > splitStringView(std::string_view str, std::string_view separator, bool trimValues=true, bool acceptEmptyString=false)
Split a string_view into a vector of string_views.
Definition Utilities.h:196
DROGON_EXPORT std::string gzipCompress(const char *data, const size_t ndata)
Compress or decompress data using gzip lib.
DROGON_EXPORT std::string formattedString(const char *format,...)
Get a formatted string.
std::set< std::string_view > splitStringViewToSet(std::string_view str, std::string_view separator, bool trimValues=true, bool acceptEmptyString=false)
Split a string_view into a set of string_views. \copyparams splitStringView.
Definition Utilities.h:239
DROGON_EXPORT bool secureRandomBytes(void *ptr, size_t size)
Generates cryptographically secure random bytes.
constexpr size_t base64DecodedLength(size_t inLen)
Get the decoded length of base64.
Definition Utilities.h:351
DROGON_EXPORT std::string getUuid(bool lowercase=true)
Get UUID string.
DROGON_EXPORT bool isBase64(std::string_view str)
Determine if the string is base64 encoded.
DROGON_EXPORT std::string hexToBinaryString(const char *ptr, size_t length)
Get a binary string from hexadecimal format.
DROGON_EXPORT size_t base64Decode(const char *encodedString, size_t inLen, unsigned char *outputBuffer)
DROGON_EXPORT bool needUrlDecoding(const char *begin, const char *end)
Check if the string need decoding.
DROGON_EXPORT std::vector< char > hexToBinaryVector(const char *ptr, size_t length)
Get a binary vector from hexadecimal format.
DROGON_EXPORT std::string urlDecode(const char *begin, const char *end)
Decode from or encode to the URL format string.
std::vector< std::string > splitString(const std::string &str, const std::string &separator, bool acceptEmptyString=false)
Split the string into multiple separated strings.
Definition Utilities.h:116
std::string_view trim(std::string_view str)
Trim leading and trailing spaces and tabs from a string_view.
Definition Utilities.h:166
DROGON_EXPORT char * getHttpFullDate(const trantor::Date &date=trantor::Date::now())
Get the http full date string.
DROGON_EXPORT void replaceAll(std::string &s, const std::string &from, const std::string &to)
Replace all occurrences of from to to inplace.
DROGON_EXPORT int createPath(const std::string &path)
Recursively create a file system path.
DROGON_EXPORT std::string secureRandomString(size_t size)
Generates cryptographically secure random string.
std::string fromWidePath(const std::wstring &strPath)
Definition Utilities.h:500
DROGON_EXPORT std::string getMd5(const char *data, const size_t dataLen)
Get the MD5 digest of a string.
const std::string & toNativePath(const std::string &strPath)
Convert a generic (UTF-8) path with to an OS native path.
Definition Utilities.h:554
Drogon Test is a minimal effort test framework developed because the major C++ test frameworks doesn'...
Definition Attribute.h:23
DROGON_EXPORT const std::string_view & statusCodeToString(int code)
Get the HTTP messages corresponding to the HTTP status codes.
STL namespace.
Definition Utilities.h:724