diff options
author | Dan Goodliffe <dan@randomdan.homeip.net> | 2015-08-28 00:36:44 +0100 |
---|---|---|
committer | Dan Goodliffe <dan@randomdan.homeip.net> | 2015-08-28 00:36:44 +0100 |
commit | f3837b3e0597bf5d7546f6f77374618980e98ca2 (patch) | |
tree | 3796683a40709c71c728506f1c483feaf8fa5de0 | |
parent | Add RuntimeContext for easy context switching (diff) | |
download | libadhocutil-f3837b3e0597bf5d7546f6f77374618980e98ca2.tar.bz2 libadhocutil-f3837b3e0597bf5d7546f6f77374618980e98ca2.tar.xz libadhocutil-f3837b3e0597bf5d7546f6f77374618980e98ca2.zip |
Add CurlStreamSource for reading a cURL request as a std::istream
-rw-r--r-- | libadhocutil/curlStream.cpp | 81 | ||||
-rw-r--r-- | libadhocutil/curlStream.h | 39 | ||||
-rw-r--r-- | libadhocutil/net.ice | 10 | ||||
-rw-r--r-- | libadhocutil/unittests/Jamfile.jam | 13 | ||||
-rw-r--r-- | libadhocutil/unittests/testCurlStream.cpp | 20 |
5 files changed, 163 insertions, 0 deletions
diff --git a/libadhocutil/curlStream.cpp b/libadhocutil/curlStream.cpp new file mode 100644 index 0000000..850dea8 --- /dev/null +++ b/libadhocutil/curlStream.cpp @@ -0,0 +1,81 @@ +#include "curlStream.h" +#include <net.h> + +CurlStreamSource::CurlStreamSource(const std::string & url) : + curl_handle(curl_easy_init()), + curl_headers(nullptr), + buflen(0), + buf(nullptr), + res(CURLE_OK) +{ + curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str()); + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, &CurlStreamSource::recvWrapper); + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, this); +} + +CurlStreamSource::~CurlStreamSource() +{ + if (curl_headers) { + curl_slist_free_all(curl_headers); + } + if (res != CURLE_OK) { + AdHoc::Net::CurlException ce(res, curl_easy_strerror(res), IceUtil::Optional<Ice::Short>()); + long http_code = 0; + if (curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &http_code) == CURLE_OK) { + ce.httpcode = http_code; + } + curl_easy_cleanup(curl_handle); + throw ce; + } + curl_easy_cleanup(curl_handle); +} + +std::streamsize +CurlStreamSource::read(char * target, std::streamsize targetSize) +{ + if (!buflen) { + SwapContext(); + } + size_t bytes = std::min<size_t>(buflen, targetSize); + memcpy(target, buf, bytes); + buflen -= bytes; + buf += bytes; + return bytes; +} + +void +CurlStreamSource::setopt(CURLoption opt, const void * & val) +{ + curl_easy_setopt(curl_handle, opt, val); +} + +void +CurlStreamSource::appendHeader(const char * header) +{ + curl_headers = curl_slist_append(curl_headers, header); +} + +void +CurlStreamSource::Callback() +{ + if (curl_headers) { + curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, curl_headers); + } + res = curl_easy_perform(curl_handle); +} + +size_t +CurlStreamSource::recvWrapper(void * data, size_t sz, size_t nm, void * css) +{ + return static_cast<CurlStreamSource *>(css)->recv(data, sz * nm); +} + +size_t +CurlStreamSource::recv(void * data, size_t datalen) +{ + buf = (char *)data; + buflen = datalen; + SwapContext(); + return datalen; +} + diff --git a/libadhocutil/curlStream.h b/libadhocutil/curlStream.h new file mode 100644 index 0000000..459a472 --- /dev/null +++ b/libadhocutil/curlStream.h @@ -0,0 +1,39 @@ +#ifndef ADHOCUTIL_CURLSTREAM_H +#define ADHOCUTIL_CURLSTREAM_H + +#include <boost/iostreams/stream.hpp> +#include "runtimeContext.h" +#include <string> +#include <curl/curl.h> +#include "visibility.h" + +class DLL_PUBLIC CurlStreamSource : public boost::iostreams::source, RuntimeContext { + public: + CurlStreamSource(const std::string & url); + ~CurlStreamSource(); + + CurlStreamSource(const CurlStreamSource &) = delete; + void operator=(const CurlStreamSource &) = delete; + + std::streamsize read(char * target, std::streamsize targetSize); + + void setopt(CURLoption opt, const void * & val); + void appendHeader(const char * header); + + private: + DLL_PRIVATE void Callback() override; + + DLL_PRIVATE static size_t recvWrapper(void * data, size_t sz, size_t nm, void * css); + DLL_PRIVATE size_t recv(void * data, size_t datalen); + + CURL * curl_handle; + struct curl_slist * curl_headers; + size_t buflen; + char * buf; + CURLcode res; +}; + +typedef boost::reference_wrapper<CurlStreamSource> css_ref; + +#endif + diff --git a/libadhocutil/net.ice b/libadhocutil/net.ice new file mode 100644 index 0000000..510d749 --- /dev/null +++ b/libadhocutil/net.ice @@ -0,0 +1,10 @@ +module AdHoc { + module Net { + exception CurlException { + int resultcode; + string message; + optional(1) short httpcode; + }; + }; +}; + diff --git a/libadhocutil/unittests/Jamfile.jam b/libadhocutil/unittests/Jamfile.jam index 65d8fad..33ff61b 100644 --- a/libadhocutil/unittests/Jamfile.jam +++ b/libadhocutil/unittests/Jamfile.jam @@ -17,3 +17,16 @@ run testContext ; +run + testCurlStream.cpp + : : : + <define>ROOT=\"$(me)\" + <define>BOOST_TEST_DYN_LINK + <library>..//adhocutil + <library>boost_utf + <library>boost_filesystem + <library>boost_system + : + testCurlStream + ; + diff --git a/libadhocutil/unittests/testCurlStream.cpp b/libadhocutil/unittests/testCurlStream.cpp new file mode 100644 index 0000000..48e3c27 --- /dev/null +++ b/libadhocutil/unittests/testCurlStream.cpp @@ -0,0 +1,20 @@ +#define BOOST_TEST_MODULE CurlStream +#include <boost/test/unit_test.hpp> + +#include "curlStream.h" +#include "definedDirs.h" + +BOOST_AUTO_TEST_CASE( fetch_file ) +{ + auto url = "file://" + RootDir.string() + "/testCurlStream.cpp"; + CurlStreamSource css(url); + boost::iostreams::stream<css_ref> curlstrm(boost::ref(css)); + std::string tok; + curlstrm >> tok; + BOOST_REQUIRE_EQUAL("#define", tok); + curlstrm >> tok; + BOOST_REQUIRE_EQUAL("BOOST_TEST_MODULE", tok); + curlstrm >> tok; + BOOST_REQUIRE_EQUAL("CurlStream", tok); +} + |