Skip to content

Commit

Permalink
[release-1.6] manual cherry-pick of envoyproxy#482 (envoyproxy#195)
Browse files Browse the repository at this point in the history
Signed-off-by: Kuat Yessenov <kuat@google.com>
  • Loading branch information
kyessenov authored Apr 17, 2020
1 parent 54f01b8 commit aba3cf3
Show file tree
Hide file tree
Showing 13 changed files with 309 additions and 73 deletions.
1 change: 1 addition & 0 deletions bazel/repositories.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ def envoy_dependencies(skip_targets = []):
_upb()
_repository_impl("com_googlesource_code_re2")
_com_google_cel_cpp()
_repository_impl("com_github_google_flatbuffers")
_repository_impl("bazel_toolchains")
_repository_impl("bazel_compdb")
_repository_impl("envoy_build_tools")
Expand Down
13 changes: 9 additions & 4 deletions bazel/repository_locations.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -296,10 +296,15 @@ REPOSITORY_LOCATIONS = dict(
urls = ["https://storage.googleapis.com/quiche-envoy-integration/googleurl_dbf5ad147f60afc125e99db7549402af49a5eae8.tar.gz"],
),
com_google_cel_cpp = dict(
sha256 = "d942a8d2e5831bcf7f5b1e99b07f90534eb082f40fd9bda05bcc24ff9c0c3571",
strip_prefix = "cel-cpp-a9eec4686b72c28980a09fe2e253ec897a781c32",
# 2019-12-09
urls = ["https://github.com/google/cel-cpp/archive/a9eec4686b72c28980a09fe2e253ec897a781c32.tar.gz"],
sha256 = "7eddffdb231e7c82f60c597cd38e742fbc0c48f54ca33015ac0a3d22bd51bba3",
strip_prefix = "cel-cpp-d88a4822af1864b481b31b12c2ecc4e631a7f8a9",
# 2019-04-13
urls = ["https://github.com/google/cel-cpp/archive/d88a4822af1864b481b31b12c2ecc4e631a7f8a9.tar.gz"],
),
com_github_google_flatbuffers = dict(
sha256 = "b8efbc25721e76780752bad775a97c3f77a0250271e2db37fc747b20e8b0f24a",
strip_prefix = "flatbuffers-a83caf5910644ba1c421c002ef68e42f21c15f9f",
urls = ["https://github.com/google/flatbuffers/archive/a83caf5910644ba1c421c002ef68e42f21c15f9f.tar.gz"],
),
com_googlesource_code_re2 = dict(
sha256 = "04ee2aaebaa5038554683329afc494e684c30f82f2a1e47eb62450e59338f84d",
Expand Down
12 changes: 12 additions & 0 deletions source/extensions/common/wasm/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ load(
"//bazel:envoy_build_system.bzl",
"envoy_cc_library",
"envoy_package",
"envoy_proto_library",
)

envoy_package()
Expand Down Expand Up @@ -54,6 +55,7 @@ envoy_cc_library(
"exports.h",
"foreign.h",
"wasm.h",
"wasm_state.h",
],
deps = [
":wasm_vm_interface",
Expand Down Expand Up @@ -82,6 +84,10 @@ envoy_cc_library(
deps = [
"//include/envoy/stream_info:filter_state_interface",
"//source/common/protobuf",
"//source/common/singleton:const_singleton",
"@com_github_google_flatbuffers//:flatbuffers",
"@com_google_cel_cpp//eval/public:cel_value",
"@com_google_cel_cpp//tools:flatbuffers_backed_impl",
],
)

Expand All @@ -94,6 +100,7 @@ envoy_cc_library(
"wasm.cc",
],
deps = [
":declare_property_cc_proto",
":wasm_hdr",
":wasm_interoperation_lib",
":wasm_vm_lib",
Expand All @@ -118,3 +125,8 @@ envoy_cc_library(
"@envoy_api//envoy/config/wasm/v3:pkg_cc_proto",
],
)

envoy_proto_library(
name = "declare_property",
srcs = ["declare_property.proto"],
)
91 changes: 41 additions & 50 deletions source/extensions/common/wasm/context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -377,47 +377,9 @@ WasmResult serializeValue(Filters::Common::Expr::CelValue value, std::string* re
return WasmResult::SerializationFailure;
}

// An expression wrapper for the WASM state
class WasmStateWrapper : public google::api::expr::runtime::CelMap {
public:
WasmStateWrapper(const StreamInfo::FilterState& filter_state,
const StreamInfo::FilterState* upstream_connection_filter_state)
: filter_state_(filter_state),
upstream_connection_filter_state_(upstream_connection_filter_state) {}
absl::optional<google::api::expr::runtime::CelValue>
operator[](google::api::expr::runtime::CelValue key) const override {
if (!key.IsString()) {
return {};
}
auto value = key.StringOrDie().value();
if (filter_state_.hasData<WasmState>(value)) {
const WasmState& result = filter_state_.getDataReadOnly<WasmState>(value);
return google::api::expr::runtime::CelValue::CreateBytes(&result.value());
}

if (upstream_connection_filter_state_ &&
upstream_connection_filter_state_->hasData<WasmState>(value)) {
const WasmState& result =
upstream_connection_filter_state_->getDataReadOnly<WasmState>(value);
return google::api::expr::runtime::CelValue::CreateBytes(&result.value());
}
return {};
}

int size() const override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; }
bool empty() const override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; }
const google::api::expr::runtime::CelList* ListKeys() const override {
NOT_IMPLEMENTED_GCOVR_EXCL_LINE;
}

private:
const StreamInfo::FilterState& filter_state_;
const StreamInfo::FilterState* upstream_connection_filter_state_;
};

