Skip to content

Commit

Permalink
Fix lua stack corruption
Browse files Browse the repository at this point in the history
Add Post method that accepts a string body and content-type
  • Loading branch information
Dreae authored and lionkor committed Dec 21, 2023
1 parent 4533ee3 commit ab9dec9
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 7 deletions.
1 change: 1 addition & 0 deletions include/TLuaEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ class TLuaEngine : public std::enable_shared_from_this<TLuaEngine>, IThreaded {
sol::table Lua_HttpCreateConnection(const std::string& host, uint16_t port);
void Lua_HttpGet(const std::string& host, const std::string& path, const sol::table& headers, const sol::function& cb);
void Lua_HttpPost(const std::string& host, const std::string& path, const sol::table& body, const sol::table& headers, const sol::function& cb);
void Lua_HttpPost(const std::string& host, const std::string& path, const std::string& body, const std::string& content_type, const sol::table& headers, const sol::function& cb);
void Lua_HttpCallCallback(httplib::Result& response, std::shared_ptr<sol::reference> cb);
sol::table Lua_JsonDecode(const std::string& str);
int Lua_GetPlayerIDByName(const std::string& Name);
Expand Down
34 changes: 27 additions & 7 deletions src/TLuaEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -628,24 +628,25 @@ void TLuaEngine::StateThreadData::Lua_HttpCallCallback(httplib::Result& response
args.push_back(response->body);

auto headers = std::unordered_map<std::string, std::string>();
for (auto &pair : response->headers) {
for (auto& pair : response->headers) {
headers.emplace(pair.first, pair.second);
}
args.push_back(headers);
} else {
auto err = response.error();
args.push_back(httplib::to_string(err));
}
// AS FAR AS I CAN TELL this shared_ptr MUST be dropped immediately, because this function runs in the context of the http thread pool.
// If we hang on to this pointer by using res.WaitUntilReady() this thread will be the last one to drop the pointer and will corrupt
// the lua stack by destructing the sol::object owned by TLuaResult.
// There is still likely a small chance of that, ideally EnqueueFunctionCall wouldn't return any references to sol objects.
auto res = this->EnqueueFunctionCall(cb_ref, args);

// This doesn't seem strictly necessary, and will make threads in the http pool wait until the lua callbacks are executed
res->WaitUntilReady();
}

void TLuaEngine::StateThreadData::Lua_HttpGet(const std::string& host, const std::string& path, const sol::table& headers, const sol::function& cb) {
auto http_headers = table_to_headers(headers);
// This method and Lua_HttpPost create a sol::reference to save the callback function in the lua registry, and then
// wrap it in a shared_ptr because passing any sol object by-value involves accessing the lua state. It is NOT safe
// wrap it in a shared_ptr because passing any sol object by-value involves accessing the lua state. It is NOT safe
// to derefence this pointer inside the http thread pool
auto cb_ref = std::make_shared<sol::reference>(cb);
boost::asio::post(this->mEngine->http_pool, [this, host, path, http_headers, cb_ref]() {
Expand All @@ -666,6 +667,7 @@ void TLuaEngine::StateThreadData::Lua_HttpPost(const std::string& host, const st
beammp_lua_error("Http:Get: Expected string-string pairs for headers, got something else, ignoring that header");
}
}

auto cb_ref = std::make_shared<sol::reference>(cb);
boost::asio::post(this->mEngine->http_pool, [this, host, path, http_headers, cb_ref, params]() {
auto client = httplib::Client(host);
Expand All @@ -675,6 +677,18 @@ void TLuaEngine::StateThreadData::Lua_HttpPost(const std::string& host, const st
});
}

void TLuaEngine::StateThreadData::Lua_HttpPost(const std::string& host, const std::string& path, const std::string& body, const std::string& content_type, const sol::table& headers, const sol::function& cb) {
auto http_headers = table_to_headers(headers);

auto cb_ref = std::make_shared<sol::reference>(cb);
boost::asio::post(this->mEngine->http_pool, [this, host, path, http_headers, cb_ref, body = std::move(body), content_type = std::move(content_type)]() {
auto client = httplib::Client(host);
client.set_follow_location(true);
auto response = client.Post(path, http_headers, body.c_str(), body.length(), content_type);
this->Lua_HttpCallCallback(response, cb_ref);
});
}

sol::table TLuaEngine::StateThreadData::Lua_HttpCreateConnection(const std::string& host, uint16_t port) {
auto table = mStateView.create_table();
table["host"] = host;
Expand Down Expand Up @@ -905,11 +919,17 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, TLuaStateI
}
));
HttpTable.set_function("Post", sol::overload(
[this](const std::string& url, const std::string& path, const sol::table& body, const sol::function& cb) {
[this](const std::string& url, const std::string& path, const sol::table& body, const sol::function& cb) {
return Lua_HttpPost(url, path, body, this->mStateView.create_table(), cb);
},
[this](const std::string& url, const std::string& path, const sol::table& body, const sol::table& headers, const sol::function& cb) {
[this](const std::string& url, const std::string& path, const sol::table& body, const sol::table& headers, const sol::function& cb) {
return Lua_HttpPost(url, path, body, headers, cb);
},
[this](const std::string& url, const std::string& path, const std::string& body, const std::string& content_type, const sol::function& cb) {
return Lua_HttpPost(url, path, body, content_type, this->mStateView.create_table(), cb);
},
[this](const std::string& url, const std::string& path, const std::string& body, const std::string& content_type, const sol::table& headers, const sol::function& cb) {
return Lua_HttpPost(url, path, body, content_type, headers, cb);
}
));

Expand Down

0 comments on commit ab9dec9

Please sign in to comment.