validate.h 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. #ifndef _VALIDATE_H
  2. #define _VALIDATE_H
  3. #include <functional>
  4. #include <regex>
  5. #include <stdexcept>
  6. #include <string>
  7. #include <typeinfo>
  8. #include <typeindex>
  9. #include <unordered_map>
  10. #if !defined(_WIN32)
  11. #include <arpa/inet.h>
  12. #else
  13. #include <winsock2.h>
  14. #include <ws2tcpip.h>
  15. // <windows.h> uses macros to #define a ton of symbols,
  16. // many of which interfere with our code here and down
  17. // the line in various extensions.
  18. #undef DELETE
  19. #undef ERROR
  20. #undef GetMessage
  21. #undef interface
  22. #undef TRUE
  23. #endif
  24. #include "google/protobuf/stubs/strutil.h" // for UTF8Len
  25. namespace pgv {
  26. using std::string;
  27. class UnimplementedException : public std::runtime_error {
  28. public:
  29. UnimplementedException() : std::runtime_error("not yet implemented") {}
  30. UnimplementedException(const std::string& message) : std::runtime_error(message) {}
  31. // Thrown by C++ validation code that is not yet implemented.
  32. };
  33. using ValidationMsg = std::string;
  34. class BaseValidator {
  35. protected:
  36. static std::unordered_map<std::type_index, BaseValidator*>& validators() {
  37. static auto* validator_map = new std::unordered_map<std::type_index, BaseValidator*>();
  38. return *validator_map;
  39. }
  40. };
  41. template <typename T>
  42. class Validator : public BaseValidator {
  43. public:
  44. Validator(std::function<bool(const T&, ValidationMsg*)> check) : check_(check)
  45. {
  46. validators()[std::type_index(typeid(T))] = this;
  47. }
  48. static bool CheckMessage(const T& m, ValidationMsg* err)
  49. {
  50. auto val = static_cast<Validator<T>*>(validators()[std::type_index(typeid(T))]);
  51. if (val) {
  52. return val->check_(m, err);
  53. }
  54. return true;
  55. }
  56. private:
  57. std::function<bool(const T&, ValidationMsg*)> check_;
  58. };
  59. static inline std::string String(const ValidationMsg& msg)
  60. {
  61. return std::string(msg);
  62. }
  63. static inline bool IsPrefix(const string& maybe_prefix, const string& search_in)
  64. {
  65. return search_in.compare(0, maybe_prefix.size(), maybe_prefix) == 0;
  66. }
  67. static inline bool IsSuffix(const string& maybe_suffix, const string& search_in)
  68. {
  69. return maybe_suffix.size() <= search_in.size() && search_in.compare(search_in.size() - maybe_suffix.size(), maybe_suffix.size(), maybe_suffix) == 0;
  70. }
  71. static inline bool Contains(const string& search_in, const string& to_find)
  72. {
  73. return search_in.find(to_find) != string::npos;
  74. }
  75. static inline bool NotContains(const string& search_in, const string& to_find)
  76. {
  77. return !Contains(search_in, to_find);
  78. }
  79. static inline bool IsIpv4(const string& to_validate) {
  80. struct sockaddr_in sa;
  81. return !(inet_pton(AF_INET, to_validate.c_str(), &sa.sin_addr) < 1);
  82. }
  83. static inline bool IsIpv6(const string& to_validate) {
  84. struct sockaddr_in6 sa_six;
  85. return !(inet_pton(AF_INET6, to_validate.c_str(), &sa_six.sin6_addr) < 1);
  86. }
  87. static inline bool IsIp(const string& to_validate) {
  88. return IsIpv4(to_validate) || IsIpv6(to_validate);
  89. }
  90. static inline bool IsHostname(const string& to_validate) {
  91. if (to_validate.length() > 253) {
  92. return false;
  93. }
  94. const std::regex dot_regex{"\\."};
  95. const auto iter_end = std::sregex_token_iterator();
  96. auto iter = std::sregex_token_iterator(to_validate.begin(), to_validate.end(), dot_regex, -1);
  97. for (; iter != iter_end; ++iter) {
  98. const std::string &part = *iter;
  99. if (part.empty() || part.length() > 63) {
  100. return false;
  101. }
  102. if (part.at(0) == '-') {
  103. return false;
  104. }
  105. if (part.at(part.length() - 1) == '-') {
  106. return false;
  107. }
  108. for (const auto &character : part) {
  109. if ((character < 'A' || character > 'Z') && (character < 'a' || character > 'z') && (character < '0' || character > '9') && character != '-') {
  110. return false;
  111. }
  112. }
  113. }
  114. return true;
  115. }
  116. static inline size_t Utf8Len(const string& narrow_string) {
  117. const char *str_char = narrow_string.c_str();
  118. ptrdiff_t byte_len = narrow_string.length();
  119. size_t unicode_len = 0;
  120. int char_len = 1;
  121. while (byte_len > 0 && char_len > 0) {
  122. char_len = google::protobuf::UTF8FirstLetterNumBytes(str_char, byte_len);
  123. str_char += char_len;
  124. byte_len -= char_len;
  125. ++unicode_len;
  126. }
  127. return unicode_len;
  128. }
  129. } // namespace pgv
  130. #endif // _VALIDATE_H