Unfortunately, standard C++ library provides no tools for working with HTTP protocol. Therefore, when we want to run some REST service, parse a webpage or write a simple bot or web crawler, we always wonder which library is better and faster in use. Sometimes a project already uses some framework (or even several). But how do we create an HTTP request using available facilities? Not to get confused each time performing such tasks, I decided to make a cheat sheet with examples of HTTP requests in C++ using different libraries. I guess Kukuruku is the best place for keeping such cheat sheets.

We’re going to take a look at the following libraries:


WinInet

Website: http://msdn.microsoft.com/en-us/library/windows/desktop/aa385483(v=vs.85).aspx
Platform: Windows 95 and later
Example
#include 
    #include   

    /// ....

    HINTERNET hIntSession = 
      ::InternetOpen(_T("MyApp"), INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);

    HINTERNET hHttpSession = 
      InternetConnect(hIntSession, _T("api.twitter.com"), 80, 0, 0, INTERNET_SERVICE_HTTP, 0, NULL);

    HINTERNET hHttpRequest = HttpOpenRequest(
      hHttpSession, 
      _T("GET"), 
      _T("1/statuses/user_timeline.xml?screen_name=twitterapi"),
      0, 0, 0, INTERNET_FLAG_RELOAD, 0);

    TCHAR* szHeaders = _T("Content-Type: text/html\nMySpecialHeder: whatever");
    CHAR szReq[1024] = "";
    if( !HttpSendRequest(hHttpRequest, szHeaders, _tcslen(szHeaders), szReq, strlen(szReq))) {
      DWORD dwErr = GetLastError();
      /// handle error
    }

    CHAR szBuffer[1025];
    DWORD dwRead=0;
    while(::InternetReadFile(hHttpRequest, szBuffer, sizeof(szBuffer)-1, &dwRead) && dwRead) {
      szBuffer[dwRead] = 0;
      OutputDebugStringA(szBuffer);
      dwRead=0;
    }

    ::InternetCloseHandle(hHttpRequest);
    ::InternetCloseHandle(hHttpSession);
    ::InternetCloseHandle(hIntSession);



WinHttp

Website: http://msdn.microsoft.com/en-us/library/windows/desktop/aa382925(v=vs.85).aspx
Platform: Windows 2000 and later
Example
DWORD dwSize = 0;
  DWORD dwDownloaded = 0;
  LPSTR pszOutBuffer;
  BOOL  bResults = FALSE;
  HINTERNET  hSession = NULL, 
             hConnect = NULL,
             hRequest = NULL;

  // Use WinHttpOpen to obtain a session handle.
  hSession = WinHttpOpen( L"WinHTTP Example/1.0",  
                          WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
                          WINHTTP_NO_PROXY_NAME, 
                          WINHTTP_NO_PROXY_BYPASS, 0 );

  // Specify an HTTP server.
  if( hSession )
    hConnect = WinHttpConnect( hSession, L"www.microsoft.com",
                               INTERNET_DEFAULT_HTTPS_PORT, 0 );

  // Create an HTTP request handle.
  if( hConnect )
    hRequest = WinHttpOpenRequest( hConnect, L"GET", NULL,
                                   NULL, WINHTTP_NO_REFERER, 
                                   WINHTTP_DEFAULT_ACCEPT_TYPES, 
                                   WINHTTP_FLAG_SECURE );

  // Send a request.
  if( hRequest )
    bResults = WinHttpSendRequest( hRequest,
                                   WINHTTP_NO_ADDITIONAL_HEADERS, 0,
                                   WINHTTP_NO_REQUEST_DATA, 0, 
                                   0, 0 );


  // End the request.
  if( bResults )
    bResults = WinHttpReceiveResponse( hRequest, NULL );

  // Keep checking for data until there is nothing left.
  if( bResults )
  {
    do 
    {
      // Check for available data.
      dwSize = 0;
      if( !WinHttpQueryDataAvailable( hRequest, &dwSize ) )
        printf( "Error %u in WinHttpQueryDataAvailable.\n",
                GetLastError( ) );

      // Allocate space for the buffer.
      pszOutBuffer = new char[dwSize+1];
      if( !pszOutBuffer )
      {
        printf( "Out of memory\n" );
        dwSize=0;
      }
      else
      {
        // Read the data.
        ZeroMemory( pszOutBuffer, dwSize+1 );

        if( !WinHttpReadData( hRequest, (LPVOID)pszOutBuffer, 
                              dwSize, &dwDownloaded ) )
          printf( "Error %u in WinHttpReadData.\n", GetLastError( ) );
        else
          printf( "%s", pszOutBuffer );

        // Free the memory allocated to the buffer.
        delete [] pszOutBuffer;
      }
    } while( dwSize > 0 );
  }


  // Report any errors.
  if( !bResults )
    printf( "Error %d has occurred.\n", GetLastError( ) );

  // Close any open handles.
  if( hRequest ) WinHttpCloseHandle( hRequest );
  if( hConnect ) WinHttpCloseHandle( hConnect );
  if( hSession ) WinHttpCloseHandle( hSession );



