#include "CHttpClient.h"
#include <QFile>

#include <mutex>

#include <openssl/err.h>
#include <openssl/ssl.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/dh.h>
#include <openssl/conf.h>
#include <openssl/engine.h>
#include <openssl/buffer.h>
#include <openssl/rsa.h>


std::once_flag CHttpClient::oc_init;
std::once_flag CHttpClient::oc_destory;

CHttpClient::CHttpClient()
{
    m_pCurl = nullptr;
    m_pList = nullptr;
    m_nTimeOutSecord = 30;
    m_formpost = nullptr;
    m_lastptr = nullptr;

    std::call_once(oc_init, [&](){
        CURLcode res = curl_global_init(CURL_GLOBAL_ALL);
        if(CURLE_OK != res)
        {
            m_sErrorMsg = "curl_global_init初始化失败";
        }
    });
}

CHttpClient::~CHttpClient()
{
    std::call_once(oc_destory, [](){curl_global_cleanup();});
}


struct MemoryStruct
{
    char *memory;
    size_t size;
    MemoryStruct()
    {
        memory = (char *)malloc(1);
        size = 0;
    }
    ~MemoryStruct()
    {
        free(memory);
        memory = NULL;
        size = 0;
    }
};

struct FileStruct
{
    std::string fileName;
    FILE *pFile;
    size_t size;
    bool setFile(std::string sFileName)
    {
        QFile file(sFileName.c_str());
        if(file.exists())
        {
            file.remove();
        }

        pFile = fopen(sFileName.c_str(), "wb");
        if( pFile == NULL )
        {
            return false;
        }
        fileName = sFileName;
        return true;
    }
    void saveFile()
    {
        fclose(pFile);
    }
    FileStruct()
    {
        pFile = nullptr;
        fileName = "";
        size = 0;
    }
    ~FileStruct()
    {
        size = 0;
    }
};

size_t WriteFileCallback(void *ptr, size_t size, size_t nmemb, void *data)
{
    size_t realsize = size * nmemb;
    FileStruct *file = (FileStruct *)data;

    if(file->pFile)
    {
        fwrite(ptr,realsize,1,file->pFile);
        file->size += realsize;
    }
    return realsize;
}

size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
{
    size_t realsize = size * nmemb;
    MemoryStruct *mem = (MemoryStruct *)data;

    mem->memory = (char *)realloc(mem->memory, mem->size + realsize + 1);
    if (mem->memory)
    {
        memcpy(&(mem->memory[mem->size]), ptr, realsize);
        mem->size += realsize;
        mem->memory[mem->size] = 0;
    }
    return realsize;
}

void CHttpClient::setTimeOut(int nTimeOut)
{
    m_nTimeOutSecord = nTimeOut;
}

void CHttpClient::addParam(std::string sKey, std::string sValue)
{
    std::string sEncodeValue = encodeStr(sValue);
    if(m_sParmStr.empty())
    {
        m_sParmStr = sKey + "=" + sEncodeValue;
    }
    else
    {
        m_sParmStr = m_sParmStr + "&" + sKey + "=" + sEncodeValue;
    }
}

void CHttpClient::addHeader(std::string sKey, std::string sValue)
{
    m_pList = curl_slist_append(m_pList, (sKey + ":" + sValue).c_str());
}

