Skip to content

Commit

Permalink
Merge pull request #335 from spelunky-fyi/HttpGet
Browse files Browse the repository at this point in the history
Add http GET api
  • Loading branch information
Dregu authored Sep 27, 2023
2 parents fe13d9a + 9a3f333 commit 60ff1bd
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 0 deletions.
126 changes: 126 additions & 0 deletions src/game_api/script/usertypes/socket_lua.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,16 @@
#include <tuple> // for get
#include <type_traits> // for move
#include <utility> // for max, min
#include <wininet.h> // for InternetCloseHandle, InternetOpenA, InternetG...
#include <winsock2.h> // for sockaddr_in, SOCKET
#include <ws2tcpip.h> // for inet_ntop

#include "logger.h" // for DEBUG, ByteStr
#include "script/lua_backend.hpp" // for LuaBackend
#include "script/safe_cb.hpp" // for make_safe_cb

#pragma comment(lib, "wininet.lib")

void udp_data(sockpp::udp_socket socket, UdpServer* server)
{
ssize_t n;
Expand Down Expand Up @@ -69,6 +72,105 @@ int myRecvfrom(SOCKET s, char* buf, int len, int flags, sockaddr_in* addr, int*
return ret;
}

bool http_get(const char* sURL, std::string& out, std::string& err)
{
const int BUFFER_SIZE = 32768;
DWORD iFlags;
const char* sAgent = "curl";
const char* sHeader = NULL;
HINTERNET hInternet;
HINTERNET hConnect;
char acBuffer[BUFFER_SIZE];
DWORD iReadBytes;
DWORD iBytesToRead = 0;
DWORD iReadBytesOfRq = 4;

// Get connection state
InternetGetConnectedState(&iFlags, 0);
if (iFlags & INTERNET_CONNECTION_OFFLINE)
{
err = "Can't connect to the internet";
return false;
}

// Open internet session
if (!(iFlags & INTERNET_CONNECTION_PROXY))
{
hInternet = InternetOpenA(sAgent, INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY, NULL, NULL, 0);
}
else
{
hInternet = InternetOpenA(sAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
}
if (hInternet)
{
if (sHeader == NULL)
{
sHeader = "Accept: */*\r\n\r\n";
}

hConnect = InternetOpenUrlA(hInternet, sURL, sHeader, lstrlenA(sHeader), INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_RELOAD, 0);
if (!hConnect)
{
InternetCloseHandle(hInternet);
err = "Can't connect to the url";
return false;
}

// Get content size
if (!HttpQueryInfo(hConnect, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, (LPVOID)&iBytesToRead, &iReadBytesOfRq, NULL))
{
iBytesToRead = 0;
}

do
{
if (!InternetReadFile(hConnect, acBuffer, BUFFER_SIZE, &iReadBytes))
{
InternetCloseHandle(hInternet);
err = "GET request failed";
return false;
}
if (iReadBytes > 0)
{
out += std::string(acBuffer, iReadBytes);
}
if (iReadBytes <= 0)
{
break;
}
} while (TRUE);
InternetCloseHandle(hInternet);
}
else
{
err = "Can't connect to the internet";
return false;
}

return true;
}

void http_get_async(HttpRequest* req)
{
if (http_get(req->url.c_str(), req->response, req->error))
{
req->cb(req->response, std::nullopt);
}
else
{
req->cb(std::nullopt, req->error);
}
delete req;
}

HttpRequest::HttpRequest(std::string url_, std::function<HttpCb> cb_)
: url(url_), cb(cb_)
{
std::thread thr(http_get_async, this);
thr.detach();
}

namespace NSocket
{
void register_usertypes(sol::state& lua)
Expand Down Expand Up @@ -104,5 +206,29 @@ void register_usertypes(sol::state& lua)
DEBUG("Failed hooking network: {}\n", error);
}
};

/// Send a synchronous HTTP GET request and return response as a string or nil on an error
lua["http_get"] = [&lua](std::string url) -> sol::optional<std::string>
{
std::string out;
std::string err;
if (http_get(url.c_str(), out, err))
{
return out;
}
else
{
luaL_error(lua, err.c_str());
}
return std::nullopt;
};

/// Send an asynchronous HTTP GET request and run the callback when done. If there is an error, response will be nil and vice versa.
/// The callback signature is nil on_data(string response, string error)
lua["http_get_async"] = [](std::string url, sol::function on_data) -> HttpRequest*
{
auto req = new HttpRequest(std::move(url), make_safe_cb<HttpRequest::HttpCb>(std::move(on_data)));
return req;
};
}
}; // namespace NSocket
12 changes: 12 additions & 0 deletions src/game_api/script/usertypes/socket_lua.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ class UdpServer
sockpp::udp_socket sock;
};

class HttpRequest
{
public:
using HttpCb = void(std::optional<std::string>, std::optional<std::string>);

HttpRequest(std::string url, std::function<HttpCb> cb);
std::string url;
std::function<HttpCb> cb;
std::string response;
std::string error;
};

namespace NSocket
{
void register_usertypes(sol::state& lua);
Expand Down

0 comments on commit 60ff1bd

Please sign in to comment.