/proc/self/cwd/source/extensions/filters/common/expr/context.cc
Line | Count | Source (jump to first uncovered line) |
1 | | #include "source/extensions/filters/common/expr/context.h" |
2 | | |
3 | | #include "source/common/grpc/common.h" |
4 | | #include "source/common/http/header_map_impl.h" |
5 | | #include "source/common/http/utility.h" |
6 | | #include "source/extensions/filters/common/expr/cel_state.h" |
7 | | |
8 | | #include "absl/strings/numbers.h" |
9 | | #include "absl/time/time.h" |
10 | | |
11 | | namespace Envoy { |
12 | | namespace Extensions { |
13 | | namespace Filters { |
14 | | namespace Common { |
15 | | namespace Expr { |
16 | | |
17 | | Http::RegisterCustomInlineHeader<Http::CustomInlineHeaderRegistry::Type::RequestHeaders> |
18 | | referer_handle(Http::CustomHeaders::get().Referer); |
19 | | |
20 | 936 | absl::optional<CelValue> convertHeaderEntry(const Http::HeaderEntry* header) { |
21 | 936 | if (header == nullptr) { |
22 | 912 | return {}; |
23 | 912 | } |
24 | 24 | return CelValue::CreateStringView(header->value().getStringView()); |
25 | 936 | } |
26 | | |
27 | | absl::optional<CelValue> |
28 | | convertHeaderEntry(Protobuf::Arena& arena, |
29 | 131k | Http::HeaderUtility::GetAllOfHeaderAsStringResult&& result) { |
30 | 131k | if (!result.result().has_value()) { |
31 | 510 | return {}; |
32 | 130k | } else if (!result.backingString().empty()) { |
33 | 40.1k | return CelValue::CreateString( |
34 | 40.1k | Protobuf::Arena::Create<std::string>(&arena, result.backingString())); |
35 | 90.7k | } else { |
36 | 90.7k | return CelValue::CreateStringView(result.result().value()); |
37 | 90.7k | } |
38 | 131k | } |
39 | | |
40 | | namespace { |
41 | | |
42 | | absl::optional<CelValue> extractSslInfo(const Ssl::ConnectionInfo& ssl_info, |
43 | 2.39k | absl::string_view value) { |
44 | 2.39k | if (value == TLSVersion) { |
45 | 19 | return CelValue::CreateString(&ssl_info.tlsVersion()); |
46 | 2.37k | } else if (value == SubjectLocalCertificate) { |
47 | 23 | return CelValue::CreateString(&ssl_info.subjectLocalCertificate()); |
48 | 2.35k | } else if (value == SubjectPeerCertificate) { |
49 | 59 | return CelValue::CreateString(&ssl_info.subjectPeerCertificate()); |
50 | 2.29k | } else if (value == URISanLocalCertificate) { |
51 | 62 | if (!ssl_info.uriSanLocalCertificate().empty()) { |
52 | 0 | return CelValue::CreateString(&ssl_info.uriSanLocalCertificate()[0]); |
53 | 0 | } |
54 | 2.23k | } else if (value == URISanPeerCertificate) { |
55 | 66 | if (!ssl_info.uriSanPeerCertificate().empty()) { |
56 | 0 | return CelValue::CreateString(&ssl_info.uriSanPeerCertificate()[0]); |
57 | 0 | } |
58 | 2.16k | } else if (value == DNSSanLocalCertificate) { |
59 | 48 | if (!ssl_info.dnsSansLocalCertificate().empty()) { |
60 | 0 | return CelValue::CreateString(&ssl_info.dnsSansLocalCertificate()[0]); |
61 | 0 | } |
62 | 2.11k | } else if (value == DNSSanPeerCertificate) { |
63 | 61 | if (!ssl_info.dnsSansPeerCertificate().empty()) { |
64 | 0 | return CelValue::CreateString(&ssl_info.dnsSansPeerCertificate()[0]); |
65 | 0 | } |
66 | 2.05k | } else if (value == SHA256PeerCertificateDigest) { |
67 | 505 | if (!ssl_info.sha256PeerCertificateDigest().empty()) { |
68 | 0 | return CelValue::CreateString(&ssl_info.sha256PeerCertificateDigest()); |
69 | 0 | } |
70 | 505 | } |
71 | 2.29k | return {}; |
72 | 2.39k | } |
73 | | |
74 | | } // namespace |
75 | | |
76 | 8.05k | absl::optional<CelValue> RequestWrapper::operator[](CelValue key) const { |
77 | 8.05k | if (!key.IsString()) { |
78 | 102 | return {}; |
79 | 102 | } |
80 | 7.95k | auto value = key.StringOrDie().value(); |
81 | | |
82 | 7.95k | if (value == Headers) { |
83 | 3.14k | return CelValue::CreateMap(&headers_); |
84 | 4.81k | } else if (value == Time) { |
85 | 16 | return CelValue::CreateTimestamp(absl::FromChrono(info_.startTime())); |
86 | 4.79k | } else if (value == Size) { |
87 | | // it is important to make a choice whether to rely on content-length vs stream info |
88 | | // (which is not available at the time of the request headers) |
89 | 384 | if (headers_.value_ != nullptr && headers_.value_->ContentLength() != nullptr) { |
90 | 298 | int64_t length; |
91 | 298 | if (absl::SimpleAtoi(headers_.value_->getContentLengthValue(), &length)) { |
92 | 48 | return CelValue::CreateInt64(length); |
93 | 48 | } |
94 | 298 | } else { |
95 | 86 | return CelValue::CreateInt64(info_.bytesReceived()); |
96 | 86 | } |
97 | 4.41k | } else if (value == TotalSize) { |
98 | 50 | return CelValue::CreateInt64(info_.bytesReceived() + |
99 | 50 | (headers_.value_ ? headers_.value_->byteSize() : 0)); |
100 | 4.36k | } else if (value == Duration) { |
101 | 51 | auto duration = info_.requestComplete(); |
102 | 51 | if (duration.has_value()) { |
103 | 51 | return CelValue::CreateDuration(absl::FromChrono(duration.value())); |
104 | 51 | } |
105 | 4.31k | } else if (value == Protocol) { |
106 | 180 | if (info_.protocol().has_value()) { |
107 | 0 | return CelValue::CreateString(&Http::Utility::getProtocolString(info_.protocol().value())); |
108 | 180 | } else { |
109 | 180 | return {}; |
110 | 180 | } |
111 | 180 | } |
112 | | |
113 | 4.38k | if (headers_.value_ != nullptr) { |
114 | 4.38k | if (value == Path) { |
115 | 48 | return convertHeaderEntry(headers_.value_->Path()); |
116 | 4.33k | } else if (value == UrlPath) { |
117 | 589 | absl::string_view path = headers_.value_->getPathValue(); |
118 | 589 | size_t query_offset = path.find('?'); |
119 | 589 | if (query_offset == absl::string_view::npos) { |
120 | 413 | return CelValue::CreateStringView(path); |
121 | 413 | } |
122 | 176 | return CelValue::CreateStringView(path.substr(0, query_offset)); |
123 | 3.74k | } else if (value == Host) { |
124 | 56 | return convertHeaderEntry(headers_.value_->Host()); |
125 | 3.69k | } else if (value == Scheme) { |
126 | 48 | return convertHeaderEntry(headers_.value_->Scheme()); |
127 | 3.64k | } else if (value == Method) { |
128 | 49 | return convertHeaderEntry(headers_.value_->Method()); |
129 | 3.59k | } else if (value == Referer) { |
130 | 72 | return convertHeaderEntry(headers_.value_->getInline(referer_handle.handle())); |
131 | 3.52k | } else if (value == ID) { |
132 | 0 | return convertHeaderEntry(headers_.value_->RequestId()); |
133 | 3.52k | } else if (value == UserAgent) { |
134 | 663 | return convertHeaderEntry(headers_.value_->UserAgent()); |
135 | 2.85k | } else if (value == Query) { |
136 | 856 | absl::string_view path = headers_.value_->getPathValue(); |
137 | 856 | auto query_offset = path.find('?'); |
138 | 856 | if (query_offset == absl::string_view::npos) { |
139 | 740 | return CelValue::CreateStringView(absl::string_view()); |
140 | 740 | } |
141 | 116 | path = path.substr(query_offset + 1); |
142 | 116 | auto fragment_offset = path.find('#'); |
143 | 116 | return CelValue::CreateStringView(path.substr(0, fragment_offset)); |
144 | 856 | } |
145 | 4.38k | } |
146 | 2.00k | return {}; |
147 | 4.38k | } |
148 | | |
149 | 6.97k | absl::optional<CelValue> ResponseWrapper::operator[](CelValue key) const { |
150 | 6.97k | if (!key.IsString()) { |
151 | 153 | return {}; |
152 | 153 | } |
153 | 6.82k | auto value = key.StringOrDie().value(); |
154 | 6.82k | if (value == Code) { |
155 | 321 | auto code = info_.responseCode(); |
156 | 321 | if (code.has_value()) { |
157 | 51 | return CelValue::CreateInt64(code.value()); |
158 | 51 | } |
159 | 270 | return {}; |
160 | 6.50k | } else if (value == Size) { |
161 | 111 | return CelValue::CreateInt64(info_.bytesSent()); |
162 | 6.39k | } else if (value == Headers) { |
163 | 1.90k | return CelValue::CreateMap(&headers_); |
164 | 4.48k | } else if (value == Trailers) { |
165 | 1.59k | return CelValue::CreateMap(&trailers_); |
166 | 2.88k | } else if (value == Flags) { |
167 | 48 | return CelValue::CreateInt64(info_.responseFlags()); |
168 | 2.83k | } else if (value == GrpcStatus) { |
169 | 1.18k | auto const& optional_status = Grpc::Common::getGrpcStatus( |
170 | 1.18k | trailers_.value_ ? *trailers_.value_ : *Http::StaticEmptyHeaders::get().response_trailers, |
171 | 1.18k | headers_.value_ ? *headers_.value_ : *Http::StaticEmptyHeaders::get().response_headers, |
172 | 1.18k | info_); |
173 | 1.18k | if (optional_status.has_value()) { |
174 | 993 | return CelValue::CreateInt64(optional_status.value()); |
175 | 993 | } |
176 | 190 | return {}; |
177 | 1.65k | } else if (value == TotalSize) { |
178 | 251 | return CelValue::CreateInt64(info_.bytesSent() + |
179 | 251 | (headers_.value_ ? headers_.value_->byteSize() : 0) + |
180 | 251 | (trailers_.value_ ? trailers_.value_->byteSize() : 0)); |
181 | 1.40k | } else if (value == CodeDetails) { |
182 | 56 | const absl::optional<std::string>& details = info_.responseCodeDetails(); |
183 | 56 | if (details.has_value()) { |
184 | 0 | return CelValue::CreateString(&details.value()); |
185 | 0 | } |
186 | 56 | return {}; |
187 | 56 | } |
188 | 1.34k | return {}; |
189 | 6.82k | } |
190 | | |
191 | 3.67k | absl::optional<CelValue> ConnectionWrapper::operator[](CelValue key) const { |
192 | 3.67k | if (!key.IsString()) { |
193 | 500 | return {}; |
194 | 500 | } |
195 | 3.17k | auto value = key.StringOrDie().value(); |
196 | 3.17k | if (value == MTLS) { |
197 | 0 | return CelValue::CreateBool( |
198 | 0 | info_.downstreamAddressProvider().sslConnection() != nullptr && |
199 | 0 | info_.downstreamAddressProvider().sslConnection()->peerCertificatePresented()); |
200 | 3.17k | } else if (value == RequestedServerName) { |
201 | 68 | return CelValue::CreateStringView(info_.downstreamAddressProvider().requestedServerName()); |
202 | 3.11k | } else if (value == ID) { |
203 | 609 | auto id = info_.downstreamAddressProvider().connectionID(); |
204 | 609 | if (id.has_value()) { |
205 | 212 | return CelValue::CreateUint64(id.value()); |
206 | 212 | } |
207 | 397 | return {}; |
208 | 2.50k | } else if (value == ConnectionTerminationDetails) { |
209 | 56 | if (info_.connectionTerminationDetails().has_value()) { |
210 | 0 | return CelValue::CreateString(&info_.connectionTerminationDetails().value()); |
211 | 0 | } |
212 | 56 | return {}; |
213 | 56 | } |
214 | | |
215 | 2.44k | auto ssl_info = info_.downstreamAddressProvider().sslConnection(); |
216 | 2.44k | if (ssl_info != nullptr) { |
217 | 2.39k | return extractSslInfo(*ssl_info, value); |
218 | 2.39k | } |
219 | | |
220 | 49 | return {}; |
221 | 2.44k | } |
222 | | |
223 | 4.23k | absl::optional<CelValue> UpstreamWrapper::operator[](CelValue key) const { |
224 | 4.23k | if (!key.IsString() || !info_.upstreamInfo().has_value()) { |
225 | 34 | return {}; |
226 | 34 | } |
227 | 4.20k | auto value = key.StringOrDie().value(); |
228 | 4.20k | if (value == Address) { |
229 | 16 | auto upstream_host = info_.upstreamInfo().value().get().upstreamHost(); |
230 | 16 | if (upstream_host != nullptr && upstream_host->address() != nullptr) { |
231 | 16 | return CelValue::CreateStringView(upstream_host->address()->asStringView()); |
232 | 16 | } |
233 | 4.18k | } else if (value == Port) { |
234 | 56 | auto upstream_host = info_.upstreamInfo().value().get().upstreamHost(); |
235 | 56 | if (upstream_host != nullptr && upstream_host->address() != nullptr && |
236 | 56 | upstream_host->address()->ip() != nullptr) { |
237 | 56 | return CelValue::CreateInt64(upstream_host->address()->ip()->port()); |
238 | 56 | } |
239 | 4.12k | } else if (value == UpstreamLocalAddress) { |
240 | 187 | auto upstream_local_address = info_.upstreamInfo().value().get().upstreamLocalAddress(); |
241 | 187 | if (upstream_local_address != nullptr) { |
242 | 187 | return CelValue::CreateStringView(upstream_local_address->asStringView()); |
243 | 187 | } |
244 | 3.94k | } else if (value == UpstreamTransportFailureReason) { |
245 | 49 | return CelValue::CreateStringView( |
246 | 49 | info_.upstreamInfo().value().get().upstreamTransportFailureReason()); |
247 | 49 | } |
248 | | |
249 | 3.89k | auto ssl_info = info_.upstreamInfo().value().get().upstreamSslConnection(); |
250 | 3.89k | if (ssl_info != nullptr) { |
251 | 0 | return extractSslInfo(*ssl_info, value); |
252 | 0 | } |
253 | | |
254 | 3.89k | return {}; |
255 | 3.89k | } |
256 | | |
257 | 1.34k | absl::optional<CelValue> PeerWrapper::operator[](CelValue key) const { |
258 | 1.34k | if (!key.IsString()) { |
259 | 426 | return {}; |
260 | 426 | } |
261 | 921 | auto value = key.StringOrDie().value(); |
262 | 921 | if (value == Address) { |
263 | 112 | if (local_) { |
264 | 48 | return CelValue::CreateStringView( |
265 | 48 | info_.downstreamAddressProvider().localAddress()->asStringView()); |
266 | 64 | } else { |
267 | 64 | return CelValue::CreateStringView( |
268 | 64 | info_.downstreamAddressProvider().remoteAddress()->asStringView()); |
269 | 64 | } |
270 | 809 | } else if (value == Port) { |
271 | 652 | if (local_) { |
272 | 225 | if (info_.downstreamAddressProvider().localAddress()->ip() != nullptr) { |
273 | 142 | return CelValue::CreateInt64( |
274 | 142 | info_.downstreamAddressProvider().localAddress()->ip()->port()); |
275 | 142 | } |
276 | 427 | } else { |
277 | 427 | if (info_.downstreamAddressProvider().remoteAddress()->ip() != nullptr) { |
278 | 358 | return CelValue::CreateInt64( |
279 | 358 | info_.downstreamAddressProvider().remoteAddress()->ip()->port()); |
280 | 358 | } |
281 | 427 | } |
282 | 652 | } |
283 | | |
284 | 309 | return {}; |
285 | 921 | } |
286 | | |
287 | | class FilterStateObjectWrapper : public google::api::expr::runtime::CelMap { |
288 | | public: |
289 | | FilterStateObjectWrapper(const StreamInfo::FilterState::ObjectReflection* reflection) |
290 | 0 | : reflection_(reflection) {} |
291 | 0 | absl::optional<CelValue> operator[](CelValue key) const override { |
292 | 0 | if (reflection_ == nullptr || !key.IsString()) { |
293 | 0 | return {}; |
294 | 0 | } |
295 | 0 | auto field_value = reflection_->getField(key.StringOrDie().value()); |
296 | 0 | return absl::visit(Visitor{}, field_value); |
297 | 0 | } |
298 | | // Default stubs. |
299 | 0 | int size() const override { return 0; } |
300 | 0 | bool empty() const override { return true; } |
301 | 0 | absl::StatusOr<const google::api::expr::runtime::CelList*> ListKeys() const override { |
302 | 0 | return &WrapperFields::get().Empty; |
303 | 0 | } |
304 | | |
305 | | private: |
306 | | struct Visitor { |
307 | 0 | absl::optional<CelValue> operator()(int64_t val) { return CelValue::CreateInt64(val); } |
308 | 0 | absl::optional<CelValue> operator()(absl::string_view val) { |
309 | 0 | return CelValue::CreateStringView(val); |
310 | 0 | } |
311 | 0 | absl::optional<CelValue> operator()(absl::monostate) { return {}; } |
312 | | }; |
313 | | const StreamInfo::FilterState::ObjectReflection* reflection_; |
314 | | }; |
315 | | |
316 | 1.03k | absl::optional<CelValue> FilterStateWrapper::operator[](CelValue key) const { |
317 | 1.03k | if (!key.IsString()) { |
318 | 456 | return {}; |
319 | 456 | } |
320 | 576 | auto value = key.StringOrDie().value(); |
321 | 576 | if (const StreamInfo::FilterState::Object* object = filter_state_.getDataReadOnlyGeneric(value); |
322 | 576 | object != nullptr) { |
323 | 0 | const CelState* cel_state = dynamic_cast<const CelState*>(object); |
324 | 0 | if (cel_state) { |
325 | 0 | return cel_state->exprValue(&arena_, false); |
326 | 0 | } else if (object != nullptr) { |
327 | | // Attempt to find the reflection object. |
328 | 0 | auto factory = |
329 | 0 | Registry::FactoryRegistry<StreamInfo::FilterState::ObjectFactory>::getFactory(value); |
330 | 0 | if (factory) { |
331 | 0 | auto reflection = factory->reflect(object); |
332 | 0 | if (reflection) { |
333 | 0 | auto* raw_reflection = reflection.release(); |
334 | 0 | arena_.Own(raw_reflection); |
335 | 0 | return CelValue::CreateMap( |
336 | 0 | ProtobufWkt::Arena::Create<FilterStateObjectWrapper>(&arena_, raw_reflection)); |
337 | 0 | } |
338 | 0 | } |
339 | 0 | absl::optional<std::string> serialized = object->serializeAsString(); |
340 | 0 | if (serialized.has_value()) { |
341 | 0 | std::string* out = ProtobufWkt::Arena::Create<std::string>(&arena_, serialized.value()); |
342 | 0 | return CelValue::CreateBytes(out); |
343 | 0 | } |
344 | 0 | } |
345 | 0 | } |
346 | 576 | return {}; |
347 | 576 | } |
348 | | |
349 | 2.09k | absl::optional<CelValue> XDSWrapper::operator[](CelValue key) const { |
350 | 2.09k | if (!key.IsString()) { |
351 | 129 | return {}; |
352 | 129 | } |
353 | 1.96k | auto value = key.StringOrDie().value(); |
354 | 1.96k | if (value == ClusterName) { |
355 | 94 | const auto cluster_info = info_.upstreamClusterInfo(); |
356 | 94 | if (cluster_info && cluster_info.value()) { |
357 | 0 | return CelValue::CreateString(&cluster_info.value()->name()); |
358 | 0 | } |
359 | 1.87k | } else if (value == ClusterMetadata) { |
360 | 53 | const auto cluster_info = info_.upstreamClusterInfo(); |
361 | 53 | if (cluster_info && cluster_info.value()) { |
362 | 0 | return CelProtoWrapper::CreateMessage(&cluster_info.value()->metadata(), &arena_); |
363 | 0 | } |
364 | 1.81k | } else if (value == RouteName) { |
365 | 48 | if (info_.route()) { |
366 | 0 | return CelValue::CreateString(&info_.route()->routeName()); |
367 | 0 | } |
368 | 1.77k | } else if (value == RouteMetadata) { |
369 | 48 | if (info_.route()) { |
370 | 0 | return CelProtoWrapper::CreateMessage(&info_.route()->metadata(), &arena_); |
371 | 0 | } |
372 | 1.72k | } else if (value == UpstreamHostMetadata) { |
373 | 35 | const auto upstream_info = info_.upstreamInfo(); |
374 | 35 | if (upstream_info && upstream_info->upstreamHost()) { |
375 | 35 | return CelProtoWrapper::CreateMessage(upstream_info->upstreamHost()->metadata().get(), |
376 | 35 | &arena_); |
377 | 35 | } |
378 | 1.68k | } else if (value == FilterChainName) { |
379 | 62 | const auto filter_chain_info = info_.downstreamAddressProvider().filterChainInfo(); |
380 | 62 | const absl::string_view filter_chain_name = |
381 | 62 | filter_chain_info.has_value() ? filter_chain_info->name() : absl::string_view{}; |
382 | 62 | return CelValue::CreateStringView(filter_chain_name); |
383 | 62 | } |
384 | 1.86k | return {}; |
385 | 1.96k | } |
386 | | |
387 | | } // namespace Expr |
388 | | } // namespace Common |
389 | | } // namespace Filters |
390 | | } // namespace Extensions |
391 | | } // namespace Envoy |