Casablanca

Website: https://casablanca.codeplex.com
Platform: all
Example
http_client client(L"http://www.myhttpserver.com");
http_request request(methods::GET);
client.request(request).then([](http_response response)
    {
        // Perform actions here to inspect the HTTP response...
        if(response.status_code() == status_codes::OK)
        {
        }
    });



Qt

Website: http://qt-project.org
Platform: all
Example use for Qt 4.x (already outdated)
#include "handler.h"
 
Handler::Handler(QObject *parent) :QObject(parent)  {
    http = new QHttp(this);
    connect(http, SIGNAL(stateChanged(int)), this, SLOT(stateChanged(int)));
    connect(http, SIGNAL(responseHeaderReceived(QHttpResponseHeader)), this, SLOT(responseHeaderReceived(QHttpResponseHeader)));
    connect(http, SIGNAL(requestFinished(int,bool)), this, SLOT(requestFinished(int,bool)));
}
 
void Handler::doHttp()  {
    http->setHost("google.com");
    http->get("/");
}
 
void Handler::stateChanged(int state)   {
    switch(state)   {
    case 0:
        qDebug() readAll();
    }
}


Example use for Qt 5.x
void Downloader::doDownload()
{
    manager = new QNetworkAccessManager(this);

    connect(manager, SIGNAL(finished(QNetworkReply*)),
            this, SLOT(replyFinished(QNetworkReply*)));

    manager->get(QNetworkRequest(QUrl("http://google.com")));
}

void Downloader::replyFinished (QNetworkReply *reply)
{
   if(reply->error() != QNetworkReply::NoError)
    {
        qDebug() errorString();
    }
    else
    {
        qDebug() header(QNetworkRequest::ContentTypeHeader).toString();
        qDebug() header(QNetworkRequest::LastModifiedHeader).toDateTime().toString();
        qDebug() header(QNetworkRequest::ContentLengthHeader).toULongLong();
        qDebug() attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
        qDebug() attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();

        QFile file("C:/Qt/Dummy/downloaded.txt");
        if(file.open(QFile::Append))
        {
            file.write(reply->readAll());
        }
    }

    reply->deleteLater();
}



POCO

Website: http://pocoproject.org
Platform: all
Example
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace Poco::Net;
using namespace Poco;
using namespace std;