bool CHttpClient::post(std::string uri, std::string &sResponse, int &nResCode)
{
    m_pCurl = curl_easy_init();

    if( NULL == m_pCurl)
    {
        m_sErrorMsg = "curl_easy_init初始化失败";
        return false;
    }
    m_pList = curl_slist_append(m_pList,"Content-Type:application/x-www-form-urlencoded;charset=UTF-8");
    m_pList = curl_slist_append(m_pList,"Accept-Language:zh-CN,zh;q=0.8");
    curl_easy_setopt(m_pCurl, CURLOPT_HTTPHEADER, m_pList);

    curl_easy_setopt(m_pCurl, CURLOPT_TIMEOUT,m_nTimeOutSecord); //设置超时时长
    curl_easy_setopt(m_pCurl, CURLOPT_URL, uri.c_str() ); //提交表单的URL地址

    curl_easy_setopt(m_pCurl, CURLOPT_HEADER, 0L);  //启用时会将头文件的信息作为数据流输
    curl_easy_setopt(m_pCurl, CURLOPT_FOLLOWLOCATION, 1L);//允许重定向
    curl_easy_setopt(m_pCurl, CURLOPT_NOSIGNAL, 1L);

    //将返回结果通过回调函数写到自定义的对象中
    MemoryStruct oDataChunk;
    curl_easy_setopt(m_pCurl, CURLOPT_WRITEDATA, &oDataChunk);
    curl_easy_setopt(m_pCurl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);

    curl_easy_setopt(m_pCurl, CURLOPT_VERBOSE, 1L); //启用时会汇报所有的信息
    //libcur的相关POST配置项
    curl_easy_setopt(m_pCurl, CURLOPT_POST, 1L);
    curl_easy_setopt(m_pCurl, CURLOPT_POSTFIELDS, m_sParmStr.c_str());
    curl_easy_setopt(m_pCurl, CURLOPT_POSTFIELDSIZE, m_sParmStr.size());

  //  curl_easy_setopt(m_pCurl, CURLOPT_SSL_VERIFYPEER, false);
 //   curl_easy_setopt(m_pCurl, CURLOPT_SSL_VERIFYHOST, false);
	sslVerify();

    CURLcode res = curl_easy_perform(m_pCurl);

    long res_code = -1;
    res = curl_easy_getinfo(m_pCurl, CURLINFO_RESPONSE_CODE, &res_code);
    nResCode = res_code;
    if( res == CURLE_OK )
    {
        sResponse = std::string(oDataChunk.memory, oDataChunk.size);
        curl_slist_free_all(m_pList);
        m_pList = NULL;
        m_sParmStr = "";
        curl_easy_cleanup(m_pCurl);
        return true;
    }
    else
    {
        curl_slist_free_all(m_pList);
        m_pList = NULL;
        m_sParmStr = "";
        curl_easy_cleanup(m_pCurl);
        return false;
    }
}

bool CHttpClient::post(std::string uri, std::string sPostStr, std::string &sResponse, int &nResCode)
{
    m_pCurl = curl_easy_init();

    if( NULL == m_pCurl)
    {
        m_sErrorMsg = "curl_easy_init初始化失败";
        return false;
    }
    m_pList = curl_slist_append(m_pList,"Content-Type:application/json");
    m_pList = curl_slist_append(m_pList,"Accept-Language:zh-CN,zh;q=0.8");
    curl_easy_setopt(m_pCurl, CURLOPT_HTTPHEADER, m_pList);

    curl_easy_setopt(m_pCurl, CURLOPT_TIMEOUT,m_nTimeOutSecord); //设置超时时长
    curl_easy_setopt(m_pCurl, CURLOPT_URL, uri.c_str() ); //提交表单的URL地址

    curl_easy_setopt(m_pCurl, CURLOPT_HEADER, 0L);  //启用时会将头文件的信息作为数据流输
    curl_easy_setopt(m_pCurl, CURLOPT_FOLLOWLOCATION, 1L);//允许重定向
    curl_easy_setopt(m_pCurl, CURLOPT_NOSIGNAL, 1L);

    //将返回结果通过回调函数写到自定义的对象中
    MemoryStruct oDataChunk;
    curl_easy_setopt(m_pCurl, CURLOPT_WRITEDATA, &oDataChunk);
    curl_easy_setopt(m_pCurl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);

    curl_easy_setopt(m_pCurl, CURLOPT_VERBOSE, 1L); //启用时会汇报所有的信息
    //libcur的相关POST配置项
    curl_easy_setopt(m_pCurl, CURLOPT_POST, 1L);
    curl_easy_setopt(m_pCurl, CURLOPT_POSTFIELDS, sPostStr.c_str());
    curl_easy_setopt(m_pCurl, CURLOPT_POSTFIELDSIZE, sPostStr.size());

    //curl_easy_setopt(m_pCurl, CURLOPT_SSL_VERIFYPEER, false);
    //curl_easy_setopt(m_pCurl, CURLOPT_SSL_VERIFYHOST, false);
	sslVerify();

    CURLcode res = curl_easy_perform(m_pCurl);

    long res_code = -1;
    res = curl_easy_getinfo(m_pCurl, CURLINFO_RESPONSE_CODE, &res_code);
    nResCode = res_code;
    if( res == CURLE_OK )
    {
        sResponse = std::string(oDataChunk.memory, oDataChunk.size);
        curl_slist_free_all(m_pList);
        m_pList = NULL;
        m_sParmStr = "";
        curl_easy_cleanup(m_pCurl);
        return true;
    }
    else
    {
        curl_slist_free_all(m_pList);
        m_pList = NULL;
        m_sParmStr = "";
        curl_easy_cleanup(m_pCurl);
        return false;
    }
}

