diff --git a/source/extensions/filters/http/ext_authz/ext_authz.cc b/source/extensions/filters/http/ext_authz/ext_authz.cc index 38d86bc85709..ba050edeaa24 100644 --- a/source/extensions/filters/http/ext_authz/ext_authz.cc +++ b/source/extensions/filters/http/ext_authz/ext_authz.cc @@ -323,6 +323,9 @@ bool Filter::isBufferFull() const { } void Filter::continueDecoding() { + // After sending the check request, we don't need to buffer the data anymore. + buffer_data_ = false; + filter_return_ = FilterReturn::ContinueDecoding; if (!initiating_call_) { callbacks_->continueDecoding(); diff --git a/test/extensions/filters/http/ext_authz/ext_authz_test.cc b/test/extensions/filters/http/ext_authz/ext_authz_test.cc index 456f62328c92..3456b0e57259 100644 --- a/test/extensions/filters/http/ext_authz/ext_authz_test.cc +++ b/test/extensions/filters/http/ext_authz/ext_authz_test.cc @@ -489,6 +489,62 @@ TEST_F(HttpFilterTest, RequestDataWithPartialMessage) { EXPECT_EQ(Http::FilterTrailersStatus::StopIteration, filter_->decodeTrailers(request_trailers_)); } +// Checks that the filter initiates an authorization request when the buffer reaches maximum +// request bytes and allow_partial_message is set to true. In addition to that, after the filter +// sends the check request, data decoding continues. +TEST_F(HttpFilterTest, RequestDataWithPartialMessageThenContinueDecoding) { + InSequence s; + + initialize(R"EOF( + grpc_service: + envoy_grpc: + cluster_name: "ext_authz_server" + failure_mode_allow: false + with_request_body: + max_request_bytes: 10 + allow_partial_message: true + )EOF"); + + ON_CALL(filter_callbacks_, connection()).WillByDefault(Return(&connection_)); + ON_CALL(filter_callbacks_, decodingBuffer()).WillByDefault(Return(&data_)); + EXPECT_CALL(filter_callbacks_, setDecoderBufferLimit(_)).Times(0); + EXPECT_CALL(connection_, remoteAddress()).WillOnce(ReturnRef(addr_)); + EXPECT_CALL(connection_, localAddress()).WillOnce(ReturnRef(addr_)); + + // The check call should only be called once. + EXPECT_CALL(*client_, check(_, _, _, testing::A(), _)) + .WillOnce( + WithArgs<0>(Invoke([&](Filters::Common::ExtAuthz::RequestCallbacks& callbacks) -> void { + request_callbacks_ = &callbacks; + }))); + + EXPECT_CALL(filter_callbacks_, continueDecoding()); + + EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, + filter_->decodeHeaders(request_headers_, false)); + + data_.add("foo"); + EXPECT_EQ(Http::FilterDataStatus::StopIterationAndBuffer, filter_->decodeData(data_, false)); + + data_.add("bar"); + EXPECT_EQ(Http::FilterDataStatus::StopIterationAndBuffer, filter_->decodeData(data_, false)); + + data_.add("barfoo"); + EXPECT_EQ(Http::FilterDataStatus::StopIterationAndWatermark, filter_->decodeData(data_, false)); + + data_.add("more data after watermark is set is possible"); + EXPECT_EQ(Http::FilterDataStatus::StopIterationAndWatermark, filter_->decodeData(data_, false)); + + Filters::Common::ExtAuthz::Response response{}; + response.status = Filters::Common::ExtAuthz::CheckStatus::OK; + request_callbacks_->onComplete(std::make_unique(response)); + + data_.add("more data after calling check request"); + EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data_, true)); + + EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->decodeTrailers(request_trailers_)); +} + // Checks that the filter initiates the authorization process only when the filter decode trailers // is called. TEST_F(HttpFilterTest, RequestDataWithSmallBuffer) {