HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Tiny Curl C++ wrapper

Submitted by: @import:stackexchange-codereview··
0
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);

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:

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.