patterncppMinor
Tiny Curl C++ wrapper
Viewed 0 times
wrappercurltiny
Problem
I have written this sample code to fetch a web page in C++ using libcurl. Please review it.
```
#include
#include
#include
#include
extern "C"
{
#include
#include
}
//Exception class for curl exception
class CurlException : std::exception
{
public:
CurlException(std::string message):m_message(message) { }
CurlException(CURLcode error)
{
m_message = curl_easy_strerror(error);
}
const char* what() throw()
{
return m_message.c_str();
}
~CurlException() throw() { }
private:
std::string m_message;
};
//A tiny wrapper around Curl C Library
class CppCurl
{
public:
CppCurl(std::string url) throw (CurlException)
{
m_handle = curl_easy_init();
if ( m_handle == NULL )
throw CurlException("Unable to initialize curl handler");
if ( url.length() == 0 )
throw CurlException("URL can't be of zero length");
m_url = url;
}
std::string Fetch() throw (CurlException)
{
SetOptions();
SendGetRequest();
return m_data;
}
~CppCurl() throw()
{
curl_easy_cleanup(m_handle);
}
private:
void SetOptions() throw (CurlException)
{
CURLcode res;
//set the url
res = curl_easy_setopt(m_handle, CURLOPT_URL, m_url.c_str());
if ( res != CURLE_OK)
throw CurlException(res);
//progress bar is not require
res = curl_easy_setopt(m_handle, CURLOPT_NOPROGRESS, 1L);
if ( res != CURLE_OK )
throw CurlException(res);
//set the callback function
res = curl_easy_setopt(m_handle, CURLOPT_WRITEFUNCTION,
CppCurl::WriteDataCallback);
if ( res != CURLE_OK )
throw CurlException(res);
//set pointer in call back function
res = curl_easy_setopt(m_handle, CURLOPT_WRITEDATA, this);
if ( res != CURLE_OK )
throw CurlException(res);
}
void SendGetRequest()
{
CURLcode res;
res = curl_easy_perform(m_handle);
```
#include
#include
#include
#include
extern "C"
{
#include
#include
}
//Exception class for curl exception
class CurlException : std::exception
{
public:
CurlException(std::string message):m_message(message) { }
CurlException(CURLcode error)
{
m_message = curl_easy_strerror(error);
}
const char* what() throw()
{
return m_message.c_str();
}
~CurlException() throw() { }
private:
std::string m_message;
};
//A tiny wrapper around Curl C Library
class CppCurl
{
public:
CppCurl(std::string url) throw (CurlException)
{
m_handle = curl_easy_init();
if ( m_handle == NULL )
throw CurlException("Unable to initialize curl handler");
if ( url.length() == 0 )
throw CurlException("URL can't be of zero length");
m_url = url;
}
std::string Fetch() throw (CurlException)
{
SetOptions();
SendGetRequest();
return m_data;
}
~CppCurl() throw()
{
curl_easy_cleanup(m_handle);
}
private:
void SetOptions() throw (CurlException)
{
CURLcode res;
//set the url
res = curl_easy_setopt(m_handle, CURLOPT_URL, m_url.c_str());
if ( res != CURLE_OK)
throw CurlException(res);
//progress bar is not require
res = curl_easy_setopt(m_handle, CURLOPT_NOPROGRESS, 1L);
if ( res != CURLE_OK )
throw CurlException(res);
//set the callback function
res = curl_easy_setopt(m_handle, CURLOPT_WRITEFUNCTION,
CppCurl::WriteDataCallback);
if ( res != CURLE_OK )
throw CurlException(res);
//set pointer in call back function
res = curl_easy_setopt(m_handle, CURLOPT_WRITEDATA, this);
if ( res != CURLE_OK )
throw CurlException(res);
}
void SendGetRequest()
{
CURLcode res;
res = curl_easy_perform(m_handle);
Solution
You should probably derive from std::runtime_error.
It takes a string in the constructor as the message and stored it for use with what() in a way that is safe even in low memory situations:
Your exception class is then simplified too:
The use of exception specifications in C++ was an experiment that ultimitely showed it was a bad idea. The only useful specification was the no throw specification (and then only when you made sure it really was no-throw).
In C++11 exception specifications have been deprecated.
The curl library is a C library. It only knows about C calling conventions. Thus you can NOT pass it C++ functions. If it works it is pure luck and definately non portable.
Even though
You should do something like this:
Not a big deal but I would have used insert rather than +=.
It takes a string in the constructor as the message and stored it for use with what() in a way that is safe even in low memory situations:
Your exception class is then simplified too:
class CurlException : public std::runtime_error
{
public:
CurlException(std::string const& message): std::runtime_error(message) {}
// ^^^^^^^ pass message by const reference.
CurlException(CURLcode error): std::runtime_error(curl_easy_strerror(error)) {}
};The use of exception specifications in C++ was an experiment that ultimitely showed it was a bad idea. The only useful specification was the no throw specification (and then only when you made sure it really was no-throw).
void SetOptions() throw (CurlException)
// ^^^^^^^^^^^^^^^^^^^^^ Get rid of this bit.In C++11 exception specifications have been deprecated.
The curl library is a C library. It only knows about C calling conventions. Thus you can NOT pass it C++ functions. If it works it is pure luck and definately non portable.
res = curl_easy_setopt(m_handle, CURLOPT_WRITEFUNCTION,
CppCurl::WriteDataCallback);Even though
CppCurl::WriteDataCallback is a static function there is no guarantee that static methods have the same calling convention as a C function. Future versions of the compiler may break your code.You should do something like this:
extern "C" size_t WriteDataCallback(void *ptr, size_t size, size_t nmemb, void* pInstance)
{
CppCurl* obj = reinterpret_cast(pInstance);
return obj->write_data(ptr, size, nmemb);
}Not a big deal but I would have used insert rather than +=.
m_data += std::string(iter, iterEnd);
// -- or.
m_data.insert(m_data.begin(), iter, iterEnd);Code Snippets
class CurlException : public std::runtime_error
{
public:
CurlException(std::string const& message): std::runtime_error(message) {}
// ^^^^^^^ pass message by const reference.
CurlException(CURLcode error): std::runtime_error(curl_easy_strerror(error)) {}
};void SetOptions() throw (CurlException)
// ^^^^^^^^^^^^^^^^^^^^^ Get rid of this bit.res = curl_easy_setopt(m_handle, CURLOPT_WRITEFUNCTION,
CppCurl::WriteDataCallback);extern "C" size_t WriteDataCallback(void *ptr, size_t size, size_t nmemb, void* pInstance)
{
CppCurl* obj = reinterpret_cast<CppCurl*>(pInstance);
return obj->write_data(ptr, size, nmemb);
}m_data += std::string(iter, iterEnd);
// -- or.
m_data.insert(m_data.begin(), iter, iterEnd);Context
StackExchange Code Review Q#14389, answer score: 7
Revisions (0)
No revisions yet.