-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Flow control for Http::Filters #1417
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
a604e38
4804be6
1040f67
647845a
3a8cf94
a445e52
4f80dec
9267859
8ac29e1
95de98b
ae42c02
f705fed
f99ca46
d0a823a
7e5b7c1
471fe64
668932f
37d940e
19aaf38
1292a58
558fb59
9ac14b1
6b5f615
220fcf3
9685ee9
a970125
1409730
eaed1ae
9bf5df7
0bead86
612eacb
3bfbc51
a94b527
be29d74
0d534df
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -149,6 +149,7 @@ void ConnectionManagerImpl::doEndStream(ActiveStream& stream) { | |
| } | ||
|
|
||
| void ConnectionManagerImpl::doDeferredStreamDestroy(ActiveStream& stream) { | ||
| stream.destroyed_ = true; | ||
| for (auto& filter : stream.decoder_filters_) { | ||
| filter->handle_->onDestroy(); | ||
| } | ||
|
|
@@ -172,6 +173,7 @@ StreamDecoder& ConnectionManagerImpl::newStream(StreamEncoder& response_encoder) | |
| ActiveStreamPtr new_stream(new ActiveStream(*this)); | ||
| new_stream->response_encoder_ = &response_encoder; | ||
| new_stream->response_encoder_->getStream().addCallbacks(*new_stream); | ||
| new_stream->buffer_limit_ = new_stream->response_encoder_->getStream().bufferLimit(); | ||
| config_.filterFactory().createFilterChain(*new_stream); | ||
| new_stream->moveIntoList(std::move(new_stream), streams_); | ||
| return **streams_.begin(); | ||
|
|
@@ -367,13 +369,31 @@ void ConnectionManagerImpl::ActiveStream::addStreamDecoderFilterWorker( | |
| StreamDecoderFilterSharedPtr filter, bool dual_filter) { | ||
| ActiveStreamDecoderFilterPtr wrapper(new ActiveStreamDecoderFilter(*this, filter, dual_filter)); | ||
| filter->setDecoderFilterCallbacks(*wrapper); | ||
|
|
||
| BufferLimitSettings settings{buffer_limit_, Http::FilterType::STREAMING}; | ||
| filter->setDecoderBufferLimit(settings); | ||
| // FIXME corner cases with 0 here and below. | ||
| if (settings.buffer_limit_ > buffer_limit_) { | ||
| buffer_limit_ = settings.buffer_limit_; | ||
| } | ||
| if (settings.filter_type_ == Http::FilterType::BUFFERING) { | ||
| decoder_filters_all_streaming_ = false; | ||
| } | ||
| wrapper->moveIntoListBack(std::move(wrapper), decoder_filters_); | ||
| } | ||
|
|
||
| void ConnectionManagerImpl::ActiveStream::addStreamEncoderFilterWorker( | ||
| StreamEncoderFilterSharedPtr filter, bool dual_filter) { | ||
| ActiveStreamEncoderFilterPtr wrapper(new ActiveStreamEncoderFilter(*this, filter, dual_filter)); | ||
| filter->setEncoderFilterCallbacks(*wrapper); | ||
| BufferLimitSettings settings{buffer_limit_, Http::FilterType::STREAMING}; | ||
| filter->setEncoderBufferLimit(settings); | ||
| if (settings.buffer_limit_ > buffer_limit_) { | ||
| buffer_limit_ = settings.buffer_limit_; | ||
| } | ||
| if (settings.filter_type_ == Http::FilterType::BUFFERING) { | ||
| encoder_filters_all_streaming_ = false; | ||
| } | ||
| wrapper->moveIntoListBack(std::move(wrapper), encoder_filters_); | ||
| } | ||
|
|
||
|
|
@@ -966,7 +986,7 @@ void ConnectionManagerImpl::ActiveStreamFilterBase::commonHandleBufferData( | |
| // rebuffer, because we assume the filter has modified the buffer as it wishes in place. | ||
| if (bufferedData().get() != &provided_data) { | ||
| if (!bufferedData()) { | ||
| bufferedData().reset(new Buffer::OwnedImpl()); | ||
| bufferedData().reset(createBuffer().release()); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: |
||
| } | ||
| bufferedData()->move(provided_data); | ||
| } | ||
|
|
@@ -1067,6 +1087,30 @@ void ConnectionManagerImpl::ActiveStreamDecoderFilter:: | |
| parent_.connection_manager_.stats_.named_.downstream_flow_control_paused_reading_total_.inc(); | ||
| } | ||
|
|
||
| void ConnectionManagerImpl::ActiveStreamDecoderFilter::requestDataTooLarge() { | ||
| if (parent_.encoder_filters_all_streaming_) { | ||
| onDecoderFilterAboveWriteBufferHighWatermark(); | ||
| } else { | ||
| HeaderMapPtr response_headers{new HeaderMapImpl{ | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should probably use sendLocalReply here. |
||
| {Headers::get().Status, std::to_string(enumToInt(Http::Code::PayloadTooLarge))}}}; | ||
| std::string body_text = CodeUtility::toString(Http::Code::PayloadTooLarge); | ||
| response_headers->insertContentLength().value(body_text.size()); | ||
| response_headers->insertContentType().value(Headers::get().ContentTypeValues.Text); | ||
|
|
||
| encodeHeaders(std::move(response_headers), false); | ||
| if (!parent_.destroyed_) { | ||
| Buffer::OwnedImpl buffer(body_text); | ||
| encodeData(buffer, true); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| void ConnectionManagerImpl::ActiveStreamDecoderFilter::requestDataDrained() { | ||
| if (parent_.encoder_filters_all_streaming_) { | ||
| onDecoderFilterBelowWriteBufferLowWatermark(); | ||
| } | ||
| } | ||
|
|
||
| void ConnectionManagerImpl::ActiveStreamDecoderFilter:: | ||
| onDecoderFilterBelowWriteBufferLowWatermark() { | ||
| ENVOY_STREAM_LOG(debug, "Read-enabling downstream stream due to filter callbacks.", parent_); | ||
|
|
@@ -1092,6 +1136,31 @@ void ConnectionManagerImpl::ActiveStreamEncoderFilter:: | |
|
|
||
| void ConnectionManagerImpl::ActiveStreamEncoderFilter::continueEncoding() { commonContinue(); } | ||
|
|
||
| void ConnectionManagerImpl::ActiveStreamEncoderFilter::responseDataTooLarge() { | ||
| if (parent_.encoder_filters_all_streaming_) { | ||
| onEncoderFilterAboveWriteBufferHighWatermark(); | ||
| } else { | ||
| // FIXME 500 | ||
| HeaderMapPtr response_headers{new HeaderMapImpl{ | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this case needs a bit of thinking. It is technically possible for the response to start, but then have buffering occur, so I think we need to check if response has started and if so reset, otherwise we can send a 500.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess one could argue this is filter bug. Not sure. (Like if filter continues headers but then buffers data it's really a streaming filter). Anyway needs a bit of thinking IMO. |
||
| {Headers::get().Status, std::to_string(enumToInt(Http::Code::InternalServerError))}}}; | ||
| std::string body_text = CodeUtility::toString(Http::Code::InternalServerError); | ||
| response_headers->insertContentLength().value(body_text.size()); | ||
| response_headers->insertContentType().value(Headers::get().ContentTypeValues.Text); | ||
|
|
||
| parent_.response_headers_ = std::move(response_headers); | ||
| parent_.encodeHeaders(nullptr, *parent_.response_headers_, false); | ||
| if (!parent_.destroyed_) { | ||
| Buffer::OwnedImpl buffer(body_text); | ||
| parent_.encodeData(nullptr, buffer, true); | ||
| } | ||
| } | ||
| } | ||
| void ConnectionManagerImpl::ActiveStreamEncoderFilter::responseDataDrained() { | ||
| if (parent_.encoder_filters_all_streaming_) { | ||
| onEncoderFilterBelowWriteBufferLowWatermark(); | ||
| } | ||
| } | ||
|
|
||
| void ConnectionManagerImpl::ActiveStreamFilterBase::resetStream() { | ||
| parent_.connection_manager_.stats_.named_.downstream_rq_tx_reset_.inc(); | ||
| parent_.connection_manager_.doEndStream(this->parent_); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thought: It might be better to just return a struct here to make it more clear that the filter needs to tell the connection manager what it wants. We could even make the default constructor for the struct set sane defaults. I think for this type of struct the compiler will optimize well.