Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 36 additions & 2 deletions docs/root/configuration/http_filters/lua_filter.rst
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,17 @@ Returns :repo:`information <include/request_info/request_info.h>` related to the

Returns a :ref:`request info object <config_http_filters_lua_request_info_wrapper>`.

connection()
^^^^^^^^^^^^

.. code-block:: lua

connection = handle:connection()

Returns the current request's underlying :repo:`connection <include/envoy/network/connection.h>`.

Returns a :ref:`connection object <config_http_filters_lua_connection_wrapper>`.

.. _config_http_filters_lua_header_wrapper:

Header object API
Expand Down Expand Up @@ -401,7 +412,7 @@ get()
metadata:get(key)

Gets a metadata. *key* is a string that supplies the metadata key. Returns the corresponding
value of the given metadata key. The type of the value can be: *null*, *boolean*, *number*,
value of the given metadata key. The type of the value can be: *nil*, *boolean*, *number*,
*string* and *table*.

__pairs()
Expand All @@ -428,4 +439,27 @@ protocol()
requestInfo:protocol()

Returns the string representation of :repo:`HTTP protocol <include/envoy/http/protocol.h>`
used by the current request. The possible values are: *HTTP/1.0*, *HTTP/1.1*, and *HTTP/2*.
used by the current request. The possible values are: *HTTP/1.0*, *HTTP/1.1*, and *HTTP/2*.

.. _config_http_filters_lua_connection_wrapper:

Connection object API
---------------------

ssl()
^^^^^^^^

.. code-block:: lua

if connection:ssl() == nil then
print("plain")
else
print("secure")
end

Returns :repo:`SSL connection <include/envoy/ssl/connection.h>` object when the connection is
secured and *nil* when it is not.

.. note::

Currently the SSL connection object has no exposed APIs.
7 changes: 4 additions & 3 deletions docs/root/intro/version_history.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ Version history

1.8.0 (Pending)
===============
* access log: added :ref:`response flag filter <envoy_api_msg_config.filter.accesslog.v2.ResponseFlagFilter>`
to filter based on the presence of Envoy response flags.
* admin: added :http:get:`/hystrix_event_stream` as an endpoint for monitoring envoy's statistics
* access log: added :ref:`response flag filter <envoy_api_msg_config.filter.accesslog.v2.ResponseFlagFilter>`
to filter based on the presence of Envoy response flags.
* admin: added :http:get:`/hystrix_event_stream` as an endpoint for monitoring envoy's statistics
through `Hystrix dashboard <https://github.com/Netflix-Skunkworks/hystrix-dashboard/wiki>`_.
* http: response filters not applied to early error paths such as http_parser generated 400s.
* lua: added :ref:`connection() <config_http_filters_lua_connection_wrapper>` wrapper and *ssl()* API.
* lua: added :ref:`requestInfo() <config_http_filters_lua_request_info_wrapper>` wrapper and *protocol()* API.
* ratelimit: added support for :repo:`api/envoy/service/ratelimit/v2/rls.proto`.
Lyft's reference implementation of the `ratelimit <https://github.com/lyft/ratelimit>`_ service also supports the data-plane-api proto as of v1.1.0.
Expand Down
14 changes: 14 additions & 0 deletions source/extensions/filters/common/lua/wrappers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,20 @@ int MetadataMapWrapper::luaPairs(lua_State* state) {
return 1;
}

int ConnectionWrapper::luaSsl(lua_State* state) {
const auto& ssl = connection_->ssl();
if (ssl != nullptr) {
if (ssl_connection_wrapper_.get() != nullptr) {
ssl_connection_wrapper_.pushStack();
} else {
ssl_connection_wrapper_.reset(SslConnectionWrapper::create(state, ssl), true);
}
} else {
lua_pushnil(state);
}
return 1;
}

} // namespace Lua
} // namespace Common
} // namespace Filters
Expand Down
33 changes: 33 additions & 0 deletions source/extensions/filters/common/lua/wrappers.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,39 @@ class MetadataMapWrapper : public BaseLuaObject<MetadataMapWrapper> {
friend class MetadataMapIterator;
};

/**
* Lua wrapper for Ssl::Connection.
*/
class SslConnectionWrapper : public BaseLuaObject<SslConnectionWrapper> {
public:
SslConnectionWrapper(const Ssl::Connection*) {}
static ExportedFunctions exportedFunctions() { return {}; }

// TODO(dio): Add more Lua APIs around Ssl::Connection.
};

