From d0fed58046019bcff9cf6b48f7a021c13506ffd8 Mon Sep 17 00:00:00 2001 From: John Plevyak Date: Thu, 28 May 2020 10:44:16 -0700 Subject: [PATCH 01/16] Add support for onForeignFunction and proxy-specific extensions. Signed-off-by: John Plevyak --- bazel/repository_locations.bzl | 12 +- source/extensions/common/wasm/BUILD | 1 + source/extensions/common/wasm/context.cc | 61 +++++-- source/extensions/common/wasm/context.h | 47 ++++-- source/extensions/common/wasm/ext/BUILD | 27 ++++ source/extensions/common/wasm/ext/README.md | 1 + .../common/wasm/ext/envoy_context.h | 21 +++ .../common/wasm/ext/envoy_proxy_wasm_api.h | 18 +++ source/extensions/common/wasm/wasm.cc | 104 +++++++++--- source/extensions/common/wasm/wasm.h | 19 ++- source/extensions/common/wasm/wasm_vm.cc | 30 ++++ source/extensions/common/wasm/wasm_vm.h | 15 +- test/extensions/common/wasm/BUILD | 2 + test/extensions/common/wasm/test_data/BUILD | 27 ++++ .../common/wasm/test_data/test_context_cpp.cc | 75 +++++++++ .../test_data/test_context_cpp_null_plugin.cc | 16 ++ .../common/wasm/test_data/test_cpp.cc | 9 ++ test/extensions/common/wasm/wasm_test.cc | 90 ++++++++++- test/extensions/common/wasm/wasm_vm_test.cc | 2 + .../filters/http/wasm/wasm_filter_test.cc | 150 +++++++++--------- .../filters/network/wasm/wasm_filter_test.cc | 8 +- test/extensions/wasm/wasm_speed_test.cc | 4 +- test/extensions/wasm/wasm_test.cc | 8 +- test/test_common/wasm_base.h | 16 +- 24 files changed, 597 insertions(+), 166 deletions(-) create mode 100644 source/extensions/common/wasm/ext/BUILD create mode 100644 source/extensions/common/wasm/ext/README.md create mode 100644 source/extensions/common/wasm/ext/envoy_context.h create mode 100644 source/extensions/common/wasm/ext/envoy_proxy_wasm_api.h create mode 100644 test/extensions/common/wasm/test_data/test_context_cpp.cc create mode 100644 test/extensions/common/wasm/test_data/test_context_cpp_null_plugin.cc diff --git a/bazel/repository_locations.bzl b/bazel/repository_locations.bzl index 3ca226ac73..df2d224840 100644 --- a/bazel/repository_locations.bzl +++ b/bazel/repository_locations.bzl @@ -346,14 +346,14 @@ REPOSITORY_LOCATIONS = dict( urls = ["https://github.com/dpkp/kafka-python/archive/2.0.0.tar.gz"], ), proxy_wasm_cpp_sdk = dict( - sha256 = "3531281b8190ff532b730e92c1f247a2b87995f17a4fd9eaf2ebac6136fbc308", - strip_prefix = "proxy-wasm-cpp-sdk-96927d814b3ec14893b56793e122125e095654c7", - urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-sdk/archive/96927d814b3ec14893b56793e122125e095654c7.tar.gz"], + sha256 = "19ee6b22c6fb44974a2777493cd00d48388f6331956d951c6bd3a865be56095e", + strip_prefix = "proxy-wasm-cpp-sdk-4ca655cd1af9047a03a82cd9b296a30a8f2a237f", + urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-sdk/archive/4ca655cd1af9047a03a82cd9b296a30a8f2a237f.tar.gz"], ), proxy_wasm_cpp_host = dict( - sha256 = "08f90872054779e966bcedafaed44faebaf5277696aea6d1ba4975f097c3cd8d", - strip_prefix = "proxy-wasm-cpp-host-65652f008f9f19be958d84b023ce2511c0dca3ae", - urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-host/archive/65652f008f9f19be958d84b023ce2511c0dca3ae.tar.gz"], + sha256 = "8a42287d350ea6493511998b0fe42d2d5f585ff8f31ab432aa394e38586eda73", + strip_prefix = "proxy-wasm-cpp-host-938c41d075b2e37933b940917d3ec3505c2b0951", + urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-host/archive/938c41d075b2e37933b940917d3ec3505c2b0951.tar.gz"], ), emscripten_toolchain = dict( sha256 = "4ac0f1f3de8b3f1373d435cd7e58bd94de4146e751f099732167749a229b443b", diff --git a/source/extensions/common/wasm/BUILD b/source/extensions/common/wasm/BUILD index 39437ca7f6..0a0f9bd841 100644 --- a/source/extensions/common/wasm/BUILD +++ b/source/extensions/common/wasm/BUILD @@ -83,6 +83,7 @@ envoy_cc_library( "//source/common/http:message_lib", "//source/common/http:utility_lib", "//source/common/tracing:http_tracer_lib", + "//source/extensions/common/wasm/ext:envoy_proxy_wasm_api", "//source/extensions/filters/common/expr:context_lib", "@com_google_cel_cpp//eval/eval:field_access", "@com_google_cel_cpp//eval/eval:field_backed_list_impl", diff --git a/source/extensions/common/wasm/context.cc b/source/extensions/common/wasm/context.cc index 1cfca619ea..39dda135b2 100644 --- a/source/extensions/common/wasm/context.cc +++ b/source/extensions/common/wasm/context.cc @@ -81,10 +81,10 @@ template static uint32_t headerSize(const P& p) { return p ? p->siz // Test support. size_t Buffer::size() const { - if (buffer_instance_) { - return buffer_instance_->length(); + if (const_buffer_instance_) { + return const_buffer_instance_->length(); } - return data_.size(); + return proxy_wasm::BufferBase::size(); } WasmResult Buffer::copyTo(WasmBase* wasm, size_t start, size_t length, uint64_t ptr_ptr, @@ -104,11 +104,7 @@ WasmResult Buffer::copyTo(WasmBase* wasm, size_t start, size_t length, uint64_t } return WasmResult::Ok; } - absl::string_view s = data_.substr(start, length); - if (!wasm->copyToPointerSize(s, ptr_ptr, size_ptr)) { - return WasmResult::InvalidMemoryAccess; - } - return WasmResult::Ok; + return proxy_wasm::BufferBase::copyTo(wasm, start, length, ptr_ptr, size_ptr); } WasmResult Buffer::copyFrom(size_t start, size_t length, absl::string_view data) { @@ -134,8 +130,7 @@ WasmResult Buffer::copyFrom(size_t start, size_t length, absl::string_view data) if (const_buffer_instance_) { // This buffer is immutable. return WasmResult::BadArgument; } - // Setting a string buffer not supported (no use case). - return WasmResult::BadArgument; + return proxy_wasm::BufferBase::copyFrom(start, length, data); } Context::Context() = default; @@ -158,11 +153,6 @@ void Context::initializeRoot(WasmBase* wasm, std::shared_ptr plugin) root_local_info_ = &std::static_pointer_cast(plugin)->local_info_; } -WasmResult Context::setTimerPeriod(std::chrono::milliseconds tick_period, uint32_t*) { - wasm()->setTimerPeriod(root_context_id_ ? root_context_id_ : id_, tick_period); - return WasmResult::Ok; -} - uint64_t Context::getCurrentTimeNanoseconds() { return std::chrono::duration_cast( wasm()->time_source_.systemTime().time_since_epoch()) @@ -179,6 +169,44 @@ void Context::onCloseTCP() { onDelete(); } +void Context::onResolveDns(uint32_t token, Envoy::Network::DnsResolver::ResolutionStatus status, + std::list&& response) { + proxy_wasm::DeferAfterCallActions actions(this); + if (!wasm()->on_dns_resolved_) { + return; + } + if (status != Network::DnsResolver::ResolutionStatus::Success) { + buffer_.set(""); + wasm()->on_dns_resolved_(this, id_, token, 0); + return; + } + // buffer format: + // 4 bytes number of entries = N + // N * 4 bytes TTL for each entry + // N * null-terminated addresses + uint32_t s = 4; // length + for (auto& e : response) { + s += 4; // for TTL + s += e.address_->asStringView().size() + 1; // null terminated. + } + auto buffer = std::unique_ptr(new char[s]); + char* b = buffer.get(); + memcpy(b, &s, sizeof(uint32_t)); + b += sizeof(uint32_t); + for (auto& e : response) { + uint32_t ttl = e.ttl_.count(); + memcpy(b, &ttl, sizeof(uint32_t)); + b += sizeof(uint32_t); + }; + for (auto& e : response) { + memcpy(b, e.address_->asStringView().data(), e.address_->asStringView().size()); + b += e.address_->asStringView().size(); + *b++ = 0; + }; + buffer_.set(std::move(buffer), s); + wasm()->on_dns_resolved_(this, id_, token, s); +} + // Native serializer carrying over bit representation from CEL value to the extension WasmResult serializeValue(Filters::Common::Expr::CelValue value, std::string* result) { using Filters::Common::Expr::CelValue; @@ -639,6 +667,9 @@ WasmResult Context::getHeaderMapSize(WasmHeaderMapType type, uint32_t* result) { BufferInterface* Context::getBuffer(WasmBufferType type) { switch (type) { + case WasmBufferType::CallData: + // Set before the call. + return &buffer_; case WasmBufferType::VmConfiguration: return buffer_.set(wasm()->vm_configuration()); case WasmBufferType::PluginConfiguration: diff --git a/source/extensions/common/wasm/context.h b/source/extensions/common/wasm/context.h index 4ec4260ae1..e0f1f8497e 100644 --- a/source/extensions/common/wasm/context.h +++ b/source/extensions/common/wasm/context.h @@ -17,7 +17,7 @@ #include "extensions/filters/common/expr/evaluator.h" #include "eval/public/activation.h" -#include "include/proxy-wasm/context.h" + #include "include/proxy-wasm/wasm.h" namespace Envoy { @@ -25,10 +25,9 @@ namespace Extensions { namespace Common { namespace Wasm { -#include "proxy_wasm_common.h" - using proxy_wasm::BufferInterface; using proxy_wasm::CloseType; +using proxy_wasm::ContextBase; using proxy_wasm::MetricType; using proxy_wasm::Pairs; using proxy_wasm::PairsWithStringValues; @@ -41,6 +40,7 @@ using proxy_wasm::WasmBufferType; using proxy_wasm::WasmHandleBase; using proxy_wasm::WasmHeaderMapType; using proxy_wasm::WasmResult; +using proxy_wasm::Word; using GrpcService = envoy::config::core::v3::GrpcService; @@ -54,30 +54,43 @@ class StorageObject { virtual ~StorageObject() = default; }; -class Buffer : public proxy_wasm::BufferInterface { +class Buffer : public proxy_wasm::BufferBase { public: Buffer() = default; - Buffer* set(absl::string_view data) { - data_ = data; + // proxy_wasm::BufferInterface + size_t size() const override; + WasmResult copyTo(WasmBase* wasm, size_t start, size_t length, uint64_t ptr_ptr, + uint64_t size_ptr) const override; + WasmResult copyFrom(size_t start, size_t length, absl::string_view data) override; + + // proxy_wasm::BufferBase + void clear() override { + proxy_wasm::BufferBase::clear(); const_buffer_instance_ = nullptr; buffer_instance_ = nullptr; - return this; } + Buffer* set(absl::string_view data) { + return static_cast(proxy_wasm::BufferBase::set(data)); + } + Buffer* set(std::unique_ptr owned_data, uint32_t owned_data_size) { + return static_cast( + proxy_wasm::BufferBase::set(std::move(owned_data), owned_data_size)); + } + Buffer* set(::Envoy::Buffer::Instance* buffer_instance) { - data_ = ""; + clear(); buffer_instance_ = buffer_instance; const_buffer_instance_ = buffer_instance; return this; } - - size_t size() const override; - WasmResult copyTo(WasmBase* wasm, size_t start, size_t length, uint64_t ptr_ptr, - uint64_t size_ptr) const override; - WasmResult copyFrom(size_t start, size_t length, absl::string_view data) override; + Buffer* set(const ::Envoy::Buffer::Instance* buffer_instance) { + clear(); + const_buffer_instance_ = buffer_instance; + return this; + } private: - absl::string_view data_; const ::Envoy::Buffer::Instance* const_buffer_instance_{}; ::Envoy::Buffer::Instance* buffer_instance_{}; }; @@ -119,6 +132,7 @@ class Context : public proxy_wasm::ContextBase, Plugin* plugin() const; Context* rootContext() const; Upstream::ClusterManager& clusterManager() const; + Buffer& buffer() { return buffer_; } // proxy_wasm::ContextBase void error(absl::string_view message) override; @@ -192,7 +206,6 @@ class Context : public proxy_wasm::ContextBase, // General WasmResult log(uint32_t level, absl::string_view message) override; - WasmResult setTimerPeriod(std::chrono::milliseconds tick_period, uint32_t* token) override; uint64_t getCurrentTimeNanoseconds() override; std::pair getStatus() override; @@ -252,6 +265,10 @@ class Context : public proxy_wasm::ContextBase, WasmResult grpcCancel(uint32_t token) override; WasmResult grpcSend(uint32_t token, absl::string_view message, bool end_stream) override; + // Envoy specific ABI + void onResolveDns(uint32_t token, Envoy::Network::DnsResolver::ResolutionStatus status, + std::list&& response); + // CEL evaluation std::vector FindFunctionOverloads(absl::string_view) const override { diff --git a/source/extensions/common/wasm/ext/BUILD b/source/extensions/common/wasm/ext/BUILD new file mode 100644 index 0000000000..b9625744c6 --- /dev/null +++ b/source/extensions/common/wasm/ext/BUILD @@ -0,0 +1,27 @@ +licenses(["notice"]) # Apache 2 + +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_library", + "envoy_package", + "envoy_proto_library", +) + +envoy_package() + +envoy_cc_library( + name = "envoy_proxy_wasm_api", + hdrs = [ + "envoy_context.h", + "envoy_proxy_wasm_api.h", + ], + deps = [ + "@proxy_wasm_cpp_sdk//:api_lib", + "@proxy_wasm_cpp_sdk//:common_lib", + ], +) + +cc_library( + name = "envoy_context", + hdrs = ["envoy_context.h"], +) diff --git a/source/extensions/common/wasm/ext/README.md b/source/extensions/common/wasm/ext/README.md new file mode 100644 index 0000000000..b9e1e44d4d --- /dev/null +++ b/source/extensions/common/wasm/ext/README.md @@ -0,0 +1 @@ +# Envoy specific extensions to the proxy-wasm SDK diff --git a/source/extensions/common/wasm/ext/envoy_context.h b/source/extensions/common/wasm/ext/envoy_context.h new file mode 100644 index 0000000000..47f40e23b3 --- /dev/null +++ b/source/extensions/common/wasm/ext/envoy_context.h @@ -0,0 +1,21 @@ +// NOLINT(namespace-envoy) +#pragma once + +class EnvoyContextBase { +public: + virtual ~EnvoyContextBase() = default; + + virtual void onResolveDns(uint32_t /* token */, uint32_t /* result_size */) {} +}; + +class EnvoyRootContext : public RootContext, public EnvoyContextBase { +public: + EnvoyRootContext(uint32_t id, StringView root_id) : RootContext(id, root_id) {} + ~EnvoyRootContext() override = default; +}; + +class EnvoyContext : public Context, public EnvoyContextBase { +public: + EnvoyContext(uint32_t id, RootContext* root) : Context(id, root) {} + ~EnvoyContext() override = default; +}; diff --git a/source/extensions/common/wasm/ext/envoy_proxy_wasm_api.h b/source/extensions/common/wasm/ext/envoy_proxy_wasm_api.h new file mode 100644 index 0000000000..4e8caef128 --- /dev/null +++ b/source/extensions/common/wasm/ext/envoy_proxy_wasm_api.h @@ -0,0 +1,18 @@ +// NOLINT(namespace-envoy) +#pragma once + +namespace proxy_wasm { +namespace null_plugin { + +template using Optional = absl::optional; +using StringView = absl::string_view; + +#include "proxy_wasm_enums.h" +#include "proxy_wasm_common.h" +#include "proxy_wasm_enums.h" +#include "proxy_wasm_externs.h" +#include "proxy_wasm_api.h" +#include "extensions/common/wasm/ext/envoy_context.h" + +} // namespace null_plugin +} // namespace proxy_wasm diff --git a/source/extensions/common/wasm/wasm.cc b/source/extensions/common/wasm/wasm.cc index 839fdf8f00..38761a7895 100644 --- a/source/extensions/common/wasm/wasm.cc +++ b/source/extensions/common/wasm/wasm.cc @@ -8,6 +8,10 @@ #include "absl/strings/str_cat.h" +#define WASM_CONTEXT(_c) \ + static_cast(proxy_wasm::exports::ContextOrEffectiveContext( \ + static_cast((void)_c, proxy_wasm::current_context_))) + namespace Envoy { using ScopeWeakPtr = std::weak_ptr; @@ -133,36 +137,15 @@ Wasm::Wasm(WasmHandleSharedPtr base_wasm_handle, Event::Dispatcher& dispatcher) ENVOY_LOG(debug, "Thread-Local Wasm created {} now active", active_wasms); } -void Wasm::setTimerPeriod(uint32_t context_id, std::chrono::milliseconds new_tick_period) { - auto& tick_period = tick_period_[context_id]; - auto& timer = timer_[context_id]; - bool was_running = timer && tick_period.count() > 0; - tick_period = new_tick_period; - if (was_running) { - timer->disableTimer(); - } - if (tick_period.count() > 0) { - timer = dispatcher_.createTimer( - [weak = std::weak_ptr(std::static_pointer_cast(shared_from_this())), - context_id]() { - auto shared = weak.lock(); - if (shared) { - shared->tickHandler(context_id); - } - }); - timer->enableTimer(tick_period); - } -} - void Wasm::tickHandler(uint32_t root_context_id) { - auto tick_period = tick_period_.find(root_context_id); + auto period = timer_period_.find(root_context_id); auto timer = timer_.find(root_context_id); - if (tick_period == tick_period_.end() || timer == timer_.end() || !on_tick_) { + if (period == timer_period_.end() || timer == timer_.end() || !on_tick_) { return; } - tick(root_context_id); - if (timer->second && tick_period->second.count() > 0) { - timer->second->enableTimer(tick_period->second); + timerReady(root_context_id); + if (timer->second && period->second.count() > 0) { + timer->second->enableTimer(period->second); } } @@ -175,6 +158,54 @@ Wasm::~Wasm() { } } +// NOLINTNEXTLINE(readability-identifier-naming) +Word resolve_dns(void* raw_context, Word dns_address_ptr, Word dns_address_size, Word token_ptr) { + auto context = WASM_CONTEXT(raw_context); + auto root_context = context->isRootContext() ? context : context->rootContext(); + auto path = context->wasmVm()->getMemory(dns_address_ptr, dns_address_size); + if (!path) { + return WasmResult::InvalidMemoryAccess; + } + // Verify set and verify token_ptr before initiating the async resolve. + uint32_t token = context->wasm()->nextDnsToken(); + if (!context->wasm()->setDatatype(token_ptr, token)) { + return WasmResult::InvalidMemoryAccess; + } + auto callback = [weak_wasm = std::weak_ptr(context->wasm()->sharedThis()), root_context, + context_id = context->id(), + token](Envoy::Network::DnsResolver::ResolutionStatus status, + std::list&& response) { + auto wasm = weak_wasm.lock(); + if (!wasm) { + return; + } + root_context->onResolveDns(token, status, std::move(response)); + }; + if (!context->wasm()->dnsResolver()) { + context->wasm()->dnsResolver() = context->wasm()->dispatcher().createDnsResolver({}, false); + } + context->wasm()->dnsResolver()->resolve(std::string(path.value()), Network::DnsLookupFamily::Auto, + callback); + return WasmResult::Ok; +} + +void Wasm::registerCallbacks() { + WasmBase::registerCallbacks(); +#define _REGISTER(_fn) \ + wasm_vm_->registerCallback( \ + "env", "envoy_" #_fn, &_fn, \ + &proxy_wasm::ConvertFunctionWordToUint32::convertFunctionWordToUint32) + _REGISTER(resolve_dns); +#undef _REGISTER +} + +void Wasm::getFunctions() { + WasmBase::getFunctions(); +#define _GET(_fn) wasm_vm_->getFunction("envoy_" #_fn, &_fn##_); + _GET(on_dns_resolved) +#undef _GET +} + proxy_wasm::CallOnThreadFunction Wasm::callOnThreadFunction() { auto& dispatcher = dispatcher_; return [&dispatcher](const std::function& f) { return dispatcher.post(f); }; @@ -187,6 +218,27 @@ ContextBase* Wasm::createContext(std::shared_ptr plugin) { return new Context(this); } +void Wasm::setTimerPeriod(uint32_t context_id, std::chrono::milliseconds new_period) { + auto& period = timer_period_[context_id]; + auto& timer = timer_[context_id]; + bool was_running = timer && period.count() > 0; + period = new_period; + if (was_running) { + timer->disableTimer(); + } + if (period.count() > 0) { + timer = dispatcher_.createTimer( + [weak = std::weak_ptr(std::static_pointer_cast(shared_from_this())), + context_id]() { + auto shared = weak.lock(); + if (shared) { + shared->tickHandler(context_id); + } + }); + timer->enableTimer(period); + } +} + void Wasm::log(absl::string_view root_id, const Http::RequestHeaderMap* request_headers, const Http::ResponseHeaderMap* response_headers, const Http::ResponseTrailerMap* response_trailers, diff --git a/source/extensions/common/wasm/wasm.h b/source/extensions/common/wasm/wasm.h index caf04d9723..08200d04a4 100644 --- a/source/extensions/common/wasm/wasm.h +++ b/source/extensions/common/wasm/wasm.h @@ -58,13 +58,17 @@ class Wasm : public WasmBase, Logger::Loggable { Context* getRootContext(absl::string_view root_id) { return static_cast(WasmBase::getRootContext(root_id)); } - void setTimerPeriod(uint32_t root_context_id, std::chrono::milliseconds tick_period); + void setTimerPeriod(uint32_t root_context_id, std::chrono::milliseconds period) override; virtual void tickHandler(uint32_t root_context_id); + std::shared_ptr sharedThis() { return std::static_pointer_cast(shared_from_this()); } + Network::DnsResolverSharedPtr& dnsResolver() { return dns_resolver_; } // WasmBase - void error(absl::string_view message) override { throw WasmException(std::string(message)); } proxy_wasm::CallOnThreadFunction callOnThreadFunction() override; ContextBase* createContext(std::shared_ptr plugin) override; + void registerCallbacks() override; + void getFunctions() override; + void error(absl::string_view message) override { throw WasmException(std::string(message)); } // AccessLog::Instance void log(absl::string_view root_id, const Http::RequestHeaderMap* request_headers, @@ -73,11 +77,19 @@ class Wasm : public WasmBase, Logger::Loggable { const StreamInfo::StreamInfo& stream_info); void initializeLifecycle(Server::ServerLifecycleNotifier& lifecycle_notifier); + uint32_t nextDnsToken() { + do { + dns_token_++; + } while (!dns_token_); + return dns_token_; + } private: friend class Context; void initializeStats(); + // Calls into the VM. + proxy_wasm::WasmCallVoid<3> on_dns_resolved_; Stats::ScopeSharedPtr scope_; Upstream::ClusterManager& cluster_manager_; @@ -93,6 +105,9 @@ class Wasm : public WasmBase, Logger::Loggable { absl::flat_hash_map counters_; absl::flat_hash_map gauges_; absl::flat_hash_map histograms_; + + Network::DnsResolverSharedPtr dns_resolver_; + uint32_t dns_token_ = 1; }; using WasmSharedPtr = std::shared_ptr; diff --git a/source/extensions/common/wasm/wasm_vm.cc b/source/extensions/common/wasm/wasm_vm.cc index 167d8f612e..eb2cc913b0 100644 --- a/source/extensions/common/wasm/wasm_vm.cc +++ b/source/extensions/common/wasm/wasm_vm.cc @@ -3,11 +3,17 @@ #include #include +#include "extensions/common/wasm/ext/envoy_proxy_wasm_api.h" +#include "extensions/common/wasm/context.h" #include "extensions/common/wasm/well_known_names.h" #include "include/proxy-wasm/null.h" +#include "include/proxy-wasm/null_plugin.h" #include "include/proxy-wasm/v8.h" +using ContextBase = proxy_wasm::ContextBase; +using Word = proxy_wasm::Word; + namespace Envoy { namespace Extensions { namespace Common { @@ -17,6 +23,30 @@ void EnvoyWasmVmIntegration::error(absl::string_view message) { throw WasmException(std::string(message)); } +bool EnvoyWasmVmIntegration::getNullVmFunction(absl::string_view function_name, bool returns_word, + int number_of_arguments, + proxy_wasm::NullPlugin* plugin, + void* ptr_to_function_return) { + if (function_name == "envoy_on_dns_resolved" && returns_word == false && + number_of_arguments == 3) { + *reinterpret_cast*>(ptr_to_function_return) = + [plugin](ContextBase* context, Word context_id, Word token, Word result_size) { + proxy_wasm::SaveRestoreContext saved_context(context); + // Need to add a new API header available to both .wasm and null vm targets. + auto context_base = plugin->getContextBase(context_id); + if (auto root = context_base->asRoot()) { + static_cast(root)->onResolveDns( + token, result_size); + } else { + static_cast(context_base->asContext()) + ->onResolveDns(token, result_size); + } + }; + return true; + } + return false; +} + WasmVmPtr createWasmVm(absl::string_view runtime, const Stats::ScopeSharedPtr& scope) { if (runtime.empty()) { throw WasmException("Failed to create Wasm VM with unspecified runtime."); diff --git a/source/extensions/common/wasm/wasm_vm.h b/source/extensions/common/wasm/wasm_vm.h index 94055414b6..e9270ca1fe 100644 --- a/source/extensions/common/wasm/wasm_vm.h +++ b/source/extensions/common/wasm/wasm_vm.h @@ -18,11 +18,6 @@ namespace Extensions { namespace Common { namespace Wasm { -using Word = proxy_wasm::Word; -using WasmVm = proxy_wasm::WasmVm; -using Cloneable = proxy_wasm::Cloneable; -using ContextBase = proxy_wasm::ContextBase; - /** * Wasm host stats. */ @@ -49,14 +44,18 @@ class EnvoyWasmVmIntegration : public proxy_wasm::WasmVmIntegration, stats_.active_.inc(); ENVOY_LOG(debug, "WasmVm created {} now active", runtime_, stats_.active_.value()); } - virtual ~EnvoyWasmVmIntegration() { + ~EnvoyWasmVmIntegration() override { stats_.active_.dec(); ENVOY_LOG(debug, "~WasmVm {} {} remaining active", runtime_, stats_.active_.value()); } + + // proxy_wasm::WasmVmIntegration proxy_wasm::WasmVmIntegration* clone() override { return new EnvoyWasmVmIntegration(scope_, runtime_, short_runtime_); } - // void log(proxy_wasm::LogLevel level, absl::string_view message) override; + bool getNullVmFunction(absl::string_view function_name, bool returns_word, + int number_of_arguments, proxy_wasm::NullPlugin* plugin, + void* ptr_to_function_return) override; void error(absl::string_view message) override; const std::string& runtime() const { return runtime_; } @@ -79,7 +78,7 @@ class WasmException : public EnvoyException { using EnvoyException::EnvoyException; }; -using WasmVmPtr = std::unique_ptr; +using WasmVmPtr = std::unique_ptr; // Create a new low-level Wasm VM using runtime of the given type (e.g. "envoy.wasm.runtime.wavm"). WasmVmPtr createWasmVm(absl::string_view runtime, const Stats::ScopeSharedPtr& scope); diff --git a/test/extensions/common/wasm/BUILD b/test/extensions/common/wasm/BUILD index 00eaf0fb21..152d3fc360 100644 --- a/test/extensions/common/wasm/BUILD +++ b/test/extensions/common/wasm/BUILD @@ -27,6 +27,7 @@ envoy_cc_test( srcs = ["wasm_test.cc"], data = [ "//test/extensions/common/wasm/test_data:bad_signature_cpp.wasm", + "//test/extensions/common/wasm/test_data:test_context_cpp.wasm", "//test/extensions/common/wasm/test_data:test_cpp.wasm", ], external_deps = ["abseil_optional"], @@ -42,5 +43,6 @@ envoy_cc_test( "//test/mocks/server:server_mocks", "//test/test_common:environment_lib", "//test/test_common:simulated_time_system_lib", + "//test/test_common:wasm_lib", ], ) diff --git a/test/extensions/common/wasm/test_data/BUILD b/test/extensions/common/wasm/test_data/BUILD index c302e5042e..e99d89a69d 100644 --- a/test/extensions/common/wasm/test_data/BUILD +++ b/test/extensions/common/wasm/test_data/BUILD @@ -34,6 +34,24 @@ envoy_cc_library( ], ) +envoy_cc_library( + name = "test_context_cpp_plugin", + srcs = [ + "test_context_cpp.cc", + "test_context_cpp_null_plugin.cc", + ], + copts = ["-DNULL_PLUGIN=1"], + deps = [ + "//external:abseil_node_hash_map", + "//source/common/common:assert_lib", + "//source/common/common:c_smart_ptr_lib", + "//source/extensions/common/wasm:wasm_hdr", + "//source/extensions/common/wasm:wasm_lib", + "//source/extensions/common/wasm:well_known_names", + "//source/extensions/common/wasm/ext:envoy_proxy_wasm_api", + ], +) + wasm_cc_binary( name = "test_cpp.wasm", srcs = ["test_cpp.cc"], @@ -42,6 +60,15 @@ wasm_cc_binary( ], ) +wasm_cc_binary( + name = "test_context_cpp.wasm", + srcs = ["test_context_cpp.cc"], + deps = [ + "//source/extensions/common/wasm/ext:envoy_context", + "@proxy_wasm_cpp_sdk//:proxy_wasm_intrinsics", + ], +) + wasm_cc_binary( name = "bad_signature_cpp.wasm", srcs = ["bad_signature_cpp.cc"], diff --git a/test/extensions/common/wasm/test_data/test_context_cpp.cc b/test/extensions/common/wasm/test_data/test_context_cpp.cc new file mode 100644 index 0000000000..6bf87291e1 --- /dev/null +++ b/test/extensions/common/wasm/test_data/test_context_cpp.cc @@ -0,0 +1,75 @@ +// NOLINT(namespace-envoy) +#include +#include +#include + +#ifndef NULL_PLUGIN +#include "proxy_wasm_intrinsics.h" +#include "source/extensions/common/wasm/ext/envoy_context.h" +#else +#include "include/proxy-wasm/null_plugin.h" +using namespace proxy_wasm::null_plugin; +#include "extensions/common/wasm/ext/envoy_context.h" +#endif + +START_WASM_PLUGIN(CommonWasmTestContextCpp) + +class TestContext : public EnvoyContext { +public: + explicit TestContext(uint32_t id, RootContext* root) : EnvoyContext(id, root) {} + + void onResolveDns(uint32_t token, uint32_t results_size) override; + void onDone() override; +}; + +class TestRootContext : public RootContext { +public: + explicit TestRootContext(uint32_t id, StringView root_id) : RootContext(id, root_id) {} + + bool onDone() override; +}; + +static RegisterContextFactory register_TestContext(CONTEXT_FACTORY(TestContext), + ROOT_FACTORY(TestRootContext)); + +struct DnsResult { + uint32_t ttl_seconds; + std::string address; +}; + +std::vector convertDnsResults(StringView data) { + if (data.size() < 4) { + return {}; + } + const uint32_t* pn = reinterpret_cast(data.data()); + uint32_t n = *pn++; + std::vector results; + results.resize(n); + const char* pa = data.data() + (1 + n) * sizeof(uint32_t); // skip n + n TTLs + for (uint32_t i = 0; i < n; i++) { + auto& e = results[i]; + e.ttl_seconds = *pn++; + auto alen = strlen(pa); + e.address.assign(pa, alen); + pa += alen + 1; + } + return results; +} + +void TestContext::onResolveDns(uint32_t token, uint32_t result_size) { + logWarn("TestContext::onResolveDns " + std::to_string(token)); + auto dns_buffer = getBufferBytes(WasmBufferType::CallData, 0, result_size); + auto dns = convertDnsResults(dns_buffer->view()); + for (auto& e : dns) { + logInfo("TestContext::onResolveDns dns " + std::to_string(e.ttl_seconds) + " " + e.address); + } +} + +void TestContext::onDone() { logWarn("TestContext::onDone " + std::to_string(id())); } + +bool TestRootContext::onDone() { + logWarn("TestRootContext::onDone " + std::to_string(id())); + return true; +} + +END_WASM_PLUGIN diff --git a/test/extensions/common/wasm/test_data/test_context_cpp_null_plugin.cc b/test/extensions/common/wasm/test_data/test_context_cpp_null_plugin.cc new file mode 100644 index 0000000000..88e3a18943 --- /dev/null +++ b/test/extensions/common/wasm/test_data/test_context_cpp_null_plugin.cc @@ -0,0 +1,16 @@ +// NOLINT(namespace-envoy) +#include "include/proxy-wasm/null_plugin.h" + +namespace proxy_wasm { +namespace null_plugin { +namespace CommonWasmTestContextCpp { +NullPluginRegistry* context_registry_; +} // namespace CommonWasmTestContextCpp + +RegisterNullVmPluginFactory + register_common_wasm_test_context_cpp_plugin("CommonWasmTestContextCpp", []() { + return std::make_unique(CommonWasmTestContextCpp::context_registry_); + }); + +} // namespace null_plugin +} // namespace proxy_wasm diff --git a/test/extensions/common/wasm/test_data/test_cpp.cc b/test/extensions/common/wasm/test_data/test_cpp.cc index 762bb0b6ed..b03f8494cb 100644 --- a/test/extensions/common/wasm/test_data/test_cpp.cc +++ b/test/extensions/common/wasm/test_data/test_cpp.cc @@ -169,6 +169,9 @@ WASM_EXPORT(uint32_t, proxy_on_vm_start, (uint32_t context_id, uint32_t configur if (errno != EBADF || tty != 0) { FAIL_NOW("isatty errors on bad fds. errno = " + std::to_string(errno)); } + } else if (configuration == "on_foreign") { + std::string message = "on_foreign start"; + proxy_log(LogLevel::debug, message.c_str(), message.size()); } else { std::string message = "on_vm_start " + configuration; proxy_log(LogLevel::info, message.c_str(), message.size()); @@ -193,6 +196,12 @@ WASM_EXPORT(uint32_t, proxy_on_configure, (uint32_t, uint32_t configuration_size return 1; } +WASM_EXPORT(void, proxy_on_foreign_function, (uint32_t, uint32_t token, uint32_t data_size)) { + std::string message = + "on_foreign_function " + std::to_string(token) + " " + std::to_string(data_size); + proxy_log(LogLevel::info, message.c_str(), message.size()); +} + WASM_EXPORT(uint32_t, proxy_on_done, (uint32_t)) { std::string message = "on_done logging"; proxy_log(LogLevel::info, message.c_str(), message.size()); diff --git a/test/extensions/common/wasm/wasm_test.cc b/test/extensions/common/wasm/wasm_test.cc index c6bf657b42..2bead38b23 100644 --- a/test/extensions/common/wasm/wasm_test.cc +++ b/test/extensions/common/wasm/wasm_test.cc @@ -10,6 +10,7 @@ #include "test/mocks/upstream/mocks.h" #include "test/test_common/environment.h" #include "test/test_common/utility.h" +#include "test/test_common/wasm_base.h" #include "absl/types/optional.h" #include "gmock/gmock.h" @@ -119,7 +120,7 @@ TEST_P(WasmCommonTest, Logging) { EXPECT_TRUE(wasm_weak.lock()->initialize(code, false)); auto thread_local_wasm = std::make_shared(wasm_handle, *dispatcher); thread_local_wasm.reset(); - wasm_weak.lock()->setContext(test_root_context.get()); + wasm_weak.lock()->setContextForTesting(test_root_context.get()); auto test_root_context_ptr = test_root_context.get(); wasm_weak.lock()->startForTesting(std::move(test_root_context), plugin); wasm_weak.lock()->configure(test_root_context_ptr, plugin); @@ -387,6 +388,46 @@ TEST_P(WasmCommonTest, Foreign) { wasm->startForTesting(std::move(context), plugin); } +TEST_P(WasmCommonTest, OnForeign) { + Stats::IsolatedStoreImpl stats_store; + Api::ApiPtr api = Api::createApiForTest(stats_store); + Upstream::MockClusterManager cluster_manager; + Event::DispatcherPtr dispatcher(api->allocateDispatcher("wasm_test")); + auto scope = Stats::ScopeSharedPtr(stats_store.createScope("wasm.")); + NiceMock local_info; + auto name = ""; + auto root_id = ""; + auto vm_id = ""; + auto vm_configuration = "on_foreign"; + auto vm_key = ""; + auto plugin_configuration = ""; + auto plugin = std::make_shared( + name, root_id, vm_id, plugin_configuration, + envoy::config::core::v3::TrafficDirection::UNSPECIFIED, local_info, nullptr); + auto wasm = std::make_unique( + absl::StrCat("envoy.wasm.runtime.", GetParam()), vm_id, vm_configuration, vm_key, scope, + cluster_manager, *dispatcher); + EXPECT_NE(wasm, nullptr); + std::string code; + if (GetParam() != "null") { + code = TestEnvironment::readFileToStringForTest(TestEnvironment::substitute( + absl::StrCat("{{ test_rundir }}/test/extensions/common/wasm/test_data/test_cpp.wasm"))); + } else { + // The name of the Null VM plugin. + code = "CommonWasmTestCpp"; + } + EXPECT_FALSE(code.empty()); + auto context = std::make_unique(wasm.get()); + + EXPECT_CALL(*context, log_(spdlog::level::debug, Eq("on_foreign start"))); + EXPECT_CALL(*context, log_(spdlog::level::info, Eq("on_foreign_function 7 13"))); + + EXPECT_TRUE(wasm->initialize(code, false)); + auto context_ptr = context.get(); + wasm->startForTesting(std::move(context), plugin); + context_ptr->onForeignFunction(7, 13); +} + TEST_P(WasmCommonTest, WASI) { if (GetParam() == "null") { // This test has no meaning unless it is invoked by actual Wasm code @@ -682,6 +723,53 @@ TEST_P(WasmCommonTest, RemoteCodeMultipleRetry) { dispatcher->clearDeferredDeleteList(); } +class WasmCommonContextTest + : public Common::Wasm::WasmTestBase> { +public: + WasmCommonContextTest() = default; + + void setup(const std::string& code, std::string root_id = "") { + setupBase(GetParam(), code, std::make_unique(wasm_->wasm().get(), plugin_), + root_id); + } + void setupContext() { + context_ = std::make_unique(wasm_->wasm().get(), root_context_->id(), plugin_); + } + + TestContext& root_context() { return *static_cast(root_context_); } + TestContext& context() { return *context_; } + + std::unique_ptr context_; +}; + +TEST_P(WasmCommonContextTest, OnDnsResolve) { + std::string code; + if (GetParam() != "null") { + code = TestEnvironment::readFileToStringForTest(TestEnvironment::substitute(absl::StrCat( + "{{ test_rundir }}/test/extensions/common/wasm/test_data/test_context_cpp.wasm"))); + } else { + // The name of the Null VM plugin. + code = "CommonWasmTestContextCpp"; + } + EXPECT_FALSE(code.empty()); + setup(code); + setupContext(); + + EXPECT_CALL(context(), log_(spdlog::level::debug, Eq("on_foreign start"))); + EXPECT_CALL(context(), log_(spdlog::level::info, Eq("on_foreign_function 7 13"))); + + uint32_t token = 7; + std::list dns_results; + dns_results.emplace(dns_results.end(), + std::make_shared("192.168.1.101"), + std::chrono::seconds(101)); + dns_results.emplace(dns_results.end(), + std::make_shared("192.168.1.102"), + std::chrono::seconds(102)); + context_->onResolveDns(token, Envoy::Network::DnsResolver::ResolutionStatus::Success, + std::move(dns_results)); +} + } // namespace Wasm } // namespace Common } // namespace Extensions diff --git a/test/extensions/common/wasm/wasm_vm_test.cc b/test/extensions/common/wasm/wasm_vm_test.cc index c783297082..7910b36daa 100644 --- a/test/extensions/common/wasm/wasm_vm_test.cc +++ b/test/extensions/common/wasm/wasm_vm_test.cc @@ -11,8 +11,10 @@ #include "gtest/gtest.h" #include "include/proxy-wasm/null_vm_plugin.h" +using proxy_wasm::Cloneable; using proxy_wasm::WasmCallVoid; using proxy_wasm::WasmCallWord; +using proxy_wasm::Word; using testing::HasSubstr; using testing::Return; diff --git a/test/extensions/filters/http/wasm/wasm_filter_test.cc b/test/extensions/filters/http/wasm/wasm_filter_test.cc index 423c8ea47f..22b8a19733 100644 --- a/test/extensions/filters/http/wasm/wasm_filter_test.cc +++ b/test/extensions/filters/http/wasm/wasm_filter_test.cc @@ -71,7 +71,7 @@ class WasmHttpFilterTest void setupFilter(const std::string root_id = "") { setupFilterBase(root_id); } TestRoot& root_context() { return *static_cast(root_context_); } - TestFilter& filter() { return *static_cast(filter_.get()); } + TestFilter& filter() { return *static_cast(context_.get()); } }; INSTANTIATE_TEST_SUITE_P(Runtimes, WasmHttpFilterTest, @@ -98,10 +98,10 @@ TEST_P(WasmHttpFilterTest, HeadersOnlyRequestHeadersOnly) { EXPECT_CALL(filter(), log_(spdlog::level::info, Eq(absl::string_view("header path /")))); EXPECT_CALL(filter(), log_(spdlog::level::warn, Eq(absl::string_view("onDone 2")))); Http::TestRequestHeaderMapImpl request_headers{{":path", "/"}, {"server", "envoy"}}; - EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter().decodeHeaders(request_headers, true)); EXPECT_THAT(request_headers.get_("newheader"), Eq("newheadervalue")); EXPECT_THAT(request_headers.get_("server"), Eq("envoy-wasm")); - filter_->onDestroy(); + filter().onDestroy(); } // Script touching headers only, request that is headers only. @@ -114,10 +114,10 @@ TEST_P(WasmHttpFilterTest, HeadersOnlyRequestHeadersAndBody) { EXPECT_CALL(filter(), log_(spdlog::level::err, Eq(absl::string_view("onRequestBody hello")))); EXPECT_CALL(filter(), log_(spdlog::level::warn, Eq(absl::string_view("onDone 2")))); Http::TestRequestHeaderMapImpl request_headers{{":path", "/"}}; - EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter().decodeHeaders(request_headers, true)); Buffer::OwnedImpl data("hello"); - EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data, true)); - filter_->onDestroy(); + EXPECT_EQ(Http::FilterDataStatus::Continue, filter().decodeData(data, true)); + filter().onDestroy(); } TEST_P(WasmHttpFilterTest, HeadersStopAndContinue) { @@ -130,11 +130,11 @@ TEST_P(WasmHttpFilterTest, HeadersStopAndContinue) { EXPECT_CALL(filter(), log_(spdlog::level::warn, Eq(absl::string_view("onDone 2")))); Http::TestRequestHeaderMapImpl request_headers{{":path", "/"}, {"server", "envoy-wasm-pause"}}; EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, - filter_->decodeHeaders(request_headers, true)); + filter().decodeHeaders(request_headers, true)); root_context_->onTick(0); EXPECT_THAT(request_headers.get_("newheader"), Eq("newheadervalue")); EXPECT_THAT(request_headers.get_("server"), Eq("envoy-wasm-continue")); - filter_->onDestroy(); + filter().onDestroy(); } TEST_P(WasmHttpFilterTest, HeadersStopAndEndStream) { @@ -148,11 +148,11 @@ TEST_P(WasmHttpFilterTest, HeadersStopAndEndStream) { Http::TestRequestHeaderMapImpl request_headers{{":path", "/"}, {"server", "envoy-wasm-end-stream"}}; EXPECT_EQ(Http::FilterHeadersStatus::ContinueAndEndStream, - filter_->decodeHeaders(request_headers, true)); + filter().decodeHeaders(request_headers, true)); root_context_->onTick(0); EXPECT_THAT(request_headers.get_("newheader"), Eq("newheadervalue")); EXPECT_THAT(request_headers.get_("server"), Eq("envoy-wasm-continue")); - filter_->onDestroy(); + filter().onDestroy(); } TEST_P(WasmHttpFilterTest, HeadersStopAndBuffer) { @@ -166,11 +166,11 @@ TEST_P(WasmHttpFilterTest, HeadersStopAndBuffer) { Http::TestRequestHeaderMapImpl request_headers{{":path", "/"}, {"server", "envoy-wasm-stop-buffer"}}; EXPECT_EQ(Http::FilterHeadersStatus::StopAllIterationAndBuffer, - filter_->decodeHeaders(request_headers, true)); + filter().decodeHeaders(request_headers, true)); root_context_->onTick(0); EXPECT_THAT(request_headers.get_("newheader"), Eq("newheadervalue")); EXPECT_THAT(request_headers.get_("server"), Eq("envoy-wasm-continue")); - filter_->onDestroy(); + filter().onDestroy(); } TEST_P(WasmHttpFilterTest, HeadersStopAndWatermark) { @@ -184,11 +184,11 @@ TEST_P(WasmHttpFilterTest, HeadersStopAndWatermark) { Http::TestRequestHeaderMapImpl request_headers{{":path", "/"}, {"server", "envoy-wasm-stop-watermark"}}; EXPECT_EQ(Http::FilterHeadersStatus::StopAllIterationAndWatermark, - filter_->decodeHeaders(request_headers, true)); + filter().decodeHeaders(request_headers, true)); root_context_->onTick(0); EXPECT_THAT(request_headers.get_("newheader"), Eq("newheadervalue")); EXPECT_THAT(request_headers.get_("server"), Eq("envoy-wasm-continue")); - filter_->onDestroy(); + filter().onDestroy(); } // Script that reads the body. @@ -198,10 +198,10 @@ TEST_P(WasmHttpFilterTest, BodyRequestReadBody) { setupFilter(); EXPECT_CALL(filter(), log_(spdlog::level::err, Eq(absl::string_view("onRequestBody hello")))); Http::TestRequestHeaderMapImpl request_headers{{":path", "/"}, {"x-test-operation", "ReadBody"}}; - EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter().decodeHeaders(request_headers, true)); Buffer::OwnedImpl data("hello"); - EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data, true)); - filter_->onDestroy(); + EXPECT_EQ(Http::FilterDataStatus::Continue, filter().decodeData(data, true)); + filter().onDestroy(); } // Script that prepends and appends to the body. @@ -213,10 +213,10 @@ TEST_P(WasmHttpFilterTest, BodyRequestPrependAndAppendToBody) { Eq(absl::string_view("onRequestBody prepend.hello.append")))); Http::TestRequestHeaderMapImpl request_headers{{":path", "/"}, {"x-test-operation", "PrependAndAppendToBody"}}; - EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter().decodeHeaders(request_headers, true)); Buffer::OwnedImpl data("hello"); - EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data, true)); - filter_->onDestroy(); + EXPECT_EQ(Http::FilterDataStatus::Continue, filter().decodeData(data, true)); + filter().onDestroy(); } // Script that replaces the body. @@ -227,10 +227,10 @@ TEST_P(WasmHttpFilterTest, BodyRequestReplaceBody) { EXPECT_CALL(filter(), log_(spdlog::level::err, Eq(absl::string_view("onRequestBody replace")))); Http::TestRequestHeaderMapImpl request_headers{{":path", "/"}, {"x-test-operation", "ReplaceBody"}}; - EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter().decodeHeaders(request_headers, true)); Buffer::OwnedImpl data("hello"); - EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data, true)); - filter_->onDestroy(); + EXPECT_EQ(Http::FilterDataStatus::Continue, filter().decodeData(data, true)); + filter().onDestroy(); } // Script that removes the body. @@ -241,10 +241,10 @@ TEST_P(WasmHttpFilterTest, BodyRequestRemoveBody) { EXPECT_CALL(filter(), log_(spdlog::level::err, Eq(absl::string_view("onRequestBody ")))); Http::TestRequestHeaderMapImpl request_headers{{":path", "/"}, {"x-test-operation", "RemoveBody"}}; - EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter().decodeHeaders(request_headers, true)); Buffer::OwnedImpl data("hello"); - EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data, true)); - filter_->onDestroy(); + EXPECT_EQ(Http::FilterDataStatus::Continue, filter().decodeData(data, true)); + filter().onDestroy(); } // Script that buffers the body. @@ -255,7 +255,7 @@ TEST_P(WasmHttpFilterTest, BodyRequestBufferBody) { Http::TestRequestHeaderMapImpl request_headers{{":path", "/"}, {"x-test-operation", "BufferBody"}}; - EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, false)); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter().decodeHeaders(request_headers, false)); Buffer::OwnedImpl bufferedBody; EXPECT_CALL(decoder_callbacks_, decodingBuffer()).WillRepeatedly(Return(&bufferedBody)); @@ -266,33 +266,33 @@ TEST_P(WasmHttpFilterTest, BodyRequestBufferBody) { bufferedBody.add(data1); EXPECT_CALL(filter(), log_(spdlog::level::err, Eq(absl::string_view("onRequestBody hello")))) .Times(1); - EXPECT_EQ(Http::FilterDataStatus::StopIterationAndBuffer, filter_->decodeData(data1, false)); + EXPECT_EQ(Http::FilterDataStatus::StopIterationAndBuffer, filter().decodeData(data1, false)); Buffer::OwnedImpl data2(" again "); bufferedBody.add(data2); EXPECT_CALL(filter(), log_(spdlog::level::err, Eq(absl::string_view("onRequestBody hello again ")))) .Times(1); - EXPECT_EQ(Http::FilterDataStatus::StopIterationAndBuffer, filter_->decodeData(data2, false)); + EXPECT_EQ(Http::FilterDataStatus::StopIterationAndBuffer, filter().decodeData(data2, false)); EXPECT_CALL(filter(), log_(spdlog::level::err, Eq(absl::string_view("onRequestBody hello again hello")))) .Times(1); Buffer::OwnedImpl data3("hello"); bufferedBody.add(data3); - EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data3, true)); + EXPECT_EQ(Http::FilterDataStatus::Continue, filter().decodeData(data3, true)); // Verify that the response still works even though we buffered the request. Http::TestResponseHeaderMapImpl response_headers{{":status", "200"}, {"x-test-operation", "ReadBody"}}; - EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->encodeHeaders(response_headers, false)); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter().encodeHeaders(response_headers, false)); // Should not buffer this time EXPECT_CALL(filter(), log_(spdlog::level::err, Eq(absl::string_view("onRequestBody hello")))) .Times(2); - EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->encodeData(data1, false)); - EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->encodeData(data1, true)); + EXPECT_EQ(Http::FilterDataStatus::Continue, filter().encodeData(data1, false)); + EXPECT_EQ(Http::FilterDataStatus::Continue, filter().encodeData(data1, true)); - filter_->onDestroy(); + filter().onDestroy(); } // Script that prepends and appends to the buffered body. @@ -304,10 +304,10 @@ TEST_P(WasmHttpFilterTest, BodyRequestPrependAndAppendToBufferedBody) { Eq(absl::string_view("onRequestBody prepend.hello.append")))); Http::TestRequestHeaderMapImpl request_headers{ {":path", "/"}, {"x-test-operation", "PrependAndAppendToBufferedBody"}}; - EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter().decodeHeaders(request_headers, true)); Buffer::OwnedImpl data("hello"); - EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data, true)); - filter_->onDestroy(); + EXPECT_EQ(Http::FilterDataStatus::Continue, filter().decodeData(data, true)); + filter().onDestroy(); } // Script that replaces the buffered body. @@ -318,10 +318,10 @@ TEST_P(WasmHttpFilterTest, BodyRequestReplaceBufferedBody) { EXPECT_CALL(filter(), log_(spdlog::level::err, Eq(absl::string_view("onRequestBody replace")))); Http::TestRequestHeaderMapImpl request_headers{{":path", "/"}, {"x-test-operation", "ReplaceBufferedBody"}}; - EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter().decodeHeaders(request_headers, true)); Buffer::OwnedImpl data("hello"); - EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data, true)); - filter_->onDestroy(); + EXPECT_EQ(Http::FilterDataStatus::Continue, filter().decodeData(data, true)); + filter().onDestroy(); } // Script that removes the buffered body. @@ -332,10 +332,10 @@ TEST_P(WasmHttpFilterTest, BodyRequestRemoveBufferedBody) { EXPECT_CALL(filter(), log_(spdlog::level::err, Eq(absl::string_view("onRequestBody ")))); Http::TestRequestHeaderMapImpl request_headers{{":path", "/"}, {"x-test-operation", "RemoveBufferedBody"}}; - EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter().decodeHeaders(request_headers, true)); Buffer::OwnedImpl data("hello"); - EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data, true)); - filter_->onDestroy(); + EXPECT_EQ(Http::FilterDataStatus::Continue, filter().decodeData(data, true)); + filter().onDestroy(); } // Script that buffers the first part of the body and streams the rest @@ -345,7 +345,7 @@ TEST_P(WasmHttpFilterTest, BodyRequestBufferThenStreamBody) { setupFilter(); Http::TestRequestHeaderMapImpl request_headers{{":path", "/"}}; - EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter().decodeHeaders(request_headers, true)); Buffer::OwnedImpl bufferedBody; EXPECT_CALL(decoder_callbacks_, decodingBuffer()).WillRepeatedly(Return(&bufferedBody)); @@ -354,12 +354,12 @@ TEST_P(WasmHttpFilterTest, BodyRequestBufferThenStreamBody) { Http::TestResponseHeaderMapImpl response_headers{{":status", "200"}, {"x-test-operation", "BufferTwoBodies"}}; - EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->encodeHeaders(response_headers, false)); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter().encodeHeaders(response_headers, false)); Buffer::OwnedImpl data1("hello"); EXPECT_CALL(filter(), log_(spdlog::level::err, Eq(absl::string_view("onRequestBody hello")))) .Times(1); - EXPECT_EQ(Http::FilterDataStatus::StopIterationAndBuffer, filter_->decodeData(data1, false)); + EXPECT_EQ(Http::FilterDataStatus::StopIterationAndBuffer, filter().decodeData(data1, false)); bufferedBody.add(data1); Buffer::OwnedImpl data2(", there, "); @@ -367,7 +367,7 @@ TEST_P(WasmHttpFilterTest, BodyRequestBufferThenStreamBody) { EXPECT_CALL(filter(), log_(spdlog::level::err, Eq(absl::string_view("onRequestBody hello, there, ")))) .Times(1); - EXPECT_EQ(Http::FilterDataStatus::StopIterationAndBuffer, filter_->decodeData(data2, false)); + EXPECT_EQ(Http::FilterDataStatus::StopIterationAndBuffer, filter().decodeData(data2, false)); // Previous callbacks returned "Buffer" so we have buffered so far Buffer::OwnedImpl data3("world!"); @@ -375,21 +375,21 @@ TEST_P(WasmHttpFilterTest, BodyRequestBufferThenStreamBody) { EXPECT_CALL(filter(), log_(spdlog::level::err, Eq(absl::string_view("onRequestBody hello, there, world!")))) .Times(1); - EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data3, false)); + EXPECT_EQ(Http::FilterDataStatus::Continue, filter().decodeData(data3, false)); // Last callback returned "continue" so we just see individual chunks. Buffer::OwnedImpl data4("So it's "); EXPECT_CALL(filter(), log_(spdlog::level::err, Eq(absl::string_view("onRequestBody So it's ")))) .Times(1); - EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data4, false)); + EXPECT_EQ(Http::FilterDataStatus::Continue, filter().decodeData(data4, false)); Buffer::OwnedImpl data5("goodbye, then!"); EXPECT_CALL(filter(), log_(spdlog::level::err, Eq(absl::string_view("onRequestBody goodbye, then!")))) .Times(1); - EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data5, true)); + EXPECT_EQ(Http::FilterDataStatus::Continue, filter().decodeData(data5, true)); - filter_->onDestroy(); + filter().onDestroy(); } // Script testing AccessLog::Instance::log. @@ -404,12 +404,12 @@ TEST_P(WasmHttpFilterTest, AccessLog) { EXPECT_CALL(filter(), log_(spdlog::level::warn, Eq(absl::string_view("onDone 2")))); Http::TestRequestHeaderMapImpl request_headers{{":path", "/"}}; - EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter().decodeHeaders(request_headers, true)); Buffer::OwnedImpl data("hello"); - EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data, true)); - filter_->onDestroy(); + EXPECT_EQ(Http::FilterDataStatus::Continue, filter().decodeData(data, true)); + filter().onDestroy(); StreamInfo::MockStreamInfo log_stream_info; - filter_->log(&request_headers, nullptr, nullptr, log_stream_info); + filter().log(&request_headers, nullptr, nullptr, log_stream_info); } TEST_P(WasmHttpFilterTest, AsyncCall) { @@ -439,7 +439,7 @@ TEST_P(WasmHttpFilterTest, AsyncCall) { EXPECT_CALL(filter(), log_(spdlog::level::debug, Eq("response"))); EXPECT_CALL(filter(), log_(spdlog::level::info, Eq(":status -> 200"))); EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, - filter_->decodeHeaders(request_headers, false)); + filter().decodeHeaders(request_headers, false)); Http::ResponseMessagePtr response_message(new Http::ResponseMessageImpl( Http::ResponseHeaderMapPtr{new Http::TestResponseHeaderMapImpl{{":status", "200"}}})); @@ -476,12 +476,12 @@ TEST_P(WasmHttpFilterTest, AsyncCallAfterDestroyed) { })); EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, - filter_->decodeHeaders(request_headers, false)); + filter().decodeHeaders(request_headers, false)); EXPECT_CALL(request, cancel()).WillOnce([&]() { callbacks = nullptr; }); // Destroy the Context, Plugin and VM. - filter_.reset(); + context_.reset(); plugin_.reset(); wasm_.reset(); @@ -533,7 +533,7 @@ TEST_P(WasmHttpFilterTest, GrpcCall) { EXPECT_CALL(root_context(), log_(spdlog::level::debug, Eq("response"))); Http::TestRequestHeaderMapImpl request_headers{{":path", "/"}}; EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, - filter_->decodeHeaders(request_headers, false)); + filter().decodeHeaders(request_headers, false)); ProtobufWkt::Value value; value.set_string_value("response"); @@ -584,12 +584,12 @@ TEST_P(WasmHttpFilterTest, GrpcCallAfterDestroyed) { Http::TestRequestHeaderMapImpl request_headers{{":path", "/"}}; EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, - filter_->decodeHeaders(request_headers, false)); + filter().decodeHeaders(request_headers, false)); EXPECT_CALL(request, cancel()).WillOnce([&]() { callbacks = nullptr; }); // Destroy the Context, Plugin and VM. - filter_.reset(); + context_.reset(); plugin_.reset(); wasm_.reset(); @@ -640,13 +640,13 @@ TEST_P(WasmHttpFilterTest, Metadata) { EXPECT_CALL(filter(), log_(spdlog::level::info, Eq(absl::string_view("duration is 15000000")))); EXPECT_CALL(filter(), log_(spdlog::level::info, Eq(absl::string_view("grpc service: test")))); Http::TestRequestHeaderMapImpl request_headers{{":path", "/"}}; - EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter().decodeHeaders(request_headers, true)); Buffer::OwnedImpl data("hello"); - EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data, true)); - filter_->onDestroy(); + EXPECT_EQ(Http::FilterDataStatus::Continue, filter().decodeData(data, true)); + filter().onDestroy(); StreamInfo::MockStreamInfo log_stream_info; - filter_->log(&request_headers, nullptr, nullptr, log_stream_info); + filter().log(&request_headers, nullptr, nullptr, log_stream_info); const auto& result = request_stream_info_.filterState()->getDataReadOnly( "wasm.wasm_request_set_key"); @@ -661,10 +661,10 @@ TEST_F(WasmHttpFilterTest, NullPluginRequestHeadersOnly) { EXPECT_CALL(filter(), log_(spdlog::level::info, Eq(absl::string_view("header path /")))); EXPECT_CALL(filter(), log_(spdlog::level::warn, Eq(absl::string_view("onDone 2")))); Http::TestRequestHeaderMapImpl request_headers{{":path", "/"}, {"server", "envoy"}}; - EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter().decodeHeaders(request_headers, true)); EXPECT_THAT(request_headers.get_("newheader"), Eq("newheadervalue")); EXPECT_THAT(request_headers.get_("server"), Eq("envoy-wasm")); - filter_->onDestroy(); + filter().onDestroy(); } TEST_F(WasmHttpFilterTest, NullVmResolver) { @@ -698,9 +698,9 @@ TEST_F(WasmHttpFilterTest, NullVmResolver) { root_context_->onTick(0); Http::TestRequestHeaderMapImpl request_headers{{":path", "/test_context"}}; - EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter().decodeHeaders(request_headers, true)); StreamInfo::MockStreamInfo log_stream_info; - filter_->log(&request_headers, nullptr, nullptr, log_stream_info); + filter().log(&request_headers, nullptr, nullptr, log_stream_info); } TEST_P(WasmHttpFilterTest, SharedData) { @@ -718,9 +718,9 @@ TEST_P(WasmHttpFilterTest, SharedData) { log_(spdlog::level::debug, Eq(absl::string_view("second get of bad key not found")))); Http::TestRequestHeaderMapImpl request_headers{{":path", "/"}}; - EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter().decodeHeaders(request_headers, true)); StreamInfo::MockStreamInfo log_stream_info; - filter_->log(&request_headers, nullptr, nullptr, log_stream_info); + filter().log(&request_headers, nullptr, nullptr, log_stream_info); } TEST_P(WasmHttpFilterTest, SharedQueue) { @@ -738,7 +738,7 @@ TEST_P(WasmHttpFilterTest, SharedQueue) { EXPECT_CALL(root_context(), log_(spdlog::level::info, Eq(absl::string_view("onQueueReady")))); EXPECT_CALL(root_context(), log_(spdlog::level::debug, Eq(absl::string_view("data data1 Ok")))); Http::TestRequestHeaderMapImpl request_headers{{":path", "/"}}; - EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter().decodeHeaders(request_headers, true)); auto token = proxy_wasm::resolveQueueForTest("vm_id", "my_shared_queue"); wasm_->wasm()->queueReady(root_context_->id(), token); } @@ -749,7 +749,7 @@ TEST_P(WasmHttpFilterTest, RootIdNotRegistered) { "{{ test_rundir }}/test/extensions/filters/http/wasm/test_data/root_id_cpp.wasm"))); setupFilter(); Http::TestRequestHeaderMapImpl request_headers; - EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter().decodeHeaders(request_headers, true)); } // Script using an explicit root_id which is registered. @@ -760,7 +760,7 @@ TEST_P(WasmHttpFilterTest, RootId1) { setupFilter("context1"); EXPECT_CALL(filter(), log_(spdlog::level::debug, Eq(absl::string_view("onRequestHeaders1 2")))); Http::TestRequestHeaderMapImpl request_headers; - EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter().decodeHeaders(request_headers, true)); } // Script using an explicit root_id which is registered. @@ -771,7 +771,7 @@ TEST_P(WasmHttpFilterTest, RootId2) { setupFilter("context2"); EXPECT_CALL(filter(), log_(spdlog::level::debug, Eq(absl::string_view("onRequestHeaders2 2")))); Http::TestRequestHeaderMapImpl request_headers; - EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter().decodeHeaders(request_headers, true)); } } // namespace Wasm diff --git a/test/extensions/filters/network/wasm/wasm_filter_test.cc b/test/extensions/filters/network/wasm/wasm_filter_test.cc index 1987d1cb6a..aad14371c8 100644 --- a/test/extensions/filters/network/wasm/wasm_filter_test.cc +++ b/test/extensions/filters/network/wasm/wasm_filter_test.cc @@ -47,7 +47,7 @@ class WasmNetworkFilterTest void setupFilter() { setupFilterBase(""); } - TestFilter& filter() { return *static_cast(filter_.get()); } + TestFilter& filter() { return *static_cast(context_.get()); } }; INSTANTIATE_TEST_SUITE_P(Runtimes, WasmNetworkFilterTest, @@ -71,19 +71,19 @@ TEST_P(WasmNetworkFilterTest, HappyPath) { setupFilter(); EXPECT_CALL(filter(), log_(spdlog::level::trace, Eq(absl::string_view("onNewConnection 2")))); - EXPECT_EQ(Network::FilterStatus::Continue, filter_->onNewConnection()); + EXPECT_EQ(Network::FilterStatus::Continue, filter().onNewConnection()); Buffer::OwnedImpl fake_downstream_data("Fake"); EXPECT_CALL(filter(), log_(spdlog::level::trace, Eq(absl::string_view("onDownstreamData 2 len=4 end_stream=0\nFake")))); - EXPECT_EQ(Network::FilterStatus::Continue, filter_->onData(fake_downstream_data, false)); + EXPECT_EQ(Network::FilterStatus::Continue, filter().onData(fake_downstream_data, false)); Buffer::OwnedImpl fake_upstream_data("Done"); EXPECT_CALL(filter(), log_(spdlog::level::trace, Eq(absl::string_view("onUpstreamData 2 len=4 end_stream=1\nDone")))); EXPECT_CALL(filter(), log_(spdlog::level::trace, Eq(absl::string_view("onUpstreamConnectionClose 2 0")))); - EXPECT_EQ(Network::FilterStatus::Continue, filter_->onWrite(fake_upstream_data, true)); + EXPECT_EQ(Network::FilterStatus::Continue, filter().onWrite(fake_upstream_data, true)); EXPECT_CALL(filter(), log_(spdlog::level::trace, Eq(absl::string_view("onDownstreamConnectionClose 2 1")))); diff --git a/test/extensions/wasm/wasm_speed_test.cc b/test/extensions/wasm/wasm_speed_test.cc index 510e328966..eb20b29a05 100644 --- a/test/extensions/wasm/wasm_speed_test.cc +++ b/test/extensions/wasm/wasm_speed_test.cc @@ -72,11 +72,11 @@ static void BM_WasmSimpleCallSpeedTest(benchmark::State& state, std::string test } EXPECT_FALSE(code.empty()); EXPECT_TRUE(wasm->initialize(code, false)); - wasm->setContext(root_context); + wasm->setContextForTesting(root_context); wasm->startForTesting(std::unique_ptr(root_context), plugin); EXPECT_NE(wasm, nullptr); for (auto _ : state) { - wasm->tick(root_context->id()); + wasm->timerReady(root_context->id()); } } diff --git a/test/extensions/wasm/wasm_test.cc b/test/extensions/wasm/wasm_test.cc index 6cd9e7fa13..7f0b417105 100644 --- a/test/extensions/wasm/wasm_test.cc +++ b/test/extensions/wasm/wasm_test.cc @@ -113,7 +113,7 @@ TEST_P(WasmTestMatrix, Logging) { EXPECT_CALL(*context, log_(spdlog::level::info, Eq("onDelete logging"))); EXPECT_TRUE(wasm_weak.lock()->initialize(code, false)); - wasm_weak.lock()->setContext(context.get()); + wasm_weak.lock()->setContextForTesting(context.get()); auto root_context = context.get(); wasm_weak.lock()->startForTesting(std::move(context), plugin_); wasm_weak.lock()->configure(root_context, plugin_); @@ -165,7 +165,7 @@ TEST_P(WasmTest, DivByZero) { auto context = std::make_unique(wasm_.get()); EXPECT_CALL(*context, log_(spdlog::level::err, Eq("before div by zero"))); EXPECT_TRUE(wasm_->initialize(code, false)); - wasm_->setContext(context.get()); + wasm_->setContextForTesting(context.get()); if (GetParam() == "v8") { EXPECT_THROW_WITH_MESSAGE( @@ -262,7 +262,7 @@ TEST_P(WasmTest, StatsHigherLevel) { "histogram_bool_tag.true.test_histogram")))); EXPECT_TRUE(wasm_->initialize(code, false)); - wasm_->setContext(context.get()); + wasm_->setContextForTesting(context.get()); context->onTick(0); } @@ -289,7 +289,7 @@ TEST_P(WasmTest, StatsHighLevel) { // Get is not supported on histograms. // EXPECT_CALL(*context, log_(spdlog::level::err, Eq("stack_h = 3"))); EXPECT_TRUE(wasm_->initialize(code, false)); - wasm_->setContext(context.get()); + wasm_->setContextForTesting(context.get()); context->onLog(); } diff --git a/test/test_common/wasm_base.h b/test/test_common/wasm_base.h index e34fa3f541..b0f04cb89d 100644 --- a/test/test_common/wasm_base.h +++ b/test/test_common/wasm_base.h @@ -65,6 +65,7 @@ template class WasmTestBase : public Base { } WasmHandleSharedPtr& wasm() { return wasm_; } + Context* root_context() { return root_context_; } Stats::IsolatedStoreImpl stats_store_; Stats::ScopeSharedPtr scope_; @@ -75,7 +76,6 @@ template class WasmTestBase : public Base { NiceMock init_manager_; WasmHandleSharedPtr wasm_; PluginSharedPtr plugin_; - std::unique_ptr filter_; NiceMock ssl_; NiceMock connection_; NiceMock decoder_callbacks_; @@ -90,15 +90,15 @@ template class WasmTestBase : public Base { template class WasmHttpFilterTestBase : public WasmTestBase { public: template void setupFilterBase(const std::string root_id = "") { - filter_ = std::make_unique( + context_ = std::make_unique( WasmTestBase::wasm_->wasm().get(), WasmTestBase::wasm_->wasm()->getRootContext(root_id)->id(), WasmTestBase::plugin_); - filter_->setDecoderFilterCallbacks(decoder_callbacks_); - filter_->setEncoderFilterCallbacks(encoder_callbacks_); + context_->setDecoderFilterCallbacks(decoder_callbacks_); + context_->setEncoderFilterCallbacks(encoder_callbacks_); } - std::unique_ptr filter_; + std::unique_ptr context_; NiceMock decoder_callbacks_; NiceMock encoder_callbacks_; NiceMock request_stream_info_; @@ -108,14 +108,14 @@ template class WasmNetworkFilterTestBase : public WasmTestBase { public: template void setupFilterBase(const std::string root_id = "") { - filter_ = std::make_unique( + context_ = std::make_unique( WasmTestBase::wasm_->wasm().get(), WasmTestBase::wasm_->wasm()->getRootContext(root_id)->id(), WasmTestBase::plugin_); - filter_->initializeReadFilterCallbacks(read_filter_callbacks_); + context_->initializeReadFilterCallbacks(read_filter_callbacks_); } - std::unique_ptr filter_; + std::unique_ptr context_; NiceMock read_filter_callbacks_; }; From c078e5a90fef01ba5d0e40d1bf67bd3123638e6c Mon Sep 17 00:00:00 2001 From: John Plevyak Date: Thu, 28 May 2020 13:24:01 -0700 Subject: [PATCH 02/16] Fix tests. Signed-off-by: John Plevyak --- bazel/repository_locations.bzl | 6 +-- source/extensions/common/wasm/BUILD | 2 +- source/extensions/common/wasm/context.cc | 9 ++-- source/extensions/common/wasm/ext/BUILD | 20 ++++++-- .../common/wasm/ext/envoy_context.h | 21 -------- .../common/wasm/ext/envoy_null_vm_wasm_api.h | 17 +++++++ .../common/wasm/ext/envoy_proxy_wasm_api.h | 51 ++++++++++++++----- source/extensions/common/wasm/wasm.cc | 2 +- source/extensions/common/wasm/wasm.h | 2 +- source/extensions/common/wasm/wasm_vm.cc | 4 +- test/extensions/common/wasm/BUILD | 1 + test/extensions/common/wasm/test_data/BUILD | 5 +- .../common/wasm/test_data/test_context_cpp.cc | 33 ++---------- test/extensions/common/wasm/wasm_test.cc | 27 +++++++--- 14 files changed, 110 insertions(+), 90 deletions(-) delete mode 100644 source/extensions/common/wasm/ext/envoy_context.h create mode 100644 source/extensions/common/wasm/ext/envoy_null_vm_wasm_api.h diff --git a/bazel/repository_locations.bzl b/bazel/repository_locations.bzl index df2d224840..c0fcb924e0 100644 --- a/bazel/repository_locations.bzl +++ b/bazel/repository_locations.bzl @@ -346,9 +346,9 @@ REPOSITORY_LOCATIONS = dict( urls = ["https://github.com/dpkp/kafka-python/archive/2.0.0.tar.gz"], ), proxy_wasm_cpp_sdk = dict( - sha256 = "19ee6b22c6fb44974a2777493cd00d48388f6331956d951c6bd3a865be56095e", - strip_prefix = "proxy-wasm-cpp-sdk-4ca655cd1af9047a03a82cd9b296a30a8f2a237f", - urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-sdk/archive/4ca655cd1af9047a03a82cd9b296a30a8f2a237f.tar.gz"], + sha256 = "dc94754dd581fd272fbbb21d17c89bae27b0d3403ff9a054a3b5ae8d405d2ba7", + strip_prefix = "proxy-wasm-cpp-sdk-145e796fd60021158119c08854a80ef15359fbd1", + urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-sdk/archive/145e796fd60021158119c08854a80ef15359fbd1.tar.gz"], ), proxy_wasm_cpp_host = dict( sha256 = "8a42287d350ea6493511998b0fe42d2d5f585ff8f31ab432aa394e38586eda73", diff --git a/source/extensions/common/wasm/BUILD b/source/extensions/common/wasm/BUILD index 0a0f9bd841..a4bf1ab991 100644 --- a/source/extensions/common/wasm/BUILD +++ b/source/extensions/common/wasm/BUILD @@ -83,7 +83,7 @@ envoy_cc_library( "//source/common/http:message_lib", "//source/common/http:utility_lib", "//source/common/tracing:http_tracer_lib", - "//source/extensions/common/wasm/ext:envoy_proxy_wasm_api", + "//source/extensions/common/wasm/ext:envoy_null_vm_wasm_api", "//source/extensions/filters/common/expr:context_lib", "@com_google_cel_cpp//eval/eval:field_access", "@com_google_cel_cpp//eval/eval:field_backed_list_impl", diff --git a/source/extensions/common/wasm/context.cc b/source/extensions/common/wasm/context.cc index 39dda135b2..996f9e69ab 100644 --- a/source/extensions/common/wasm/context.cc +++ b/source/extensions/common/wasm/context.cc @@ -172,12 +172,12 @@ void Context::onCloseTCP() { void Context::onResolveDns(uint32_t token, Envoy::Network::DnsResolver::ResolutionStatus status, std::list&& response) { proxy_wasm::DeferAfterCallActions actions(this); - if (!wasm()->on_dns_resolved_) { + if (!wasm()->on_resolve_dns_) { return; } if (status != Network::DnsResolver::ResolutionStatus::Success) { buffer_.set(""); - wasm()->on_dns_resolved_(this, id_, token, 0); + wasm()->on_resolve_dns_(this, id_, token, 0); return; } // buffer format: @@ -191,7 +191,8 @@ void Context::onResolveDns(uint32_t token, Envoy::Network::DnsResolver::Resoluti } auto buffer = std::unique_ptr(new char[s]); char* b = buffer.get(); - memcpy(b, &s, sizeof(uint32_t)); + uint32_t n = response.size(); + memcpy(b, &n, sizeof(uint32_t)); b += sizeof(uint32_t); for (auto& e : response) { uint32_t ttl = e.ttl_.count(); @@ -204,7 +205,7 @@ void Context::onResolveDns(uint32_t token, Envoy::Network::DnsResolver::Resoluti *b++ = 0; }; buffer_.set(std::move(buffer), s); - wasm()->on_dns_resolved_(this, id_, token, s); + wasm()->on_resolve_dns_(this, id_, token, s); } // Native serializer carrying over bit representation from CEL value to the extension diff --git a/source/extensions/common/wasm/ext/BUILD b/source/extensions/common/wasm/ext/BUILD index b9625744c6..0969f3936f 100644 --- a/source/extensions/common/wasm/ext/BUILD +++ b/source/extensions/common/wasm/ext/BUILD @@ -10,18 +10,30 @@ load( envoy_package() envoy_cc_library( - name = "envoy_proxy_wasm_api", + name = "envoy_null_vm_wasm_api", hdrs = [ - "envoy_context.h", + "envoy_null_vm_wasm_api.h", "envoy_proxy_wasm_api.h", ], deps = [ + ":envoy_proxy_wasm_api", "@proxy_wasm_cpp_sdk//:api_lib", "@proxy_wasm_cpp_sdk//:common_lib", ], ) cc_library( - name = "envoy_context", - hdrs = ["envoy_context.h"], + name = "envoy_proxy_wasm_api", + hdrs = ["envoy_proxy_wasm_api.h"], +) + +cc_library( + name = "envoy_proxy_wasm_api_lib", + srcs = ["envoy_proxy_wasm_api.cc"], + tags = ["manual"], + deps = [ + ":envoy_proxy_wasm_api", + "@proxy_wasm_cpp_sdk//:proxy_wasm_intrinsics", + ], + alwayslink = 1, ) diff --git a/source/extensions/common/wasm/ext/envoy_context.h b/source/extensions/common/wasm/ext/envoy_context.h deleted file mode 100644 index 47f40e23b3..0000000000 --- a/source/extensions/common/wasm/ext/envoy_context.h +++ /dev/null @@ -1,21 +0,0 @@ -// NOLINT(namespace-envoy) -#pragma once - -class EnvoyContextBase { -public: - virtual ~EnvoyContextBase() = default; - - virtual void onResolveDns(uint32_t /* token */, uint32_t /* result_size */) {} -}; - -class EnvoyRootContext : public RootContext, public EnvoyContextBase { -public: - EnvoyRootContext(uint32_t id, StringView root_id) : RootContext(id, root_id) {} - ~EnvoyRootContext() override = default; -}; - -class EnvoyContext : public Context, public EnvoyContextBase { -public: - EnvoyContext(uint32_t id, RootContext* root) : Context(id, root) {} - ~EnvoyContext() override = default; -}; diff --git a/source/extensions/common/wasm/ext/envoy_null_vm_wasm_api.h b/source/extensions/common/wasm/ext/envoy_null_vm_wasm_api.h new file mode 100644 index 0000000000..3c16c6f59c --- /dev/null +++ b/source/extensions/common/wasm/ext/envoy_null_vm_wasm_api.h @@ -0,0 +1,17 @@ +// NOLINT(namespace-envoy) +#pragma once + +namespace proxy_wasm { +namespace null_plugin { + +template using Optional = absl::optional; +using StringView = absl::string_view; + +#include "proxy_wasm_enums.h" +#include "proxy_wasm_common.h" +#include "proxy_wasm_enums.h" +#include "proxy_wasm_externs.h" +#include "proxy_wasm_api.h" +#include "extensions/common/wasm/ext/envoy_proxy_wasm_api.h" +} // namespace null_plugin +} // namespace proxy_wasm diff --git a/source/extensions/common/wasm/ext/envoy_proxy_wasm_api.h b/source/extensions/common/wasm/ext/envoy_proxy_wasm_api.h index 4e8caef128..4af705061d 100644 --- a/source/extensions/common/wasm/ext/envoy_proxy_wasm_api.h +++ b/source/extensions/common/wasm/ext/envoy_proxy_wasm_api.h @@ -1,18 +1,45 @@ // NOLINT(namespace-envoy) #pragma once -namespace proxy_wasm { -namespace null_plugin { +class EnvoyContextBase { +public: + virtual ~EnvoyContextBase() = default; -template using Optional = absl::optional; -using StringView = absl::string_view; + virtual void onResolveDns(uint32_t /* token */, uint32_t /* result_size */) {} +}; -#include "proxy_wasm_enums.h" -#include "proxy_wasm_common.h" -#include "proxy_wasm_enums.h" -#include "proxy_wasm_externs.h" -#include "proxy_wasm_api.h" -#include "extensions/common/wasm/ext/envoy_context.h" +class EnvoyRootContext : public RootContext, public EnvoyContextBase { +public: + EnvoyRootContext(uint32_t id, StringView root_id) : RootContext(id, root_id) {} + ~EnvoyRootContext() override = default; +}; -} // namespace null_plugin -} // namespace proxy_wasm +class EnvoyContext : public Context, public EnvoyContextBase { +public: + EnvoyContext(uint32_t id, RootContext* root) : Context(id, root) {} + ~EnvoyContext() override = default; +}; + +struct DnsResult { + uint32_t ttl_seconds; + std::string address; +}; + +inline std::vector parseDnsResults(StringView data) { + if (data.size() < 4) { + return {}; + } + const uint32_t* pn = reinterpret_cast(data.data()); + uint32_t n = *pn++; + std::vector results; + results.resize(n); + const char* pa = data.data() + (1 + n) * sizeof(uint32_t); // skip n + n TTLs + for (uint32_t i = 0; i < n; i++) { + auto& e = results[i]; + e.ttl_seconds = *pn++; + auto alen = strlen(pa); + e.address.assign(pa, alen); + pa += alen + 1; + } + return results; +} diff --git a/source/extensions/common/wasm/wasm.cc b/source/extensions/common/wasm/wasm.cc index 38761a7895..9ab4acf8e5 100644 --- a/source/extensions/common/wasm/wasm.cc +++ b/source/extensions/common/wasm/wasm.cc @@ -202,7 +202,7 @@ void Wasm::registerCallbacks() { void Wasm::getFunctions() { WasmBase::getFunctions(); #define _GET(_fn) wasm_vm_->getFunction("envoy_" #_fn, &_fn##_); - _GET(on_dns_resolved) + _GET(on_resolve_dns) #undef _GET } diff --git a/source/extensions/common/wasm/wasm.h b/source/extensions/common/wasm/wasm.h index 08200d04a4..d7866c2248 100644 --- a/source/extensions/common/wasm/wasm.h +++ b/source/extensions/common/wasm/wasm.h @@ -89,7 +89,7 @@ class Wasm : public WasmBase, Logger::Loggable { void initializeStats(); // Calls into the VM. - proxy_wasm::WasmCallVoid<3> on_dns_resolved_; + proxy_wasm::WasmCallVoid<3> on_resolve_dns_; Stats::ScopeSharedPtr scope_; Upstream::ClusterManager& cluster_manager_; diff --git a/source/extensions/common/wasm/wasm_vm.cc b/source/extensions/common/wasm/wasm_vm.cc index eb2cc913b0..f3778eb727 100644 --- a/source/extensions/common/wasm/wasm_vm.cc +++ b/source/extensions/common/wasm/wasm_vm.cc @@ -3,7 +3,7 @@ #include #include -#include "extensions/common/wasm/ext/envoy_proxy_wasm_api.h" +#include "extensions/common/wasm/ext/envoy_null_vm_wasm_api.h" #include "extensions/common/wasm/context.h" #include "extensions/common/wasm/well_known_names.h" @@ -27,7 +27,7 @@ bool EnvoyWasmVmIntegration::getNullVmFunction(absl::string_view function_name, int number_of_arguments, proxy_wasm::NullPlugin* plugin, void* ptr_to_function_return) { - if (function_name == "envoy_on_dns_resolved" && returns_word == false && + if (function_name == "envoy_on_resolve_dns" && returns_word == false && number_of_arguments == 3) { *reinterpret_cast*>(ptr_to_function_return) = [plugin](ContextBase* context, Word context_id, Word token, Word result_size) { diff --git a/test/extensions/common/wasm/BUILD b/test/extensions/common/wasm/BUILD index 152d3fc360..314664c95a 100644 --- a/test/extensions/common/wasm/BUILD +++ b/test/extensions/common/wasm/BUILD @@ -39,6 +39,7 @@ envoy_cc_test( "//source/common/stats:stats_lib", "//source/extensions/common/crypto:utility_lib", "//source/extensions/common/wasm:wasm_lib", + "//test/extensions/common/wasm/test_data:test_context_cpp_plugin", "//test/extensions/common/wasm/test_data:test_cpp_plugin", "//test/mocks/server:server_mocks", "//test/test_common:environment_lib", diff --git a/test/extensions/common/wasm/test_data/BUILD b/test/extensions/common/wasm/test_data/BUILD index e99d89a69d..37778e5f98 100644 --- a/test/extensions/common/wasm/test_data/BUILD +++ b/test/extensions/common/wasm/test_data/BUILD @@ -48,7 +48,7 @@ envoy_cc_library( "//source/extensions/common/wasm:wasm_hdr", "//source/extensions/common/wasm:wasm_lib", "//source/extensions/common/wasm:well_known_names", - "//source/extensions/common/wasm/ext:envoy_proxy_wasm_api", + "//source/extensions/common/wasm/ext:envoy_null_vm_wasm_api", ], ) @@ -64,8 +64,7 @@ wasm_cc_binary( name = "test_context_cpp.wasm", srcs = ["test_context_cpp.cc"], deps = [ - "//source/extensions/common/wasm/ext:envoy_context", - "@proxy_wasm_cpp_sdk//:proxy_wasm_intrinsics", + "//source/extensions/common/wasm/ext:envoy_proxy_wasm_api_lib", ], ) diff --git a/test/extensions/common/wasm/test_data/test_context_cpp.cc b/test/extensions/common/wasm/test_data/test_context_cpp.cc index 6bf87291e1..233defebe2 100644 --- a/test/extensions/common/wasm/test_data/test_context_cpp.cc +++ b/test/extensions/common/wasm/test_data/test_context_cpp.cc @@ -5,11 +5,11 @@ #ifndef NULL_PLUGIN #include "proxy_wasm_intrinsics.h" -#include "source/extensions/common/wasm/ext/envoy_context.h" +#include "source/extensions/common/wasm/ext/envoy_proxy_wasm_api.h" #else #include "include/proxy-wasm/null_plugin.h" using namespace proxy_wasm::null_plugin; -#include "extensions/common/wasm/ext/envoy_context.h" +#include "extensions/common/wasm/ext/envoy_proxy_wasm_api.h" #endif START_WASM_PLUGIN(CommonWasmTestContextCpp) @@ -19,7 +19,6 @@ class TestContext : public EnvoyContext { explicit TestContext(uint32_t id, RootContext* root) : EnvoyContext(id, root) {} void onResolveDns(uint32_t token, uint32_t results_size) override; - void onDone() override; }; class TestRootContext : public RootContext { @@ -32,41 +31,15 @@ class TestRootContext : public RootContext { static RegisterContextFactory register_TestContext(CONTEXT_FACTORY(TestContext), ROOT_FACTORY(TestRootContext)); -struct DnsResult { - uint32_t ttl_seconds; - std::string address; -}; - -std::vector convertDnsResults(StringView data) { - if (data.size() < 4) { - return {}; - } - const uint32_t* pn = reinterpret_cast(data.data()); - uint32_t n = *pn++; - std::vector results; - results.resize(n); - const char* pa = data.data() + (1 + n) * sizeof(uint32_t); // skip n + n TTLs - for (uint32_t i = 0; i < n; i++) { - auto& e = results[i]; - e.ttl_seconds = *pn++; - auto alen = strlen(pa); - e.address.assign(pa, alen); - pa += alen + 1; - } - return results; -} - void TestContext::onResolveDns(uint32_t token, uint32_t result_size) { logWarn("TestContext::onResolveDns " + std::to_string(token)); auto dns_buffer = getBufferBytes(WasmBufferType::CallData, 0, result_size); - auto dns = convertDnsResults(dns_buffer->view()); + auto dns = parseDnsResults(dns_buffer->view()); for (auto& e : dns) { logInfo("TestContext::onResolveDns dns " + std::to_string(e.ttl_seconds) + " " + e.address); } } -void TestContext::onDone() { logWarn("TestContext::onDone " + std::to_string(id())); } - bool TestRootContext::onDone() { logWarn("TestRootContext::onDone " + std::to_string(id())); return true; diff --git a/test/extensions/common/wasm/wasm_test.cc b/test/extensions/common/wasm/wasm_test.cc index 2bead38b23..beac4c0aba 100644 --- a/test/extensions/common/wasm/wasm_test.cc +++ b/test/extensions/common/wasm/wasm_test.cc @@ -729,11 +729,11 @@ class WasmCommonContextTest WasmCommonContextTest() = default; void setup(const std::string& code, std::string root_id = "") { - setupBase(GetParam(), code, std::make_unique(wasm_->wasm().get(), plugin_), - root_id); + setupBase(GetParam(), code, std::make_unique(), root_id); } void setupContext() { context_ = std::make_unique(wasm_->wasm().get(), root_context_->id(), plugin_); + context_->onCreate(root_context_->id()); } TestContext& root_context() { return *static_cast(root_context_); } @@ -742,6 +742,13 @@ class WasmCommonContextTest std::unique_ptr context_; }; +INSTANTIATE_TEST_SUITE_P(Runtimes, WasmCommonContextTest, + testing::Values("v8", +#if defined(ENVOY_WASM_WAVM) + "wavm", +#endif + "null")); + TEST_P(WasmCommonContextTest, OnDnsResolve) { std::string code; if (GetParam() != "null") { @@ -755,17 +762,21 @@ TEST_P(WasmCommonContextTest, OnDnsResolve) { setup(code); setupContext(); - EXPECT_CALL(context(), log_(spdlog::level::debug, Eq("on_foreign start"))); - EXPECT_CALL(context(), log_(spdlog::level::info, Eq("on_foreign_function 7 13"))); + EXPECT_CALL(context(), log_(spdlog::level::warn, Eq("TestContext::onResolveDns 7"))); + EXPECT_CALL(context(), + log_(spdlog::level::info, Eq("TestContext::onResolveDns dns 1 192.168.1.101:1001"))); + EXPECT_CALL(context(), + log_(spdlog::level::info, Eq("TestContext::onResolveDns dns 2 192.168.1.102:1002"))); + EXPECT_CALL(root_context(), log_(spdlog::level::warn, Eq("TestRootContext::onDone 1"))); uint32_t token = 7; std::list dns_results; dns_results.emplace(dns_results.end(), - std::make_shared("192.168.1.101"), - std::chrono::seconds(101)); + std::make_shared("192.168.1.101", 1001), + std::chrono::seconds(1)); dns_results.emplace(dns_results.end(), - std::make_shared("192.168.1.102"), - std::chrono::seconds(102)); + std::make_shared("192.168.1.102", 1002), + std::chrono::seconds(2)); context_->onResolveDns(token, Envoy::Network::DnsResolver::ResolutionStatus::Success, std::move(dns_results)); } From 346bff24f2ed5c36b678f7a7c16c561aab19fbc1 Mon Sep 17 00:00:00 2001 From: John Plevyak Date: Thu, 28 May 2020 13:57:37 -0700 Subject: [PATCH 03/16] Fix formating. Signed-off-by: John Plevyak --- bazel/repository_locations.bzl | 6 +++--- source/extensions/common/wasm/context.h | 1 - source/extensions/common/wasm/ext/BUILD | 1 - source/extensions/common/wasm/ext/envoy_null_vm_wasm_api.h | 7 ++++++- source/extensions/common/wasm/wasm_vm.cc | 2 +- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/bazel/repository_locations.bzl b/bazel/repository_locations.bzl index c0fcb924e0..f0bd136632 100644 --- a/bazel/repository_locations.bzl +++ b/bazel/repository_locations.bzl @@ -351,9 +351,9 @@ REPOSITORY_LOCATIONS = dict( urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-sdk/archive/145e796fd60021158119c08854a80ef15359fbd1.tar.gz"], ), proxy_wasm_cpp_host = dict( - sha256 = "8a42287d350ea6493511998b0fe42d2d5f585ff8f31ab432aa394e38586eda73", - strip_prefix = "proxy-wasm-cpp-host-938c41d075b2e37933b940917d3ec3505c2b0951", - urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-host/archive/938c41d075b2e37933b940917d3ec3505c2b0951.tar.gz"], + sha256 = "8cfffe0f63b4c14a29390bfbc8192e76c2b3880842a53553b0c5fab6e434db74", + strip_prefix = "proxy-wasm-cpp-host-55cb53d2999a5f33f3dee66957691e1498481441", + urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-host/archive/55cb53d2999a5f33f3dee66957691e1498481441.tar.gz"], ), emscripten_toolchain = dict( sha256 = "4ac0f1f3de8b3f1373d435cd7e58bd94de4146e751f099732167749a229b443b", diff --git a/source/extensions/common/wasm/context.h b/source/extensions/common/wasm/context.h index e0f1f8497e..557ba39a66 100644 --- a/source/extensions/common/wasm/context.h +++ b/source/extensions/common/wasm/context.h @@ -17,7 +17,6 @@ #include "extensions/filters/common/expr/evaluator.h" #include "eval/public/activation.h" - #include "include/proxy-wasm/wasm.h" namespace Envoy { diff --git a/source/extensions/common/wasm/ext/BUILD b/source/extensions/common/wasm/ext/BUILD index 0969f3936f..7e55aee3e0 100644 --- a/source/extensions/common/wasm/ext/BUILD +++ b/source/extensions/common/wasm/ext/BUILD @@ -4,7 +4,6 @@ load( "//bazel:envoy_build_system.bzl", "envoy_cc_library", "envoy_package", - "envoy_proto_library", ) envoy_package() diff --git a/source/extensions/common/wasm/ext/envoy_null_vm_wasm_api.h b/source/extensions/common/wasm/ext/envoy_null_vm_wasm_api.h index 3c16c6f59c..ba55517afc 100644 --- a/source/extensions/common/wasm/ext/envoy_null_vm_wasm_api.h +++ b/source/extensions/common/wasm/ext/envoy_null_vm_wasm_api.h @@ -7,11 +7,16 @@ namespace null_plugin { template using Optional = absl::optional; using StringView = absl::string_view; -#include "proxy_wasm_enums.h" #include "proxy_wasm_common.h" #include "proxy_wasm_enums.h" #include "proxy_wasm_externs.h" + +#define _THE_FOLLOWING_FILE_MUST_COME_AFTER_THOSE_ABOVE_ 1 #include "proxy_wasm_api.h" +#undef _THE_FOLLOWING_FILE_MUST_COME_AFTER_THOSE_ABOVE_ +#define _THE_FOLLOWING_FILE_MUST_COME_AFTER_THOSE_ABOVE_ 1 #include "extensions/common/wasm/ext/envoy_proxy_wasm_api.h" +#undef _THE_FOLLOWING_FILE_MUST_COME_AFTER_THOSE_ABOVE_ + } // namespace null_plugin } // namespace proxy_wasm diff --git a/source/extensions/common/wasm/wasm_vm.cc b/source/extensions/common/wasm/wasm_vm.cc index f3778eb727..12e213f10d 100644 --- a/source/extensions/common/wasm/wasm_vm.cc +++ b/source/extensions/common/wasm/wasm_vm.cc @@ -3,8 +3,8 @@ #include #include -#include "extensions/common/wasm/ext/envoy_null_vm_wasm_api.h" #include "extensions/common/wasm/context.h" +#include "extensions/common/wasm/ext/envoy_null_vm_wasm_api.h" #include "extensions/common/wasm/well_known_names.h" #include "include/proxy-wasm/null.h" From b1553f449a9a3b36424492330bded098cf419efa Mon Sep 17 00:00:00 2001 From: John Plevyak Date: Thu, 28 May 2020 14:15:19 -0700 Subject: [PATCH 04/16] Add comments. Signed-off-by: John Plevyak --- .../common/wasm/ext/envoy_null_vm_wasm_api.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/source/extensions/common/wasm/ext/envoy_null_vm_wasm_api.h b/source/extensions/common/wasm/ext/envoy_null_vm_wasm_api.h index ba55517afc..e966f9fb9e 100644 --- a/source/extensions/common/wasm/ext/envoy_null_vm_wasm_api.h +++ b/source/extensions/common/wasm/ext/envoy_null_vm_wasm_api.h @@ -11,12 +11,17 @@ using StringView = absl::string_view; #include "proxy_wasm_enums.h" #include "proxy_wasm_externs.h" -#define _THE_FOLLOWING_FILE_MUST_COME_AFTER_THOSE_ABOVE_ 1 +/* + * The following headers are used in two different environments, in the Null VM and in Wasm code + * which require different headers to preceed these such that they can not include the above + * headers directly. These macros prevent header reordering + */ +#define _THE_FOLLOWING_INCLUDE_MUST_COME_AFTER_THOSE_ABOVE_ 1 #include "proxy_wasm_api.h" -#undef _THE_FOLLOWING_FILE_MUST_COME_AFTER_THOSE_ABOVE_ -#define _THE_FOLLOWING_FILE_MUST_COME_AFTER_THOSE_ABOVE_ 1 +#undef _THE_FOLLOWING_INCLUDE_MUST_COME_AFTER_THOSE_ABOVE_ +#define _THE_FOLLOWING_INCLUDE_MUST_COME_AFTER_THOSE_ABOVE_ 1 #include "extensions/common/wasm/ext/envoy_proxy_wasm_api.h" -#undef _THE_FOLLOWING_FILE_MUST_COME_AFTER_THOSE_ABOVE_ +#undef _THE_FOLLOWING_INCLUDE_MUST_COME_AFTER_THOSE_ABOVE_ } // namespace null_plugin } // namespace proxy_wasm From 2a7c6d1c25a53c933506458310831ffea2dd3951 Mon Sep 17 00:00:00 2001 From: John Plevyak Date: Thu, 28 May 2020 15:47:37 -0700 Subject: [PATCH 05/16] Add missing file. Signed-off-by: John Plevyak --- .../common/wasm/ext/envoy_proxy_wasm_api.cc | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 source/extensions/common/wasm/ext/envoy_proxy_wasm_api.cc diff --git a/source/extensions/common/wasm/ext/envoy_proxy_wasm_api.cc b/source/extensions/common/wasm/ext/envoy_proxy_wasm_api.cc new file mode 100644 index 0000000000..a0fcbb80bf --- /dev/null +++ b/source/extensions/common/wasm/ext/envoy_proxy_wasm_api.cc @@ -0,0 +1,35 @@ +// NOLINT(namespace-envoy) + +#include "proxy_wasm_intrinsics.h" + +/* + * These headers span repositories and therefor the following header can not include the above + * header to enforce the required order. This macros prevent header reordering. + */ +#define _THE_FOLLOWING_INCLUDE_MUST_COME_AFTER_THOSE_ABOVE_ 1 +#include "source/extensions/common/wasm/ext/envoy_proxy_wasm_api.h" +#undef _THE_FOLLOWING_INCLUDE_MUST_COME_AFTER_THOSE_ABOVE_ + +EnvoyContextBase* getEnvoyContextBase(uint32_t context_id) { + auto context_base = getContextBase(context_id); + if (auto root = context_base->asRoot()) { + return static_cast(static_cast(root)); + } else { + return static_cast(static_cast(context_base->asContext())); + } +} + +EnvoyContext* getEnvoyContext(uint32_t context_id) { + auto context_base = getContextBase(context_id); + return static_cast(context_base->asContext()); +} + +EnvoyRootContext* getEnvoyRootContext(uint32_t context_id) { + auto context_base = getContextBase(context_id); + return static_cast(context_base->asRoot()); +} + +extern "C" PROXY_WASM_KEEPALIVE void envoy_on_resolve_dns(uint32_t context_id, uint32_t token, + uint32_t data_size) { + getEnvoyContextBase(context_id)->onResolveDns(token, data_size); +} From 7dd6e9241b847fe951bc3cfd6bf20280156539f2 Mon Sep 17 00:00:00 2001 From: John Plevyak Date: Sun, 31 May 2020 20:59:22 -0700 Subject: [PATCH 06/16] Format. Signed-off-by: John Plevyak --- source/extensions/common/wasm/ext/envoy_null_vm_wasm_api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/extensions/common/wasm/ext/envoy_null_vm_wasm_api.h b/source/extensions/common/wasm/ext/envoy_null_vm_wasm_api.h index e966f9fb9e..a4cbed7544 100644 --- a/source/extensions/common/wasm/ext/envoy_null_vm_wasm_api.h +++ b/source/extensions/common/wasm/ext/envoy_null_vm_wasm_api.h @@ -13,7 +13,7 @@ using StringView = absl::string_view; /* * The following headers are used in two different environments, in the Null VM and in Wasm code - * which require different headers to preceed these such that they can not include the above + * which require different headers to precede these such that they can not include the above * headers directly. These macros prevent header reordering */ #define _THE_FOLLOWING_INCLUDE_MUST_COME_AFTER_THOSE_ABOVE_ 1 From 54132ca67f1e76f5a56a71441cf84708f0acd664 Mon Sep 17 00:00:00 2001 From: John Plevyak Date: Mon, 1 Jun 2020 11:13:52 -0700 Subject: [PATCH 07/16] Update test. Signed-off-by: John Plevyak --- test/extensions/common/wasm/test_data/test_context_cpp.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/extensions/common/wasm/test_data/test_context_cpp.cc b/test/extensions/common/wasm/test_data/test_context_cpp.cc index 233defebe2..e531a7974f 100644 --- a/test/extensions/common/wasm/test_data/test_context_cpp.cc +++ b/test/extensions/common/wasm/test_data/test_context_cpp.cc @@ -21,9 +21,9 @@ class TestContext : public EnvoyContext { void onResolveDns(uint32_t token, uint32_t results_size) override; }; -class TestRootContext : public RootContext { +class TestRootContext : public EnvoyRootContext { public: - explicit TestRootContext(uint32_t id, StringView root_id) : RootContext(id, root_id) {} + explicit TestRootContext(uint32_t id, StringView root_id) : EnvoyRootContext(id, root_id) {} bool onDone() override; }; From 055f674f4d3b45a2b0dbf5bb2bfbcd0560aef9ec Mon Sep 17 00:00:00 2001 From: John Plevyak Date: Mon, 1 Jun 2020 13:50:25 -0700 Subject: [PATCH 08/16] Fix asan. Signed-off-by: John Plevyak --- source/extensions/common/wasm/ext/BUILD | 10 ++++++---- source/extensions/common/wasm/ext/envoy_null_plugin.h | 11 +++++++++++ test/extensions/common/wasm/test_data/BUILD | 2 +- .../common/wasm/test_data/test_context_cpp.cc | 4 +--- 4 files changed, 19 insertions(+), 8 deletions(-) create mode 100644 source/extensions/common/wasm/ext/envoy_null_plugin.h diff --git a/source/extensions/common/wasm/ext/BUILD b/source/extensions/common/wasm/ext/BUILD index 7e55aee3e0..8c1d16dd34 100644 --- a/source/extensions/common/wasm/ext/BUILD +++ b/source/extensions/common/wasm/ext/BUILD @@ -15,23 +15,25 @@ envoy_cc_library( "envoy_proxy_wasm_api.h", ], deps = [ - ":envoy_proxy_wasm_api", "@proxy_wasm_cpp_sdk//:api_lib", "@proxy_wasm_cpp_sdk//:common_lib", ], ) cc_library( - name = "envoy_proxy_wasm_api", - hdrs = ["envoy_proxy_wasm_api.h"], + name = "envoy_null_plugin", + hdrs = [ + "envoy_null_plugin.h", + "envoy_proxy_wasm_api.h", + ], ) cc_library( name = "envoy_proxy_wasm_api_lib", srcs = ["envoy_proxy_wasm_api.cc"], + hdrs = ["envoy_proxy_wasm_api.h"], tags = ["manual"], deps = [ - ":envoy_proxy_wasm_api", "@proxy_wasm_cpp_sdk//:proxy_wasm_intrinsics", ], alwayslink = 1, diff --git a/source/extensions/common/wasm/ext/envoy_null_plugin.h b/source/extensions/common/wasm/ext/envoy_null_plugin.h new file mode 100644 index 0000000000..22f013ea01 --- /dev/null +++ b/source/extensions/common/wasm/ext/envoy_null_plugin.h @@ -0,0 +1,11 @@ +// NOLINT(namespace-envoy) +#pragma once + +#include "include/proxy-wasm/null_plugin.h" + +namespace proxy_wasm { +namespace null_plugin { +#include "source/extensions/common/wasm/ext/envoy_proxy_wasm_api.h" +} // namespace null_plugin +} // namespace proxy_wasm +using namespace proxy_wasm::null_plugin; diff --git a/test/extensions/common/wasm/test_data/BUILD b/test/extensions/common/wasm/test_data/BUILD index 37778e5f98..7b5dd6f129 100644 --- a/test/extensions/common/wasm/test_data/BUILD +++ b/test/extensions/common/wasm/test_data/BUILD @@ -48,7 +48,7 @@ envoy_cc_library( "//source/extensions/common/wasm:wasm_hdr", "//source/extensions/common/wasm:wasm_lib", "//source/extensions/common/wasm:well_known_names", - "//source/extensions/common/wasm/ext:envoy_null_vm_wasm_api", + "//source/extensions/common/wasm/ext:envoy_null_plugin", ], ) diff --git a/test/extensions/common/wasm/test_data/test_context_cpp.cc b/test/extensions/common/wasm/test_data/test_context_cpp.cc index e531a7974f..26ad559df7 100644 --- a/test/extensions/common/wasm/test_data/test_context_cpp.cc +++ b/test/extensions/common/wasm/test_data/test_context_cpp.cc @@ -7,9 +7,7 @@ #include "proxy_wasm_intrinsics.h" #include "source/extensions/common/wasm/ext/envoy_proxy_wasm_api.h" #else -#include "include/proxy-wasm/null_plugin.h" -using namespace proxy_wasm::null_plugin; -#include "extensions/common/wasm/ext/envoy_proxy_wasm_api.h" +#include "source/extensions/common/wasm/ext/envoy_null_plugin.h" #endif START_WASM_PLUGIN(CommonWasmTestContextCpp) From 19c7be8c415a44a2ec1fe1b65ce4e90ad1203ad5 Mon Sep 17 00:00:00 2001 From: John Plevyak Date: Tue, 2 Jun 2020 22:52:37 -0700 Subject: [PATCH 09/16] s/cc_library/envoy_cc_library/ Signed-off-by: John Plevyak --- source/extensions/common/wasm/ext/BUILD | 2 +- source/extensions/common/wasm/ext/envoy_null_plugin.h | 2 +- test/extensions/common/wasm/test_data/test_context_cpp.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source/extensions/common/wasm/ext/BUILD b/source/extensions/common/wasm/ext/BUILD index 8c1d16dd34..261042593f 100644 --- a/source/extensions/common/wasm/ext/BUILD +++ b/source/extensions/common/wasm/ext/BUILD @@ -20,7 +20,7 @@ envoy_cc_library( ], ) -cc_library( +envoy_cc_library( name = "envoy_null_plugin", hdrs = [ "envoy_null_plugin.h", diff --git a/source/extensions/common/wasm/ext/envoy_null_plugin.h b/source/extensions/common/wasm/ext/envoy_null_plugin.h index 22f013ea01..48f05d777a 100644 --- a/source/extensions/common/wasm/ext/envoy_null_plugin.h +++ b/source/extensions/common/wasm/ext/envoy_null_plugin.h @@ -5,7 +5,7 @@ namespace proxy_wasm { namespace null_plugin { -#include "source/extensions/common/wasm/ext/envoy_proxy_wasm_api.h" +#include "extensions/common/wasm/ext/envoy_proxy_wasm_api.h" } // namespace null_plugin } // namespace proxy_wasm using namespace proxy_wasm::null_plugin; diff --git a/test/extensions/common/wasm/test_data/test_context_cpp.cc b/test/extensions/common/wasm/test_data/test_context_cpp.cc index 26ad559df7..3079c4f716 100644 --- a/test/extensions/common/wasm/test_data/test_context_cpp.cc +++ b/test/extensions/common/wasm/test_data/test_context_cpp.cc @@ -7,7 +7,7 @@ #include "proxy_wasm_intrinsics.h" #include "source/extensions/common/wasm/ext/envoy_proxy_wasm_api.h" #else -#include "source/extensions/common/wasm/ext/envoy_null_plugin.h" +#include "extensions/common/wasm/ext/envoy_null_plugin.h" #endif START_WASM_PLUGIN(CommonWasmTestContextCpp) From 2c73954f69369e0a3afaf2a1e4f93a946dda157a Mon Sep 17 00:00:00 2001 From: John Plevyak Date: Wed, 3 Jun 2020 15:28:21 -0700 Subject: [PATCH 10/16] Update SDK. Signed-off-by: John Plevyak --- bazel/repository_locations.bzl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bazel/repository_locations.bzl b/bazel/repository_locations.bzl index f0bd136632..a486221b21 100644 --- a/bazel/repository_locations.bzl +++ b/bazel/repository_locations.bzl @@ -346,9 +346,9 @@ REPOSITORY_LOCATIONS = dict( urls = ["https://github.com/dpkp/kafka-python/archive/2.0.0.tar.gz"], ), proxy_wasm_cpp_sdk = dict( - sha256 = "dc94754dd581fd272fbbb21d17c89bae27b0d3403ff9a054a3b5ae8d405d2ba7", - strip_prefix = "proxy-wasm-cpp-sdk-145e796fd60021158119c08854a80ef15359fbd1", - urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-sdk/archive/145e796fd60021158119c08854a80ef15359fbd1.tar.gz"], + sha256 = "9ba21add517a8407f8f5247856f3964b86aac3baed083ee9eece1d7d286378f9", + strip_prefix = "proxy-wasm-cpp-sdk-5669dfad87f43146ce5ca3bf80a63a87c5d36a53", + urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-sdk/archive/5669dfad87f43146ce5ca3bf80a63a87c5d36a53.tar.gz"], ), proxy_wasm_cpp_host = dict( sha256 = "8cfffe0f63b4c14a29390bfbc8192e76c2b3880842a53553b0c5fab6e434db74", From 3f81739cea4b56abd73b96b19be56bf4cf6f30bb Mon Sep 17 00:00:00 2001 From: John Plevyak Date: Thu, 4 Jun 2020 10:04:28 -0700 Subject: [PATCH 11/16] Switch Wasm coverage fix. Signed-off-by: John Plevyak --- bazel/repository_locations.bzl | 12 ++++++------ bazel/wasm/wasm.bzl | 2 ++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/bazel/repository_locations.bzl b/bazel/repository_locations.bzl index 1503beb75b..91d2461b71 100644 --- a/bazel/repository_locations.bzl +++ b/bazel/repository_locations.bzl @@ -346,14 +346,14 @@ REPOSITORY_LOCATIONS = dict( urls = ["https://github.com/dpkp/kafka-python/archive/2.0.0.tar.gz"], ), proxy_wasm_cpp_sdk = dict( - sha256 = "701150a9396f81623061fda4d9fa919523166d6d8613dbe44b6ac155bd1f9e97", - strip_prefix = "proxy-wasm-cpp-sdk-e93a4988b90d726bcbe174301cc2607f95b46f25", - urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-sdk/archive/e93a4988b90d726bcbe174301cc2607f95b46f25.tar.gz"], + sha256 = "0e5b0d3c17c0737e5b48408bda6060a4057f7508a38afa8e0174ad410d370a6f", + strip_prefix = "proxy-wasm-cpp-sdk-f750d1f5da6a2f20cc55da75dd9772b7ba1650ca", + urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-sdk/archive/f750d1f5da6a2f20cc55da75dd9772b7ba1650ca.tar.gz"], ), proxy_wasm_cpp_host = dict( - sha256 = "010bc0238dcb87b1f790b3512c245a37c524f3b97d6810cec79f9376cfbf1241", - strip_prefix = "proxy-wasm-cpp-host-8cc8602d51d85553b0b6a901315a46cd3f4ef787", - urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-host/archive/8cc8602d51d85553b0b6a901315a46cd3f4ef787.tar.gz"], + sha256 = "59cef796d482198ae22158060c081109927127ef9c1abb8afea6a6f6dff8d6df", + strip_prefix = "proxy-wasm-cpp-host-303a5c0a938a708ac6a7913e5d97d2f5d72f6da8", + urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-host/archive/303a5c0a938a708ac6a7913e5d97d2f5d72f6da8.tar.gz"], ), emscripten_toolchain = dict( sha256 = "4ac0f1f3de8b3f1373d435cd7e58bd94de4146e751f099732167749a229b443b", diff --git a/bazel/wasm/wasm.bzl b/bazel/wasm/wasm.bzl index 1a7718d6e7..426cf56e87 100644 --- a/bazel/wasm/wasm.bzl +++ b/bazel/wasm/wasm.bzl @@ -8,6 +8,7 @@ def _wasm_transition_impl(settings, attr): "//command_line_option:copt": [], "//command_line_option:cxxopt": [], "//command_line_option:linkopt": [], + "//command_line_option:collect_code_coverage": "false", } wasm_transition = transition( @@ -19,6 +20,7 @@ wasm_transition = transition( "//command_line_option:copt", "//command_line_option:cxxopt", "//command_line_option:linkopt", + "//command_line_option:collect_code_coverage", ], ) From 6c0803234dbed5d37fb7df74898609d7ee0aca03 Mon Sep 17 00:00:00 2001 From: John Plevyak Date: Fri, 5 Jun 2020 12:37:08 -0700 Subject: [PATCH 12/16] Update tests. Signed-off-by: John Plevyak --- bazel/repository_locations.bzl | 6 ++-- source/extensions/common/wasm/context.cc | 27 ++++++++++++++++++ source/extensions/common/wasm/context.h | 1 + .../common/wasm/test_data/test_cpp.cc | 2 ++ test/extensions/wasm/test_data/logging_cpp.cc | 2 ++ .../wasm/test_data/logging_rust.wasm | Bin 360234 -> 360056 bytes .../wasm/test_data/logging_rust/src/lib.rs | 15 ++++++---- 7 files changed, 44 insertions(+), 9 deletions(-) diff --git a/bazel/repository_locations.bzl b/bazel/repository_locations.bzl index 91d2461b71..f7036d2415 100644 --- a/bazel/repository_locations.bzl +++ b/bazel/repository_locations.bzl @@ -351,9 +351,9 @@ REPOSITORY_LOCATIONS = dict( urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-sdk/archive/f750d1f5da6a2f20cc55da75dd9772b7ba1650ca.tar.gz"], ), proxy_wasm_cpp_host = dict( - sha256 = "59cef796d482198ae22158060c081109927127ef9c1abb8afea6a6f6dff8d6df", - strip_prefix = "proxy-wasm-cpp-host-303a5c0a938a708ac6a7913e5d97d2f5d72f6da8", - urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-host/archive/303a5c0a938a708ac6a7913e5d97d2f5d72f6da8.tar.gz"], + sha256 = "d40eb35527b2f1f97231f617674090ae85df4ed4824e5fef2cb7001575dbe221", + strip_prefix = "proxy-wasm-cpp-host-83b3009ed32577c2d35306cde6e7557df3e693b9", + urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-host/archive/83b3009ed32577c2d35306cde6e7557df3e693b9.tar.gz"], ), emscripten_toolchain = dict( sha256 = "4ac0f1f3de8b3f1373d435cd7e58bd94de4146e751f099732167749a229b443b", diff --git a/source/extensions/common/wasm/context.cc b/source/extensions/common/wasm/context.cc index f01f324f99..d5adf82305 100644 --- a/source/extensions/common/wasm/context.cc +++ b/source/extensions/common/wasm/context.cc @@ -1222,6 +1222,7 @@ Http::FilterDataStatus convertFilterDataStatus(proxy_wasm::FilterDataStatus stat }; Network::FilterStatus Context::onNewConnection() { + onCreate(id_); return convertNetworkFilterStatus(onNetworkNewConnection()); }; @@ -1276,6 +1277,9 @@ void Context::log(const Http::RequestHeaderMap* request_headers, const Http::ResponseHeaderMap* response_headers, const Http::ResponseTrailerMap* response_trailers, const StreamInfo::StreamInfo& stream_info) { + if (!http_request_started_) { + return; + } access_log_request_headers_ = request_headers; // ? request_trailers ? access_log_response_headers_ = response_headers; @@ -1341,6 +1345,8 @@ WasmResult Context::sendLocalResponse(uint32_t response_code, absl::string_view } Http::FilterHeadersStatus Context::decodeHeaders(Http::RequestHeaderMap& headers, bool end_stream) { + onCreate(id_); + http_request_started_ = true; request_headers_ = &headers; end_of_stream_ = end_stream; auto result = convertFilterHeadersStatus(onRequestHeaders(headerSize(&headers), end_stream)); @@ -1351,6 +1357,9 @@ Http::FilterHeadersStatus Context::decodeHeaders(Http::RequestHeaderMap& headers } Http::FilterDataStatus Context::decodeData(::Envoy::Buffer::Instance& data, bool end_stream) { + if (!http_request_started_) { + return Http::FilterDataStatus::Continue; + } request_body_buffer_ = &data; end_of_stream_ = end_stream; auto result = convertFilterDataStatus(onRequestBody(data.length(), end_stream)); @@ -1370,6 +1379,9 @@ Http::FilterDataStatus Context::decodeData(::Envoy::Buffer::Instance& data, bool } Http::FilterTrailersStatus Context::decodeTrailers(Http::RequestTrailerMap& trailers) { + if (!http_request_started_) { + return Http::FilterTrailersStatus::Continue; + } request_trailers_ = &trailers; auto result = convertFilterTrailersStatus(onRequestTrailers(headerSize(&trailers))); if (result == Http::FilterTrailersStatus::Continue) { @@ -1379,6 +1391,9 @@ Http::FilterTrailersStatus Context::decodeTrailers(Http::RequestTrailerMap& trai } Http::FilterMetadataStatus Context::decodeMetadata(Http::MetadataMap& request_metadata) { + if (!http_request_started_) { + return Http::FilterMetadataStatus::Continue; + } request_metadata_ = &request_metadata; auto result = convertFilterMetadataStatus(onRequestMetadata(headerSize(&request_metadata))); if (result == Http::FilterMetadataStatus::Continue) { @@ -1397,6 +1412,9 @@ Http::FilterHeadersStatus Context::encode100ContinueHeaders(Http::ResponseHeader Http::FilterHeadersStatus Context::encodeHeaders(Http::ResponseHeaderMap& headers, bool end_stream) { + if (!http_request_started_) { + return Http::FilterHeadersStatus::Continue; + } response_headers_ = &headers; end_of_stream_ = end_stream; auto result = convertFilterHeadersStatus(onResponseHeaders(headerSize(&headers), end_stream)); @@ -1407,6 +1425,9 @@ Http::FilterHeadersStatus Context::encodeHeaders(Http::ResponseHeaderMap& header } Http::FilterDataStatus Context::encodeData(::Envoy::Buffer::Instance& data, bool end_stream) { + if (!http_request_started_) { + return Http::FilterDataStatus::Continue; + } response_body_buffer_ = &data; end_of_stream_ = end_stream; auto result = convertFilterDataStatus(onResponseBody(data.length(), end_stream)); @@ -1426,6 +1447,9 @@ Http::FilterDataStatus Context::encodeData(::Envoy::Buffer::Instance& data, bool } Http::FilterTrailersStatus Context::encodeTrailers(Http::ResponseTrailerMap& trailers) { + if (!http_request_started_) { + return Http::FilterTrailersStatus::Continue; + } response_trailers_ = &trailers; auto result = convertFilterTrailersStatus(onResponseTrailers(headerSize(&trailers))); if (result == Http::FilterTrailersStatus::Continue) { @@ -1435,6 +1459,9 @@ Http::FilterTrailersStatus Context::encodeTrailers(Http::ResponseTrailerMap& tra } Http::FilterMetadataStatus Context::encodeMetadata(Http::MetadataMap& response_metadata) { + if (!http_request_started_) { + return Http::FilterMetadataStatus::Continue; + } response_metadata_ = &response_metadata; auto result = convertFilterMetadataStatus(onResponseMetadata(headerSize(&response_metadata))); if (result == Http::FilterMetadataStatus::Continue) { diff --git a/source/extensions/common/wasm/context.h b/source/extensions/common/wasm/context.h index 557ba39a66..1743916915 100644 --- a/source/extensions/common/wasm/context.h +++ b/source/extensions/common/wasm/context.h @@ -415,6 +415,7 @@ class Context : public proxy_wasm::ContextBase, ::Envoy::Buffer::Instance* network_upstream_data_buffer_{}; // HTTP filter state. + bool http_request_started_ = false; // When decodeHeaders() is called the rquest is "started". Http::RequestHeaderMap* request_headers_{}; Http::ResponseHeaderMap* response_headers_{}; ::Envoy::Buffer::Instance* request_body_buffer_{}; diff --git a/test/extensions/common/wasm/test_data/test_cpp.cc b/test/extensions/common/wasm/test_data/test_cpp.cc index b03f8494cb..f5ddc3e8d4 100644 --- a/test/extensions/common/wasm/test_data/test_cpp.cc +++ b/test/extensions/common/wasm/test_data/test_cpp.cc @@ -37,6 +37,8 @@ static float gInfinity = INFINITY; abort(); \ } while (0) +WASM_EXPORT(void, proxy_on_context_create, (uint32_t, uint32_t)) {} + WASM_EXPORT(uint32_t, proxy_on_vm_start, (uint32_t context_id, uint32_t configuration_size)) { const char* configuration_ptr = nullptr; size_t size; diff --git a/test/extensions/wasm/test_data/logging_cpp.cc b/test/extensions/wasm/test_data/logging_cpp.cc index c1d88f3a16..07404ada13 100644 --- a/test/extensions/wasm/test_data/logging_cpp.cc +++ b/test/extensions/wasm/test_data/logging_cpp.cc @@ -16,6 +16,8 @@ extern "C" PROXY_WASM_KEEPALIVE uint32_t proxy_on_configure(uint32_t, uint32_t c return 1; } +extern "C" PROXY_WASM_KEEPALIVE void proxy_on_context_create(uint32_t, uint32_t) {} + extern "C" PROXY_WASM_KEEPALIVE uint32_t proxy_on_vm_start(uint32_t, uint32_t) { logTrace("test trace logging"); logDebug("test debug logging"); diff --git a/test/extensions/wasm/test_data/logging_rust.wasm b/test/extensions/wasm/test_data/logging_rust.wasm index 978aaeee629fc676438f6eaf9f1802e473ec46dc..66aecd98c545f44acbc519a8f70e1446f9dd7280 100755 GIT binary patch delta 48106 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 diff --git a/test/extensions/wasm/test_data/logging_rust/src/lib.rs b/test/extensions/wasm/test_data/logging_rust/src/lib.rs index 296d4fae60..ec0505db1c 100644 --- a/test/extensions/wasm/test_data/logging_rust/src/lib.rs +++ b/test/extensions/wasm/test_data/logging_rust/src/lib.rs @@ -9,17 +9,20 @@ pub fn proxy_abi_version_0_1_0() {} use log::{debug, error, info, trace, warn}; extern "C" { - fn proxy_done() -> u32; + fn proxy_done() -> u32; } #[no_mangle] -pub fn proxy_on_configure(_context_id : u32, _plugin_configuration_size: u32) -> u32 { +pub fn proxy_on_configure(_context_id: u32, _plugin_configuration_size: u32) -> u32 { warn!("warn configure-test"); 1 } #[no_mangle] -pub fn proxy_on_vm_start(_context_id : u32, _vm_configuration_size : u32) -> u32 { +pub fn proxy_on_context_create(_context_id: u32, _parent_context_id_: u32) {} + +#[no_mangle] +pub fn proxy_on_vm_start(_context_id: u32, _vm_configuration_size: u32) -> u32 { trace!("test trace logging"); debug!("test debug logging"); error!("test error logging"); @@ -27,7 +30,7 @@ pub fn proxy_on_vm_start(_context_id : u32, _vm_configuration_size : u32) -> u32 } #[no_mangle] -pub fn proxy_on_tick(_context_id : u32) { +pub fn proxy_on_tick(_context_id: u32) { info!("test tick logging"); unsafe { proxy_done(); @@ -35,12 +38,12 @@ pub fn proxy_on_tick(_context_id : u32) { } #[no_mangle] -pub fn proxy_on_done(_context_id : u32) -> u32 { +pub fn proxy_on_done(_context_id: u32) -> u32 { info!("onDone logging"); 0 } #[no_mangle] -pub fn proxy_on_delete(_context_id : u32) { +pub fn proxy_on_delete(_context_id: u32) { info!("onDelete logging"); } From 87cd432ee6d117499afba7f5a7c25a5c299715bb Mon Sep 17 00:00:00 2001 From: John Plevyak Date: Mon, 8 Jun 2020 10:40:45 -0700 Subject: [PATCH 13/16] Format. Signed-off-by: John Plevyak --- bazel/repository_locations.bzl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/bazel/repository_locations.bzl b/bazel/repository_locations.bzl index 9f6c28ce5b..535a56b4be 100644 --- a/bazel/repository_locations.bzl +++ b/bazel/repository_locations.bzl @@ -498,16 +498,16 @@ DEPENDENCY_REPOSITORIES = dict( use_category = ["test"], ), proxy_wasm_cpp_sdk = dict( - sha256 = "0e5b0d3c17c0737e5b48408bda6060a4057f7508a38afa8e0174ad410d370a6f", - strip_prefix = "proxy-wasm-cpp-sdk-f750d1f5da6a2f20cc55da75dd9772b7ba1650ca", - urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-sdk/archive/f750d1f5da6a2f20cc55da75dd9772b7ba1650ca.tar.gz"], + sha256 = "f3f6d10243aa42c6ade5a5e46adead3a3ff38efeffce6c4fd17ca0a9fe441222", + strip_prefix = "proxy-wasm-cpp-sdk-246314dc6cf6faee4ade26d614ecbf98f6036e3c", + urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-sdk/archive/246314dc6cf6faee4ade26d614ecbf98f6036e3c.tar.gz"], use_category = ["dataplane"], cpe = "N/A", ), proxy_wasm_cpp_host = dict( - sha256 = "43cdadab1774264c993ba6e5287ded493aaf06aeb92eabca69c797121593ce19", - strip_prefix = "proxy-wasm-cpp-host-ddeac9838741238adc8b300fea1ed52c4d4ce7c0", - urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-host/archive/ddeac9838741238adc8b300fea1ed52c4d4ce7c0.tar.gz"], + sha256 = "1087dafbd2a4bcf3727425c6a2daad20bce3000a7768e9cc354e3e794ef29687", + strip_prefix = "proxy-wasm-cpp-host-f8fab0f8cce39dde336a5e9e78dde61005f56129", + urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-host/archive/f8fab0f8cce39dde336a5e9e78dde61005f56129.tar.gz"], use_category = ["dataplane"], cpe = "N/A", ), From d7f36ac89dd244d37f2f89ddcbab9a4a018f782a Mon Sep 17 00:00:00 2001 From: John Plevyak Date: Mon, 8 Jun 2020 10:42:11 -0700 Subject: [PATCH 14/16] Fix formatting. Signed-off-by: John Plevyak --- source/extensions/common/wasm/ext/BUILD | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/extensions/common/wasm/ext/BUILD b/source/extensions/common/wasm/ext/BUILD index 261042593f..e9134f43cb 100644 --- a/source/extensions/common/wasm/ext/BUILD +++ b/source/extensions/common/wasm/ext/BUILD @@ -1,11 +1,12 @@ -licenses(["notice"]) # Apache 2 - +load("@rules_cc//cc:defs.bzl", "cc_library") load( "//bazel:envoy_build_system.bzl", "envoy_cc_library", "envoy_package", ) +licenses(["notice"]) # Apache 2 + envoy_package() envoy_cc_library( From 9a88f25d2f91be21f59b5277dc435d9aa3a33fc7 Mon Sep 17 00:00:00 2001 From: John Plevyak Date: Fri, 12 Jun 2020 16:59:32 -0700 Subject: [PATCH 15/16] Fix sig mismatch trap. Signed-off-by: John Plevyak --- bazel/external/wee8.genrule_cmd | 2 ++ bazel/repository_locations.bzl | 6 +++--- source/extensions/common/wasm/context.cc | 4 ++-- test/extensions/common/wasm/wasm_test.cc | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/bazel/external/wee8.genrule_cmd b/bazel/external/wee8.genrule_cmd index 02ce523366..a254216e26 100644 --- a/bazel/external/wee8.genrule_cmd +++ b/bazel/external/wee8.genrule_cmd @@ -54,10 +54,12 @@ fi # Debug/release build. if [[ $(COMPILATION_MODE) == "dbg" && $${ENVOY_UBSAN_VPTR-} != "1" && $${ENVOY_MSAN-} != "1" && $${ENVOY_TSAN-} != "1" ]]; then WEE8_BUILD_ARGS+=" is_debug=true" + WEE8_BUILD_ARGS+=" v8_symbol_level=2" WEE8_BUILD_ARGS+=" symbol_level=2" WEE8_BUILD_ARGS+=" v8_optimized_debug=false" else WEE8_BUILD_ARGS+=" is_debug=false" + WEE8_BUILD_ARGS+=" v8_symbol_level=1" WEE8_BUILD_ARGS+=" symbol_level=1" WEE8_BUILD_ARGS+=" v8_enable_handle_zapping=false" fi diff --git a/bazel/repository_locations.bzl b/bazel/repository_locations.bzl index 535a56b4be..57d772c279 100644 --- a/bazel/repository_locations.bzl +++ b/bazel/repository_locations.bzl @@ -505,9 +505,9 @@ DEPENDENCY_REPOSITORIES = dict( cpe = "N/A", ), proxy_wasm_cpp_host = dict( - sha256 = "1087dafbd2a4bcf3727425c6a2daad20bce3000a7768e9cc354e3e794ef29687", - strip_prefix = "proxy-wasm-cpp-host-f8fab0f8cce39dde336a5e9e78dde61005f56129", - urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-host/archive/f8fab0f8cce39dde336a5e9e78dde61005f56129.tar.gz"], + sha256 = "0eb4164f2d777d2a65c254f3901aa00461e9e50c592e8dfac793bc3d2a76fb21", + strip_prefix = "proxy-wasm-cpp-host-2523cfb1968aff039fa08703b20c701824a165c3", + urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-host/archive/2523cfb1968aff039fa08703b20c701824a165c3.tar.gz"], use_category = ["dataplane"], cpe = "N/A", ), diff --git a/source/extensions/common/wasm/context.cc b/source/extensions/common/wasm/context.cc index dd84688d2f..86b3d174b6 100644 --- a/source/extensions/common/wasm/context.cc +++ b/source/extensions/common/wasm/context.cc @@ -1222,7 +1222,7 @@ Http::FilterDataStatus convertFilterDataStatus(proxy_wasm::FilterDataStatus stat }; Network::FilterStatus Context::onNewConnection() { - onCreate(id_); + onCreate(); return convertNetworkFilterStatus(onNetworkNewConnection()); }; @@ -1354,7 +1354,7 @@ WasmResult Context::sendLocalResponse(uint32_t response_code, absl::string_view } Http::FilterHeadersStatus Context::decodeHeaders(Http::RequestHeaderMap& headers, bool end_stream) { - onCreate(id_); + onCreate(); http_request_started_ = true; request_headers_ = &headers; end_of_stream_ = end_stream; diff --git a/test/extensions/common/wasm/wasm_test.cc b/test/extensions/common/wasm/wasm_test.cc index beac4c0aba..34b630a8cd 100644 --- a/test/extensions/common/wasm/wasm_test.cc +++ b/test/extensions/common/wasm/wasm_test.cc @@ -733,7 +733,7 @@ class WasmCommonContextTest } void setupContext() { context_ = std::make_unique(wasm_->wasm().get(), root_context_->id(), plugin_); - context_->onCreate(root_context_->id()); + context_->onCreate(); } TestContext& root_context() { return *static_cast(root_context_); } From cf65a7e769bc9fa5a7cba0e7ca813fc4fc0de18b Mon Sep 17 00:00:00 2001 From: John Plevyak Date: Thu, 25 Jun 2020 18:01:54 +0000 Subject: [PATCH 16/16] Address comments. Signed-off-by: John Plevyak --- bazel/external/wee8.genrule_cmd | 2 -- source/extensions/common/wasm/context.h | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/bazel/external/wee8.genrule_cmd b/bazel/external/wee8.genrule_cmd index a254216e26..5dec8d0049 100644 --- a/bazel/external/wee8.genrule_cmd +++ b/bazel/external/wee8.genrule_cmd @@ -55,12 +55,10 @@ fi if [[ $(COMPILATION_MODE) == "dbg" && $${ENVOY_UBSAN_VPTR-} != "1" && $${ENVOY_MSAN-} != "1" && $${ENVOY_TSAN-} != "1" ]]; then WEE8_BUILD_ARGS+=" is_debug=true" WEE8_BUILD_ARGS+=" v8_symbol_level=2" - WEE8_BUILD_ARGS+=" symbol_level=2" WEE8_BUILD_ARGS+=" v8_optimized_debug=false" else WEE8_BUILD_ARGS+=" is_debug=false" WEE8_BUILD_ARGS+=" v8_symbol_level=1" - WEE8_BUILD_ARGS+=" symbol_level=1" WEE8_BUILD_ARGS+=" v8_enable_handle_zapping=false" fi diff --git a/source/extensions/common/wasm/context.h b/source/extensions/common/wasm/context.h index 8cf8c6b21a..c0314d8385 100644 --- a/source/extensions/common/wasm/context.h +++ b/source/extensions/common/wasm/context.h @@ -414,7 +414,7 @@ class Context : public proxy_wasm::ContextBase, ::Envoy::Buffer::Instance* network_upstream_data_buffer_{}; // HTTP filter state. - bool http_request_started_ = false; // When decodeHeaders() is called the rquest is "started". + bool http_request_started_ = false; // When decodeHeaders() is called the request is "started". Http::RequestHeaderMap* request_headers_{}; Http::ResponseHeaderMap* response_headers_{}; ::Envoy::Buffer::Instance* request_body_buffer_{};