Add HTTP GET function

The function performs a HTTP GET on a URL and returns the HTTP response.
This commit is contained in:
Markus Mäkelä 2018-08-19 07:05:22 +03:00
parent 91ab59530f
commit f8fb9510c9
No known key found for this signature in database
GPG Key ID: 72D48FCE664F7B19
6 changed files with 111 additions and 3 deletions

View File

@ -16,7 +16,7 @@ then
build-essential libssl-dev ncurses-dev bison flex \
perl libtool libpcre3-dev tcl tcl-dev uuid \
uuid-dev libsqlite3-dev liblzma-dev libpam0g-dev pkg-config \
libedit-dev
libedit-dev libcurl4-openssl-dev
## separatelibgnutls installation process for Ubuntu Trusty
cat /etc/*release | grep -E "Trusty|wheezy"
@ -49,7 +49,7 @@ else
make libtool libopenssl-devel libaio libaio-devel flex \
pcre-devel git wget tcl libuuid-devel \
xz-devel sqlite3 sqlite3-devel pkg-config lua lua-devel \
gnutls-devel libgcrypt-devel pam-devel
gnutls-devel libgcrypt-devel pam-devel libcurl-devel
sudo zypper -n install rpm-build
cat /etc/*-release | grep "SUSE Linux Enterprise Server 11"
@ -66,7 +66,7 @@ else
libedit-devel systemtap-sdt-devel rpm-sign wget \
gnupg pcre-devel flex rpmdevtools git wget tcl openssl libuuid-devel xz-devel \
sqlite sqlite-devel pkgconfig lua lua-devel rpm-build createrepo yum-utils \
gnutls-devel libgcrypt-devel pam-devel
gnutls-devel libgcrypt-devel pam-devel libcurl-devel
# Attempt to install libasan, it'll only work on CentOS 7
sudo yum install -y --nogpgcheck libasan

View File

@ -44,6 +44,7 @@ find_package(GSSAPI)
find_package(SQLite)
find_package(ASAN)
find_package(TSAN)
find_package(CURL)
# Build PCRE2 so we always know the version
# Read BuildPCRE2 for details about how to add pcre2 as a dependency to a target

View File

@ -11,6 +11,7 @@ requirements are as follows:
* Flex 2.5.35 or later
* libuuid
* GNUTLS
* libcurl
This is the minimum set of requirements that must be met to build the MaxScale
core package.

View File

@ -22,12 +22,14 @@
#include <array>
#include <functional>
#include <iterator>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
#include <maxscale/buffer.h>
#include <maxscale/utils.h>
#include <maxscale/jansson.hh>
namespace maxscale
{
@ -645,4 +647,26 @@ uint64_t get_byteN(const uint8_t* ptr, int bytes);
*/
uint8_t* set_byteN(uint8_t* ptr, uint64_t value, int bytes);
namespace http
{
struct Result
{
int code; // HTTP response code
std::string raw_body; // Raw response body
std::unique_ptr<json_t> body; // JSON form of the body if it was valid JSON
std::unordered_map<std::string, std::string> headers; // Headers attached to the response
};
/**
* Do a HTTP GET
*
* @param url URL to use
*
* @return A Result
*/
Result get(const std::string& url);
}
}

View File

@ -74,6 +74,7 @@ target_link_libraries(maxscale-common
gnutls
gcrypt
${MICROHTTPD_LIBRARIES}
${CURL_LIBRARIES}
)
find_library(HAVE_LIBDL NAMES dl)

View File

@ -40,6 +40,7 @@
#include <sys/types.h>
#include <netinet/tcp.h>
#include <openssl/sha.h>
#include <curl/curl.h>
#include <maxscale/alloc.h>
#include <maxscale/config.h>
@ -1198,4 +1199,84 @@ std::string string_printf(const char* format, ...)
return rval;
}
namespace
{
size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
{
std::string* buf = static_cast<std::string*>(userdata);
if (nmemb > 0)
{
buf->append(ptr, nmemb);
}
return nmemb;
}
size_t header_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
{
std::unordered_map<std::string, std::string>* map =
static_cast<std::unordered_map<std::string, std::string>*>(userdata);
if (nmemb > 0)
{
std::string data(ptr, size * nmemb);
auto pos = data.find_first_of(':');
if (pos != std::string::npos)
{
std::string key = data.substr(0, pos);
std::string value = data.substr(pos + 1);
trim(key);
trim(value);
map->insert(std::make_pair(key, value));
}
}
return nmemb * size;
}
}
namespace http
{
Result get(const std::string& url)
{
Result res;
char errbuf[CURL_ERROR_SIZE + 1] = "";
CURL* curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &res.raw_body);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, &res.headers);
long code = 0; // needs to be a long
if (curl_easy_perform(curl) == CURLE_OK)
{
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
res.code = code;
}
else
{
res.code = -1;
res.raw_body = errbuf;
}
// Even the errors are valid JSON so this should be OK
json_error_t err;
res.body.reset(json_loads(res.raw_body.c_str(), 0, &err));
curl_easy_cleanup(curl);
return std::move(res);
}
}
}