#define PROPERTY_TOKENS(_f) \
_f(METADATA) _f(FILTER_STATE) _f(REQUEST) _f(RESPONSE) _f(CONNECTION) _f(UPSTREAM) _f(NODE) \
_f(SOURCE) _f(DESTINATION) _f(LISTENER_DIRECTION) _f(LISTENER_METADATA) _f(CLUSTER_NAME) \
_f(METADATA) _f(REQUEST) _f(RESPONSE) _f(CONNECTION) _f(UPSTREAM) _f(NODE) _f(SOURCE) \
_f(DESTINATION) _f(LISTENER_DIRECTION) _f(LISTENER_METADATA) _f(CLUSTER_NAME) \
_f(CLUSTER_METADATA) _f(ROUTE_NAME) _f(ROUTE_METADATA) _f(PLUGIN_NAME) \
_f(PLUGIN_ROOT_ID) _f(PLUGIN_VM_ID)

Expand All @@ -438,25 +400,33 @@ absl::optional<google::api::expr::runtime::CelValue>
Context::FindValue(absl::string_view name, Protobuf::Arena* arena) const {
using google::api::expr::runtime::CelValue;

const StreamInfo::StreamInfo* info = getConstRequestStreamInfo();

// Convert into a dense token to enable a jump table implementation.
auto part_token = property_tokens.find(name);
if (part_token == property_tokens.end()) {
if (info) {
std::string key;
absl::StrAppend(&key, WasmStateKeyPrefix, name);
const WasmState* state;
if (info->filterState().hasData<WasmState>(key)) {
state = &info->filterState().getDataReadOnly<WasmState>(key);
} else if (info->upstreamFilterState()->hasData<WasmState>(key)) {
state = &info->upstreamFilterState()->getDataReadOnly<WasmState>(key);
} else {
return {};
}
return state->exprValue(arena);
}
return {};
}

const StreamInfo::StreamInfo* info = getConstRequestStreamInfo();
switch (part_token->second) {
case PropertyToken::METADATA:
if (info) {
return CelValue::CreateMessage(&info->dynamicMetadata(), arena);
}
break;
case PropertyToken::FILTER_STATE:
if (info) {
return CelValue::CreateMap(Protobuf::Arena::Create<WasmStateWrapper>(
arena, info->filterState(), info->upstreamFilterState().get()));
}
break;
case PropertyToken::REQUEST:
if (info) {
return CelValue::CreateMap(Protobuf::Arena::Create<Filters::Common::Expr::RequestWrapper>(
Expand Down Expand Up @@ -1084,13 +1054,34 @@ const Network::Connection* Context::getConnection() const {
return nullptr;
}

WasmResult Context::setProperty(absl::string_view key, absl::string_view serialized_value) {
WasmResult Context::setProperty(absl::string_view path, absl::string_view value) {
auto* stream_info = getRequestStreamInfo();
if (!stream_info) {
return WasmResult::NotFound;
}
stream_info->filterState()->setData(key, std::make_unique<WasmState>(serialized_value),
StreamInfo::FilterState::StateType::Mutable);
std::string key;
absl::StrAppend(&key, WasmStateKeyPrefix, path);
WasmState* state;
if (stream_info->filterState()->hasData<WasmState>(key)) {
state = &stream_info->filterState()->getDataMutable<WasmState>(key);
} else {
const auto& it = rootContext()->state_prototypes_.find(path);
auto state_ptr = std::make_unique<WasmState>(it == rootContext()->state_prototypes_.end()
? DefaultWasmStatePrototype::get()
: *it->second.get());
state = state_ptr.get();
stream_info->filterState()->setData(key, std::move(state_ptr),
StreamInfo::FilterState::StateType::ReadOnly);
}
if (!state->setValue(value)) {
return WasmResult::BadArgument;
}
return WasmResult::Ok;
}

WasmResult Context::declareProperty(absl::string_view path,
std::unique_ptr<const WasmStatePrototype> state_prototype) {
state_prototypes_[path] = std::move(state_prototype);
return WasmResult::Ok;
}

Expand Down
16 changes: 15 additions & 1 deletion source/extensions/common/wasm/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "common/common/assert.h"
#include "common/common/logger.h"

#include "extensions/common/wasm/wasm_state.h"
#include "extensions/filters/common/expr/evaluator.h"

#include "eval/public/activation.h"
Expand Down Expand Up @@ -218,7 +219,9 @@ class Context : public Logger::Loggable<Logger::Id::wasm>,

// State accessors
virtual WasmResult getProperty(absl::string_view path, std::string* result);
virtual WasmResult setProperty(absl::string_view key, absl::string_view serialized_value);
virtual WasmResult setProperty(absl::string_view path, absl::string_view value);
WasmResult declareProperty(absl::string_view path,
std::unique_ptr<const WasmStatePrototype> state_prototype);

// Continue
virtual void continueRequest();
Expand Down Expand Up @@ -310,6 +313,14 @@ class Context : public Logger::Loggable<Logger::Id::wasm>,
virtual absl::optional<google::api::expr::runtime::CelValue>
FindValue(absl::string_view name, Protobuf::Arena* arena) const override;
virtual bool IsPathUnknown(absl::string_view) const override { return false; }
const std::vector<google::api::expr::runtime::CelAttributePattern>&
unknown_attribute_patterns() const override {
static const std::vector<google::api::expr::runtime::CelAttributePattern> empty;
return empty;
}
const Protobuf::FieldMask unknown_paths() const override {
return Protobuf::FieldMask::default_instance();
}

// Foreign function state
virtual void setForeignData(absl::string_view data_name, std::unique_ptr<StorageObject> data) {
Expand Down Expand Up @@ -497,6 +508,9 @@ class Context : public Logger::Loggable<Logger::Id::wasm>,
bool upstream_closed_ = false;
bool downstream_closed_ = false;
bool tcp_connection_closed_ = false;

// Filter state prototype declaration.
absl::flat_hash_map<std::string, std::unique_ptr<const WasmStatePrototype>> state_prototypes_;
};

using ContextSharedPtr = std::shared_ptr<Context>;
Expand Down
24 changes: 24 additions & 0 deletions source/extensions/common/wasm/declare_property.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
syntax = "proto3";

package envoy.source.extensions.common.wasm;

enum WasmType {
Bytes = 0;
String = 1;
FlatBuffers = 2;
Protobuf = 3;
};

enum LifeSpan {
FilterChain = 0;
DownstreamRequest = 1;
DownstreamConnection = 2;
};

message DeclarePropertyArguments {
string name = 1;
bool readonly = 2;
WasmType type = 3;
bytes schema = 4;
LifeSpan span = 5;
};
63 changes: 60 additions & 3 deletions source/extensions/common/wasm/foreign.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#include "common/common/logger.h"

#include "source/extensions/common/wasm/declare_property.pb.h"

#include "eval/public/builtin_func_registrar.h"
#include "eval/public/cel_expr_builder_factory.h"
#include "parser/parser.h"
Expand Down Expand Up @@ -128,7 +130,7 @@ class CreateExpressionFactory : public ExpressionFactory, public ForeignFunction
auto token = expr_context.createToken();
auto& handler = expr_context.getExpression(token);

handler.parsed_expr_ = parse_status.ValueOrDie();
handler.parsed_expr_ = parse_status.value();
auto cel_expression_status = expr_context.builder()->CreateExpression(
&handler.parsed_expr_.expr(), &handler.parsed_expr_.source_info());
if (!cel_expression_status.ok()) {
Expand All @@ -137,7 +139,7 @@ class CreateExpressionFactory : public ExpressionFactory, public ForeignFunction
return WasmResult::BadArgument;
}

handler.compiled_expr_ = std::move(cel_expression_status.ValueOrDie());
handler.compiled_expr_ = std::move(cel_expression_status.value());
auto result = reinterpret_cast<uint32_t*>(alloc_result(sizeof(uint32_t)));
*result = token;
return WasmResult::Ok;
Expand Down Expand Up @@ -169,7 +171,7 @@ class EvaluateExpressionFactory : public ExpressionFactory, public ForeignFuncti
return WasmResult::InternalFailure;
}
std::string result;
auto serialize_status = serializeValue(eval_status.ValueOrDie(), &result);
auto serialize_status = serializeValue(eval_status.value(), &result);
if (serialize_status != WasmResult::Ok) {
return serialize_status;
}
Expand Down Expand Up @@ -201,6 +203,61 @@ class DeleteExpressionFactory : public ExpressionFactory, public ForeignFunction
};
REGISTER_FACTORY(DeleteExpressionFactory, ForeignFunctionFactory);

// TODO(kyessenov) The factories should be separated into individual compilation units.
// TODO(kyessenov) Leverage the host argument marshaller instead of the protobuf argument list.
class DeclarePropertyFactory : public ForeignFunctionFactory {
public:
std::string name() const override { return "declare_property"; }
WasmForeignFunction create() const override {
WasmForeignFunction f = [](Wasm&, absl::string_view arguments,
std::function<void*(size_t size)>) -> WasmResult {
envoy::source::extensions::common::wasm::DeclarePropertyArguments args;
if (args.ParseFromArray(arguments.data(), arguments.size())) {
WasmType type = WasmType::Bytes;
switch (args.type()) {
case envoy::source::extensions::common::wasm::WasmType::Bytes:
type = WasmType::Bytes;
break;
case envoy::source::extensions::common::wasm::WasmType::Protobuf:
type = WasmType::Protobuf;
break;
case envoy::source::extensions::common::wasm::WasmType::String:
type = WasmType::String;
break;
case envoy::source::extensions::common::wasm::WasmType::FlatBuffers:
type = WasmType::FlatBuffers;
break;
default:
// do nothing
break;
}
StreamInfo::FilterState::LifeSpan span = StreamInfo::FilterState::LifeSpan::FilterChain;
switch (args.span()) {
case envoy::source::extensions::common::wasm::LifeSpan::FilterChain:
span = StreamInfo::FilterState::LifeSpan::FilterChain;
break;
case envoy::source::extensions::common::wasm::LifeSpan::DownstreamRequest:
span = StreamInfo::FilterState::LifeSpan::DownstreamRequest;
break;
case envoy::source::extensions::common::wasm::LifeSpan::DownstreamConnection:
span = StreamInfo::FilterState::LifeSpan::DownstreamConnection;
break;
default:
// do nothing
break;
}
auto context = static_cast<Context*>(current_context_);
return context->declareProperty(
args.name(),
std::make_unique<const WasmStatePrototype>(args.readonly(), type, args.schema(), span));
}
return WasmResult::BadArgument;
};
return f;
}
};
REGISTER_FACTORY(DeclarePropertyFactory, ForeignFunctionFactory);

} // namespace Wasm
} // namespace Common
} // namespace Extensions
Expand Down
1 change: 1 addition & 0 deletions source/extensions/common/wasm/null/sample_plugin/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ envoy_cc_library(
"//source/common/common:assert_lib",
"//source/common/common:c_smart_ptr_lib",
"//source/common/protobuf",
"//source/extensions/common/wasm:declare_property_cc_proto",
"//source/extensions/common/wasm:wasm_hdr",
"//source/extensions/common/wasm:well_known_names",
"//source/extensions/common/wasm/null:null_plugin_lib",
Expand Down
Loading

0 comments on commit aba3cf3

Please sign in to comment.