-
Notifications
You must be signed in to change notification settings - Fork 5.5k
http_filter: add addEncodedTrailers and addDecodedTrailers #3980
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 1 commit
34bd3d1
688bc4d
e0b74f3
acfa3d8
baee8aa
42443b0
52c5780
8495e41
36103a1
f6ca600
483b48b
5412bb8
cd25726
c3a900b
90c6233
3667d6a
7637fa3
f2b6210
815a07b
2321031
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 |
|---|---|---|
|
|
@@ -395,6 +395,13 @@ class StreamEncoderFilterCallbacks : public virtual StreamFilterCallbacks { | |
| */ | ||
| virtual void addEncodedData(Buffer::Instance& data, bool streaming_filter) PURE; | ||
|
|
||
| /** | ||
| * Provides a trailer map that can be used to modify the trailers for a response. Used when | ||
| * trailers need to be injected into a response and the upstream response did not contain any | ||
| * trailers (in which case encodeTrailers is not called). | ||
| */ | ||
| virtual HeaderMap& addEncodedTrailers() PURE; | ||
|
Contributor
Author
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. unsure what the best signature was here - it seems like
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. How does this work if the target stream protocol is not able to support trailers?
Contributor
Author
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. From what I understand the http/1.1 codec will just ignore the trailers: https://github.com/envoyproxy/envoy/blob/master/source/common/http/http1/codec_impl.cc#L148
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. Perhaps we should just pass a HeaderMapPtr via move? This would just overwrite existing trailers? It would be uyp to the user to figure out if trailers already exist? Thoughts?
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.
In that case you'll leaking HeaderMapImpl into filter codes and let filter create the HeaderMapPtr. Can we somehow (e.g. ASSERT) make sure this can be only called after or in
Contributor
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. We will want to make sure for any protocol which doesn't support trailers we don't then lose the end_stream=true passing through the pipeline, but that's what tests are for :-) |
||
|
|
||
| /** | ||
| * Called when an encoder filter goes over its high watermark. | ||
| */ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1058,6 +1058,13 @@ void ConnectionManagerImpl::ActiveStream::encodeHeaders(ActiveStreamEncoderFilte | |
| } | ||
| } | ||
|
|
||
| HeaderMap& ConnectionManagerImpl::ActiveStream::addEncodedTrailers() { | ||
| if (!response_trailers_) { | ||
|
Contributor
Author
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. this whole interaction ends up becoming somewhat complicated so i wanted to put up the PR before spending too much time on the edge cases: the This similarly applies to so my question: should we try to make this behavior more sane (e.g. try to merge added trailers with upstream trailers?) or simply document
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 commented above. IMO this is a real filter edge case, and I think I would just go around all of this and pass the new trailers by move semantics, which then overwrite. Thoughts?
Contributor
Author
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 that makes sense and works with our use case. Seems cleaner than to have to reason about how it may interact with existing trailers. |
||
| response_trailers_ = std::make_unique<Http::HeaderMapImpl>(); | ||
| } | ||
| return *response_trailers_; | ||
| } | ||
|
|
||
| void ConnectionManagerImpl::ActiveStream::addEncodedData(ActiveStreamEncoderFilter& filter, | ||
| Buffer::Instance& data, bool streaming) { | ||
| if (state_.filter_call_state_ == 0 || | ||
|
|
@@ -1099,8 +1106,14 @@ void ConnectionManagerImpl::ActiveStream::encodeData(ActiveStreamEncoderFilter* | |
| end_stream); | ||
|
|
||
| request_info_.addBytesSent(data.length()); | ||
| response_encoder_->encodeData(data, end_stream); | ||
| maybeEndEncode(end_stream); | ||
| if (end_stream && response_trailers_) { | ||
|
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'm a little confused about the semantics here. When is a filter expected to add trailers for the first time? Do we want to support setting trailers during the final data frame where end_stream was otherwise true? I don't think we want to support that and we probably do? Also where is the parallel to this code on the decoding side?
Contributor
Author
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. What happens right now (since you can override trailers whenever)
3 is definitely confusing, so I'd be happy to prevent that. The question to me that remains is whether we want trailers to be written out at the end of What steered me away from that originally was that was that it doesn't seem like So after thinking about it some, how about this: This does mean we get both a
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 is more on the right track.
I don't think this is going to work as it will completely confuse filters that do things when end_stream is true. I think this is the behavior you want:
I don't think this should be too hard to implement and should cleanly cover both encode/decode. Does that make sense? For the error checking side of things, IMO I would probably just block trailers being added in any context other than decodeData(..., true). Does it make sense anywhere else? The otehr thing to consider is what if someone calls this when a filter has been paused and then calls continue? Will it work correctly?
Contributor
Author
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. Yeah that makes sense for the most part. One question:
Do you mean
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. No I meant what I said, that I think the only valid context to add trailers should be within a
Contributor
Author
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. Ah, that makes perfect sense. Thanks for clarifying. |
||
| response_encoder_->encodeData(data, false); | ||
| response_encoder_->encodeTrailers(*response_trailers_); | ||
| maybeEndEncode(true); | ||
| } else { | ||
| response_encoder_->encodeData(data, end_stream); | ||
| maybeEndEncode(end_stream); | ||
| } | ||
| } | ||
|
|
||
| void ConnectionManagerImpl::ActiveStream::encodeTrailers(ActiveStreamEncoderFilter* filter, | ||
|
|
@@ -1473,6 +1486,10 @@ void ConnectionManagerImpl::ActiveStreamEncoderFilter::addEncodedData(Buffer::In | |
| return parent_.addEncodedData(*this, data, streaming); | ||
| } | ||
|
|
||
| HeaderMap& ConnectionManagerImpl::ActiveStreamEncoderFilter::addEncodedTrailers() { | ||
| return parent_.addEncodedTrailers(); | ||
| } | ||
|
|
||
| void ConnectionManagerImpl::ActiveStreamEncoderFilter:: | ||
| onEncoderFilterAboveWriteBufferHighWatermark() { | ||
| ENVOY_STREAM_LOG(debug, "Disabling upstream stream due to filter callbacks.", 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.
As long as we are in here and have all of this logic paged in, can we add a similar function on the decoding side? It should be symmetrical and pretty trivial to duplicate tests for.
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.
yeah, will do