void CHttpClient::addFormDataList(FORM_DATA_TYPE nType, std::string sKey, std::vector<std::string> sValue)
{
	curl_forms *pArray = new curl_forms[sValue.size()+1];
	curl_forms *temp = pArray;
	
	for (std::string sItem : sValue)
	{
		if (nType == fdt_content)
		{
			temp->option = CURLFORM_COPYCONTENTS;
		}
		else
		{
			temp->option = CURLFORM_FILE;
		}
		temp->value = sItem.c_str();
		temp++;
	}
	
	temp->option = CURLFORM_END;

	curl_formadd(&m_formpost, &m_lastptr,
		CURLFORM_COPYNAME, sKey.c_str(),
		CURLFORM_ARRAY, pArray, CURLFORM_END);
	delete [] pArray;
}

void CHttpClient::addFormData(FORM_DATA_TYPE nType, std::string sKey, std::string sValue)
{
    if(nType == fdt_content)
    {
        curl_formadd(&m_formpost, &m_lastptr,
                CURLFORM_COPYNAME, sKey.c_str(),
                CURLFORM_COPYCONTENTS, sValue.c_str(), CURLFORM_END);       
    }
    else
    {
        curl_formadd(&m_formpost, &m_lastptr,
                CURLFORM_COPYNAME, sKey.c_str(),
                CURLFORM_FILE, sValue.c_str(), CURLFORM_END);
    }
}