/**
* Lua wrapper for Network::Connection.
*/
class ConnectionWrapper : public BaseLuaObject<ConnectionWrapper> {
public:
ConnectionWrapper(const Network::Connection* connection) : connection_{connection} {}
static ExportedFunctions exportedFunctions() { return {{"ssl", static_luaSsl}}; }

private:
/**
* Get the Ssl::Connection wrapper
* @return object if secured and nil if not.
*/
DECLARE_LUA_FUNCTION(ConnectionWrapper, luaSsl);

// Envoy::Lua::BaseLuaObject
void onMarkDead() override { ssl_connection_wrapper_.reset(); }

const Network::Connection* connection_;
LuaDeathRef<SslConnectionWrapper> ssl_connection_wrapper_;
};

} // namespace Lua
} // namespace Common
} // namespace Filters
Expand Down
13 changes: 13 additions & 0 deletions source/extensions/filters/http/lua/lua_filter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,17 @@ int StreamHandleWrapper::luaRequestInfo(lua_State* state) {
return 1;
}

int StreamHandleWrapper::luaConnection(lua_State* state) {
ASSERT(state_ == State::Running);
if (connection_wrapper_.get() != nullptr) {
connection_wrapper_.pushStack();
} else {
connection_wrapper_.reset(
Filters::Common::Lua::ConnectionWrapper::create(state, callbacks_.connection()), true);
}
return 1;
}

int StreamHandleWrapper::luaLogTrace(lua_State* state) {
const char* message = luaL_checkstring(state, 2);
filter_.scriptLog(spdlog::level::trace, message);
Expand Down Expand Up @@ -419,6 +430,8 @@ FilterConfig::FilterConfig(const std::string& lua_code, ThreadLocal::SlotAllocat
lua_state_.registerType<Filters::Common::Lua::BufferWrapper>();
lua_state_.registerType<Filters::Common::Lua::MetadataMapWrapper>();
lua_state_.registerType<Filters::Common::Lua::MetadataMapIterator>();
lua_state_.registerType<Filters::Common::Lua::ConnectionWrapper>();
lua_state_.registerType<Filters::Common::Lua::SslConnectionWrapper>();
lua_state_.registerType<HeaderMapWrapper>();
lua_state_.registerType<HeaderMapIterator>();
lua_state_.registerType<RequestInfoWrapper>();
Expand Down
19 changes: 17 additions & 2 deletions source/extensions/filters/http/lua/lua_filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ class FilterCallbacks {
* accomodate write API e.g. setDynamicMetadata().
*/
virtual RequestInfo::RequestInfo& requestInfo() PURE;

/**
* @return const const Network::Connection* the current network connection handle.
*/
virtual const Network::Connection* connection() const PURE;
};

class Filter;
Expand Down Expand Up @@ -128,7 +133,8 @@ class StreamHandleWrapper : public Filters::Common::Lua::BaseLuaObject<StreamHan
{"logDebug", static_luaLogDebug}, {"logInfo", static_luaLogInfo},
{"logWarn", static_luaLogWarn}, {"logErr", static_luaLogErr},
{"logCritical", static_luaLogCritical}, {"httpCall", static_luaHttpCall},
{"respond", static_luaRespond}, {"requestInfo", static_luaRequestInfo}};
{"respond", static_luaRespond}, {"requestInfo", static_luaRequestInfo},
{"connection", static_luaConnection}};
}

private:
Expand Down Expand Up @@ -187,6 +193,11 @@ class StreamHandleWrapper : public Filters::Common::Lua::BaseLuaObject<StreamHan
*/
DECLARE_LUA_FUNCTION(StreamHandleWrapper, luaRequestInfo);

/**
* @return a handle to the network connection.
*/
DECLARE_LUA_FUNCTION(StreamHandleWrapper, luaConnection);

