diff --git a/source/extensions/filters/common/expr/BUILD b/source/extensions/filters/common/expr/BUILD index 014af08fbb9fb..316c36b05b19d 100644 --- a/source/extensions/filters/common/expr/BUILD +++ b/source/extensions/filters/common/expr/BUILD @@ -29,6 +29,7 @@ envoy_cc_library( hdrs = ["context.h"], deps = [ "//source/common/grpc:common_lib", + "//source/common/http:header_map_lib", "//source/common/http:utility_lib", "//source/common/stream_info:utility_lib", "@com_google_cel_cpp//eval/public:cel_value", diff --git a/source/extensions/filters/common/expr/context.cc b/source/extensions/filters/common/expr/context.cc index 6ae0eef652d34..ac5338cb86e9f 100644 --- a/source/extensions/filters/common/expr/context.cc +++ b/source/extensions/filters/common/expr/context.cc @@ -1,6 +1,7 @@ #include "extensions/filters/common/expr/context.h" #include "common/grpc/common.h" +#include "common/http/header_map_impl.h" #include "common/http/utility.h" #include "absl/strings/numbers.h" @@ -80,6 +81,9 @@ absl::optional RequestWrapper::operator[](CelValue key) const { } else { return CelValue::CreateInt64(info_.bytesReceived()); } + } else if (value == TotalSize) { + return CelValue::CreateInt64(info_.bytesReceived() + + (headers_.value_ ? headers_.value_->byteSize() : 0)); } else if (value == Duration) { auto duration = info_.requestComplete(); if (duration.has_value()) { @@ -115,8 +119,6 @@ absl::optional RequestWrapper::operator[](CelValue key) const { return convertHeaderEntry(headers_.value_->RequestId()); } else if (value == UserAgent) { return convertHeaderEntry(headers_.value_->UserAgent()); - } else if (value == TotalSize) { - return CelValue::CreateInt64(info_.bytesReceived() + headers_.value_->byteSize()); } } return {}; @@ -141,15 +143,17 @@ absl::optional ResponseWrapper::operator[](CelValue key) const { } else if (value == Flags) { return CelValue::CreateInt64(info_.responseFlags()); } else if (value == GrpcStatus) { - auto const& optional_status = - Grpc::Common::getGrpcStatus(*(trailers_.value_), *(headers_.value_), info_); + auto const& optional_status = Grpc::Common::getGrpcStatus( + trailers_.value_ ? *trailers_.value_ : ConstSingleton::get(), + headers_.value_ ? *headers_.value_ : ConstSingleton::get(), info_); if (optional_status.has_value()) { return CelValue::CreateInt64(optional_status.value()); } return {}; } else if (value == TotalSize) { - return CelValue::CreateInt64(info_.bytesSent() + headers_.value_->byteSize() + - trailers_.value_->byteSize()); + return CelValue::CreateInt64(info_.bytesSent() + + (headers_.value_ ? headers_.value_->byteSize() : 0) + + (trailers_.value_ ? trailers_.value_->byteSize() : 0)); } return {}; } diff --git a/test/extensions/filters/common/expr/context_test.cc b/test/extensions/filters/common/expr/context_test.cc index 8768d811a2f1f..549bdd842a530 100644 --- a/test/extensions/filters/common/expr/context_test.cc +++ b/test/extensions/filters/common/expr/context_test.cc @@ -32,12 +32,14 @@ TEST(Context, EmptyHeadersAttributes) { TEST(Context, RequestAttributes) { NiceMock info; + NiceMock empty_info; Http::TestHeaderMapImpl header_map{ {":method", "POST"}, {":scheme", "http"}, {":path", "/meow?yes=1"}, {":authority", "kittens.com"}, {"referer", "dogs.com"}, {"user-agent", "envoy-mobile"}, {"content-length", "10"}, {"x-request-id", "blah"}, }; RequestWrapper request(&header_map, info); + RequestWrapper empty_request(nullptr, empty_info); EXPECT_CALL(info, bytesReceived()).WillRepeatedly(Return(10)); // "2018-04-03T23:06:09.123Z". @@ -67,6 +69,12 @@ TEST(Context, RequestAttributes) { ASSERT_TRUE(value.value().IsString()); EXPECT_EQ("http", value.value().StringOrDie().value()); } + + { + auto value = empty_request[CelValue::CreateStringView(Scheme)]; + EXPECT_FALSE(value.has_value()); + } + { auto value = request[CelValue::CreateStringView(Host)]; EXPECT_TRUE(value.has_value()); @@ -131,6 +139,14 @@ TEST(Context, RequestAttributes) { EXPECT_EQ(138, value.value().Int64OrDie()); } + { + auto value = empty_request[CelValue::CreateStringView(TotalSize)]; + EXPECT_TRUE(value.has_value()); + ASSERT_TRUE(value.value().IsInt64()); + // this includes the headers size + EXPECT_EQ(0, value.value().Int64OrDie()); + } + { auto value = request[CelValue::CreateStringView(Time)]; EXPECT_TRUE(value.has_value()); @@ -159,12 +175,22 @@ TEST(Context, RequestAttributes) { EXPECT_EQ("15ms", absl::FormatDuration(value.value().DurationOrDie())); } + { + auto value = empty_request[CelValue::CreateStringView(Duration)]; + EXPECT_FALSE(value.has_value()); + } + { auto value = request[CelValue::CreateStringView(Protocol)]; EXPECT_TRUE(value.has_value()); ASSERT_TRUE(value.value().IsString()); EXPECT_EQ("HTTP/2", value.value().StringOrDie().value()); } + + { + auto value = empty_request[CelValue::CreateStringView(Protocol)]; + EXPECT_FALSE(value.has_value()); + } } TEST(Context, RequestFallbackAttributes) { @@ -195,12 +221,14 @@ TEST(Context, RequestFallbackAttributes) { TEST(Context, ResponseAttributes) { NiceMock info; + NiceMock empty_info; const std::string header_name = "test-header"; const std::string trailer_name = "test-trailer"; const std::string grpc_status = "grpc-status"; Http::TestHeaderMapImpl header_map{{header_name, "a"}}; Http::TestHeaderMapImpl trailer_map{{trailer_name, "b"}, {grpc_status, "8"}}; ResponseWrapper response(&header_map, &trailer_map, info); + ResponseWrapper empty_response(nullptr, nullptr, empty_info); EXPECT_CALL(info, responseCode()).WillRepeatedly(Return(404)); EXPECT_CALL(info, bytesSent()).WillRepeatedly(Return(123)); @@ -230,6 +258,13 @@ TEST(Context, ResponseAttributes) { EXPECT_EQ(160, value.value().Int64OrDie()); } + { + auto value = empty_response[CelValue::CreateStringView(TotalSize)]; + EXPECT_TRUE(value.has_value()); + ASSERT_TRUE(value.value().IsInt64()); + EXPECT_EQ(0, value.value().Int64OrDie()); + } + { auto value = response[CelValue::CreateStringView(Code)]; EXPECT_TRUE(value.has_value()); @@ -267,18 +302,26 @@ TEST(Context, ResponseAttributes) { ASSERT_TRUE(header.value().IsString()); EXPECT_EQ("b", header.value().StringOrDie().value()); } + { auto value = response[CelValue::CreateStringView(Flags)]; EXPECT_TRUE(value.has_value()); ASSERT_TRUE(value.value().IsInt64()); EXPECT_EQ(0x1, value.value().Int64OrDie()); } + { auto value = response[CelValue::CreateStringView(GrpcStatus)]; EXPECT_TRUE(value.has_value()); ASSERT_TRUE(value.value().IsInt64()); EXPECT_EQ(0x8, value.value().Int64OrDie()); } + + { + auto value = empty_response[CelValue::CreateStringView(GrpcStatus)]; + EXPECT_FALSE(value.has_value()); + } + { Http::TestHeaderMapImpl header_map{{header_name, "a"}, {grpc_status, "7"}}; Http::TestHeaderMapImpl trailer_map{{trailer_name, "b"}};