/** @file * @brief HTTPHelper class implementation. This class represents a Helper to perform HTTP operations easily. * * * * @copyright Intra2net AG * @license GPLv2 */ #include "httphelper.hpp" #include "version_info.h" using namespace std; /** * Default Constructor. */ HTTPHelper::HTTPHelper() : Log(new Logger) , ProxyPort(0) , CurlError(CURLE_OK) , CurlInitError(CURLE_OK) { CurlEasyHandle = init_curl(CurlWritedataBuff, CurlErrBuff); } /** * Constructor. Use this constructor if HTTP AUTH should be used. Username and password will then be set as HTTP auth options. * @param _log Logger Object * @param _proxy Proxy to use * @param _proxy_port Proxy Port * @param _username Username * @param _password Password */ HTTPHelper::HTTPHelper(Logger::Ptr _log, const string& _proxy, const int _proxy_port, const string& _username, const string& _password) : Log(_log) , Proxy(_proxy) , ProxyPort(_proxy_port) , CurlError(CURLE_OK) , CurlInitError(CURLE_OK) , Username(_username) , Password(_password) { CurlEasyHandle = init_curl(CurlWritedataBuff, CurlErrBuff); if ( CurlEasyHandle != NULL ) { if ( (CurlInitError = set_curl_auth(Username,Password)) != CURLE_OK ) { curl_easy_cleanup(CurlEasyHandle); CurlEasyHandle = NULL; } } } /** * Constructor. Use this constructor if you have to encode the username and password into the url * @param _log Logger Object * @param _proxy Proxy to use * @param _proxy_port Proxy Port */ HTTPHelper::HTTPHelper(Logger::Ptr _log, const string& _proxy, const int _proxy_port) : Log(_log) , Proxy(_proxy) , ProxyPort(_proxy_port) , CurlError(CURLE_OK) , CurlInitError(CURLE_OK) { CurlEasyHandle = init_curl(CurlWritedataBuff, CurlErrBuff); } /** * Destructor */ HTTPHelper::~HTTPHelper() { // Free memory if ( CurlEasyHandle != NULL ) { curl_easy_cleanup(CurlEasyHandle); CurlEasyHandle = NULL; } } /** * Re-Init curl */ void HTTPHelper::re_initialize() { CurlEasyHandle = init_curl(CurlWritedataBuff, CurlErrBuff); if ( (CurlEasyHandle != NULL) && !(Username.empty()) && !(Password.empty()) ) { if ( (CurlInitError = set_curl_auth(Username,Password)) != CURLE_OK ) { curl_easy_cleanup(CurlEasyHandle); CurlEasyHandle = NULL; } } } /** * Perform a HTTP GET operation * @param url URL for HTTP GET operation * @return The status code from the http operation or -1 if an curl error occurs */ long HTTPHelper::http_get(const string& url) { long curl_info; CurlError = CURLE_OK; if ( CurlEasyHandle != NULL ) { if ( (CurlInitError = set_curl_url(url)) != CURLE_OK ) { Log->print_curl_error(url,CurlInitError,CurlErrBuff); CurlWritedataBuff.clear(); return -1; } if ( (CurlError = curl_easy_perform(CurlEasyHandle) ) != CURLE_OK ) { Log->print_curl_error(url,CurlError,CurlErrBuff); CurlWritedataBuff.clear(); return -1; } if ( (CurlError = curl_easy_getinfo(CurlEasyHandle,CURLINFO_RESPONSE_CODE,&curl_info)) != CURLE_OK ) { Log->print_curl_error(url,CurlError); CurlWritedataBuff.clear(); return -1; } Log->print_curl_data(CurlWritedataBuff); // Copy the received data received via curl from the curl data buffer member to the received data member. This is needed because curl appends data to the buffer rather than overrites it. ReceivedCurlData = CurlWritedataBuff; CurlWritedataBuff.clear(); // Operation performed without any problems so we can return the curl_info return curl_info; } return -1; } /** * Getter for member CurlWritedataBuff * @return CurlWritedataBuff */ string HTTPHelper::get_curl_data() const { return ReceivedCurlData; } /** * Initialized curl easy handle with a few options. * @param curl_writedata_buff Reference to a string wich will be filled with the curl result * @param curl_err_buff A pointer to an char array which will be filled with error message. * @return A pointer to the easy curl handle or NULL if something went wrong. */ CURL* HTTPHelper::init_curl(string& curl_writedata_buff,char* curl_err_buff) { CurlInitError = CURLE_OK; ostringstream user_agent_stream; user_agent_stream << "Intra2net AG - Bullet Proof DYNDNS Daemon - " << MAJOR_VERSION << "." << MINOR_VERSION; string user_agent = user_agent_stream.str(); CURL *curl_easy_handle = curl_easy_init(); if ( curl_easy_handle == NULL ) { // something went wrong. CurlInitError = CURLE_FAILED_INIT; Log->print_curl_error_init("Could not initialize CURL object.",CURLE_FAILED_INIT); return NULL; } CurlInitError = curl_easy_setopt(curl_easy_handle,CURLOPT_NOPROGRESS,1); if ( CurlInitError == CURLE_OK) CurlInitError = curl_easy_setopt(curl_easy_handle,CURLOPT_CONNECTTIMEOUT,5); if ( CurlInitError == CURLE_OK) CurlInitError = curl_easy_setopt(curl_easy_handle,CURLOPT_TIMEOUT,10); if ( CurlInitError == CURLE_OK) CurlInitError = curl_easy_setopt(curl_easy_handle,CURLOPT_BUFFERSIZE,1024); if ( CurlInitError == CURLE_OK) CurlInitError = curl_easy_setopt(curl_easy_handle,CURLOPT_ERRORBUFFER,curl_err_buff); if ( CurlInitError == CURLE_OK) CurlInitError = curl_easy_setopt(curl_easy_handle,CURLOPT_WRITEFUNCTION,http_receive); if ( CurlInitError == CURLE_OK) CurlInitError = curl_easy_setopt(curl_easy_handle,CURLOPT_WRITEDATA,&curl_writedata_buff); if ( CurlInitError == CURLE_OK) CurlInitError = curl_easy_setopt(curl_easy_handle,CURLOPT_USERAGENT,user_agent.c_str()); if ( CurlInitError == CURLE_OK) CurlInitError = curl_easy_setopt(curl_easy_handle,CURLOPT_SSL_VERIFYHOST,0); if ( CurlInitError == CURLE_OK) CurlInitError = curl_easy_setopt(curl_easy_handle,CURLOPT_SSL_VERIFYPEER,0); if ( !Proxy.empty() ) { if ( CurlInitError == CURLE_OK) CurlInitError = curl_easy_setopt(curl_easy_handle,CURLOPT_PROXY,Proxy.c_str()); if ( CurlInitError == CURLE_OK) CurlInitError = curl_easy_setopt(curl_easy_handle,CURLOPT_PROXYPORT,ProxyPort); } if ( CurlInitError != CURLE_OK ) { // Some options could not be set, so destroy the CURL handle. Log->print_curl_error_init("Could not set CURL options properly.",CurlInitError); curl_easy_cleanup(curl_easy_handle); curl_easy_handle = NULL; } return curl_easy_handle; } /** * Test if the curl handle is initialized correctly. * @return True if correctly initialized, false if something went wrong during initialization. */ bool HTTPHelper::is_initialized() const { if ( (CurlInitError == CURLE_OK) && (CurlEasyHandle != NULL) ) { return true; } return false; } /** * Sets a url to the easy curl handle * @param url The url to set. * @return CURLcode CURLE_OK if everything is right. */ CURLcode HTTPHelper::set_curl_url(const string& url) { CURLcode curlError = CURLE_OK; if ( (CurlEasyHandle != NULL) && (CurlInitError == CURLE_OK) ) { curlError = curl_easy_setopt(CurlEasyHandle,CURLOPT_URL,url.c_str()); if ( curlError != CURLE_OK ) { // Some options could not be set, so destroy the CURL handle. Log->print_curl_error_init("Could not set CURL URL properly.",curlError); curl_easy_cleanup(CurlEasyHandle); CurlEasyHandle = NULL; } } else { return CURLE_FAILED_INIT; } return curlError; } /** * Sets HTTP AUTH parameters * @param username The username for HTTP AUTH * @param password The password for HTTP AUTH * @return CURLcode CURLE_OK if everything is right. */ CURLcode HTTPHelper::set_curl_auth(const string& username, const string& password) { CURLcode curlError = CURLE_OK; if ( (CurlEasyHandle != NULL) && (CurlInitError == CURLE_OK) ) { curlError = curl_easy_setopt(CurlEasyHandle,CURLOPT_USERNAME,username.c_str()); if ( curlError != CURLE_OK ) Log->print_curl_error_init("Could not set CURL username properly.",curlError); curlError = curl_easy_setopt(CurlEasyHandle,CURLOPT_PASSWORD,password.c_str()); if ( curlError != CURLE_OK ) Log->print_curl_error_init("Could not set CURL password properly.",curlError); } else { return CURLE_FAILED_INIT; } return curlError; } /** * Callback Function is called every time CURL is receiving data from HTTPS-Server and will copy all received Data to the given stream pointer * @param inBuffer Pointer to input. * @param size How many mem blocks are received * @param nmemb size of each memblock * @param outBuffer Pointer to output stream. * @return The size received. */ size_t HTTPHelper::http_receive( void *inBuffer, size_t size, size_t nmemb, string *outBuffer ) { outBuffer->append(static_cast(inBuffer), size*nmemb); return (size*nmemb); } //lint !e818