diff --git a/BUILD/install_build_deps.sh b/BUILD/install_build_deps.sh index 64d54048e..810bbf718 100755 --- a/BUILD/install_build_deps.sh +++ b/BUILD/install_build_deps.sh @@ -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 diff --git a/CMakeLists.txt b/CMakeLists.txt index 093c8d64e..7553b86de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/Documentation/Getting-Started/Building-MaxScale-from-Source-Code.md b/Documentation/Getting-Started/Building-MaxScale-from-Source-Code.md index be7621fab..c40021e94 100644 --- a/Documentation/Getting-Started/Building-MaxScale-from-Source-Code.md +++ b/Documentation/Getting-Started/Building-MaxScale-from-Source-Code.md @@ -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. diff --git a/include/maxscale/utils.hh b/include/maxscale/utils.hh index 34821ad58..a87d5c4ef 100644 --- a/include/maxscale/utils.hh +++ b/include/maxscale/utils.hh @@ -22,12 +22,14 @@ #include #include #include +#include #include #include #include #include #include +#include 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 body; // JSON form of the body if it was valid JSON + std::unordered_map headers; // Headers attached to the response +}; + +/** + * Do a HTTP GET + * + * @param url URL to use + * + * @return A Result + */ +Result get(const std::string& url); + +} + } diff --git a/server/core/CMakeLists.txt b/server/core/CMakeLists.txt index 2d3f7ce9b..c86a0c101 100644 --- a/server/core/CMakeLists.txt +++ b/server/core/CMakeLists.txt @@ -74,6 +74,7 @@ target_link_libraries(maxscale-common gnutls gcrypt ${MICROHTTPD_LIBRARIES} + ${CURL_LIBRARIES} ) find_library(HAVE_LIBDL NAMES dl) diff --git a/server/core/utils.cc b/server/core/utils.cc index 5f0130afa..4d77fa8f7 100644 --- a/server/core/utils.cc +++ b/server/core/utils.cc @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -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(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* map = + static_cast*>(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); +} + +} + }