Pull to refresh
0
Инфопульс Украина
Creating Value, Delivering Excellence

Шпаргалка по HTTP-библиотекам для С++

Reading time 12 min
Views 107K
К сожалению, в стандартной библиотеке языка С++ нет никаких средств для работы с протоколом HTTP. Возможно, в будущем появятся, но на данный момент каждый раз при необходимости дёрнуть какой-нибудь REST-сервис, пропарсить веб-страничку, написать простенького бота или краулера приходится задаваться вопросами «А какую же библиотеку взять, так чтобы побыстрее и попроще?». Иногда проект уже использует какой-то фреймворк (а иногда даже несколько) и тогда приходится вспоминать «А как же сделать HTTP-запрос имеющимися средствами?». Чтобы не путаться я решил написать для себя шпаргалку с примерами HTTP-запросов на С++ с применением разных библиотек. А самое удобное место для хранения подобных шпаргалок — Хабр: и сам не потеряешь, и другим может пригодиться.

Будут рассмотрены:
  • WinInet
  • WinHttp
  • Casablanca
  • Qt
  • POCO
  • wxWidgets
  • Boost.Asio
  • libcurl
  • neon
  • .NET (С++/CLI)
  • IXMLHTTPRequest
  • HappyHttp
  • cpp-netlib




WinInet


Сайт: http://msdn.microsoft.com/en-us/library/windows/desktop/aa385483(v=vs.85).aspx
Платформа: Windows 95 и выше
Пример использования
 #include <tchar.h>
    #include <wininet.h>  

    /// ....

    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


Сайт: http://msdn.microsoft.com/en-us/library/windows/desktop/aa382925(v=vs.85).aspx
Платформа: Windows 2000 и выше
Пример использования
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

Сайт: https://casablanca.codeplex.com
Платформа: все
Пример использования
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

Сайт: http://qt-project.org
Платформа: все
Пример использования для Qt 4.x (уже устарел)
#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() << "Unconnected";
        break;
    case 1:
        qDebug() << "Host Lookup";
        break;
    case 2:
        qDebug() << "Connecting";
        break;
    case 3:
        qDebug() << "Sending";
        break;
    case 4:
        qDebug() << "Reading";
        break;
    case 5:
        qDebug() << "Connect";
        break;
    case 6:
        qDebug() << "Closing";
        break;
    }
}
 
void Handler::responseHeaderReceived(const QHttpResponseHeader &resp)   {
    qDebug() << "Size : " << resp.contentLength();
    qDebug() << "Type : " << resp.contentType();
    qDebug() << "Status Code : " << resp.statusCode();
}
 
void Handler::requestFinished(int id, bool error)   {
    qDebug() << "Request Id : " << id;
    if(error)   {
        qDebug() << "Error";
    }   else    {
        qDebug() << http->readAll();
    }
}

Пример использования для 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() << "ERROR!";
        qDebug() << reply->errorString();
    }
    else
    {
        qDebug() << reply->header(QNetworkRequest::ContentTypeHeader).toString();
        qDebug() << reply->header(QNetworkRequest::LastModifiedHeader).toDateTime().toString();
        qDebug() << reply->header(QNetworkRequest::ContentLengthHeader).toULongLong();
        qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
        qDebug() << reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();

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

    reply->deleteLater();
}



POCO

Сайт: http://pocoproject.org
Платформа: все
Пример использования
#include <Poco/Net/HTTPClientSession.h>
#include <Poco/Net/HTTPRequest.h>
#include <Poco/Net/HTTPResponse.h>
#include <Poco/StreamCopier.h>
#include <Poco/Path.h>
#include <Poco/URI.h>
#include <Poco/Exception.h>
#include <iostream>
#include <string>

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

int main(int argc, char **argv)
{
  if (argc != 2)
  {
    cout << "Usage: " << argv[0] << " <uri>" << endl;
    cout << "       fetches the resource identified by <uri> and print it" << endl;
    return -1;
  }

  try
  {
    // prepare session
    URI uri(argv[1]);
    HTTPClientSession session(uri.getHost(), uri.getPort());

    // prepare path
    string path(uri.getPathAndQuery());
    if (path.empty()) path = "/";

    // send request
    HTTPRequest req(HTTPRequest::HTTP_GET, path, HTTPMessage::HTTP_1_1);
    session.sendRequest(req);

    // get response
    HTTPResponse res;
    cout << res.getStatus() << " " << res.getReason() << endl;

    // print response
    istream &is = session.receiveResponse(res);
    StreamCopier::copyStream(is, cout);
  }
  catch (Exception &ex)
  {
    cerr << ex.displayText() << endl;
    return -1;
  }

  return 0;
}



wxWidgets

Сайт: http://www.wxwidgets.org
Платформа: все
Пример использования
#include <wx/sstream.h>
#include <wx/protocol/http.h>
 
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: ")) << get.GetResponse() << _T("-") << ((resStream)? _T("OK ") : _T("FAILURE ")) << get.GetError() );
 
if (get.GetError() == wxPROTO_NOERR)
{
    wxString res;
    wxStringOutputStream out_stream(&res);
    httpStream->Read(out_stream);
 
    wxMessageBox(res);
    // wxLogVerbose( wxString(_T(" returned document length: ")) << res.Length() );
}
else
{
    wxMessageBox(_T("Unable to connect!"));
}
 
