...

среда, 18 июня 2014 г.

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


сегодня в 11:54


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

Будут рассмотрены:



  • WinInet

  • Casablanca

  • Qt

  • POCO

  • wxWidgets

  • Boost.Asio

  • libcurl

  • neon

  • .NET (С++/CLI)

  • IXMLHTTPRequest

  • HappyHttp

  • cpp-netlib


WinInet




Сайт: http://ift.tt/U9uK36

Платформа: 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);





Casablanca



Сайт: http://ift.tt/1r5zh1o

Платформа: все

Пример использования


http_client client(L"http://ift.tt/1r5zh1p");
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

Платформа: все

Пример использования


#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();
}
}





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://ift.tt/HKkKqy

Платформа: все

Пример использования


#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://ift.tt/1lunkB7

Платформа: все

Пример использования


#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://ift.tt/155EMjj

Платформа: все

Пример использования


#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://ift.tt/1r5zjWR

Платформа: все

Пример использования


#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://ift.tt/LyDp4P

Платформа: 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://ift.tt/1r5zjWX

Платформа: 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("http://ift.tt/1cjbqFH"),
_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://ift.tt/1r5zjWZ

Платформа: все

Пример использования


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.


Только зарегистрированные пользователи могут оставлять комментарии.

Войдите, пожалуйста.


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Комментариев нет:

Отправить комментарий