bool CHttpClient::postFormData(std::string uri, std::string &sResponse, int &nResCode)
{
    m_pCurl = curl_easy_init();

    if( NULL == m_pCurl)
    {
        m_sErrorMsg = "curl_easy_init初始化失败";
        return false;
    }

    m_pList = curl_slist_append(m_pList,"Content-type:multipart/form-data");
    m_pList = curl_slist_append(m_pList,"Accept-Language:zh-CN,zh;q=0.8");
    curl_easy_setopt(m_pCurl, CURLOPT_HTTPHEADER, m_pList);

    curl_easy_setopt(m_pCurl, CURLOPT_URL, uri.c_str() ); //提交表单的URL地址

    // 设置Form表单参数
    curl_easy_setopt(m_pCurl, CURLOPT_HTTPPOST, m_formpost);

//    curl_easy_setopt(m_pCurl, CURLOPT_HEADER, 0L);  //启用时会将头文件的信息作为数据流输
//    curl_easy_setopt(m_pCurl, CURLOPT_FOLLOWLOCATION, 1L);//允许重定向
    curl_easy_setopt(m_pCurl, CURLOPT_NOSIGNAL, 1L);




    //将返回结果通过回调函数写到自定义的对象中
    MemoryStruct oDataChunk;
    curl_easy_setopt(m_pCurl, CURLOPT_WRITEDATA, &oDataChunk);
    curl_easy_setopt(m_pCurl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);

    curl_easy_setopt(m_pCurl, CURLOPT_VERBOSE, 1L); //启用时会汇报所有的信息
    //libcur的相关POST配置项
//    curl_easy_setopt(m_pCurl, CURLOPT_POST, 1L);
//    curl_easy_setopt(m_pCurl, CURLOPT_POSTFIELDS, m_sParmStr.c_str());
//    curl_easy_setopt(m_pCurl, CURLOPT_POSTFIELDSIZE, m_sParmStr.size());

    curl_easy_setopt(m_pCurl, CURLOPT_TIMEOUT,m_nTimeOutSecord);

    //curl_easy_setopt(m_pCurl, CURLOPT_SSL_VERIFYPEER, false);
    //curl_easy_setopt(m_pCurl, CURLOPT_SSL_VERIFYHOST, false);
	sslVerify();

    CURLcode res = curl_easy_perform(m_pCurl);

    long res_code = -1;
    res = curl_easy_getinfo(m_pCurl, CURLINFO_RESPONSE_CODE, &res_code);
    nResCode = res_code;
    if( res == CURLE_OK )
    {
        sResponse = std::string(oDataChunk.memory, oDataChunk.size);

        curl_easy_cleanup(m_pCurl);

        curl_slist_free_all(m_pList);
        curl_formfree(m_formpost);
        m_formpost = NULL;
        m_lastptr = NULL;
        m_pList = NULL;
        m_sParmStr = "";

        return true;
    }
    else
    {
        curl_easy_cleanup(m_pCurl);

        curl_slist_free_all(m_pList);
        curl_formfree(m_formpost);
        m_lastptr = NULL;
        m_pList = NULL;
        m_sParmStr = "";

        return false;
    }
}




