-
Notifications
You must be signed in to change notification settings - Fork 5.5k
transcoding: Teach transcoding filter to be aware of per vhost / per route settings #11188
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 7 commits
814287e
0444f24
2930989
0122662
86f1db7
61dbd65
4987496
1476538
7da8c2c
3313680
4e3cf4c
15566b9
0ee774e
302fb86
92f0422
3acafa4
d203bda
6c29fa1
84cdb5c
92b81fd
5e6cc98
8427d0a
58da4ec
1ce6453
d980425
6082b1c
312c43e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,6 +17,7 @@ | |
| #include "common/protobuf/utility.h" | ||
|
|
||
| #include "extensions/filters/http/grpc_json_transcoder/http_body_utils.h" | ||
| #include "extensions/filters/http/well_known_names.h" | ||
|
|
||
| #include "google/api/annotations.pb.h" | ||
| #include "google/api/http.pb.h" | ||
|
|
@@ -106,6 +107,12 @@ JsonTranscoderConfig::JsonTranscoderConfig( | |
| const envoy::extensions::filters::http::grpc_json_transcoder::v3::GrpcJsonTranscoder& | ||
| proto_config, | ||
| Api::Api& api) { | ||
|
|
||
| disabled_ = (proto_config.services().size() == 0); | ||
|
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 |
||
| if (disabled_) { | ||
| return; | ||
| } | ||
|
|
||
| FileDescriptorSet descriptor_set; | ||
|
|
||
| switch (proto_config.descriptor_set_case()) { | ||
|
|
@@ -258,7 +265,13 @@ bool JsonTranscoderConfig::convertGrpcStatus() const { return convert_grpc_statu | |
| ProtobufUtil::Status JsonTranscoderConfig::createTranscoder( | ||
| const Http::RequestHeaderMap& headers, ZeroCopyInputStream& request_input, | ||
| google::grpc::transcoding::TranscoderInputStream& response_input, | ||
| std::unique_ptr<Transcoder>& transcoder, MethodInfoSharedPtr& method_info) { | ||
| std::unique_ptr<Transcoder>& transcoder, MethodInfoSharedPtr& method_info) const { | ||
|
|
||
| if (disabled_) { | ||
|
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. You should guard this before this getting called, in
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. ping?
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. hey! there is a check for
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. Yeah if it is checked there, we shouldn't have a check here. What flow hits here?
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. well, this is a public method so theoretically any flow could hit it
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. Generally we don't do defensive coding like this. I would switch this to an ASSERT with a comment if you like. |
||
| return ProtobufUtil::Status(Code::INVALID_ARGUMENT, | ||
| "JsonTranscoderFilter for this route is disabled"); | ||
| } | ||
|
|
||
| if (Grpc::Common::isGrpcRequestHeaders(headers)) { | ||
| return ProtobufUtil::Status(Code::INVALID_ARGUMENT, | ||
| "Request headers has application/grpc content-type"); | ||
|
|
@@ -328,7 +341,7 @@ ProtobufUtil::Status JsonTranscoderConfig::createTranscoder( | |
|
|
||
| ProtobufUtil::Status | ||
| JsonTranscoderConfig::methodToRequestInfo(const MethodInfoSharedPtr& method_info, | ||
| google::grpc::transcoding::RequestInfo* info) { | ||
| google::grpc::transcoding::RequestInfo* info) const { | ||
| const std::string& request_type_full_name = method_info->descriptor_->input_type()->full_name(); | ||
| auto request_type_url = Grpc::Common::typeUrl(request_type_full_name); | ||
| info->message_type = type_helper_->Info()->GetTypeByTypeUrl(request_type_url); | ||
|
|
@@ -343,18 +356,33 @@ JsonTranscoderConfig::methodToRequestInfo(const MethodInfoSharedPtr& method_info | |
|
|
||
| ProtobufUtil::Status | ||
| JsonTranscoderConfig::translateProtoMessageToJson(const Protobuf::Message& message, | ||
| std::string* json_out) { | ||
| std::string* json_out) const { | ||
| return ProtobufUtil::BinaryToJsonString( | ||
| type_helper_->Resolver(), Grpc::Common::typeUrl(message.GetDescriptor()->full_name()), | ||
| message.SerializeAsString(), json_out, print_options_); | ||
| } | ||
|
|
||
| JsonTranscoderFilter::JsonTranscoderFilter(JsonTranscoderConfig& config) : config_(config) {} | ||
|
|
||
| void JsonTranscoderFilter::initPerRouteConfig() { | ||
| if (!decoder_callbacks_->route() || !decoder_callbacks_->route()->routeEntry()) { | ||
| per_route_config_ = &config_; | ||
| return; | ||
|
lizan marked this conversation as resolved.
Outdated
|
||
| } | ||
|
|
||
| const std::string& name = HttpFilterNames::get().GrpcJsonTranscoder; | ||
| const auto* entry = decoder_callbacks_->route()->routeEntry(); | ||
| const auto* route_local = entry->mostSpecificPerFilterConfigTyped<JsonTranscoderConfig>(name); | ||
|
|
||
| per_route_config_ = route_local ? route_local : &config_; | ||
| } | ||
|
|
||
| Http::FilterHeadersStatus JsonTranscoderFilter::decodeHeaders(Http::RequestHeaderMap& headers, | ||
| bool end_stream) { | ||
|
|
||
| initPerRouteConfig(); | ||
| const auto status = | ||
| config_.createTranscoder(headers, request_in_, response_in_, transcoder_, method_); | ||
| per_route_config_->createTranscoder(headers, request_in_, response_in_, transcoder_, method_); | ||
|
|
||
| if (!status.ok()) { | ||
| // If transcoder couldn't be created, it might be a normal gRPC request, so the filter will | ||
|
|
@@ -392,7 +420,7 @@ Http::FilterHeadersStatus JsonTranscoderFilter::decodeHeaders(Http::RequestHeade | |
| headers.setReferenceMethod(Http::Headers::get().MethodValues.Post); | ||
| headers.setReferenceTE(Http::Headers::get().TEValues.Trailers); | ||
|
|
||
| if (!config_.matchIncomingRequestInfo()) { | ||
| if (!per_route_config_->matchIncomingRequestInfo()) { | ||
| decoder_callbacks_->clearRouteCache(); | ||
| } | ||
|
|
||
|
|
@@ -554,7 +582,7 @@ JsonTranscoderFilter::encodeTrailers(Http::ResponseTrailerMap& trailers) { | |
| } | ||
|
|
||
| void JsonTranscoderFilter::doTrailers(Http::ResponseHeaderOrTrailerMap& headers_or_trailers) { | ||
| if (error_ || !transcoder_) { | ||
| if (error_ || !transcoder_ || per_route_config_->disabled()) { | ||
|
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. is it possible that per_route_config_ is not initialized in this call? e.g. decodeHeader() is not called. Same question for maybeConvertGrpcStatus() function |
||
| return; | ||
| } | ||
|
|
||
|
|
@@ -705,7 +733,8 @@ bool JsonTranscoderFilter::buildResponseFromHttpBodyOutput( | |
|
|
||
| bool JsonTranscoderFilter::maybeConvertGrpcStatus(Grpc::Status::GrpcStatus grpc_status, | ||
| Http::ResponseHeaderOrTrailerMap& trailers) { | ||
| if (!config_.convertGrpcStatus()) { | ||
| ASSERT(!per_route_config_->disabled()); | ||
| if (!per_route_config_->convertGrpcStatus()) { | ||
| return false; | ||
| } | ||
|
|
||
|
|
@@ -734,7 +763,8 @@ bool JsonTranscoderFilter::maybeConvertGrpcStatus(Grpc::Status::GrpcStatus grpc_ | |
| } | ||
|
|
||
| std::string json_status; | ||
| auto translate_status = config_.translateProtoMessageToJson(*status_details, &json_status); | ||
| auto translate_status = | ||
| per_route_config_->translateProtoMessageToJson(*status_details, &json_status); | ||
| if (!translate_status.ok()) { | ||
| ENVOY_LOG(debug, "Transcoding status error {}", translate_status.ToString()); | ||
| return false; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -56,7 +56,9 @@ void createHttpBodyEnvelope(Buffer::Instance& output, | |
| /** | ||
| * Global configuration for the gRPC JSON transcoder filter. Factory for the Transcoder interface. | ||
| */ | ||
| class JsonTranscoderConfig : public Logger::Loggable<Logger::Id::config> { | ||
| class JsonTranscoderConfig : public Logger::Loggable<Logger::Id::config>, | ||
| public Router::RouteSpecificFilterConfig { | ||
|
|
||
| public: | ||
| /** | ||
| * constructor that loads protobuf descriptors from the file specified in the JSON config. | ||
|
|
@@ -81,13 +83,13 @@ class JsonTranscoderConfig : public Logger::Loggable<Logger::Id::config> { | |
| Protobuf::io::ZeroCopyInputStream& request_input, | ||
| google::grpc::transcoding::TranscoderInputStream& response_input, | ||
| std::unique_ptr<google::grpc::transcoding::Transcoder>& transcoder, | ||
| MethodInfoSharedPtr& method_info); | ||
| MethodInfoSharedPtr& method_info) const; | ||
|
|
||
| /** | ||
| * Converts an arbitrary protobuf message to JSON. | ||
| */ | ||
| ProtobufUtil::Status translateProtoMessageToJson(const Protobuf::Message& message, | ||
| std::string* json_out); | ||
| std::string* json_out) const; | ||
|
|
||
| /** | ||
| * If true, skip clearing the route cache after the incoming request has been modified. | ||
|
|
@@ -102,12 +104,19 @@ class JsonTranscoderConfig : public Logger::Loggable<Logger::Id::config> { | |
| */ | ||
| bool convertGrpcStatus() const; | ||
|
|
||
| bool disabled() const { return disabled_; } | ||
|
|
||
| private: | ||
| /** | ||
| * Convert method descriptor to RequestInfo that needed for transcoding library | ||
| */ | ||
| ProtobufUtil::Status methodToRequestInfo(const MethodInfoSharedPtr& method_info, | ||
| google::grpc::transcoding::RequestInfo* info); | ||
| google::grpc::transcoding::RequestInfo* info) const; | ||
|
|
||
| JsonTranscoderConfig( | ||
| const envoy::extensions::filters::http::grpc_json_transcoder::v3::GrpcJsonTranscoder& | ||
| proto_config, | ||
| Api::Api& api, bool disabled); | ||
|
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. is this still needed? |
||
|
|
||
| private: | ||
| void addFileDescriptor(const Protobuf::FileDescriptorProto& file); | ||
|
|
@@ -124,6 +133,8 @@ class JsonTranscoderConfig : public Logger::Loggable<Logger::Id::config> { | |
| bool match_incoming_request_route_{false}; | ||
| bool ignore_unknown_query_parameters_{false}; | ||
| bool convert_grpc_status_{false}; | ||
|
|
||
| bool disabled_; | ||
| }; | ||
|
|
||
| using JsonTranscoderConfigSharedPtr = std::shared_ptr<JsonTranscoderConfig>; | ||
|
|
@@ -172,15 +183,17 @@ class JsonTranscoderFilter : public Http::StreamFilter, public Logger::Loggable< | |
| Http::ResponseHeaderOrTrailerMap& trailers); | ||
| bool hasHttpBodyAsOutputType(); | ||
| void doTrailers(Http::ResponseHeaderOrTrailerMap& headers_or_trailers); | ||
| void initPerRouteConfig(); | ||
|
|
||
| JsonTranscoderConfig& config_; | ||
| const JsonTranscoderConfig* per_route_config_{}; | ||
| std::unique_ptr<google::grpc::transcoding::Transcoder> transcoder_; | ||
| TranscoderInputStreamImpl request_in_; | ||
| TranscoderInputStreamImpl response_in_; | ||
| Http::StreamDecoderFilterCallbacks* decoder_callbacks_{nullptr}; | ||
| Http::StreamEncoderFilterCallbacks* encoder_callbacks_{nullptr}; | ||
| Http::StreamDecoderFilterCallbacks* decoder_callbacks_{}; | ||
| Http::StreamEncoderFilterCallbacks* encoder_callbacks_{}; | ||
| MethodInfoSharedPtr method_; | ||
| Http::ResponseHeaderMap* response_headers_{nullptr}; | ||
| Http::ResponseHeaderMap* response_headers_{}; | ||
| Grpc::Decoder decoder_; | ||
|
|
||
| // Data of the initial request message, initialized from query arguments, path, 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.
We need to be more descriptive on per-route configuration, because it is really confusing is grpc transocder is changing route decision, that means the per-route configuration for grpc-transcoder must match the route BEFORE grpc transcoder, as opposed to what actually transocded requests are routed to.