int main(int argc, char **argv)
{
  if (argc != 2)
  {
    cout "  and print it" 



wxWidgets

Website: http://www.wxwidgets.org
Platform: all
Example
#include 
#include 
 
wxHTTP get;
get.SetHeader(_T("Content-type"), _T("text/html; charset=utf-8"));
get.SetTimeout(10); // 10 seconds of timeout instead of 10 minutes ...
 
// this will wait until the user connects to the internet. It is important in case of dialup (or ADSL) connections
while (!get.Connect(_T("www.google.com")))  // only the server, no pages here yet ...
    wxSleep(5);
 
wxApp::IsMainLoopRunning(); // should return true
 
// use _T("/") for index.html, index.php, default.asp, etc.
wxInputStream *httpStream = get.GetInputStream(_T("/intl/en/about.html"));
 
// wxLogVerbose( wxString(_T(" GetInputStream: ")) Read(out_stream);
 
    wxMessageBox(res);
    // wxLogVerbose( wxString(_T(" returned document length: ")) 



Boost.Asio

Website: http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio.html
Platform: all
Example
#include 
#include 
#include 
#include 
#include 

using boost::asio::ip::tcp;

int main(int argc, char* argv[])
{
  try
  {
    if (argc != 3)
    {
      std::cout  \n";
      std::cout > http_version;
    unsigned int status_code;
    response_stream >> status_code;
    std::string status_message;
    std::getline(response_stream, status_message);
    if (!response_stream || http_version.substr(0, 5) != "HTTP/")
    {
      std::cout  0)
      std::cout 



libcurl

Website: http://curl.haxx.se/libcurl
Platform: all
Example
#include 
#include 
 
int main(void)
{
  CURL *curl;
  CURLcode res;
 
  curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "http://example.com");
    /* example.com is redirected, so we tell libcurl to follow redirection */ 
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
 
    /* Perform the request, res will get the return code */ 
    res = curl_easy_perform(curl);
    /* Check for errors */ 
    if(res != CURLE_OK)
      fprintf(stderr, "curl_easy_perform() failed: %s\n",
              curl_easy_strerror(res));
 
    /* always cleanup */ 
    curl_easy_cleanup(curl);
  }
  return 0;
}



neon

Website: http://www.webdav.org/neon
Platform: all
Example
#include 
#include 
#include 
#include 

int httpResponseReader(void *userdata, const char *buf, size_t len)
{
    string *str = (string *)userdata;
    str->append(buf, len);
    return 0;
}
 
int do_get(string host)
{
    ne_session *sess;
    ne_request *req;
    string response;
 
    ne_sock_init();
 
    sess = ne_session_create("http", host.c_str(), 80);
    ne_set_useragent(sess, "MyAgent/1.0");
 
    req = ne_request_create(sess, "GET", "/SomeURL/method?with=parameter&value=data");
    // if accepting only 2xx codes, use "ne_accept_2xx"
    ne_add_response_body_reader(req, ne_accept_always, httpResponseReader, &response);
 
    int result = ne_request_dispatch(req);
    int status = ne_get_status(req)->code;
 
    ne_request_destroy(req);
 
    string errorMessage = ne_get_error(sess);
    ne_session_destroy(sess);
 
    printf("result %d, status %d\n", result, status);
    cout 



.NET

Website: http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.aspx
Platform: Windows XP and later
Example
#using 

using namespace System;
using namespace System::Net;
using namespace System::Text;
using namespace System::IO;

// Specify the URL to receive the request.
int main()
{
   array^args = Environment::GetCommandLineArgs();
   HttpWebRequest^ request = dynamic_cast(WebRequest::Create( args[ 1 ] ));

   // Set some reasonable limits on resources used by this request
   request->MaximumAutomaticRedirections = 4;
   request->MaximumResponseHeadersLength = 4;

   // Set credentials to use for this request.
   request->Credentials = CredentialCache::DefaultCredentials;
   HttpWebResponse^ response = dynamic_cast(request->GetResponse());
   Console::WriteLine( "Content length is {0}", response->ContentLength );
   Console::WriteLine( "Content type is {0}", response->ContentType );

   // Get the stream associated with the response.
   Stream^ receiveStream = response->GetResponseStream();

   // Pipes the stream to a higher level stream reader with the required encoding format. 
   StreamReader^ readStream = gcnew StreamReader( receiveStream,Encoding::UTF8 );
   Console::WriteLine( "Response stream received." );
   Console::WriteLine( readStream->ReadToEnd() );
   response->Close();
   readStream->Close();
}



IXMLHTTPRequest

Website: http://msdn.microsoft.com/en-us/library/ms759148(v=vs.85).aspx
Platform: Windows XP and later
Example
#include 
#include 

HRESULT hr;
CComPtr request;

hr = request.CoCreateInstance(CLSID_XMLHTTP60);
hr = request->open(
    _bstr_t("GET"),
    _bstr_t("https://www.google.com/images/srpr/logo11w.png"),
    _variant_t(VARIANT_FALSE),
    _variant_t(),
    _variant_t());
hr = request->send(_variant_t());

// get status - 200 if succuss
long status;
hr = request->get_status(&status);

// load image data (if url points to an image)
VARIANT responseVariant;
hr = request->get_responseStream(&responseVariant);
IStream* stream = (IStream*)responseVariant.punkVal;
CImage *image = new CImage();
image->Load(stream);
stream->Release();



HappyHttp

Website: http://scumways.com/happyhttp/happyhttp.html
Platform: all
Example
static int count=0;

// invoked when response headers have been received
void OnBegin( const happyhttp::Response* r, void* userdata )
{
    printf( "BEGIN (%d %s)\n", r->getstatus(), r->getreason() );
    count = 0;
}

// invoked to process response body data (may be called multiple times)
void OnData( const happyhttp::Response* r, void* userdata, const unsigned char* data, int n )
{
    fwrite( data,1,n, stdout );
    count += n;
}

// invoked when response is complete
void OnComplete( const happyhttp::Response* r, void* userdata )
{
    printf( "COMPLETE (%d bytes)\n", count );
}


void TestGET()
{
    happyhttp::Connection conn( "www.scumways.com", 80 );
    conn.setcallbacks( OnBegin, OnData, OnComplete, 0 );

    conn.request( "GET", "/happyhttp/test.php" );

    while( conn.outstanding() )
        conn.pump();
}



cpp-netlib

Website: http://cpp-netlib.org
Platform: all
Example
using namespace boost::network;
using namespace boost::network::http;

client::request request_("http://127.0.0.1:8000/");
request_ 



It’s High Time to Find Out the Perfect One!

If you want to use the trusted classics – use libcurl. If you’re writing an application with a visual interface – use Qt. For those writing in С++11, Casablanca is the best choice. If you’re writing under .NET, then you should use standard platform facilities. But if you’re writing something with no interface and besides an HTTP client you want to have various handy tools as well, use Boost or POCO.

Write your own articles at Kukuruku Hub

1 comment

Corvusoft
I see Restbed didn't make the cut.

Restbed brings asynchronous RESTful service to C++11 applications. I'm full throttle on the development and hope to have HTTP 2 functionality towards the end of the year.

I'd love to hear any feed back regarding the project.

Read Next

Hi Everyone! We are about to launch a new project very soon - CrowdMind.co. Sign up to get a private beta access!