CURLcode CHttpClient::sslctx_function(CURL *curl, void *sslctx, void *parm)
{
	X509 *cert = NULL;
	BIO *bio = NULL;
	BIO *kbio = NULL;
	RSA *rsa = NULL;
	int ret;
	
	const char *mypem = "-----BEGIN CERTIFICATE-----\n"
		"MIIDOjCCAiICBQCHhjV3MA0GCSqGSIb3DQEBBAUAMIGiMQswCQYDVQQGEwJDTjES\n"
		"MBAGA1UECAwJR3VhbmdEb25nMRIwEAYDVQQHDAlTaGVuWmhlbmcxEDAOBgNVBAoM\n"
		"B0FsaWJhYmExDTALBgNVBAsMBFByb2QxKDAmBgNVBAMMH29lLXN0dWRlbnQtY2xp\n"
		"ZW50LmV4YW0tY2xvdWQuY24xIDAeBgkqhkiG9w0BCQEWEWh1eXVlQHFtdGguY29t\n"
		"LmNuMB4XDTIxMTExMTA5MDUyM1oXDTMxMTEwOTA5MDUyM1owgaIxCzAJBgNVBAYT\n"
		"AkNOMRIwEAYDVQQIDAlHdWFuZ0RvbmcxEDAOBgNVBAoMB0FsaWJhYmExDTALBgNV\n"
		"BAsMBFByb2QxEjAQBgNVBAcMCVNoZW5aaGVuZzEoMCYGA1UEAwwfb2Utc3R1ZGVu\n"
		"dC1jbGllbnQuZXhhbS1jbG91ZC5jbjEgMB4GCSqGSIb3DQEJARYRaHV5dWVAcW10\n"
		"aC5jb20uY24wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMss/6qUMhiOdu80\n"
		"cyhZpkwBGO3raA+81ujwt8lEiK0idRE4dj+G6Bd6KjNJGdhQogfOgDPklv+oLxU/\n"
		"w4mXogHtb1DtFYPfEY72kdvEeLtRtG0gaRXN2/BJ1U6qZ+zvmhjEiqf/k5Q0HkZi\n"
		"hXZcADWrgPn3Dv43mUU9qvhbk9sFAgMBAAEwDQYJKoZIhvcNAQEEBQADggEBAAZa\n"
		"0K3mmslMCAQZWuidSA2O5tyRNT6uijKX/3UCm9NQ/Q98vMQ90cyXh2KyqNxi/L37\n"
		"EWPcMo1R8yuds41k8/sxSqF3A2zRs9uPTh3kYiu54dx7Z8amE31S0eh07fQs8qvp\n"
		"Jdi6vyARhgzNKKvvPi5hF5X03BAVdTGKaAWi2gMZMmeDuC8pjENTycixt9+usylV\n"
		"uB+Cheb9M/8FtJU6bKTwOyw3mYqhMK1wgKahjBSnUkp7IEXoaITDkn2Mz44xqCtN\n"
		"zZJ4R8wtV9uGm8HalDVaS9LWR1NPdLSkaIjtfESfjnWd4cjWOrHZ035yClab0uj4\n"
		"OyGCQKEQjVOot6szUP8=\n"
		"-----END CERTIFICATE-----";

	/*replace the XXX with the actual RSA key*/	
	const char *mykey = "-----BEGIN RSA PRIVATE KEY-----\n"
		"MIICXgIBAAKBgQDLLP+qlDIYjnbvNHMoWaZMARjt62gPvNbo8LfJRIitInUROHY/\n"
		"hugXeiozSRnYUKIHzoAz5Jb/qC8VP8OJl6IB7W9Q7RWD3xGO9pHbxHi7UbRtIGkV\n"
		"zdvwSdVOqmfs75oYxIqn/5OUNB5GYoV2XAA1q4D59w7+N5lFPar4W5PbBQIDAQAB\n"
		"AoGBAK++19REZmTpbqWRN/9yNK/PzzGWDCh4z2klN8SoPJWOlbb0oQxodIBCUxiT\n"
		"pgCAFvgrvqeklpzEbR2zTz/IYwA+8wMVXT/V72QNygVKOohuhRYFH88LHTNOQV/X\n"
		"ieg6OoYz5bGvaNYHwx7kIqkeE2sBDtq89sX73bR9NWTb/n8hAkEA7XPDDHN2qdhh\n"
		"9xAl14L18UVTlTUK/cXZXaxNp0nmKL1jnQtHibWSUgyTDdv0vplXnqjRIk2mEtR/\n"
		"We3np/9mTQJBANsL0yGQrsMhAcRRHptYd4E9SrYp27L6/Oi3TGn8QNv5lawaGfCu\n"
		"0tat8AJfGzNgOWP16lwAz3/nns9HFVi4E5kCQQCbrGdVxGUpmPkxFt8YWX2Qflj7\n"
		"21inY4zMQuhuIp7IWtHx5bEy8V1KeX/3eBsO0k2FcTwa9zlH4xTTCovzsheJAkEA\n"
		"rEwK0NYbgUUPPLqKFqtppPDvOYaHV6txECROKPfQlLcnce4+BUGeelrq9RKWNL01\n"
		"p1kh9Sh2DyfDlUtWkSiJ0QJAZSLI92yo116QJz6SmU9g10pm8LSlAPa7j+1lfLvz\n"
		"eTIXiFpu5fbF1I1sFMuLKISSoqWPihMCIWxsE5a5i5OOuA== \n"
		"-----END RSA PRIVATE KEY-----";

	(void)curl; /* avoid warnings */
	(void)parm; /* avoid warnings */

	/* get a BIO */
	bio = BIO_new_mem_buf((char *)mypem, -1);

	if (bio == NULL) {
		printf("BIO_new_mem_buf failed\n");
	}

	/* use it to read the PEM formatted certificate from memory into an X509
	 * structure that SSL can use
	 */
	cert = PEM_read_bio_X509(bio, NULL, 0, NULL);
	if (cert == NULL) {
		printf("PEM_read_bio_X509 failed...\n");
	}

	/*tell SSL to use the X509 certificate*/
	ret = SSL_CTX_use_certificate((SSL_CTX*)sslctx, cert);
	if (ret != 1) {
		printf("Use certificate failed\n");
	}

	/*create a bio for the RSA key*/
	kbio = BIO_new_mem_buf((char *)mykey, -1);
	if (kbio == NULL) {
		printf("BIO_new_mem_buf failed\n");
	}

	/*read the key bio into an RSA object*/
	rsa = PEM_read_bio_RSAPrivateKey(kbio, NULL, 0, NULL);
	if (rsa == NULL) {
		printf("Failed to create key bio\n");
	}

	/*tell SSL to use the RSA key from memory*/
	ret = SSL_CTX_use_RSAPrivateKey((SSL_CTX*)sslctx, rsa);
	if (ret != 1) {
		printf("Use Key failed\n");
	}

	/* free resources that have been allocated by openssl functions */
	if (bio)
		BIO_free(bio);

	if (kbio)
		BIO_free(kbio);

	if (rsa)
		RSA_free(rsa);

	if (cert)
		X509_free(cert);

	/* all set to go */
	return CURLE_OK;
}

