1
#pragma once
2

            
3
#include "envoy/protobuf/message_validator.h"
4
#include "envoy/stats/stats.h"
5

            
6
#include "source/common/common/documentation_url.h"
7
#include "source/common/common/logger.h"
8

            
9
#include "absl/container/flat_hash_set.h"
10

            
11
namespace Envoy {
12
namespace ProtobufMessage {
13

            
14
class ValidationVisitorBase : public ValidationVisitor {
15
public:
16
32115
  void setRuntime(Runtime::Loader& runtime) { runtime_ = runtime; }
17
110
  void clearRuntime() { runtime_ = {}; } // for tests
18
282987
  OptRef<Runtime::Loader> runtime() override { return runtime_; }
19

            
20
32300
  void setSkipDeprecatedLogs(bool skip) { skip_deprecated_logs_ = skip; }
21
284
  bool isSkipDeprecatedLogs() const { return skip_deprecated_logs_; }
22

            
23
protected:
24
  OptRef<Runtime::Loader> runtime_;
25
  bool skip_deprecated_logs_{false};
26
};
27

            
28
class NullValidationVisitorImpl : public ValidationVisitorBase {
29
public:
30
  // Envoy::ProtobufMessage::ValidationVisitor
31
10
  absl::Status onUnknownField(absl::string_view) override { return absl::OkStatus(); }
32
  absl::Status onDeprecatedField(absl::string_view, bool) override { return absl::OkStatus(); }
33
99
  bool skipValidation() override { return true; }
34
  void onWorkInProgress(absl::string_view) override {}
35
};
36

            
37
ValidationVisitor& getNullValidationVisitor();
38

            
39
// Base class for both warning and strict validators.
40
class WipCounterBase {
41
protected:
42
  void setWipCounter(Stats::Counter& wip_counter);
43
  void onWorkInProgressCommon(absl::string_view description);
44

            
45
private:
46
  Stats::Counter* wip_counter_{};
47
  uint64_t prestats_wip_count_{};
48
};
49

            
50
class WarningValidationVisitorImpl : public ValidationVisitorBase,
51
                                     public WipCounterBase,
52
                                     public Logger::Loggable<Logger::Id::config> {
53
public:
54
  void setCounters(Stats::Counter& unknown_counter, Stats::Counter& wip_counter);
55

            
56
  // Envoy::ProtobufMessage::ValidationVisitor
57
  absl::Status onUnknownField(absl::string_view description) override;
58
  absl::Status onDeprecatedField(absl::string_view description, bool soft_deprecation) override;
59
115
  bool skipValidation() override { return false; }
60
  void onWorkInProgress(absl::string_view description) override;
61

            
62
private:
63
  // Track hashes of descriptions we've seen, to avoid log spam. A hash is used here to avoid
64
  // wasting memory with unused strings.
65
  absl::flat_hash_set<uint64_t> descriptions_;
66
  // This can be late initialized via setUnknownCounter(), enabling the server bootstrap loading
67
  // which occurs prior to the initialization of the stats subsystem.
68
  Stats::Counter* unknown_counter_{};
69
  uint64_t prestats_unknown_count_{};
70
};
71

            
72
class StrictValidationVisitorImpl : public ValidationVisitorBase, public WipCounterBase {
73
public:
74
10672
  void setCounters(Stats::Counter& wip_counter) { setWipCounter(wip_counter); }
75

            
76
  // Envoy::ProtobufMessage::ValidationVisitor
77
  absl::Status onUnknownField(absl::string_view description) override;
78
145837
  bool skipValidation() override { return false; }
79
  absl::Status onDeprecatedField(absl::string_view description, bool soft_deprecation) override;
80
  void onWorkInProgress(absl::string_view description) override;
81
};
82

            
83
// TODO(mattklein123): There are various places where the default strict validator is being used.
84
// This does not increment the WIP stat because nothing calls setCounters() on the stock/static
85
// version. We should remove this as a public function as well as the stock/static version and
86
// make sure that all code is either using the server validation context or the null validator.
87
ValidationVisitor& getStrictValidationVisitor();
88

            
89
class ValidationContextImpl : public ValidationContext {
90
public:
91
  ValidationContextImpl(ValidationVisitor& static_validation_visitor,
92
                        ValidationVisitor& dynamic_validation_visitor)
93
10766
      : static_validation_visitor_(static_validation_visitor),
94
10766
        dynamic_validation_visitor_(dynamic_validation_visitor) {}
95

            
96
  // Envoy::ProtobufMessage::ValidationContext
97
142635
  ValidationVisitor& staticValidationVisitor() override { return static_validation_visitor_; }
98
54467
  ValidationVisitor& dynamicValidationVisitor() override { return dynamic_validation_visitor_; }
99

            
100
private:
101
  ValidationVisitor& static_validation_visitor_;
102
  ValidationVisitor& dynamic_validation_visitor_;
103
};
104

            
105
class ProdValidationContextImpl : public ValidationContextImpl {
106
public:
107
  ProdValidationContextImpl(bool allow_unknown_static_fields, bool allow_unknown_dynamic_fields,
108
                            bool ignore_unknown_dynamic_fields, bool skip_deprecated_logs)
109
10766
      : ValidationContextImpl(
110
10766
            allow_unknown_static_fields
111
10766
                ? static_cast<ValidationVisitor&>(static_warning_validation_visitor_)
112
10766
                : strict_validation_visitor_,
113
10766
            allow_unknown_dynamic_fields
114
10766
                ? (ignore_unknown_dynamic_fields ? ProtobufMessage::getNullValidationVisitor()
115
209
                                                 : dynamic_warning_validation_visitor_)
116
10766
                : strict_validation_visitor_) {
117
10766
    strict_validation_visitor_.setSkipDeprecatedLogs(skip_deprecated_logs);
118
10766
    static_warning_validation_visitor_.setSkipDeprecatedLogs(skip_deprecated_logs);
119
10766
    dynamic_warning_validation_visitor_.setSkipDeprecatedLogs(skip_deprecated_logs);
120
10766
  }
121

            
122
  void setCounters(Stats::Counter& static_unknown_counter, Stats::Counter& dynamic_unknown_counter,
123
10671
                   Stats::Counter& wip_counter) {
124
10671
    strict_validation_visitor_.setCounters(wip_counter);
125
10671
    static_warning_validation_visitor_.setCounters(static_unknown_counter, wip_counter);
126
10671
    dynamic_warning_validation_visitor_.setCounters(dynamic_unknown_counter, wip_counter);
127
10671
  }
128

            
129
10667
  void setRuntime(Runtime::Loader& runtime) {
130
10667
    strict_validation_visitor_.setRuntime(runtime);
131
10667
    static_warning_validation_visitor_.setRuntime(runtime);
132
10667
    dynamic_warning_validation_visitor_.setRuntime(runtime);
133
10667
  }
134

            
135
private:
136
  StrictValidationVisitorImpl strict_validation_visitor_;
137
  ProtobufMessage::WarningValidationVisitorImpl static_warning_validation_visitor_;
138
  ProtobufMessage::WarningValidationVisitorImpl dynamic_warning_validation_visitor_;
139
};
140

            
141
} // namespace ProtobufMessage
142
} // namespace Envoy