Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
814287e
Implement GRPC transcoding filter per route
May 9, 2020
0444f24
integration tests
May 12, 2020
2930989
Merge branch 'master' of github.com:gagata/envoy into issue-11038
May 23, 2020
0122662
spellcheck + addressing review comments
May 23, 2020
86f1db7
fix unnecessary constructor definition
May 26, 2020
61dbd65
review updates
Jun 5, 2020
4987496
review updates
Jun 9, 2020
1476538
fix test coverage
Jun 17, 2020
7da8c2c
fix
Jul 9, 2020
3313680
Merge branch 'master' of https://github.com/envoyproxy/envoy into iss…
Jul 29, 2020
4e3cf4c
udpates after rebase
Jul 29, 2020
15566b9
Merge branch 'master' of https://github.com/envoyproxy/envoy into iss…
Aug 10, 2020
0ee774e
review changes
Aug 10, 2020
302fb86
proto_format
Aug 10, 2020
92f0422
Merge branch 'master' of https://github.com/envoyproxy/envoy into iss…
Aug 28, 2020
3acafa4
Merge branch 'master' of https://github.com/envoyproxy/envoy into iss…
Sep 3, 2020
d203bda
Merge branch 'master' of https://github.com/envoyproxy/envoy into iss…
Sep 17, 2020
6c29fa1
Merge branch 'master' of https://github.com/envoyproxy/envoy into iss…
Oct 9, 2020
84cdb5c
Merge branch 'master' of https://github.com/envoyproxy/envoy into iss…
Dec 4, 2020
92b81fd
fix test
Dec 4, 2020
5e6cc98
review updates
Dec 30, 2020
8427d0a
Merge branch 'master' of https://github.com/envoyproxy/envoy into iss…
Dec 30, 2020
58da4ec
Merge branch 'master' of https://github.com/envoyproxy/envoy into iss…
Jan 15, 2021
1ce6453
review update (removing the disabled_ check)
Jan 15, 2021
d980425
Merge branch 'main' of https://github.com/envoyproxy/envoy into issue…
Jan 22, 2021
6082b1c
Release note
Jan 22, 2021
312c43e
Merge branch 'main' of https://github.com/envoyproxy/envoy into issue…
Jan 27, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE;
// [#extension: envoy.filters.http.grpc_json_transcoder]

// [#next-free-field: 11]
// GrpcJsonTranscoder filter configuration.
// The filter itself can be used per route / per virtual host or on the general level. The most
// specific one is being used for a given route. If the list of services is empty - filter
// is considered to be disabled.
Copy link
Member

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.