void CHttpClient::sslVerify()
{
	curl_easy_setopt(m_pCurl, CURLOPT_SSL_VERIFYPEER, false);
	curl_easy_setopt(m_pCurl, CURLOPT_SSL_VERIFYHOST, false);
	/*
	curl_easy_setopt(m_pCurl, CURLOPT_SSL_VERIFYPEER, 0);
	curl_easy_setopt(m_pCurl, CURLOPT_SSL_VERIFYHOST, 2);
	curl_easy_setopt(m_pCurl, CURLOPT_SSLCERTTYPE, "PEM");
	curl_easy_setopt(m_pCurl, CURLOPT_SSLKEYTYPE, "PEM");
	curl_easy_setopt(m_pCurl, CURLOPT_SSL_CTX_FUNCTION, *sslctx_function);
	*/
}

bool CHttpClient::get(std::string uri, std::string &sResponse, int &nResCode)
{
    m_pCurl = curl_easy_init();

    if( NULL == m_pCurl)
    {
        m_sErrorMsg = "curl_easy_init初始化失败";
        return false;
    }
    m_pList = curl_slist_append(m_pList,"Content-Type:application/json");
    m_pList = curl_slist_append(m_pList,"Accept-Language:zh-CN,zh;q=0.8");
    curl_easy_setopt(m_pCurl, CURLOPT_HTTPHEADER, m_pList);
    curl_easy_setopt(m_pCurl, CURLOPT_TIMEOUT,m_nTimeOutSecord); //设置超时时长

    std::string strUrl = "";

    strUrl = /*encodeURL*/(uri);
    curl_easy_setopt(m_pCurl, CURLOPT_URL, strUrl.c_str() ); //提交表单的URL地址

    curl_easy_setopt(m_pCurl, CURLOPT_HEADER, 0L);  //启用时会将头文件的信息作为数据流输
    curl_easy_setopt(m_pCurl, CURLOPT_FOLLOWLOCATION, 1L);//允许重定向
    curl_easy_setopt(m_pCurl, CURLOPT_NOSIGNAL, 1L);

    //将返回结果通过回调函数写到自定义的对象中
    MemoryStruct oDataChunk;
    curl_easy_setopt(m_pCurl, CURLOPT_WRITEDATA, &oDataChunk);
    curl_easy_setopt(m_pCurl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);

    curl_easy_setopt(m_pCurl, CURLOPT_VERBOSE, 1L); //启用时会汇报所有的信息
    //libcur的相关POST配置项
//    curl_easy_setopt(m_pCurl, CURLOPT_POST, 1L);
//    curl_easy_setopt(m_pCurl, CURLOPT_POSTFIELDS, m_sParmStr.c_str());
//    curl_easy_setopt(m_pCurl, CURLOPT_POSTFIELDSIZE, m_sParmStr.size());
   	
	sslVerify();

    CURLcode res = curl_easy_perform(m_pCurl);

    long res_code = -1;
    res = curl_easy_getinfo(m_pCurl, CURLINFO_RESPONSE_CODE, &res_code);
    nResCode = res_code;
    if( res == CURLE_OK )
    {
        sResponse = std::string(oDataChunk.memory, oDataChunk.size);
        curl_slist_free_all(m_pList);
        m_pList = NULL;
        m_sParmStr = "";
        curl_easy_cleanup(m_pCurl);
        return true;
    }
    else
    {
        curl_slist_free_all(m_pList);
        m_pList = NULL;
        m_sParmStr = "";
        curl_easy_cleanup(m_pCurl);
        return false;
    }
}

