Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -4,5 +4,8 @@ licenses(["notice"]) # Apache 2

api_proto_library_internal(
name = "thrift_proxy",
srcs = ["thrift_proxy.proto"],
srcs = [
"route.proto",
"thrift_proxy.proto",
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
syntax = "proto3";

package envoy.extensions.filters.network.thrift_proxy.v2alpha1;
option go_package = "v2";

import "validate/validate.proto";
import "gogoproto/gogo.proto";

// [#protodoc-title: Thrift route configuration]

// [#comment:next free field: 3]
message RouteConfiguration {
// The name of the route configuration. Reserved for future use in asynchronous route discovery.
string name = 1;

// The list of routes that will be matched, in order, against incoming requests. The first route
// that matches will be used.
repeated Route routes = 2 [(gogoproto.nullable) = false];
}

// [#comment:next free field: 3]
message Route {
// Route matching prarameters.
RouteMatch match = 1 [(validate.rules).message.required = true, (gogoproto.nullable) = false];

// Route request to some upstream cluster.
RouteAction route = 2 [(validate.rules).message.required = true, (gogoproto.nullable) = false];
}

// [#comment:next free field: 2]
message RouteMatch {
// If specified, the route must exactly match the request method name. As a special case, an
// empty string matches any request method name.
string method = 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this case-sensitive?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

}

// [#comment:next free field: 2]
message RouteAction {
// Indicates the upstream cluster to which the request should be routed.
string cluster = 1 [(validate.rules).string.min_bytes = 1];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
load("//bazel:api_build_system.bzl", "api_proto_library_internal")

licenses(["notice"]) # Apache 2

api_proto_library_internal(
name = "router",
srcs = ["router.proto"],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
syntax = "proto3";

package envoy.extensions.filters.network.thrift_proxy.v2alpha1.router;
option go_package = "router";

// [#protodoc-title: Thrift Router]
// Thrift Router configuration.
message Router {
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,55 @@ syntax = "proto3";
package envoy.extensions.filters.network.thrift_proxy.v2alpha1;
option go_package = "v2";

import "envoy/extensions/filters/network/thrift_proxy/v2alpha1/route.proto";

import "validate/validate.proto";
import "gogoproto/gogo.proto";

// [#protodoc-title: Extensions Thrift Proxy]
// Thrift Proxy filter configuration.
// [#comment:next free field: 5]
message ThriftProxy {
enum TransportType {
option (gogoproto.goproto_enum_prefix) = false;

// For every new connection, the Thrift proxy will determine which transport to use.
AUTO_TRANSPORT = 0;

// The Thrift proxy will assume the client is using the Thrift framed transport.
FRAMED = 1;

// The Thrift proxy will assume the client is using the Thrift unframed transport.
UNFRAMED = 2;
}

// Supplies the type of transport that the Thrift proxy should use. Defaults to `AUTO_TRANSPORT`.
TransportType transport = 2 [(validate.rules).enum.defined_only = true];

enum ProtocolType {
option (gogoproto.goproto_enum_prefix) = false;

// For every new connection, the Thrift proxy will determine which protocol to use.
// N.B. The older, non-strict binary protocol is not included in automatic protocol
// detection.
AUTO_PROTOCOL = 0;

// The Thrift proxy will assume the client is using the Thrift binary protocol.
BINARY = 1;

// The Thrift proxy will assume the client is using the Thrift non-strict binary protocol.
LAX_BINARY = 2;

// The Thrift proxy will assume the client is using the Thrift compact protocol.
COMPACT = 3;
}

// Supplies the type of protocol that the Thrift proxy should use. Defaults to `AUTO_PROTOCOL`.
ProtocolType protocol = 3 [(validate.rules).enum.defined_only = true];

// The human readable prefix to use when emitting statistics.
string stat_prefix = 1 [(validate.rules).string.min_bytes = 1];

// The route table for the connection manager is static and is specified in this property.
RouteConfiguration route_config = 4;
}
6 changes: 6 additions & 0 deletions source/extensions/extensions_build_config.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ EXTENSIONS = {
"envoy.stat_sinks.metrics_service": "//source/extensions/stat_sinks/metrics_service:config",
"envoy.stat_sinks.statsd": "//source/extensions/stat_sinks/statsd:config",

#
# Thrift filters
#

"envoy.filters.thrift.router": "//source/extensions/filters/network/thrift_proxy/router:config",

#
# Tracers
#
Expand Down
84 changes: 69 additions & 15 deletions source/extensions/filters/network/thrift_proxy/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@ load(

envoy_package()

envoy_cc_library(
name = "app_exception_lib",
srcs = ["app_exception_impl.cc"],
hdrs = ["app_exception_impl.h"],
deps = [
":protocol_interface",
"//include/envoy/buffer:buffer_interface",
"//source/extensions/filters/network/thrift_proxy/filters:filter_interface",
],
)

envoy_cc_library(
name = "buffer_helper_lib",
srcs = ["buffer_helper.cc"],
Expand All @@ -24,41 +35,68 @@ envoy_cc_library(
srcs = ["config.cc"],
hdrs = ["config.h"],
deps = [
":filter_lib",
":conn_manager_lib",
":decoder_lib",
":protocol_lib",
"//include/envoy/registry",
"//source/common/config:filter_json_lib",
"//source/common/config:utility_lib",
"//source/extensions/filters/network:well_known_names",
"//source/extensions/filters/network/common:factory_base_lib",
"//source/extensions/filters/network/thrift_proxy/filters:filter_config_interface",
"//source/extensions/filters/network/thrift_proxy/filters:well_known_names",
"//source/extensions/filters/network/thrift_proxy/router:router_lib",
"@envoy_api//envoy/extensions/filters/network/thrift_proxy/v2alpha1:thrift_proxy_cc",
],
)

envoy_cc_library(
name = "conn_manager_lib",
srcs = ["conn_manager.cc"],
hdrs = ["conn_manager.h"],
deps = [
":app_exception_lib",
":decoder_lib",
":protocol_converter_lib",
":protocol_lib",
":stats_lib",
":transport_lib",
"//include/envoy/event:deferred_deletable",
"//include/envoy/event:dispatcher_interface",
"//include/envoy/network:connection_interface",
"//include/envoy/network:filter_interface",
"//include/envoy/stats:stats_interface",
"//include/envoy/stats:timespan",
"//source/common/buffer:buffer_lib",
"//source/common/common:assert_lib",
"//source/common/common:linked_object",
"//source/common/common:logger_lib",
"//source/common/network:filter_lib",
"//source/extensions/filters/network/thrift_proxy/router:router_interface",
],
)

envoy_cc_library(
name = "decoder_lib",
srcs = ["decoder.cc"],
hdrs = ["decoder.h"],
deps = [
":protocol_lib",
":stats_lib",
":transport_lib",
"//source/common/buffer:buffer_lib",
"//source/extensions/filters/network/thrift_proxy/filters:filter_interface",
],
)

envoy_cc_library(
name = "filter_lib",
srcs = ["filter.cc"],
hdrs = ["filter.h"],
name = "protocol_converter_lib",
hdrs = [
"protocol_converter.h",
],
deps = [
":decoder_lib",
"//include/envoy/network:connection_interface",
"//include/envoy/network:filter_interface",
"//include/envoy/stats:stats_interface",
"//include/envoy/stats:stats_macros",
"//include/envoy/stats:timespan",
"//source/common/buffer:buffer_lib",
"//source/common/common:assert_lib",
"//source/common/common:logger_lib",
"//source/common/network:filter_lib",
":protocol_interface",
"//include/envoy/buffer:buffer_interface",
"//source/extensions/filters/network/thrift_proxy/filters:filter_interface",
],
)

Expand All @@ -70,6 +108,9 @@ envoy_cc_library(
external_deps = ["abseil_optional"],
deps = [
"//include/envoy/buffer:buffer_interface",
"//include/envoy/registry",
"//source/common/common:assert_lib",
"//source/common/config:utility_lib",
"//source/common/singleton:const_singleton",
],
)
Expand All @@ -94,12 +135,24 @@ envoy_cc_library(
],
)

envoy_cc_library(
name = "stats_lib",
hdrs = ["stats.h"],
deps = [
"//include/envoy/stats:stats_interface",
"//include/envoy/stats:stats_macros",
],
)

envoy_cc_library(
name = "transport_interface",
hdrs = ["transport.h"],
external_deps = ["abseil_optional"],
deps = [
"//include/envoy/buffer:buffer_interface",
"//include/envoy/registry",
"//source/common/common:assert_lib",
"//source/common/config:utility_lib",
"//source/common/singleton:const_singleton",
],
)
Expand All @@ -109,6 +162,7 @@ envoy_cc_library(
srcs = [
"framed_transport_impl.cc",
"transport_impl.cc",
"unframed_transport_impl.cc",
],
hdrs = [
"framed_transport_impl.h",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include "extensions/filters/network/thrift_proxy/app_exception_impl.h"

namespace Envoy {
namespace Extensions {
namespace NetworkFilters {
namespace ThriftProxy {

static const std::string TApplicationException = "TApplicationException";
static const std::string MessageField = "message";
static const std::string TypeField = "type";
static const std::string StopField = "";

void AppException::encode(ThriftProxy::Protocol& proto, Buffer::Instance& buffer) {
proto.writeMessageBegin(buffer, method_name_, ThriftProxy::MessageType::Exception, seq_id_);
proto.writeStructBegin(buffer, TApplicationException);

proto.writeFieldBegin(buffer, MessageField, ThriftProxy::FieldType::String, 1);
proto.writeString(buffer, error_message_);
proto.writeFieldEnd(buffer);

proto.writeFieldBegin(buffer, TypeField, ThriftProxy::FieldType::I32, 2);
proto.writeInt32(buffer, static_cast<int32_t>(type_));
proto.writeFieldEnd(buffer);

proto.writeFieldBegin(buffer, StopField, ThriftProxy::FieldType::Stop, 0);

proto.writeStructEnd(buffer);
proto.writeMessageEnd(buffer);
}

} // namespace ThriftProxy
} // namespace NetworkFilters
} // namespace Extensions
} // namespace Envoy
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#pragma once

#include "extensions/filters/network/thrift_proxy/filters/filter.h"

namespace Envoy {
namespace Extensions {
namespace NetworkFilters {
namespace ThriftProxy {

/**
* Thrift Application Exception types.
* See https://github.com/apache/thrift/blob/master/doc/specs/thrift-rpc.md
*/
enum class AppExceptionType {
Unknown = 0,
UnknownMethod = 1,
InvalidMessageType = 2,
WrongMethodName = 3,
BadSequenceId = 4,
MissingResult = 5,
InternalError = 6,
ProtocolError = 7,
InvalidTransform = 8,
InvalidProtocol = 9,
UnsupportedClientType = 10,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fbthrift has a few more exception types than apache thrift: https://github.com/facebook/fbthrift/blob/04ba53d4503d51a9a27f700b114eb7cea4678dc1/thrift/lib/cpp/TApplicationException.h#L57. Should these be supported too? As an example later in the code InternalError could be replaced by more specific code such as LoadShedding. Would that create sub-optimal experience for apache thrift as the enum value would not exist in the client services logic? Without using the fbthrift exception types there will be feature regressions for some client services as would no longer be able to differentiate.

Is apache thrift being treated as the standard here when there are competing standards?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think short-term, we'll stick with the apache definitions. Longer term, we'll probably want to use internal identifiers for various error conditions and then provide a configuration point to control whether they get mapped to apache or fb's values.

};

struct AppException : public ThriftFilters::DirectResponse {
AppException(const absl::string_view method_name, int32_t seq_id, AppExceptionType type,
const std::string& error_message)
: method_name_(method_name), seq_id_(seq_id), type_(type), error_message_(error_message) {}

void encode(ThriftProxy::Protocol& proto, Buffer::Instance& buffer) override;

const std::string method_name_;
const int32_t seq_id_;
const AppExceptionType type_;
const std::string error_message_;
};

} // namespace ThriftProxy
} // namespace NetworkFilters
} // namespace Extensions
} // namespace Envoy
Loading