wxDELETE(httpStream);
get.Close();



Boost.Asio

Сайт: http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio.html
Платформа: все
Пример использования
#include <iostream>
#include <istream>
#include <ostream>
#include <string>
#include <boost/asio.hpp>

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

int main(int argc, char* argv[])
{
  try
  {
    if (argc != 3)
    {
      std::cout << "Usage: sync_client <server> <path>\n";
      std::cout << "Example:\n";
      std::cout << "  sync_client www.boost.org /LICENSE_1_0.txt\n";
      return 1;
    }

    boost::asio::io_service io_service;

    // Get a list of endpoints corresponding to the server name.
    tcp::resolver resolver(io_service);
    tcp::resolver::query query(argv[1], "http");
    tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);

    // Try each endpoint until we successfully establish a connection.
    tcp::socket socket(io_service);
    boost::asio::connect(socket, endpoint_iterator);

    // Form the request. We specify the "Connection: close" header so that the
    // server will close the socket after transmitting the response. This will
    // allow us to treat all data up until the EOF as the content.
    boost::asio::streambuf request;
    std::ostream request_stream(&request);
    request_stream << "GET " << argv[2] << " HTTP/1.0\r\n";
    request_stream << "Host: " << argv[1] << "\r\n";
    request_stream << "Accept: */*\r\n";
    request_stream << "Connection: close\r\n\r\n";

    // Send the request.
    boost::asio::write(socket, request);

    // Read the response status line. The response streambuf will automatically
    // grow to accommodate the entire line. The growth may be limited by passing
    // a maximum size to the streambuf constructor.
    boost::asio::streambuf response;
    boost::asio::read_until(socket, response, "\r\n");

    // Check that response is OK.
    std::istream response_stream(&response);
    std::string http_version;
    response_stream >> 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 << "Invalid response\n";
      return 1;
    }
    if (status_code != 200)
    {
      std::cout << "Response returned with status code " << status_code << "\n";
      return 1;
    }

    // Read the response headers, which are terminated by a blank line.
    boost::asio::read_until(socket, response, "\r\n\r\n");

    // Process the response headers.
    std::string header;
    while (std::getline(response_stream, header) && header != "\r")
      std::cout << header << "\n";
    std::cout << "\n";

    // Write whatever content we already have to output.
    if (response.size() > 0)
      std::cout << &response;

    // Read until EOF, writing data to output as we go.
    boost::system::error_code error;
    while (boost::asio::read(socket, response,
          boost::asio::transfer_at_least(1), error))
      std::cout << &response;
    if (error != boost::asio::error::eof)
      throw boost::system::system_error(error);
  }
  catch (std::exception& e)
  {
    std::cout << "Exception: " << e.what() << "\n";
  }

  return 0;
}



libcurl

Сайт: http://curl.haxx.se/libcurl
Платформа: все
Пример использования
#include <stdio.h>
#include <curl/curl.h>
 
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

Сайт: http://www.webdav.org/neon
Платформа: все
Пример использования
#include <ne_session.h>
#include <ne_request.h>
#include <ne_utils.h>
#include <ne_uri.h>

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 << response << "\n";
 
    switch (result) {
    case NE_OK:
        break;
    case NE_CONNECT:
        throw ConnectionError(errorMessage);
    case NE_TIMEOUT:
        throw TimeOutError(errorMessage);
    case NE_AUTH:
        throw AuthenticationError(errorMessage);
    default:
        throw AnotherWebError(errorMessage);
    }
 
    return 0;
}



.NET

Сайт: http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.aspx
Платформа: Windows XP и выше
Пример использования
#using <System.dll>

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<String^>^args = Environment::GetCommandLineArgs();
   HttpWebRequest^ request = dynamic_cast<HttpWebRequest^>(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<HttpWebResponse^>(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

Сайт: http://msdn.microsoft.com/en-us/library/ms759148(v=vs.85).aspx
Платформа: Windows XP и выше
Пример использования
#include <atlbase.h>
#include <msxml6.h>

HRESULT hr;
CComPtr<IXMLHTTPRequest> 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

Сайт: http://scumways.com/happyhttp/happyhttp.html
Платформа: все
Пример использования
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

Сайт: http://cpp-netlib.org
Платформа: все
Пример использования
using namespace boost::network;
using namespace boost::network::http;

client::request request_("http://127.0.0.1:8000/");
request_ << header("Connection", "close");
client client_;
client::response response_ = client_.get(request_);
std::string body_ = body(response_);



Так, скажи уже в конце концов, что использовать!


Хотите проверенной годами классики — берите libcurl. Пишете приложение с визуальным интерфейсом — берите Qt. Хотите писать на С++11 — берите Casablanca. Пишете под .NET — используйте стандартные средства платформы. Пишете что-то без интерфейса и кроме HTTP-клиента хотите вообще иметь разные удобные инструменты — Boost или POCO.
Tags:
Hubs:
+82
Comments 38
Comments Comments 38

Articles

Information

Website
www.infopulse.com
Registered
Founded
1992
Employees
1,001–5,000 employees
Location
Украина