Line data Source code
1 : #include "source/extensions/router/cluster_specifiers/lua/lua_cluster_specifier.h" 2 : 3 : #include "source/common/router/config_impl.h" 4 : 5 : namespace Envoy { 6 : namespace Extensions { 7 : namespace Router { 8 : namespace Lua { 9 : 10 : PerLuaCodeSetup::PerLuaCodeSetup(const std::string& lua_code, ThreadLocal::SlotAllocator& tls) 11 0 : : lua_state_(lua_code, tls) { 12 0 : lua_state_.registerType<HeaderMapWrapper>(); 13 0 : lua_state_.registerType<RouteHandleWrapper>(); 14 : 15 0 : const Filters::Common::Lua::InitializerList initializers; 16 : 17 0 : cluster_function_slot_ = lua_state_.registerGlobal("envoy_on_route", initializers); 18 0 : if (lua_state_.getGlobalRef(cluster_function_slot_) == LUA_REFNIL) { 19 0 : throw EnvoyException( 20 0 : "envoy_on_route() function not found. Lua will not hook cluster specifier."); 21 0 : } 22 0 : } 23 : 24 0 : int HeaderMapWrapper::luaGet(lua_State* state) { 25 0 : absl::string_view key = Filters::Common::Lua::getStringViewFromLuaString(state, 2); 26 0 : const Envoy::Http::HeaderUtility::GetAllOfHeaderAsStringResult value = 27 0 : Envoy::Http::HeaderUtility::getAllOfHeaderAsString(headers_, 28 0 : Envoy::Http::LowerCaseString(key)); 29 0 : if (value.result().has_value()) { 30 0 : lua_pushlstring(state, value.result().value().data(), value.result().value().size()); 31 0 : return 1; 32 0 : } else { 33 0 : return 0; 34 0 : } 35 0 : } 36 : 37 0 : int RouteHandleWrapper::luaHeaders(lua_State* state) { 38 0 : if (headers_wrapper_.get() != nullptr) { 39 0 : headers_wrapper_.pushStack(); 40 0 : } else { 41 0 : headers_wrapper_.reset(HeaderMapWrapper::create(state, headers_), true); 42 0 : } 43 0 : return 1; 44 0 : } 45 : 46 : LuaClusterSpecifierConfig::LuaClusterSpecifierConfig( 47 : const LuaClusterSpecifierConfigProto& config, 48 : Server::Configuration::CommonFactoryContext& context) 49 : : main_thread_dispatcher_(context.mainThreadDispatcher()), 50 0 : default_cluster_(config.default_cluster()) { 51 0 : const std::string code_str = Config::DataSource::read(config.source_code(), true, context.api()); 52 0 : per_lua_code_setup_ptr_ = std::make_unique<PerLuaCodeSetup>(code_str, context.threadLocal()); 53 0 : } 54 : 55 : LuaClusterSpecifierPlugin::LuaClusterSpecifierPlugin(LuaClusterSpecifierConfigSharedPtr config) 56 : : config_(config), 57 : function_ref_(config_->perLuaCodeSetup() ? config_->perLuaCodeSetup()->clusterFunctionRef() 58 0 : : LUA_REFNIL) {} 59 : 60 0 : std::string LuaClusterSpecifierPlugin::startLua(const Http::HeaderMap& headers) const { 61 0 : if (function_ref_ == LUA_REFNIL) { 62 0 : return config_->defaultCluster(); 63 0 : } 64 0 : Filters::Common::Lua::CoroutinePtr coroutine = config_->perLuaCodeSetup()->createCoroutine(); 65 : 66 0 : RouteHandleRef handle; 67 0 : handle.reset(RouteHandleWrapper::create(coroutine->luaState(), headers), true); 68 : 69 0 : TRY_NEEDS_AUDIT { 70 0 : coroutine->start(function_ref_, 1, []() {}); 71 0 : } 72 0 : END_TRY catch (const Filters::Common::Lua::LuaException& e) { 73 0 : ENVOY_LOG(error, "script log: {}, use default cluster", e.what()); 74 0 : return config_->defaultCluster(); 75 0 : } 76 0 : if (!lua_isstring(coroutine->luaState(), -1)) { 77 0 : ENVOY_LOG(error, "script log: return value is not string, use default cluster"); 78 0 : return config_->defaultCluster(); 79 0 : } 80 0 : return std::string(Filters::Common::Lua::getStringViewFromLuaString(coroutine->luaState(), -1)); 81 0 : } 82 : 83 : Envoy::Router::RouteConstSharedPtr 84 : LuaClusterSpecifierPlugin::route(Envoy::Router::RouteConstSharedPtr parent, 85 0 : const Http::RequestHeaderMap& headers) const { 86 0 : return std::make_shared<Envoy::Router::RouteEntryImplBase::DynamicRouteEntry>( 87 0 : dynamic_cast<const Envoy::Router::RouteEntryImplBase*>(parent.get()), parent, 88 0 : startLua(headers)); 89 0 : } 90 : } // namespace Lua 91 : } // namespace Router 92 : } // namespace Extensions 93 : } // namespace Envoy