diff options
| -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); +} + | 
