-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
Calling addEncodedData from the encodeTrailers callback fails when encodeHeaders had previously returned StopIteration.
A filter (e.g. the grpc-json transcoder) wants to turn a headers-only response into a response with a body. And StreamEncoderFilterCallbacks::addEncodedData allows that:
1) If a headers only response needs to be turned into a response with a body, this method can
be called to add body in the encodeHeaders() callback. Subsequent filters will receive
encodeHeaders(..., false) followed by encodeData(..., true). This works both in the direct
iteration as well as the continuation case.
However it doesn't work when upstream sends a header frame and a trailer frame:
The filter returns StopIteration from encodeHeaders.
In encodeTrailers, it calls addEncodedData.
ConnectionManagerImpl::ActiveStream::addEncodedData has a special branch for EncodeTrailers, which calls encodeData with the comment:
// In this case we need to inline dispatch the data to further filters. If those filters
// choose to buffer/stop iteration that's fine.
Now there are two cases:
- if there is another filter, encodeData will call its encodeData callback, and then fail the
ASSERT(headers_continued_)inActiveStreamFilterBase::commonHandleAfterDataCallback- this filter never had its encodeHeaders called. - if there is no filter to iterate, ActiveStream::encodeData will call
response_encoder_->encodeDataand write response body before writing any headers.
For HTTP/1.1 downstream it will assume chunked transfer-encoding and write something like:
4
body
HTTP/1.1 200 OK
other: headers
How to fix that:
For EncodeTrailers, the ActiveStream::addEncodedData should buffer data when filter stopped iteration.