summaryrefslogtreecommitdiff
path: root/vendor/github.com/envoyproxy/protoc-gen-validate/validate/validate.h
blob: d6cf6c9d903517db5c7dc5a18bcb9bf04d4e1df2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#ifndef _VALIDATE_H
#define _VALIDATE_H

#include <functional>
#include <regex>
#include <stdexcept>
#include <string>
#include <typeindex>
#include <typeinfo>
#include <unordered_map>

#if !defined(_WIN32)
#include <arpa/inet.h>
#else
#include <winsock2.h>
#include <ws2tcpip.h>

// <windows.h> uses macros to #define a ton of symbols,
// many of which interfere with our code here and down
// the line in various extensions.
#undef DELETE
#undef ERROR
#undef GetMessage
#undef interface
#undef TRUE
#undef min

#endif

#include "google/protobuf/message.h"

namespace pgv {
using std::string;

class UnimplementedException : public std::runtime_error {
public:
  UnimplementedException() : std::runtime_error("not yet implemented") {}
  UnimplementedException(const std::string& message) : std::runtime_error(message) {}
  // Thrown by C++ validation code that is not yet implemented.
};

using ValidationMsg = std::string;

class BaseValidator {
public:
  /**
   * Validate/check a generic message object with a registered validator for the concrete message
   * type.
   * @param m supplies the message to check.
   * @param err supplies the place to return error information.
   * @return true if the validation passes OR there is no registered validator for the concrete
   *         message type. false is returned if validation explicitly fails.
   */
  static bool AbstractCheckMessage(const google::protobuf::Message& m, ValidationMsg* err) {
    // Polymorphic lookup is used to see if there is a matching concrete validator. If so, call it.
    // Otherwise return success.
    auto it = abstractValidators().find(std::type_index(typeid(m)));
    if (it == abstractValidators().end()) {
      return true;
    }
    return it->second(m, err);
  }

protected:
  // Used to implement AbstractCheckMessage() above. Every message that is linked into the binary
  // will register itself by type_index, allowing for polymorphic lookup later.
  static std::unordered_map<std::type_index,
                            std::function<bool(const google::protobuf::Message&, ValidationMsg*)>>&
  abstractValidators() {
    static auto* validator_map = new std::unordered_map<
        std::type_index, std::function<bool(const google::protobuf::Message&, ValidationMsg*)>>();
    return *validator_map;
  }
};

template <typename T> class Validator : public BaseValidator {
public:
  Validator(std::function<bool(const T&, ValidationMsg*)> check) : check_(check) {
    abstractValidators()[std::type_index(typeid(T))] = [this](const google::protobuf::Message& m,
                                                              ValidationMsg* err) -> bool {
      return check_(dynamic_cast<const T&>(m), err);
    };
  }

private:
  std::function<bool(const T&, ValidationMsg*)> check_;
};

static inline std::string String(const ValidationMsg& msg) { return std::string(msg); }

static inline bool IsPrefix(const string& maybe_prefix, const string& search_in) {
  return search_in.compare(0, maybe_prefix.size(), maybe_prefix) == 0;
}

static inline bool IsSuffix(const string& maybe_suffix, const string& search_in) {
  return maybe_suffix.size() <= search_in.size() &&
         search_in.compare(search_in.size() - maybe_suffix.size(), maybe_suffix.size(),
                           maybe_suffix) == 0;
}

static inline bool Contains(const string& search_in, const string& to_find) {
  return search_in.find(to_find) != string::npos;
}

static inline bool NotContains(const string& search_in, const string& to_find) {
  return !Contains(search_in, to_find);
}

static inline bool IsIpv4(const string& to_validate) {
  struct sockaddr_in sa;
  return !(inet_pton(AF_INET, to_validate.c_str(), &sa.sin_addr) < 1);
}

static inline bool IsIpv6(const string& to_validate) {
  struct sockaddr_in6 sa_six;
  return !(inet_pton(AF_INET6, to_validate.c_str(), &sa_six.sin6_addr) < 1);
}

static inline bool IsIp(const string& to_validate) {
  return IsIpv4(to_validate) || IsIpv6(to_validate);
}

static inline bool IsHostname(const string& to_validate) {
  if (to_validate.length() > 253) {
    return false;
  }

  const std::regex dot_regex{"\\."};
  const auto iter_end = std::sregex_token_iterator();
  auto iter = std::sregex_token_iterator(to_validate.begin(), to_validate.end(), dot_regex, -1);
  for (; iter != iter_end; ++iter) {
    const std::string& part = *iter;
    if (part.empty() || part.length() > 63) {
      return false;
    }
    if (part.at(0) == '-') {
      return false;
    }
    if (part.at(part.length() - 1) == '-') {
      return false;
    }
    for (const auto& character : part) {
      if ((character < 'A' || character > 'Z') && (character < 'a' || character > 'z') &&
          (character < '0' || character > '9') && character != '-') {
        return false;
      }
    }
  }

  return true;
}

namespace {

inline int OneCharLen(const char* src) {
  return "\1\1\1\1\1\1\1\1\1\1\1\1\2\2\3\4"[(*src & 0xFF) >> 4];
}

inline int UTF8FirstLetterNumBytes(const char *utf8_str, int str_len) {
  if (str_len == 0)
    return 0;
  return OneCharLen(utf8_str);
}

inline size_t Utf8Len(const string& narrow_string) {
  const char* str_char = narrow_string.c_str();
  ptrdiff_t byte_len = narrow_string.length();
  size_t unicode_len = 0;
  int char_len = 1;
  while (byte_len > 0 && char_len > 0) {
    char_len = UTF8FirstLetterNumBytes(str_char, byte_len);
    str_char += char_len;
    byte_len -= char_len;
    ++unicode_len;
  }
  return unicode_len;
}

} // namespace

} // namespace pgv

#endif // _VALIDATE_H