Skip to content

Commit

Permalink
Expose connection's streaminfo to the HTTP Lua filter
Browse files Browse the repository at this point in the history
This allows Lua to access the connection StreamInfo, and thus the
dynamic metadata. This makes it possible for HTTP requests to act on
the Cloud provider specific PROXY PROTOCOL TLV extensions.

The bulk of the lines of this are moving the StreamInfoWrapper from
the Lua HTTP directory into the common Lua directory and fixing up the
references.

This uses an (unfortunate) const_cast to match the existing semantics
of StreamInfoWrapper.  The alternatives are much more invasive at the
moment.

Signed-off-by: Ryan Anderson <[email protected]>
  • Loading branch information
pugmajere committed Feb 27, 2024
1 parent c115749 commit 04cdd53
Show file tree
Hide file tree
Showing 31 changed files with 713 additions and 665 deletions.
5 changes: 5 additions & 0 deletions changelogs/current.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,11 @@ new_features:
- area: redis
change: |
Added support for the ``ECHO`` command.
- area: lua
change: |
Exposed the ``streamInfo`` on ``connection`` to the HTTP filter
Lua, primarily to allow access to Cloud provider proxy protocol
TLV extensions stored in connection level dynamic metadata.
deprecated:
- area: listener
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class FuzzerMocks {
FuzzerMocks() : addr_(std::make_shared<Network::Address::PipeInstance>("/test/test.sock")) {

ON_CALL(decoder_callbacks_, connection())
.WillByDefault(Return(OptRef<const Network::Connection>{connection_}));
.WillByDefault(Return(OptRef<Network::Connection>{connection_}));
connection_.stream_info_.downstream_connection_info_provider_->setRemoteAddress(addr_);
connection_.stream_info_.downstream_connection_info_provider_->setLocalAddress(addr_);
}
Expand Down
12 changes: 12 additions & 0 deletions docs/root/configuration/http/http_filters/lua_filter.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ Currently supported high level features
* Performing a direct response and skipping further filter iteration. For example, a script
could make an upstream HTTP call for authentication, and then directly respond with a 403
response code.
* Inspection of connection (network) or request level dynamic metadata.

Configuration
-------------
Expand Down Expand Up @@ -924,6 +925,17 @@ secured and *nil* when it is not.

Returns an :ref:`SSL connection info object <config_http_filters_lua_ssl_socket_info>`.

streamInfo()
^^^^^^^^^^^^

.. code-block:: lua
local streamInfo = handle:streamInfo()
Returns :repo:`information <envoy/stream_info/stream_info.h>` related to the current connection.

Returns a :ref:`stream info object <config_http_filters_lua_stream_info_wrapper>`.

.. _config_http_filters_lua_ssl_socket_info:

SSL connection object API
Expand Down
2 changes: 1 addition & 1 deletion source/common/http/filter_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -1085,7 +1085,7 @@ class FilterManager : public ScopeTrackedObject,
class DownstreamFilterManager : public FilterManager {
public:
DownstreamFilterManager(FilterManagerCallbacks& filter_manager_callbacks,
Event::Dispatcher& dispatcher, const Network::Connection& connection,
Event::Dispatcher& dispatcher, Network::Connection& connection,
uint64_t stream_id, Buffer::BufferMemoryAccountSharedPtr account,
bool proxy_100_continue, uint32_t buffer_limit,
FilterChainFactory& filter_chain_factory,
Expand Down
10 changes: 8 additions & 2 deletions source/extensions/filters/common/lua/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,18 @@ envoy_cc_library(

envoy_cc_library(
name = "wrappers_lib",
srcs = ["wrappers.cc"],
hdrs = ["wrappers.h"],
srcs = [
"wrappers.cc",
],
hdrs = [
"wrappers.h",
],
deps = [
":lua_lib",
"//envoy/buffer:buffer_interface",
"//envoy/stream_info:stream_info_interface",
"//source/common/common:hex_lib",
"//source/common/http:utility_lib",
"//source/common/protobuf",
],
)
131 changes: 131 additions & 0 deletions source/extensions/filters/common/lua/wrappers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,137 @@ int ConnectionWrapper::luaSsl(lua_State* state) {
return 1;
}

int ConnectionWrapper::luaStreamInfo(lua_State* state) {
auto& streaminfo = connection_->streamInfo();
if (stream_info_wrapper_.get() != nullptr) {
stream_info_wrapper_.pushStack();
} else {
stream_info_wrapper_.reset(Filters::Common::Lua::StreamInfoWrapper::create(state, streaminfo),
true);
}
return 1;
}

int StreamInfoWrapper::luaProtocol(lua_State* state) {
const std::string& protocol =
Envoy::Http::Utility::getProtocolString(stream_info_.protocol().value());
lua_pushlstring(state, protocol.data(), protocol.size());
return 1;
}

int StreamInfoWrapper::luaDynamicMetadata(lua_State* state) {
if (dynamic_metadata_wrapper_.get() != nullptr) {
dynamic_metadata_wrapper_.pushStack();
} else {
dynamic_metadata_wrapper_.reset(DynamicMetadataMapWrapper::create(state, *this), true);
}
return 1;
}

int StreamInfoWrapper::luaDownstreamSslConnection(lua_State* state) {
const auto& ssl = stream_info_.downstreamAddressProvider().sslConnection();
if (ssl != nullptr) {
if (downstream_ssl_connection_.get() != nullptr) {
downstream_ssl_connection_.pushStack();
} else {
downstream_ssl_connection_.reset(
Filters::Common::Lua::SslConnectionWrapper::create(state, *ssl), true);
}
} else {
lua_pushnil(state);
}
return 1;
}

int StreamInfoWrapper::luaDownstreamLocalAddress(lua_State* state) {
const std::string& local_address =
stream_info_.downstreamAddressProvider().localAddress()->asString();
lua_pushlstring(state, local_address.data(), local_address.size());
return 1;
}

int StreamInfoWrapper::luaDownstreamDirectRemoteAddress(lua_State* state) {
const std::string& direct_remote_address =
stream_info_.downstreamAddressProvider().directRemoteAddress()->asString();
lua_pushlstring(state, direct_remote_address.data(), direct_remote_address.size());
return 1;
}

int StreamInfoWrapper::luaDownstreamRemoteAddress(lua_State* state) {
const std::string& remote_address =
stream_info_.downstreamAddressProvider().remoteAddress()->asString();
lua_pushlstring(state, remote_address.data(), remote_address.size());
return 1;
}

int StreamInfoWrapper::luaRequestedServerName(lua_State* state) {
absl::string_view requested_serve_name =
stream_info_.downstreamAddressProvider().requestedServerName();
lua_pushlstring(state, requested_serve_name.data(), requested_serve_name.size());
return 1;
}

DynamicMetadataMapIterator::DynamicMetadataMapIterator(DynamicMetadataMapWrapper& parent)
: parent_{parent}, current_{parent_.streamInfo().dynamicMetadata().filter_metadata().begin()} {}

StreamInfo::StreamInfo& DynamicMetadataMapWrapper::streamInfo() { return parent_.stream_info_; }

int DynamicMetadataMapIterator::luaPairsIterator(lua_State* state) {
if (current_ == parent_.streamInfo().dynamicMetadata().filter_metadata().end()) {
parent_.iterator_.reset();
return 0;
}

lua_pushlstring(state, current_->first.data(), current_->first.size());
Filters::Common::Lua::MetadataMapHelper::createTable(state, current_->second.fields());

current_++;
return 2;
}

int DynamicMetadataMapWrapper::luaGet(lua_State* state) {
const char* filter_name = luaL_checkstring(state, 2);
const auto& metadata = streamInfo().dynamicMetadata().filter_metadata();
const auto filter_it = metadata.find(filter_name);
if (filter_it == metadata.end()) {
return 0;
}

Filters::Common::Lua::MetadataMapHelper::createTable(state, filter_it->second.fields());
return 1;
}

int DynamicMetadataMapWrapper::luaSet(lua_State* state) {
if (iterator_.get() != nullptr) {
luaL_error(state, "dynamic metadata map cannot be modified while iterating");
}

const char* filter_name = luaL_checkstring(state, 2);
const char* key = luaL_checkstring(state, 3);

// MetadataMapHelper::loadValue will convert the value on top of the Lua stack,
// so push a copy of the 3rd arg ("value") to the top.
lua_pushvalue(state, 4);

ProtobufWkt::Struct value;
(*value.mutable_fields())[key] = Filters::Common::Lua::MetadataMapHelper::loadValue(state);
streamInfo().setDynamicMetadata(filter_name, value);

// Pop the copy of the metadata value from the stack.
lua_pop(state, 1);
return 0;
}

int DynamicMetadataMapWrapper::luaPairs(lua_State* state) {
if (iterator_.get() != nullptr) {
luaL_error(state, "cannot create a second iterator before completing the first");
}

iterator_.reset(DynamicMetadataMapIterator::create(state, *this), true);
lua_pushcclosure(state, DynamicMetadataMapIterator::static_luaPairsIterator, 1);
return 1;
}

} // namespace Lua
} // namespace Common
} // namespace Filters
Expand Down
Loading

0 comments on commit 04cdd53

Please sign in to comment.