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
6 changed files with 111 additions and 3 deletions

View File

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

View File

@ -44,6 +44,7 @@ find_package(GSSAPI)
find_package(SQLite) find_package(SQLite)
find_package(ASAN) find_package(ASAN)
find_package(TSAN) find_package(TSAN)
find_package(CURL)
# Build PCRE2 so we always know the version # Build PCRE2 so we always know the version
# Read BuildPCRE2 for details about how to add pcre2 as a dependency to a target # 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 * Flex 2.5.35 or later
* libuuid * libuuid
* GNUTLS * GNUTLS
* libcurl
This is the minimum set of requirements that must be met to build the MaxScale This is the minimum set of requirements that must be met to build the MaxScale
core package. core package.

View File

@ -22,12 +22,14 @@
#include <array> #include <array>
#include <functional> #include <functional>
#include <iterator> #include <iterator>
#include <memory>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include <maxscale/buffer.h> #include <maxscale/buffer.h>
#include <maxscale/utils.h> #include <maxscale/utils.h>
#include <maxscale/jansson.hh>
namespace maxscale 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); 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 gnutls
gcrypt gcrypt
${MICROHTTPD_LIBRARIES} ${MICROHTTPD_LIBRARIES}
${CURL_LIBRARIES}
) )
find_library(HAVE_LIBDL NAMES dl) find_library(HAVE_LIBDL NAMES dl)

View File

@ -40,6 +40,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <openssl/sha.h> #include <openssl/sha.h>
#include <curl/curl.h>
#include <maxscale/alloc.h> #include <maxscale/alloc.h>
#include <maxscale/config.h> #include <maxscale/config.h>
@ -1198,4 +1199,84 @@ std::string string_printf(const char* format, ...)
return rval; 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);
}
}
} }