// Note that if specifying the filter per route, first the route is matched, and then transcoding
// filter is applied. It matters when specifying the route configuration and paths to match the
// request - for per-route grpc transcoder configs, the original path should be matched, while
// in other cases, the grpc-like path is expected (the one AFTER the filter is applied).
message GrpcJsonTranscoder {
option (udpa.annotations.versioning).previous_message_type =
"envoy.config.filter.http.transcoder.v2.GrpcJsonTranscoder";
Expand Down Expand Up @@ -80,7 +88,8 @@ message GrpcJsonTranscoder {
// the transcoder will translate. If the service name doesn't exist in ``proto_descriptor``,
// Envoy will fail at startup. The ``proto_descriptor`` may contain more services than
// the service names specified here, but they won't be translated.
repeated string services = 2 [(validate.rules).repeated = {min_items: 1}];
// If the list of services is empty, filter is considered disabled.
repeated string services = 2;

// Control options for response JSON. These options are passed directly to
// `JsonPrintOptions <https://developers.google.com/protocol-buffers/docs/reference/cpp/
Expand Down
1 change: 1 addition & 0 deletions docs/root/version_history/current.rst
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ New Features
* access log: added the :ref:`formatters <envoy_v3_api_field_config.core.v3.SubstitutionFormatString.formatters>` extension point for custom formatters (command operators).
* access log: support command operator: %REQUEST_HEADERS_BYTES%, %RESPONSE_HEADERS_BYTES% and %RESPONSE_TRAILERS_BYTES%.
* dispatcher: supports a stack of `Envoy::ScopeTrackedObject` instead of a single tracked object. This will allow Envoy to dump more debug information on crash.
* grpc_json_transcoder: filter can now be configured on per-route/per-vhost level as well. Leaving empty list of services in the filter configuration disables transcoding on the specific route.
* http: added support for :ref:`:ref:`preconnecting <envoy_v3_api_msg_config.cluster.v3.Cluster.PreconnectPolicy>`. Preconnecting is off by default, but recommended for clusters serving latency-sensitive traffic, especially if using HTTP/1.1.
* http: change frame flood and abuse checks to the upstream HTTP/2 codec to ON by default. It can be disabled by setting the `envoy.reloadable_features.upstream_http2_flood_checks` runtime key to false.
* overload: add support for scaling :ref:`transport connection timeouts<envoy_v3_api_enum_value_config.overload.v3.ScaleTimersOverloadActionConfig.TimerType.TRANSPORT_SOCKET_CONNECT>`. This can be used to reduce the TLS handshake timeout in response to overload.
Expand Down

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
Expand Up @@ -30,6 +30,7 @@ envoy_cc_library(
"//source/common/grpc:common_lib",
"//source/common/http:headers_lib",
"//source/common/protobuf",
"//source/extensions/filters/http:well_known_names",
"@envoy_api//envoy/extensions/filters/http/grpc_json_transcoder/v3:pkg_cc_proto",
],
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@ Http::FilterFactoryCb GrpcJsonTranscoderFilterConfig::createFilterFactoryFromPro
};
}

Router::RouteSpecificFilterConfigConstSharedPtr
GrpcJsonTranscoderFilterConfig::createRouteSpecificFilterConfigTyped(
const envoy::extensions::filters::http::grpc_json_transcoder::v3::GrpcJsonTranscoder&
proto_config,
Server::Configuration::ServerFactoryContext& context, ProtobufMessage::ValidationVisitor&) {

return std::make_shared<JsonTranscoderConfig>(proto_config, context.api());
}

/**
* Static registration for the grpc transcoding filter. @see RegisterNamedHttpFilterConfigFactory.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ class GrpcJsonTranscoderFilterConfig
const envoy::extensions::filters::http::grpc_json_transcoder::v3::GrpcJsonTranscoder&
proto_config,
const std::string& stats_prefix, Server::Configuration::FactoryContext& context) override;

Router::RouteSpecificFilterConfigConstSharedPtr createRouteSpecificFilterConfigTyped(
const envoy::extensions::filters::http::grpc_json_transcoder::v3::GrpcJsonTranscoder&,
Server::Configuration::ServerFactoryContext& context,
ProtobufMessage::ValidationVisitor& validator) override;
};

} // namespace GrpcJsonTranscoder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -111,6 +112,12 @@ JsonTranscoderConfig::JsonTranscoderConfig(
const envoy::extensions::filters::http::grpc_json_transcoder::v3::GrpcJsonTranscoder&
proto_config,
Api::Api& api) {

disabled_ = proto_config.services().empty();
if (disabled_) {
return;
}

FileDescriptorSet descriptor_set;

switch (proto_config.descriptor_set_case()) {
Expand Down Expand Up @@ -306,8 +313,11 @@ 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, TranscoderPtr& transcoder,
MethodInfoSharedPtr& method_info) {
google::grpc::transcoding::TranscoderInputStream& response_input,
std::unique_ptr<Transcoder>& transcoder, MethodInfoSharedPtr& method_info) const {

ASSERT(!disabled_);

if (Grpc::Common::isGrpcRequestHeaders(headers)) {
return ProtobufUtil::Status(Code::INVALID_ARGUMENT,
"Request headers has application/grpc content-type");
Expand Down Expand Up @@ -384,7 +394,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);
Expand All @@ -399,18 +409,37 @@ 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;
}

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();
if (per_route_config_->disabled()) {
return Http::FilterHeadersStatus::Continue;
}

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
Expand Down Expand Up @@ -449,7 +478,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();
}

Expand Down Expand Up @@ -611,7 +640,7 @@ JsonTranscoderFilter::encodeTrailers(Http::ResponseTrailerMap& trailers) {
}

void JsonTranscoderFilter::doTrailers(Http::ResponseHeaderOrTrailerMap& headers_or_trailers) {
if (error_ || !transcoder_) {
if (error_ || !transcoder_ || !per_route_config_ || per_route_config_->disabled()) {
return;
}

Expand Down Expand Up @@ -767,7 +796,8 @@ bool JsonTranscoderFilter::buildResponseFromHttpBodyOutput(

bool JsonTranscoderFilter::maybeConvertGrpcStatus(Grpc::Status::GrpcStatus grpc_status,
Http::ResponseHeaderOrTrailerMap& trailers) {
if (!config_.convertGrpcStatus()) {
ASSERT(per_route_config_ && !per_route_config_->disabled());
if (!per_route_config_->convertGrpcStatus()) {
return false;
}

Expand Down Expand Up @@ -799,7 +829,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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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.
Expand All @@ -102,12 +104,14 @@ 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;

private:
void addFileDescriptor(const Protobuf::FileDescriptorProto& file);
Expand All @@ -128,6 +132,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>;
Expand Down Expand Up @@ -176,15 +182,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.
Expand Down
1 change: 1 addition & 0 deletions test/extensions/filters/http/grpc_json_transcoder/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ envoy_extension_cc_test(
"//test/integration:http_integration_lib",
"//test/proto:bookstore_proto_cc_proto",
"//test/test_common:utility_lib",
"@envoy_api//envoy/extensions/filters/http/grpc_json_transcoder/v3:pkg_cc_proto",
],
)

Expand Down
Loading