diff --git a/doc/en/scripting/builtins/libnetwork.md b/doc/en/scripting/builtins/libnetwork.md index a93eaefa..e4e83048 100644 --- a/doc/en/scripting/builtins/libnetwork.md +++ b/doc/en/scripting/builtins/libnetwork.md @@ -6,9 +6,15 @@ A library for working with the network. ```lua -- Performs a GET request to the specified URL. --- After receiving the response, passes the text to the callback function. --- In case of an error, the HTTP response code will be passed to onfailure. -network.get(url: str, callback: function(str), [optional] onfailure: function(int)) +network.get( + url: str, + -- Function to call when response is received + callback: function(str), + -- Error handler + [optional] onfailure: function(int), + -- List of additional request headers + [optional] headers: table +) -- Example: network.get("https://api.github.com/repos/MihailRis/VoxelEngine-Cpp/releases/latest", function (s) @@ -16,13 +22,28 @@ network.get("https://api.github.com/repos/MihailRis/VoxelEngine-Cpp/releases/lat end) -- A variant for binary files, with a byte array instead of a string in the response. -network.get_binary(url: str, callback: function(table|ByteArray), [optional] onfailure: function(int)) +network.get_binary( + url: str, + callback: function(table|ByteArray), + [optional] onfailure: function(int), + [optional] headers: table +) -- Performs a POST request to the specified URL. -- Currently, only `Content-Type: application/json` is supported -- After receiving the response, passes the text to the callback function. -- In case of an error, the HTTP response code will be passed to onfailure. -network.post(url: str, data: table, callback: function(str), [optional] onfailure: function(int)) +network.post( + url: str, + -- Request body as a table (will be converted to JSON) or string + body: table|string, + -- Function called when response is received + callback: function(str), + -- Error handler + [optional] onfailure: function(int), + -- List of additional request headers + [optional] headers: table +) ``` ## TCP Connections diff --git a/doc/ru/scripting/builtins/libnetwork.md b/doc/ru/scripting/builtins/libnetwork.md index c9cc890c..dc960d5c 100644 --- a/doc/ru/scripting/builtins/libnetwork.md +++ b/doc/ru/scripting/builtins/libnetwork.md @@ -6,9 +6,15 @@ ```lua -- Выполняет GET запрос к указанному URL. --- После получения ответа, передаёт текст в функцию callback. --- В случае ошибки в onfailure будет передан HTTP-код ответа. -network.get(url: str, callback: function(str), [опционально] onfailure: function(int)) +network.get( + url: str, + -- Функция, вызываемая при получении ответа + callback: function(str), + -- Обработчик ошибок + [опционально] onfailure: function(int), + -- Список дополнительных заголовков запроса + [опционально] headers: table +) -- Пример: network.get("https://api.github.com/repos/MihailRis/VoxelEngine-Cpp/releases/latest", function (s) @@ -16,13 +22,28 @@ network.get("https://api.github.com/repos/MihailRis/VoxelEngine-Cpp/releases/lat end) -- Вариант для двоичных файлов, с массивом байт вместо строки в ответе. -network.get_binary(url: str, callback: function(table|ByteArray), [опционально] onfailure: function(int)) +network.get_binary( + url: str, + callback: function(table|ByteArray), + [опционально] onfailure: function(int), + [опционально] headers: table +) -- Выполняет POST запрос к указанному URL. -- На данный момент реализована поддержка только `Content-Type: application/json` -- После получения ответа, передаёт текст в функцию callback. -- В случае ошибки в onfailure будет передан HTTP-код ответа. -network.post(url: str, data: table, callback: function(str), [опционально] onfailure: function(int)) +network.post( + url: str, + -- Тело запроса в виде таблицы, конвертируемой в JSON или строки + body: table|string, + -- Функция, вызываемая при получении ответа + callback: function(str), + -- Обработчик ошибок + [опционально] onfailure: function(int), + -- Список дополнительных заголовков запроса + [опционально] headers: table +) ``` ## TCP-Соединения diff --git a/src/logic/scripting/lua/libs/libnetwork.cpp b/src/logic/scripting/lua/libs/libnetwork.cpp index 94390c93..18d26644 100644 --- a/src/logic/scripting/lua/libs/libnetwork.cpp +++ b/src/logic/scripting/lua/libs/libnetwork.cpp @@ -5,6 +5,19 @@ using namespace scripting; +static std::vector read_headers(lua::State* L, int index) { + std::vector headers; + if (lua::istable(L, index)) { + int len = lua::objlen(L, index); + for (int i = 1; i <= len; i++) { + lua::rawgeti(L, i, index); + headers.push_back(lua::tostring(L, -1)); + lua::pop(L); + } + } + return headers; +} + static int l_get(lua::State* L, network::Network& network) { std::string url(lua::require_lstring(L, 1)); @@ -12,7 +25,7 @@ static int l_get(lua::State* L, network::Network& network) { auto onResponse = lua::create_lambda_nothrow(L); network::OnReject onReject = nullptr; - if (lua::gettop(L) >= 3) { + if (!lua::isnoneornil(L, 3)) { lua::pushvalue(L, 3); auto callback = lua::create_lambda_nothrow(L); onReject = [callback](int code) { @@ -20,11 +33,13 @@ static int l_get(lua::State* L, network::Network& network) { }; } + auto headers = read_headers(L, 4); + network.get(url, [onResponse](std::vector bytes) { engine->postRunnable([=]() { onResponse({std::string(bytes.data(), bytes.size())}); }); - }, std::move(onReject)); + }, std::move(onReject), std::move(headers)); return 0; } @@ -35,7 +50,7 @@ static int l_get_binary(lua::State* L, network::Network& network) { auto onResponse = lua::create_lambda_nothrow(L); network::OnReject onReject = nullptr; - if (lua::gettop(L) >= 3) { + if (!lua::isnoneornil(L, 3)) { lua::pushvalue(L, 3); auto callback = lua::create_lambda_nothrow(L); onReject = [callback](int code) { @@ -43,6 +58,8 @@ static int l_get_binary(lua::State* L, network::Network& network) { }; } + auto headers = read_headers(L, 4); + network.get(url, [onResponse](std::vector bytes) { auto buffer = std::make_shared>( reinterpret_cast(bytes.data()), bytes.size() @@ -50,7 +67,8 @@ static int l_get_binary(lua::State* L, network::Network& network) { engine->postRunnable([=]() { onResponse({buffer}); }); - }, std::move(onReject)); + }, std::move(onReject), std::move(headers)); + return 0; } @@ -62,7 +80,7 @@ static int l_post(lua::State* L, network::Network& network) { auto onResponse = lua::create_lambda_nothrow(L); network::OnReject onReject = nullptr; - if (lua::gettop(L) >= 4) { + if (!lua::isnoneornil(L, 4)) { lua::pushvalue(L, 4); auto callback = lua::create_lambda_nothrow(L); onReject = [callback](int code) { @@ -77,6 +95,8 @@ static int l_post(lua::State* L, network::Network& network) { string = json::stringify(data, false); } + auto headers = read_headers(L, 5); + engine->getNetwork().post(url, string, [onResponse](std::vector bytes) { auto buffer = std::make_shared>( reinterpret_cast(bytes.data()), bytes.size() @@ -84,7 +104,7 @@ static int l_post(lua::State* L, network::Network& network) { engine->postRunnable([=]() { onResponse({std::string(bytes.data(), bytes.size())}); }); - }, std::move(onReject)); + }, std::move(onReject), std::move(headers)); return 0; } diff --git a/src/network/Network.cpp b/src/network/Network.cpp index 234197e4..b0482258 100644 --- a/src/network/Network.cpp +++ b/src/network/Network.cpp @@ -57,6 +57,7 @@ struct Request { long maxSize; bool followLocation = false; std::string data; + std::vector headers; }; class CurlRequests : public Requests { @@ -86,10 +87,18 @@ public: const std::string& url, OnResponse onResponse, OnReject onReject, + std::vector headers, long maxSize ) override { Request request { - RequestType::GET, url, onResponse, onReject, maxSize, false, ""}; + RequestType::GET, + url, + onResponse, + onReject, + maxSize, + false, + "", + std::move(headers)}; processRequest(std::move(request)); } @@ -98,10 +107,18 @@ public: const std::string& data, OnResponse onResponse, OnReject onReject=nullptr, + std::vector headers = {}, long maxSize=0 ) override { Request request { - RequestType::POST, url, onResponse, onReject, maxSize, false, ""}; + RequestType::POST, + url, + onResponse, + onReject, + maxSize, + false, + "", + std::move(headers)}; request.data = data; processRequest(std::move(request)); } @@ -121,6 +138,10 @@ public: curl_easy_setopt(curl, CURLOPT_POST, request.type == RequestType::POST); curl_slist* hs = NULL; + + for (const auto& header : request.headers) { + hs = curl_slist_append(hs, header.c_str()); + } switch (request.type) { case RequestType::GET: @@ -817,9 +838,10 @@ void Network::get( const std::string& url, OnResponse onResponse, OnReject onReject, + std::vector headers, long maxSize ) { - requests->get(url, onResponse, onReject, maxSize); + requests->get(url, onResponse, onReject, std::move(headers), maxSize); } void Network::post( @@ -827,9 +849,12 @@ void Network::post( const std::string& fieldsData, OnResponse onResponse, OnReject onReject, + std::vector headers, long maxSize ) { - requests->post(url, fieldsData, onResponse, onReject, maxSize); + requests->post( + url, fieldsData, onResponse, onReject, std::move(headers), maxSize + ); } Connection* Network::getConnection(u64id_t id) { diff --git a/src/network/Network.hpp b/src/network/Network.hpp index ddde70b5..41ebbe13 100644 --- a/src/network/Network.hpp +++ b/src/network/Network.hpp @@ -25,6 +25,7 @@ namespace network { const std::string& url, OnResponse onResponse, OnReject onReject=nullptr, + std::vector headers = {}, long maxSize=0 ) = 0; @@ -33,6 +34,7 @@ namespace network { const std::string& data, OnResponse onResponse, OnReject onReject=nullptr, + std::vector headers = {}, long maxSize=0 ) = 0; @@ -144,6 +146,7 @@ namespace network { const std::string& url, OnResponse onResponse, OnReject onReject = nullptr, + std::vector headers = {}, long maxSize=0 ); @@ -152,6 +155,7 @@ namespace network { const std::string& fieldsData, OnResponse onResponse, OnReject onReject = nullptr, + std::vector headers = {}, long maxSize=0 );