bool CHttpClient::put(std::string uri, std::string &sResponse, int &nResCode)
{
	m_pCurl = curl_easy_init();

	if (NULL == m_pCurl)
	{
		m_sErrorMsg = "curl_easy_init初始化失败";
		return false;
	}
	m_pList = curl_slist_append(m_pList, "Content-Type:application/json");
	m_pList = curl_slist_append(m_pList, "Accept-Language:zh-CN,zh;q=0.8");
	curl_easy_setopt(m_pCurl, CURLOPT_HTTPHEADER, m_pList);
	curl_easy_setopt(m_pCurl, CURLOPT_TIMEOUT, m_nTimeOutSecord); //设置超时时长

	std::string strUrl = "";

	strUrl = uri;
	curl_easy_setopt(m_pCurl, CURLOPT_URL, strUrl.c_str()); //提交表单的URL地址

	curl_easy_setopt(m_pCurl, CURLOPT_HEADER, 0L);  //启用时会将头文件的信息作为数据流输
	curl_easy_setopt(m_pCurl, CURLOPT_FOLLOWLOCATION, 1L);//允许重定向
	curl_easy_setopt(m_pCurl, CURLOPT_NOSIGNAL, 1L);

	
	curl_easy_setopt(m_pCurl, CURLOPT_VERBOSE, 1L); //启用时会汇报所有的信息

    curl_easy_setopt(m_pCurl, CURLOPT_PUT, 1L);

	//将返回结果通过回调函数写到自定义的对象中
	MemoryStruct oDataChunk;
	curl_easy_setopt(m_pCurl, CURLOPT_WRITEDATA, &oDataChunk);
	curl_easy_setopt(m_pCurl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);

	//curl_easy_setopt(m_pCurl, CURLOPT_SSL_VERIFYPEER, false);
	//curl_easy_setopt(m_pCurl, CURLOPT_SSL_VERIFYHOST, false);
	sslVerify();

	CURLcode res = curl_easy_perform(m_pCurl);

	long res_code = -1;
	res = curl_easy_getinfo(m_pCurl, CURLINFO_RESPONSE_CODE, &res_code);
	nResCode = res_code;
	if (res == CURLE_OK)
	{
		sResponse = std::string(oDataChunk.memory, oDataChunk.size);
	}
	curl_slist_free_all(m_pList);
	m_pList = NULL;
	m_sParmStr = "";
	curl_easy_cleanup(m_pCurl);
	if (res == CURLE_OK)
	{			
		return true;
	}
	else
	{
		return false;
	}
}