/**
* Log a message to the Envoy log.
* @param 1 (string): The log message.
Expand Down Expand Up @@ -214,6 +225,7 @@ class StreamHandleWrapper : public Filters::Common::Lua::BaseLuaObject<StreamHan
trailers_wrapper_.reset();
metadata_wrapper_.reset();
request_info_wrapper_.reset();
connection_wrapper_.reset();
}

// Http::AsyncClient::Callbacks
Expand All @@ -232,8 +244,9 @@ class StreamHandleWrapper : public Filters::Common::Lua::BaseLuaObject<StreamHan
Filters::Common::Lua::LuaDeathRef<HeaderMapWrapper> headers_wrapper_;
Filters::Common::Lua::LuaDeathRef<Filters::Common::Lua::BufferWrapper> body_wrapper_;
Filters::Common::Lua::LuaDeathRef<HeaderMapWrapper> trailers_wrapper_;
Filters::Common::Lua::LuaDeathRef<RequestInfoWrapper> request_info_wrapper_;
Filters::Common::Lua::LuaDeathRef<Filters::Common::Lua::MetadataMapWrapper> metadata_wrapper_;
Filters::Common::Lua::LuaDeathRef<RequestInfoWrapper> request_info_wrapper_;
Filters::Common::Lua::LuaDeathRef<Filters::Common::Lua::ConnectionWrapper> connection_wrapper_;
State state_{State::Running};
std::function<void()> yield_callback_;
Http::AsyncClient::Request* http_request_{};
Expand Down Expand Up @@ -324,6 +337,7 @@ class Filter : public Http::StreamFilter, Logger::Loggable<Logger::Id::lua> {

const ProtobufWkt::Struct& metadata() const override { return getMetadata(callbacks_); }
RequestInfo::RequestInfo& requestInfo() override { return callbacks_->requestInfo(); }
const Network::Connection* connection() const override { return callbacks_->connection(); }

Filter& parent_;
Http::StreamDecoderFilterCallbacks* callbacks_{};
Expand All @@ -343,6 +357,7 @@ class Filter : public Http::StreamFilter, Logger::Loggable<Logger::Id::lua> {

const ProtobufWkt::Struct& metadata() const override { return getMetadata(callbacks_); }
RequestInfo::RequestInfo& requestInfo() override { return callbacks_->requestInfo(); }
const Network::Connection* connection() const override { return callbacks_->connection(); }

Filter& parent_;
Http::StreamEncoderFilterCallbacks* callbacks_{};
Expand Down
2 changes: 2 additions & 0 deletions test/extensions/filters/common/lua/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ envoy_cc_test(
":lua_wrappers_lib",
"//source/common/buffer:buffer_lib",
"//source/extensions/filters/common/lua:wrappers_lib",
"//test/mocks/network:network_mocks",
"//test/mocks/ssl:ssl_mocks",
"//test/test_common:utility_lib",
],
)
Expand Down
43 changes: 43 additions & 0 deletions test/extensions/filters/common/lua/wrappers_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include "extensions/filters/common/lua/wrappers.h"

#include "test/extensions/filters/common/lua/lua_wrappers.h"
#include "test/mocks/network/mocks.h"
#include "test/mocks/ssl/mocks.h"
#include "test/test_common/utility.h"

namespace Envoy {
Expand All @@ -27,6 +29,42 @@ class LuaMetadataMapWrapperTest : public LuaWrappersTestBase<MetadataMapWrapper>
}
};

class LuaConnectionWrapperTest : public LuaWrappersTestBase<ConnectionWrapper> {
public:
virtual void setup(const std::string& script) {
LuaWrappersTestBase<ConnectionWrapper>::setup(script);
state_->registerType<SslConnectionWrapper>();
}

protected:
void expectSecureConnection(const bool secure) {
const std::string SCRIPT{R"EOF(
function callMe(object)
if object:ssl() == nil then
testPrint("plain")
else
testPrint("secure")
end
testPrint(type(object:ssl()))
end
)EOF"};
testing::InSequence s;
setup(SCRIPT);

// Setup secure connection if required.
EXPECT_CALL(Const(connection_), ssl()).WillOnce(Return(secure ? &ssl_ : nullptr));

ConnectionWrapper::create(coroutine_->luaState(), &connection_);
EXPECT_CALL(*this, testPrint(secure ? "secure" : "plain"));
EXPECT_CALL(Const(connection_), ssl()).WillOnce(Return(secure ? &ssl_ : nullptr));
EXPECT_CALL(*this, testPrint(secure ? "userdata" : "nil"));
start("callMe");
}

NiceMock<Envoy::Network::MockConnection> connection_;
NiceMock<Envoy::Ssl::MockConnection> ssl_;
};

// Basic buffer wrapper methods test.
TEST_F(LuaBufferWrapperTest, Methods) {
const std::string SCRIPT{R"EOF(
Expand Down Expand Up @@ -224,6 +262,11 @@ TEST_F(LuaMetadataMapWrapperTest, DontFinishIteration) {
"[string \"...\"]:5: cannot create a second iterator before completing the first");
}

TEST_F(LuaConnectionWrapperTest, Secure) {
expectSecureConnection(true);
expectSecureConnection(false);
}

} // namespace Lua
} // namespace Common
} // namespace Filters
Expand Down
2 changes: 2 additions & 0 deletions test/extensions/filters/http/lua/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ envoy_extension_cc_test(
deps = [
"//source/extensions/filters/http/lua:lua_filter_lib",
"//test/mocks/http:http_mocks",
"//test/mocks/network:network_mocks",
"//test/mocks/ssl:ssl_mocks",
"//test/mocks/thread_local:thread_local_mocks",
"//test/mocks/upstream:upstream_mocks",
"//test/test_common:utility_lib",
Expand Down
37 changes: 36 additions & 1 deletion test/extensions/filters/http/lua/lua_filter_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#include "extensions/filters/http/lua/lua_filter.h"

#include "test/mocks/http/mocks.h"
#include "test/mocks/network/mocks.h"
#include "test/mocks/ssl/mocks.h"
#include "test/mocks/thread_local/mocks.h"
#include "test/mocks/upstream/mocks.h"
#include "test/test_common/printers.h"
Expand Down Expand Up @@ -68,6 +70,11 @@ class LuaHttpFilterTest : public testing::Test {
filter_->setEncoderFilterCallbacks(encoder_callbacks_);
}

void setupSecureConnection(const bool secure) {
EXPECT_CALL(decoder_callbacks_, connection()).WillOnce(Return(&connection_));
EXPECT_CALL(Const(connection_), ssl()).Times(1).WillOnce(Return(secure ? &ssl_ : nullptr));
}

void setupMetadata(const std::string& yaml) {
MessageUtil::loadFromYaml(yaml, metadata_);
EXPECT_CALL(decoder_callbacks_.route_->route_entry_, metadata())
Expand All @@ -81,6 +88,8 @@ class LuaHttpFilterTest : public testing::Test {
Http::MockStreamDecoderFilterCallbacks decoder_callbacks_;
Http::MockStreamEncoderFilterCallbacks encoder_callbacks_;
envoy::api::v2::core::Metadata metadata_;
NiceMock<Envoy::Ssl::MockConnection> ssl_;
NiceMock<Envoy::Network::MockConnection> connection_;
NiceMock<Envoy::RequestInfo::MockRequestInfo> request_info_;

const std::string HEADER_ONLY_SCRIPT{R"EOF(
Expand Down Expand Up @@ -1463,7 +1472,7 @@ TEST_F(LuaHttpFilterTest, GetMetadataFromHandleNoLuaMetadata) {
EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true));
}

// No available Lua metadata on route.
// Get the current protocol.
TEST_F(LuaHttpFilterTest, GetCurrentProtocol) {
const std::string SCRIPT{R"EOF(
function envoy_on_request(request_handle)
Expand All @@ -1482,6 +1491,32 @@ TEST_F(LuaHttpFilterTest, GetCurrentProtocol) {
EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true));
}

// Check the connection.
TEST_F(LuaHttpFilterTest, CheckConnection) {
const std::string SCRIPT{R"EOF(
function envoy_on_request(request_handle)
if request_handle:connection():ssl() == nil then
request_handle:logTrace("plain")
else
request_handle:logTrace("secure")
end
end
)EOF"};

InSequence s;
setup(SCRIPT);

Http::TestHeaderMapImpl request_headers{{":path", "/"}};

setupSecureConnection(false);
EXPECT_CALL(*filter_, scriptLog(spdlog::level::trace, StrEq("plain")));
EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true));

setupSecureConnection(true);
EXPECT_CALL(*filter_, scriptLog(spdlog::level::trace, StrEq("secure")));
EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true));
}

} // namespace Lua
} // namespace HttpFilters
} // namespace Extensions
Expand Down
Loading