-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Add Metadata to codec #4796
Add Metadata to codec #4796
Conversation
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.
Looking good!
* Encode METADATA. | ||
* @param metadata_map is the METADATA to encode. | ||
*/ | ||
virtual void encodeMetadata(const MetadataMap& metadata_map) PURE; |
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.
I think this is a good PR to start landing docs with, even if we have them tagged as work in progress.
Let's talk about when you can encodeMetadata, how often you can encode it, when it will be passed up to filters (we can edit the docs if they change when that lands) etc.
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.
Still working on the doc.
@@ -303,6 +303,7 @@ class ConnectionManagerImpl : Logger::Loggable<Logger::Id::http>, | |||
void decodeHeaders(HeaderMapPtr&& headers, bool end_stream) override; | |||
void decodeData(Buffer::Instance& data, bool end_stream) override; | |||
void decodeTrailers(HeaderMapPtr&& trailers) override; | |||
void decodeMetadata(MetadataMap&) override { NOT_REACHED_GCOVR_EXCL_LINE; } |
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.
Do we think there should be anything done if an HTTP/1.1 codec is asked to encode metadata? If nothing else maybe error reporting stats so folks know their metadata is being swallowed?
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.
Good call! I added an error log in Http1::StreamEncoderImpl::encodeHeader().
@@ -48,8 +48,8 @@ template <typename T> static T* remove_const(const void* object) { | |||
} | |||
|
|||
ConnectionImpl::StreamImpl::StreamImpl(ConnectionImpl& parent, uint32_t buffer_limit) | |||
: parent_(parent), headers_(new HeaderMapImpl()), local_end_stream_sent_(false), | |||
remote_end_stream_(false), data_deferred_(false), | |||
: parent_(parent), headers_(new HeaderMapImpl()), metadata_map_(new MetadataMap()), |
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.
What do we think about doing lazy creation here? I think it's worth the complexity to not create a map for the vast majority of users who don't need this functionality.
Also if there's one metadata_map_ (at a time) per stream and one decoder per stream I'm not sure I follow why you moved ownership out of the decoder.
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.
Right! Moved metadata_map_ back to decoder. I thought it would be consistent to let StreamImpl hold metadata since it holds headers. But it is definitely not necessary.
encoder.releasePayload(size_to_copy); | ||
|
||
// Keep submitting extension frames if there is payload left in the encoder. | ||
if (encoder.hasNextFrame()) { |
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.
so when the caller calls encodeMetadata with a large frame, encodeMetadata calls submitMetadata, submitMetadata results in nghttp2 calling packMetadata, which may result in another submitMetadata?
Any chance we can remove the recursion by moving where we check for hasNextFrame and calling submitMetadata multiple times instead?
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.
You are right. The old code let packMetadata call submitMetadata until there is no metadata left. I can see it is very hard to understand. Changed according to the suggestion.
source/common/router/router.h
Outdated
@@ -288,6 +288,7 @@ class Filter : Logger::Loggable<Logger::Id::router>, | |||
void decodeHeaders(Http::HeaderMapPtr&& headers, bool end_stream) override; | |||
void decodeData(Buffer::Instance& data, bool end_stream) override; | |||
void decodeTrailers(Http::HeaderMapPtr&& trailers) override; | |||
void decodeMetadata(Http::MetadataMap&) override { NOT_REACHED_GCOVR_EXCL_LINE; } |
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.
I think we're going to need to implement something here. Maybe a TODO instead of marking it as not reached?
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.
Done.
@@ -280,6 +281,7 @@ class GrpcHealthCheckerImpl : public HealthCheckerImplBase { | |||
void decodeHeaders(Http::HeaderMapPtr&& headers, bool end_stream) override; | |||
void decodeData(Buffer::Instance&, bool end_stream) override; | |||
void decodeTrailers(Http::HeaderMapPtr&&) override; | |||
void decodeMetadata(Http::MetadataMap&) override {} |
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.
These ones we're probably never going to really use, but we could unit test the functions to avoid a coverage decrease
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.
Good idea! Test added.
@@ -22,10 +21,13 @@ namespace Http2 { | |||
const uint8_t METADATA_FRAME_TYPE = 0x4d; | |||
const uint8_t END_METADATA_FLAG = 0x4; | |||
|
|||
// NGHTTP2_MAX_PAYLOADLEN in nghttp2. | |||
const uint64_t METADATA_MAX_PAYLOAD_SIZE = 16384; |
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 a sanity check, if nghttp2 changed their NGHTTP2_MAX_PAYLOADLEN to be lower, they'd reject large data chunks and your large metadata frame test would fail when we imported the change, right?
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.
Great question! I increase METADATA_MAX_PAYLOAD_SIZE to 20000, and the test fails at:
source/common/http/http2/codec_impl.cc:623
ASSERT(len >= size_to_copy);
Added a comment to check NGHTTP2_MAX_PAYLOADLEN in case of the assert failure.
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.
Make this as constexpr (perhaps for all constants), and do static_assert
against NGHTTP2_MAX_PAYLOADLEN
? It will fail at compile time then.
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.
It's a good idea! But I don't think nghttp2 exposes NGHTTP2_MAX_PAYLOADLEN. I changed const to constexpr. Thanks!
Thanks for the review! I am still working on the doc part. Will update the PR when the doc is ready. I changed two if conditions to assert since the if condition should not happen, and it increases the test coverage. I am having trouble making tests hit the if condition in onMetadataReceived(): |
Signed-off-by: Yang Song <[email protected]>
Signed-off-by: Yang Song <[email protected]>
Signed-off-by: Yang Song <[email protected]>
Signed-off-by: Yang Song <[email protected]>
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.
Oh argh, I had draft comments and failed to actually send them out. So sorry for review lag!
int result = submitMetadata(); | ||
ASSERT(result == 0); | ||
parent_.sendPendingFrames(); | ||
} |
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.
Can we have an ASSERT that hasNextFrame is false, or if failure is possible should there be error handling?
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.
Good idea! Done.
// Keep submitting extension frames if there is payload left in the encoder. | ||
while (metadata_encoder_->hasNextFrame() && count++ <= frame_count) { | ||
int result = submitMetadata(); | ||
ASSERT(result == 0); |
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.
Looking at nghttp2_submit_extension the failure modes are specifying a non-registered type (I agree shouldn't happen if metadata is on), insufficient memory (I agree shouldn't happen) and the pack_extension callback not being set (shouldn't happen if metadata is on).
But then it occurred to me (which I should have caught on first pass - sorry!) we're adding H2 Metadata support by default. I think we should probably make this an opt-in feature and add it to the Http2ProtocolOptions. I'd hope you could crib where we added allow_connect support for e2e config examples when you get there.
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.
Also it does strike me as a bit weird we have a return which we assert is always 0. I'd be inclined to keep the assert lower down and keep the function void, or if we think it might legit fail, do error handling.
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.
Made metadata as an opt-in feature (will add to Http2ProtocolOptions later. TODO added). Made submitMetadata a void function, and added assert outside the loop. Thanks for the suggestions!
@@ -37,6 +37,9 @@ class StreamEncoderImpl : public StreamEncoder, | |||
void encodeHeaders(const HeaderMap& headers, bool end_stream) override; | |||
void encodeData(Buffer::Instance& data, bool end_stream) override; | |||
void encodeTrailers(const HeaderMap& trailers) override; | |||
void encodeMetadata(const MetadataMap&) override { | |||
ENVOY_LOG(error, "HTTP/1.1 doesn't support METADATA. METADATA is ignored."); |
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.
Unit test, just for coverage? :-)
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.
Ah, right! Done.
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.
Personally I would just do NOT_IMPLEMENTED and have this crash but I don't feel strongly about it.
response_encoder_->encodeMetadata(metadata_map); | ||
} | ||
|
||
TEST_P(Http2CodecImplTest, LargeMetadataTest) { |
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.
I don't think we have examples of this, but could we maybe have a test of error conditions / bad data? I think you could tweak setupDefaultConnectionMocks to corrupt the data to result in some of the calls failing and make sure nghtttp2 ends up killing the connection.
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.
Add a test with corrupted metadata. Verified exception is thrown.
Signed-off-by: Yang Song <[email protected]>
ff05613
to
e7646a0
Compare
Signed-off-by: Yang Song <[email protected]>
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.
Docs are a great addition - thanks for adding them!
source/docs/h2_metadata.md
Outdated
information is represented by a string key-value pair. For example, users can | ||
pass along RTT information associated with a stream using a key of "rtt info", and a value of | ||
"100ms". In Envoy, we call this type of information metadata. | ||
A stream can be associated with multiple metadatas, and the multiple metadatas |
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.
I think the plural of metdata is metadata, so s/metadatas/metadata/ here and below?
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.
I see! Thanks for correcting my English!
source/docs/h2_metadata.md
Outdated
|
||
### Limitation | ||
|
||
For the ease of implementation and compatibility purpose, metadata will only be |
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.
For the ease of implementation and compatibility purpose -> For ease of implementation and compatibility purposes
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.
Done. Thanks!
source/docs/h2_metadata.md
Outdated
errors or be ignored. | ||
|
||
Envoy can consume or add metadata. But for one request (or response), we expect at most one of the | ||
two operations to be performed. |
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.
You think? I'm thinking we had a 3 layer Envoy set up, the middle Envoy could consume metadata from upstream and send metadata downstream.
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.
Sorry I didn't think the limitation through. I would like to avoid the case where metadata added by one filter is consumed by another filter on the same stream. But now I think how to use the filters is up to the users. Removed this limitation.
source/docs/h2_metadata.md
Outdated
|
||
Envoy provides the functionality to proxy, process and add metadatas. | ||
|
||
## Proxy metadata |
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.
Let's have the headers consistent
Proxying meadata
Consuming metadata
Inserting metadata
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.
They are better headers! Fixed.
source/docs/h2_metadata.md
Outdated
|
||
(To be implemented) | ||
|
||
If Envoy needs to take actions when a metadata is received, users should |
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.
s/a metadata/metadata/
or "a metadata frame"?
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.
Done. Thanks!
source/docs/h2_metadata.md
Outdated
it untouched. | ||
|
||
If Envoy needs to parse a metadata sent on a response from upstream to downstream, a | ||
StreamEncodeFilter should be created. The interface to override is |
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.
Encoder
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.
Oops! Fixed.
The METADATA frame payload is not subject to HTTP/2 flow control, but the size | ||
of the payload is bounded by the maximum frame size negotiated in SETTINGS. | ||
There are no restrictions on the set of octets that may be used in keys or values. | ||
TODO(soya3129): decide if we allow METADATA frame to terminate a stream. |
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.
I'd say no for now. Folks can send 0 length data frame.
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.
+1!
If not specified, all the metadata received by Envoy is proxied to the next hop | ||
unmodified. Note that, we do not guarantee the same frame order will be preserved from | ||
hop by hop. That is, metadata from upstream at the beginning of a stream can be | ||
received by the downstream at the end of the stream. |
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.
So I agree that we don't guarantee anything with respect to body order (and doccing that up is an excellent idea!) but I think we can and probably should make sure we don't mess with end stream. For example if we forward end-stream ahead of metadata in a response headed downstream that stream may be torn down before the metadata is received. I think we have to make sure that if we've read metadata we defer end stream until metadata is flushed through the filter chain. What do you think?
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.
I totally agree! I will follow the suggestion in the implementation.
Signed-off-by: Yang Song <[email protected]>
Please hold the review until I fix the check failure. Sorry about the noisy notification! I will address the check failure and the documentation comments together. |
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.
Cool, getting there!
I think I'm pretty good on the code/test front (may do one more pass on the docs) so may be worth @mattklein123 doing a pass if he has time.
@@ -863,8 +870,10 @@ ConnectionImpl::Http2Options::Http2Options(const Http2Settings& http2_settings) | |||
if (http2_settings.hpack_table_size_ != NGHTTP2_DEFAULT_HEADER_TABLE_SIZE) { | |||
nghttp2_option_set_max_deflate_dynamic_table_size(options_, http2_settings.hpack_table_size_); | |||
} | |||
|
|||
nghttp2_option_set_user_recv_extension_type(options_, METADATA_FRAME_TYPE); | |||
// TODO(soya3129): change to ENABLE_METADATA when it's available. |
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.
AFIK nghttp2 won't take this until we make it an rfc, which is probably 1-2 years out given we haven't started anything IETF-side and it takes a while. If it were me I wouldn't TODO this (I did it for CONNECT as it was about 3 months from landing) but it's totally your call :-)
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.
Got it! Removed.
class Http2CodecImplTestEnableMetadata : public Http2CodecImplTest { | ||
public: | ||
Http2CodecImplTestEnableMetadata() : Http2CodecImplTest(true) {} | ||
}; |
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.
super nitty - I'd rather defer client_http2settings_ initialization to initialize() than subclass to set a boolean, but I'll leave it up to you.
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.
I see! Done. It's definitely cleaner.
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.
In general LGTM, a few small comments. Thank you!
include/envoy/http/codec.h
Outdated
* Called with decoded METADATA. | ||
* @param decoded METADATA. | ||
*/ | ||
virtual void decodeMetadata(MetadataMap& metadata_map) PURE; |
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.
Do we want to pass this as a unique_ptr with move semantics so that the callee can take ownership if they desire? I suspect this is what you want, much like the other header decode APIs.
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.
Fixed as suggested. Thanks!
@@ -37,6 +37,9 @@ class StreamEncoderImpl : public StreamEncoder, | |||
void encodeHeaders(const HeaderMap& headers, bool end_stream) override; | |||
void encodeData(Buffer::Instance& data, bool end_stream) override; | |||
void encodeTrailers(const HeaderMap& trailers) override; | |||
void encodeMetadata(const MetadataMap&) override { | |||
ENVOY_LOG(error, "HTTP/1.1 doesn't support METADATA. METADATA is ignored."); |
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.
Personally I would just do NOT_IMPLEMENTED and have this crash but I don't feel strongly about it.
|
||
void ConnectionImpl::StreamImpl::encodeMetadata(const MetadataMap& metadata_map) { | ||
if (!parent_.allow_metadata_) { | ||
ENVOY_CONN_LOG(error, "Connection doesn't allow metadata", parent_.connection_); |
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.
When do we envision this error happening? I'm mainly wondering if this should be a stat? Or should it just crash? Or just be a debug statement? I'm leery of error logs being useful to people.
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.
Good point! I thought it could stop encoding metadata in case metadata is not allowed. Now I realize the check should be done in ActiveStream or UpstreamRequest. Changed to ASSERT.
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.
Correct my comments above: we don't need to check allow_metadata_ not because of the reasons I stated. If allow_metadata_ is false, nghttp2 will not pass metadata to codec. We don't need to check it in envoy code anywhere. Sorry about the wrong information!
@@ -194,6 +215,15 @@ void ConnectionImpl::StreamImpl::submitTrailers(const HeaderMap& trailers) { | |||
ASSERT(rc == 0); | |||
} | |||
|
|||
void ConnectionImpl::StreamImpl::submitMetadata() { | |||
ASSERT(stream_id_ > -1); |
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.
We should never encode metadata on stream 0/connection either, right? I think this can be > 0?
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.
Right, we don't have connection usage case for now. Changed to > 0.
MetadataDecoder& ConnectionImpl::StreamImpl::getMetadataDecoder() { | ||
if (metadata_decoder_ == nullptr) { | ||
auto cb = | ||
std::bind(&ConnectionImpl::StreamImpl::onMetadataDecoded, this, std::placeholders::_1); |
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.
nit: I find bind hard to read, can you just pass an inline lambda / std::function?
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.
Changed to inline lambda.
// NGHTTP2_MAX_PAYLOADLEN is consistent with METADATA_MAX_PAYLOAD_SIZE. | ||
ASSERT(len >= size_to_copy); | ||
|
||
Buffer::OwnedImpl& p = reinterpret_cast<Buffer::OwnedImpl&>(encoder.payload()); |
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.
Doing this type of cast is a bit of an anti-pattern. Why is this needed?
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.
Oops! Fixed.
@@ -210,6 +221,8 @@ class ConnectionImpl : public virtual Connection, protected Logger::Loggable<Log | |||
[this]() -> void { this->pendingSendBufferLowWatermark(); }, | |||
[this]() -> void { this->pendingSendBufferHighWatermark(); }}; | |||
HeaderMapPtr pending_trailers_; | |||
std::unique_ptr<MetadataDecoder> metadata_decoder_{nullptr}; |
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.
nit: {nullptr}
not needed. Default init will do this. Same next line.
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.
Fixed.
Signed-off-by: Yang Song <[email protected]>
Marking as waiting. /wait |
Signed-off-by: Yang Song <[email protected]>
Very sorry about delay! |
Signed-off-by: Yang Song <[email protected]>
Signed-off-by: Yang Song <[email protected]>
Signed-off-by: Yang Song <[email protected]>
e713dc8
to
48e26b6
Compare
Signed-off-by: Yang Song <[email protected]>
2f2d2f5
to
48e26b6
Compare
Signed-off-by: Yang Song <[email protected]>
6fd54da
to
31f0838
Compare
Signed-off-by: Yang Song <[email protected]>
Signed-off-by: Yang Song <[email protected]>
Signed-off-by: Yang Song <[email protected]>
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.
Generally LGTM. Will defer to @alyssawilk for the rest of the review. Thank you!
include/envoy/http/codec.h
Outdated
* Called with decoded METADATA. | ||
* @param decoded METADATA. | ||
*/ | ||
virtual void decodeMetadata(std::unique_ptr<MetadataMap> metadata_map) PURE; |
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.
I would pass as std::unique_ptr<MetadataMap>&&
(see style doc)
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.
Fixed.
Signed-off-by: Yang Song <[email protected]>
Signed-off-by: Yang Song <[email protected]>
Thanks for the review! |
Signed-off-by: Yang Song <[email protected]>
source/docs/h2_metadata.md
Outdated
If Envoy needs to parse a metadata sent on a request from downstream to upstream, a | ||
StreamDecodeFilter should be created. The interface to override is | ||
|
||
FilterMetadataStatus StreamDecoderFilter::decodeMetadata(std::unique\_ptr\<MetadataMap\> metadata); |
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.
MetadataMapPtr&&
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.
Oops! Fixed.
@@ -58,18 +59,15 @@ class MetadataDecoder : Logger::Loggable<Logger::Id::http2> { | |||
*/ | |||
bool decodeMetadataPayloadUsingNghttp2(bool end_metadata); | |||
|
|||
// Metadata that is currently under decoding. | |||
std::unique_ptr<MetadataMap> metadata_map_; |
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.
nit: MetadataMapPtr
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.
+1, plus "is currently under decoding." -> "is currently being decoded."?
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.
Fixed the code and English. Thanks!
@@ -22,10 +21,13 @@ namespace Http2 { | |||
const uint8_t METADATA_FRAME_TYPE = 0x4d; | |||
const uint8_t END_METADATA_FLAG = 0x4; | |||
|
|||
// NGHTTP2_MAX_PAYLOADLEN in nghttp2. | |||
const uint64_t METADATA_MAX_PAYLOAD_SIZE = 16384; |
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.
Make this as constexpr (perhaps for all constants), and do static_assert
against NGHTTP2_MAX_PAYLOADLEN
? It will fail at compile time then.
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.
Looking great! just a few more nits and you're good to go.
@@ -19,7 +20,10 @@ class MetadataEncoderDecoderTest_VerifyEncoderDecoderOnMultipleMetadataMaps_Test | |||
// map of string key value pairs. | |||
class MetadataDecoder : Logger::Loggable<Logger::Id::http2> { | |||
public: | |||
MetadataDecoder(uint64_t stream_id, MetadataCallback cb); | |||
/** | |||
* @param metadata_map is where to save the decoded metadata. |
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.
update comment?
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.
Oops! Fixed.
@@ -58,18 +59,15 @@ class MetadataDecoder : Logger::Loggable<Logger::Id::http2> { | |||
*/ | |||
bool decodeMetadataPayloadUsingNghttp2(bool end_metadata); | |||
|
|||
// Metadata that is currently under decoding. | |||
std::unique_ptr<MetadataMap> metadata_map_; |
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.
+1, plus "is currently under decoding." -> "is currently being decoded."?
If not specified, all the metadata received by Envoy is proxied to the next hop | ||
unmodified. Note that, we do not guarantee the same frame order will be preserved from | ||
hop by hop. That is, metadata from upstream at the beginning of a stream can be | ||
received by the downstream at the end of the stream. |
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.
Worth commenting somewhere that empty maps will not be serialized out, i.e. if you clear the data it will functionally result in metadata being removed for the next hop?
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.
Good idea! Done.
Signed-off-by: Yang Song <[email protected]>
Thanks for the reviews! |
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.
@lizan any final comments?
Cc Biren the metadata change. |
Description: Add MetadataEncoder and MetadataDecoder to codec. I also corrected some of the design decisions in MetadataEnocder and MetadataDecoder so that they are more suitable for codec. Those corrections includes: 1. let StreamImpl owns the decoded metadata, not the decoder. 2. Remove stream_id field in decoder and encoder since stream id is stored in StreamImpl. 3. Remove set/getMaxMetadataSize(), because nghttp2 uses default max frame size. This is the second step towards supporting metadata in envoy. The next step would be add filters to add/delete/modify metadata. Risk Level: Low. Not used. Testing: Unit test. Docs Changes: Release Notes: envoyproxy#2394 Signed-off-by: Yang Song <[email protected]> Signed-off-by: Fred Douglas <[email protected]>
Signed-off-by: Yang Song [email protected]
Description: Add MetadataEncoder and MetadataDecoder to codec. I also corrected some of the design decisions in MetadataEnocder and MetadataDecoder so that they are more suitable for codec. Those corrections includes: 1. let StreamImpl owns the decoded metadata, not the decoder. 2. Remove stream_id field in decoder and encoder since stream id is stored in StreamImpl. 3. Remove set/getMaxMetadataSize(), because nghttp2 uses default max frame size.
This is the second step towards supporting metadata in envoy. The next step would be add filters to add/delete/modify metadata.
Risk Level: Low. Not used.
Testing: Unit test.
Docs Changes:
Release Notes:
#2394