bool CHttpClient::download(std::string uri, std::string sFileName, int &nResCode)
{
    m_pCurl = curl_easy_init();

    if( NULL == m_pCurl)
    {
        m_sErrorMsg = "curl_easy_init初始化失败";
        return false;
    }
//    m_pList = curl_slist_append(m_pList,"Content-Type:application/x-www-form-urlencoded;charset=UTF-8");
//    m_pList = curl_slist_append(m_pList,"Accept-Language:zh-CN,zh;q=0.8");
//    curl_easy_setopt(m_pCurl, CURLOPT_HTTPHEADER, m_pList);

    std::string strUrl = "";

    int nPos = uri.find_last_of(":");
    strUrl = uri.substr(0, nPos+1);
    strUrl += encodeURL(uri.substr(nPos + 1, uri.length() - nPos - 1));
    //myDebug()<<strUrl.c_str();
    curl_easy_setopt(m_pCurl, CURLOPT_URL, strUrl.c_str() ); //提交表单的URL地址    

    curl_easy_setopt(m_pCurl, CURLOPT_TIMEOUT,m_nTimeOutSecord); //设置超时时长

//    curl_easy_setopt(m_pCurl, CURLOPT_HEADER, 0L);  //启用时会将头文件的信息作为数据流输
//    curl_easy_setopt(m_pCurl, CURLOPT_FOLLOWLOCATION, 1L);//允许重定向
//    curl_easy_setopt(m_pCurl, CURLOPT_NOSIGNAL, 1L);

    //将返回结果通过回调函数写到自定义的对象中
    FileStruct oDataChunk;
    if(!oDataChunk.setFile(sFileName))
    {
        m_sErrorMsg = "创建文件失败！";
        return false;
    }
    curl_easy_setopt(m_pCurl, CURLOPT_WRITEDATA, &oDataChunk);
    curl_easy_setopt(m_pCurl, CURLOPT_WRITEFUNCTION, WriteFileCallback);

    curl_easy_setopt(m_pCurl, CURLOPT_VERBOSE, 1L); //启用时会汇报所有的信息
    //libcur的相关POST配置项
//    curl_easy_setopt(m_pCurl, CURLOPT_POST, 1L);
//    curl_easy_setopt(m_pCurl, CURLOPT_POSTFIELDS, m_sParmStr.c_str());
//    curl_easy_setopt(m_pCurl, CURLOPT_POSTFIELDSIZE, m_sParmStr.size());

    //curl_easy_setopt(m_pCurl, CURLOPT_SSL_VERIFYPEER, false);
    //curl_easy_setopt(m_pCurl, CURLOPT_SSL_VERIFYHOST, false);
	sslVerify();

    CURLcode res = curl_easy_perform(m_pCurl);


    long res_code = -1;
    res = curl_easy_getinfo(m_pCurl, CURLINFO_RESPONSE_CODE, &res_code);
    nResCode = res_code;

    if( res == CURLE_OK && res_code == 200)
    {
		double length;
		res = curl_easy_getinfo(m_pCurl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &length);
		fflush(oDataChunk.pFile);
		fseek(oDataChunk.pFile, 0, SEEK_END);
		long nDown = ftell(oDataChunk.pFile);

        oDataChunk.saveFile();

		curl_slist_free_all(m_pList);
		m_pList = NULL;
		m_sParmStr = "";
		curl_easy_cleanup(m_pCurl);

		if (nDown != (long)length)
		{
			nResCode = 0;
			if (!DeleteFileA(sFileName.c_str())) 
			{
				m_sErrorMsg = GetLastError();
			}
			return false;
		}        
        return true;
    }
    else
    {
		DeleteFileA(sFileName.c_str());
        curl_slist_free_all(m_pList);
        m_pList = NULL;
        m_sParmStr = "";
        curl_easy_cleanup(m_pCurl);
        return false;
    }
}

std::string CHttpClient::encodeStr(std::string sStr)
{
    char* pUri = curl_easy_escape(m_pCurl, sStr.c_str(), sStr.length());
    std::string StrRet = pUri;
    curl_free(pUri);
    return StrRet;
}

std::string CHttpClient::encodeURL(std::string sUri)
{
    std::string retUri = "";	
    QString strUri = QString::fromLocal8Bit(sUri.c_str());
    QStringList uriList = strUri.split("/");
    for(int i = 0; i < uriList.count(); i++)
    {
        if(i == 0)
        {
            retUri = uriList[i].toStdString();
        }
        else
        {
            std::string tempStr = uriList[i].toStdString();
            char* pUri = curl_easy_escape(m_pCurl, tempStr.c_str(), tempStr.length());
            retUri += std::string("/") + pUri;
            curl_free(pUri);
        }
    }

    return retUri;
}


