// ==========================================================================
// Author:  Yee Hsu
// Date:    6/7/2011
//
// Desc:    HttpClient implements a simple HTTP Client using cURL.
//          Demonstrates a simple usage of the powerful cURL library to
//          do simple HTTP request.
// ==========================================================================

#include "StdAfx.h"
#include "HttpClient.h"

HttpClient::HttpClient()
{
    if (!m_initialize)
    {
        if (curl_global_init(CURL_GLOBAL_ALL) == CURLE_OK)
            m_initialize=true;
    }
}

HttpClient::~HttpClient()
{
    if (m_initialize)
    {
        curl_global_cleanup();
    }
    m_initialize = false;
}

int HttpClient::StringWriter(char *data, size_t size, size_t nmemb, string *buffer)  
{  
    int result = 0;  

    if (data)  
    {  
        buffer->append(data, size * nmemb);  
        result = size * nmemb;  
    }  
    return result;
}

int HttpClient::StreamWriter(char *data, size_t size, size_t nmemb, std::ostream *fs)
{
    int result = 0;

    if (data)
    { 
        string buffer(data, size * nmemb);
        (*fs) << buffer;
        result = size * nmemb;  
    }
    return result;
}

string HttpClient::PostFieldsToString(PostFields const& params)
{
    CURL *curl = NULL;
    string query;

    if (curl = curl_easy_init())
    {
        for (PostFields::const_iterator iter = params.begin(); iter != params.end(); ++iter)
        {
            char *enc = NULL;

            if (iter != params.begin()) 
            {
                query.append("&");
            }
            const string& key = iter->first;
            const string& val = iter->second;

            if (enc = curl_easy_escape(curl, val.c_str(), val.size()))
            {
                query.append(key);
                query.append("=");
                query.append(enc);
                curl_free(enc);
            }
        }
        curl_easy_cleanup(curl);
    }
    return query;
}

bool HttpClient::SetCurlEasyOpts(CURL* curl, DownloadTask& task) const
{
    char err[CURL_ERROR_SIZE] = {0};

    if (curl)
    {
        if (!task.params.empty())
        {
            string data = this->PostFieldsToString(task.params);
            curl_easy_setopt(curl, CURLOPT_POST, 1L);
            curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, data.c_str());
        }

        if (task.request_timeout > 0)
            curl_easy_setopt(curl, CURLOPT_TIMEOUT, task.request_timeout);

        curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, err);
        curl_easy_setopt(curl, CURLOPT_URL, task.url.c_str());
        curl_easy_setopt(curl, CURLOPT_HEADER, 0L);
        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, StringWriter); 
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &task.resp_content); 
        curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
        curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, task.connect_timeout);
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
        curl_easy_setopt(curl, CURLOPT_USERAGENT, task.agent.c_str());
        curl_easy_setopt(curl, CURLOPT_REFERER, task.referer.c_str());
        curl_easy_setopt(curl, CURLOPT_USERNAME, task.username.c_str());
        curl_easy_setopt(curl, CURLOPT_PASSWORD, task.password.c_str());

        return true;
    }
    return false;
}

bool HttpClient::Request( DownloadTask& task ) const
{
    bool  bret = false;
    CURL* curl = NULL;

    if (curl = curl_easy_init())
    {
        this->SetCurlEasyOpts(curl, task);

        if (curl_easy_perform(curl) == CURLE_OK) 
            bret = true;

        curl_easy_cleanup(curl);
    }
    return bret;
}

bool HttpClient::GetRequest( DownloadTask& task ) const
{
    bool  bret = false;
    CURL* curl = NULL;

    if (curl = curl_easy_init())
    {
        task.params.clear();
        this->SetCurlEasyOpts(curl, task);

        if (curl_easy_perform(curl) == CURLE_OK) 
            bret = true;

        curl_easy_cleanup(curl);
    }
    return bret;
}

bool HttpClient::PostRequest( DownloadTask& task ) const
{
    bool  bret = false;
    CURL* curl = NULL;

    if (curl = curl_easy_init())
    {
        if (task.params.empty())
        {
            curl_easy_setopt(curl, CURLOPT_POST, 1L);
            curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, "");
        }
        this->SetCurlEasyOpts(curl, task);

        if (curl_easy_perform(curl) == CURLE_OK) 
            bret = true;

        curl_easy_cleanup(curl);
    }
    return bret;
}