1515
1616#include " src/envoy/tcp/mixer/filter.h"
1717#include " common/common/enum_to_int.h"
18+ #include " extensions/filters/network/well_known_names.h"
1819#include " src/envoy/utils/utils.h"
1920
2021using ::google::protobuf::util::Status;
@@ -66,6 +67,31 @@ void Filter::callCheck() {
6667 calling_check_ = false ;
6768}
6869
70+ // TODO(venilnoronha): rewrite this to deep-clone dynamic metadata for all
71+ // filters.
72+ void Filter::cacheFilterMetadata (
73+ const ::google::protobuf::Map<std::string, ::google::protobuf::Struct>
74+ &filter_metadata) {
75+ for (auto &filter_pair : filter_metadata) {
76+ if (filter_pair.first ==
77+ Extensions::NetworkFilters::NetworkFilterNames::get ().MongoProxy ) {
78+ if (cached_filter_metadata_.count (filter_pair.first ) == 0 ) {
79+ ProtobufWkt::Struct dynamic_metadata;
80+ cached_filter_metadata_[filter_pair.first ] = dynamic_metadata;
81+ }
82+
83+ auto &cached_fields =
84+ *cached_filter_metadata_[filter_pair.first ].mutable_fields ();
85+ for (const auto &message_pair : filter_pair.second .fields ()) {
86+ cached_fields[message_pair.first ].mutable_list_value ()->CopyFrom (
87+ message_pair.second .list_value ());
88+ }
89+ }
90+ }
91+ }
92+
93+ void Filter::clearCachedFilterMetadata () { cached_filter_metadata_.clear (); }
94+
6995// Network::ReadFilter
7096Network::FilterStatus Filter::onData (Buffer::Instance &data, bool ) {
7197 if (state_ == State::NotStarted) {
@@ -78,6 +104,17 @@ Network::FilterStatus Filter::onData(Buffer::Instance &data, bool) {
78104 filter_callbacks_->connection (), data.length ());
79105 received_bytes_ += data.length ();
80106
107+ // Envoy filters like the mongo_proxy filter clear previously set dynamic
108+ // metadata on each onData call. Since the Mixer filter sends metadata based
109+ // on a timer event, it's possible that the previously set metadata is cleared
110+ // off by the time the event is fired. Therefore, we append metadata from each
111+ // onData call to a local cache and send it all at once when the timer event
112+ // occurs. The local cache is cleared after reporting it on the timer event.
113+ cacheFilterMetadata (filter_callbacks_->connection ()
114+ .streamInfo ()
115+ .dynamicMetadata ()
116+ .filter_metadata ());
117+
81118 return state_ == State::Calling ? Network::FilterStatus::StopIteration
82119 : Network::FilterStatus::Continue;
83120}
@@ -150,6 +187,7 @@ bool Filter::GetSourceIpPort(std::string *str_ip, int *port) const {
150187 return Utils::GetIpPort (filter_callbacks_->connection ().remoteAddress ()->ip (),
151188 str_ip, port);
152189}
190+
153191bool Filter::GetPrincipal (bool peer, std::string *user) const {
154192 return Utils::GetPrincipal (&filter_callbacks_->connection (), peer, user);
155193}
@@ -170,20 +208,20 @@ bool Filter::GetDestinationIpPort(std::string *str_ip, int *port) const {
170208 }
171209 return false ;
172210}
211+
173212bool Filter::GetDestinationUID (std::string *uid) const {
174213 if (filter_callbacks_->upstreamHost ()) {
175214 return Utils::GetDestinationUID (
176215 *filter_callbacks_->upstreamHost ()->metadata (), uid);
177216 }
178217 return false ;
179218}
219+
180220const ::google::protobuf::Map<std::string, ::google::protobuf::Struct>
181221 &Filter::GetDynamicFilterState () const {
182- return filter_callbacks_->connection ()
183- .streamInfo ()
184- .dynamicMetadata ()
185- .filter_metadata ();
222+ return cached_filter_metadata_;
186223}
224+
187225void Filter::GetReportInfo (
188226 ::istio::control::tcp::ReportData::ReportInfo *data) const {
189227 data->received_bytes = received_bytes_;
@@ -202,6 +240,7 @@ std::string Filter::GetConnectionId() const {
202240
203241void Filter::OnReportTimer () {
204242 handler_->Report (this , ConnectionEvent::CONTINUE);
243+ clearCachedFilterMetadata ();
205244 report_timer_->enableTimer (control_.config ().report_interval_ms ());
206245}
207246
0 commit comments