A Cheat Sheet for HTTP Libraries in C++
C++Unfortunately, standard C++ library doesn’t provide tools for working with HTTP. Therefore, when we want to run a REST service, parse a webpage or write a simple bot or web crawler, we always wonder which library is better to 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
- WinHttp
- Casablanca
- Qt
- POCO
- wxWidgets
- Boost.Asio
- libcurl
- neon
- .NET (С++/CLI)
- IXMLHTTPRequest
- HappyHttp
- cpp-netlib
WinInet
Website: http://msdn.microsoft.com/en-us/library/windows/desktop/aa385483(v=vs.85).aspx Platform: Windows 95 and later
#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
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
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
#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
#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
#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
#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
#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
#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
#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
#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
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
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 what’s available in the platform’s standard. But if you’re writing something with no interface, and besides an HTTP client you also want to have various handy tools, use Boost or POCO.
Comments
Corvusoft
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.
Anton K2
Corvusoft