Network: refactor

This commit is contained in:
zvon 2020-01-15 16:30:30 +01:00
parent e50c3317a2
commit 2536881452
4 changed files with 181 additions and 129 deletions

View File

@ -1,120 +0,0 @@
#include "network.hpp"
#include <iostream>
#ifdef _WIN32
// shamelessly stolen from http://www.cplusplus.com/forum/windows/109799/
Curl::Curl() {
connect = InternetOpen( L"WinInet/1.0", INTERNET_OPEN_TYPE_PRECONFIG,
nullptr, nullptr, 0 );
if ( !connect )
std::wcerr << "Something went wrong while connecting" << std::endl;
}
Curl::~Curl() {
if ( connect )
InternetCloseHandle( connect );
}
std::string Curl::execute( const std::wstring &url ) {
std::string source{};
source.reserve( 10000 );
HINTERNET openAddress = InternetOpenUrl(
connect, url.c_str(), nullptr, 0,
INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_KEEP_CONNECTION, 0 );
if ( !openAddress ) {
unsigned long errorNum = GetLastError();
std::wcout << "Failed to open URL" << std::endl
<< "Error No: " << errorNum << std::endl;
return "";
}
char dataReceived[4096];
unsigned long numberOfBytesRead = 0;
while ( InternetReadFile( openAddress, dataReceived, 4096,
&numberOfBytesRead ) &&
numberOfBytesRead ) {
source.append( dataReceived, numberOfBytesRead );
}
InternetCloseHandle( openAddress );
return source;
}
#else
size_t writeCallback( void *contents, size_t size, size_t nmemb,
void *target ) {
*static_cast< std::string * >( target ) +=
std::string( static_cast< char * >( contents ), size * nmemb );
return size * nmemb;
}
Curl::Curl() {
curl_global_init( CURL_GLOBAL_ALL );
curl_handle = curl_easy_init();
curl_easy_setopt( curl_handle, CURLOPT_WRITEFUNCTION, writeCallback );
curl_easy_setopt( curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0" );
}
Curl::~Curl() {
curl_easy_cleanup( curl_handle );
curl_slist_free_all( chunk );
curl_global_cleanup();
}
void cleanUp( CURL *curl_handle ) {
curl_easy_setopt( curl_handle, CURLOPT_POST, 0 );
curl_easy_setopt( curl_handle, CURLOPT_POSTFIELDS, "" );
}
std::string Curl::get( const std::string &url ) {
// get rid of garbage
cleanUp( curl_handle );
std::string source;
source.reserve( 100000 );
curl_easy_setopt( curl_handle, CURLOPT_WRITEDATA,
static_cast< void * >( &source ) );
curl_easy_setopt( curl_handle, CURLOPT_URL, url.c_str() );
curl_easy_setopt( curl_handle, CURLOPT_HTTPGET, 1 );
auto res = curl_easy_perform( curl_handle );
if ( res != CURLE_OK ) {
std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror( res )
<< std::endl;
return "";
}
return source;
}
void Curl::addHeader( const std::string &header ) {
chunk = curl_slist_append( chunk, header.c_str() );
curl_easy_setopt( curl_handle, CURLOPT_HTTPHEADER, chunk );
}
void Curl::clearHeader() {
curl_slist_free_all( chunk );
chunk = NULL;
curl_easy_setopt( curl_handle, CURLOPT_HTTPHEADER, chunk );
}
std::string Curl::post( const std::string &url, const std::string &data ) {
std::string source;
source.reserve( 100000 );
curl_easy_setopt( curl_handle, CURLOPT_URL, url.c_str() );
curl_easy_setopt( curl_handle, CURLOPT_POST, 1 );
curl_easy_setopt( curl_handle, CURLOPT_POSTFIELDS, data.c_str() );
curl_easy_setopt( curl_handle, CURLOPT_WRITEDATA,
static_cast< void * >( &source ) );
auto res = curl_easy_perform( curl_handle );
if ( res != CURLE_OK ) {
std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror( res )
<< std::endl;
return "";
}
return source;
}
#endif

View File

@ -3,8 +3,9 @@
#ifdef _WIN32 #ifdef _WIN32
#include <WinInet.h>
#include <Windows.h> #include <Windows.h>
#include <WinInet.h>
#include <string>
using string = std::wstring; using string = std::wstring;
@ -17,21 +18,26 @@ using string = std::string;
#endif #endif
class Curl { class Request {
public: public:
Curl(); Request() = delete;
~Curl(); Request( const string &server );
~Request();
std::string get( const string &url ); std::string get( const string &url );
std::string post( const std::string &url, const std::string &data ); std::string post( const string &url, const std::string &data );
void addHeader( const std::string &header ); void addHeader( const string &header );
void clearHeader(); void clearHeader();
bool initSuccessful();
private: private:
#ifdef _WIN32 #ifdef _WIN32
HINTERNET connect = nullptr; HINTERNET _hInternet = nullptr;
HINTERNET _hConnect = nullptr;
std::wstring _headers = L"";
#else #else
CURL *curl_handle; CURL *_curl_handle = nullptr;
struct curl_slist *chunk = NULL; struct curl_slist *_chunk = nullptr;
const string _server;
#endif #endif
}; };

81
unix/network.cpp Normal file
View File

@ -0,0 +1,81 @@
#include "../network.hpp"
#include <iostream>
#include <memory>
size_t writeCallback( void *contents, size_t size, size_t nmemb,
void *target ) {
*static_cast< std::string * >( target ) +=
std::string( static_cast< char * >( contents ), size * nmemb );
return size * nmemb;
}
Request::Request( const string &server ) : _server( server ) {
curl_global_init( CURL_GLOBAL_ALL );
_curl_handle = curl_easy_init();
if ( _curl_handle == NULL ) {
std::cerr << "ERROR curl_easy_init" << std::endl;
}
curl_easy_setopt( _curl_handle, CURLOPT_WRITEFUNCTION, writeCallback );
curl_easy_setopt( _curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0" );
}
Request::~Request() {
curl_easy_cleanup( _curl_handle );
curl_slist_free_all( _chunk );
curl_global_cleanup();
}
void cleanUp( CURL *curl_handle ) {
curl_easy_setopt( curl_handle, CURLOPT_POST, 0 );
curl_easy_setopt( curl_handle, CURLOPT_POSTFIELDS, "" );
}
std::string Request::get( const std::string &url ) {
// get rid of garbage
cleanUp( _curl_handle );
std::string response;
response.reserve( 100000 );
curl_easy_setopt( _curl_handle, CURLOPT_WRITEDATA,
static_cast< void * >( &response ) );
curl_easy_setopt( _curl_handle, CURLOPT_URL, ( _server + url ).c_str() );
curl_easy_setopt( _curl_handle, CURLOPT_HTTPGET, 1 );
auto res = curl_easy_perform( _curl_handle );
if ( res != CURLE_OK ) {
std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror( res )
<< std::endl;
return "";
}
return response;
}
std::string Request::post( const std::string &url, const std::string &data ) {
std::string response;
response.reserve( 100000 );
curl_easy_setopt( _curl_handle, CURLOPT_URL, ( _server + url ).c_str() );
curl_easy_setopt( _curl_handle, CURLOPT_POST, 1 );
curl_easy_setopt( _curl_handle, CURLOPT_POSTFIELDS, data.c_str() );
curl_easy_setopt( _curl_handle, CURLOPT_WRITEDATA,
static_cast< void * >( &response ) );
auto res = curl_easy_perform( _curl_handle );
if ( res != CURLE_OK ) {
std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror( res )
<< std::endl;
return "";
}
return response;
}
void Request::addHeader( const std::string &header ) {
_chunk = curl_slist_append( _chunk, header.c_str() );
curl_easy_setopt( _curl_handle, CURLOPT_HTTPHEADER, _chunk );
}
void Request::clearHeader() {
curl_slist_free_all( _chunk );
_chunk = nullptr;
curl_easy_setopt( _curl_handle, CURLOPT_HTTPHEADER, _chunk );
}
bool Request::initSuccessful() {
return _curl_handle != nullptr;
}

85
windows/network.cpp Normal file
View File

@ -0,0 +1,85 @@
#include "../network.hpp"
#include <iostream>
#include <memory>
const wchar_t *acceptTypes[] = { L"text/*", L"application/json", nullptr };
Request::Request( const string &server ) {
// Start connection
_hInternet = InternetOpen( L"WinInet/1.0", INTERNET_OPEN_TYPE_PRECONFIG,
nullptr, nullptr, 0 );
if ( !_hInternet )
std::wcerr << "ERROR InternetOpen: " << GetLastError() << std::endl;
// connect to server
_hConnect = InternetConnect( _hInternet, server.c_str(),
INTERNET_DEFAULT_HTTPS_PORT, nullptr, nullptr,
INTERNET_SERVICE_HTTP, 0, 0 );
if ( !_hConnect )
std::wcerr << "ERROR InternetConnect: " << GetLastError() << std::endl;
}
Request::~Request() {
if ( _hConnect )
InternetCloseHandle( _hConnect );
if ( _hInternet )
InternetCloseHandle( _hInternet );
}
std::string sendRequest( HINTERNET hRequest, const std::wstring &headers,
const std::string &optional ) {
std::string response{};
response.reserve( 10000 );
// have to do a copy because c_str returns const
std::unique_ptr< char > opt( new char[optional.length()] );
memcpy( opt.get(), optional.c_str(), optional.length() );
auto requestSent = HttpSendRequest(
hRequest, headers.c_str(), headers.length(), opt, optional.length() );
if ( !requestSent )
std::wcerr << "ERROR HttpSendRequest: " << GetLastError() << std::endl;
char dataReceived[4096];
unsigned long numberOfBytesRead = 0;
// read while InternetReadFile returns true and reads more than 0 bytes
while (
InternetReadFile( hRequest, dataReceived, 4096, &numberOfBytesRead ) &&
numberOfBytesRead ) {
response.append( dataReceived, numberOfBytesRead );
}
return response;
}
std::string Request::get( const std::wstring &url ) {
HINTERNET hRequest =
HttpOpenRequest( _hConnect, L"GET", url.c_str(), nullptr, nullptr,
acceptTypes, INTERNET_FLAG_SECURE, 0 );
if ( !hRequest )
std::wcerr << "ERROR HttpOpenRequest: " << GetLastError() << std::endl;
return sendRequest( hRequest, _headers, "" );
}
std::string Request::post( const std::wstring &url, const std::string &data ) {
HINTERNET hRequest =
HttpOpenRequest( _hConnect, L"POST", url.c_str(), nullptr, nullptr,
acceptTypes, INTERNET_FLAG_SECURE, 0 );
if ( !hRequest )
std::wcerr << "ERROR HttpOpenRequest: " << GetLastError() << std::endl;
return sendRequest( hRequest, _headers, data );
}
void Request::addHeader( const std::wstring &header ) {
_headers += header + L"\r\n";
}
void Request::clearHeader() {
_headers = L"";
}
bool Request::initSuccessful() {
return _hInternet != nullptr && _hConnect != nullptr;
}