// 定义HTTP接口返回值类型
enum XHTTPRET_T
{
	XHTTPRET_SUCCESS = 0,                          // 操作成功
	XHTTPRET_ERROR_PARAMETER,                      // 函数参数错误
	XHTTPRET_ERROR_OPENFILE,                       // 打开文件错误
	XHTTPRET_ERROR_CURLEASYINIT,                   // curl_easy_init失败
	XHTTPRET_ERROR_CURLEASYPERFORM,                // curl_easy_perform失败	
	XHTTPRET_ERROR_PERFORMOPERATIONTIMEDOUT,       // curl_easy_perform失败,curlCode=CURLE_OPERATION_TIMEDOUT
	XHTTPRET_ERROR_READUPLOADFILE,                 // 读取上传文件失败
};

// HTTP发送一个GET请求
XHTTPLIB_API
XHTTPRET_T
XHTTP_SendRequest(
	IN  LPCWSTR lpURL,                                      // URL
	IN  LPCWSTR lpHeaders,                                  // Headers
	OUT string *pRetBuf,                                    // 输出返回结果数据,注意返回的是数据不是字符串  
	OUT LONG *pCurlRetCode = NULL,                          // 输出CURL执行结果,出错时便于分析
	IN  LONG lTimeOutSeconds = 20                           // 超时时间,单位秒
	);

// HTTP发送一个POST请求
XHTTPLIB_API
XHTTPRET_T
XHTTP_PostRequest(
	IN  LPCWSTR lpURL,                                      // URL
	IN  LPCWSTR lpHeaders,                                  // Headers
	IN  const string &strPostData,                          // POST数据
	OUT string *pRetBuf,                                    // 输出返回结果数据,注意返回的是数据不是字符串  
	OUT LONG *pCurlRetCode = NULL,                          // 输出CURL执行结果,出错时便于分析
	IN  LONG lTimeOutSeconds = 20                           // 超时时间,单位秒
	);

//////////////////////////////////////////////////////////////////////////
// 数据写入string中回调函数
static size_t XCURLIN_WriteDataToStringFunctionCallback(char *ptr, size_t size, size_t nmemb, string *pRetBuf)  
{  
	// 参数有效性
	if (ptr==NULL || size==0 || nmemb==0 || pRetBuf==NULL)
	{
		return 0;
	}

	// 追加数据到string
	size_t szBytes = size * nmemb;
	pRetBuf->append(ptr, szBytes);
	return szBytes;
} 

// HTTP发送一个GET请求
XHTTPLIB_API
XHTTPRET_T
XHTTP_SendRequest(
	IN  LPCWSTR lpURL,                                      // URL
	IN  LPCWSTR lpHeaders,                                  // Headers
	OUT string *pRetBuf,                                    // 输出返回结果数据,注意返回的是数据不是字符串  
	OUT LONG *pCurlRetCode,                                 // 输出CURL执行结果,出错时便于分析
	IN  LONG lTimeOutSeconds                                // 超时时间,单位秒
	)
{
	// 初始化输出参数
	if (pRetBuf != NULL)
	{
		pRetBuf->clear();
	}
	if (pCurlRetCode != NULL)
	{
		*pCurlRetCode = CURLE_OK;
	}

	// 参数有效性
	string strUrlUtf8 = STRF_UnicodeToUtf8(lpURL);
	if (strUrlUtf8.length() == 0)
	{
		return XHTTPRET_ERROR_PARAMETER;
	}

	// 申请句柄
	CURL *pcurl = curl_easy_init();
	if (pcurl == NULL)
	{
		return XHTTPRET_ERROR_CURLEASYINIT;
	}

	// 设置Headers
	curl_slist *pHeaderList = NULL;
	string strHeaderUtf8 = STRF_UnicodeToUtf8(lpHeaders);
	if (strHeaderUtf8.length() > 0)
	{
		pHeaderList = curl_slist_append(pHeaderList, strHeaderUtf8.c_str()); 
		curl_easy_setopt(pcurl, CURLOPT_HTTPHEADER, pHeaderList); 		
	}

	// 设置返回结果写入string
	if (pRetBuf != NULL)
	{
		curl_easy_setopt(pcurl, CURLOPT_WRITEFUNCTION, XCURLIN_WriteDataToStringFunctionCallback); 
		curl_easy_setopt(pcurl, CURLOPT_WRITEDATA, pRetBuf);  
	}

	// 设置超时时间
	if (lTimeOutSeconds > 0)
	{
		curl_easy_setopt(pcurl, CURLOPT_TIMEOUT, lTimeOutSeconds);
	}

	// 设置其他参数
	curl_easy_setopt(pcurl, CURLOPT_CONNECTTIMEOUT, 10L);
	curl_easy_setopt(pcurl, CURLOPT_NOSIGNAL, 1L);
	curl_easy_setopt(pcurl, CURLOPT_NOPROGRESS, 1L);
	curl_easy_setopt(pcurl, CURLOPT_HEADER, 0L);	
	curl_easy_setopt(pcurl, CURLOPT_FOLLOWLOCATION, 1L);
	curl_easy_setopt(pcurl, CURLOPT_SSL_VERIFYPEER, 0L);
	curl_easy_setopt(pcurl, CURLOPT_SSL_VERIFYHOST, 2L);
	curl_easy_setopt(pcurl, CURLOPT_URL, strUrlUtf8.c_str());

	// 发起请求
	CURLcode curlRetCode = curl_easy_perform(pcurl);

	// 释放句柄
	curl_easy_cleanup(pcurl); 

	// 释放头列表
	if (pHeaderList != NULL)
	{
		curl_slist_free_all(pHeaderList);
	}

	// 得到输出参数
	if (pCurlRetCode != NULL)
	{
		*pCurlRetCode = curlRetCode;
	}	

	// 返回成功
	if (curlRetCode == CURLE_OK)
	{
		return XHTTPRET_SUCCESS;
	}

	// 超时返回单独的值	
	return (curlRetCode == CURLE_OPERATION_TIMEDOUT) ? XHTTPRET_ERROR_PERFORMOPERATIONTIMEDOUT : XHTTPRET_ERROR_CURLEASYPERFORM;
}


// HTTP发送一个POST请求
XHTTPLIB_API
XHTTPRET_T
XHTTP_PostRequest(
	IN  LPCWSTR lpURL,                                      // URL
	IN  LPCWSTR lpHeaders,                                  // Headers
	IN  const string &strPostData,                          // POST数据
	OUT string *pRetBuf,                                    // 输出返回结果数据,注意返回的是数据不是字符串  
	OUT LONG *pCurlRetCode,                                 // 输出CURL执行结果,出错时便于分析
	IN  LONG lTimeOutSeconds                                // 超时时间,单位秒
	)
{
	// 初始化输出参数
	if (pRetBuf != NULL)
	{
		pRetBuf->clear();
	}
	if (pCurlRetCode != NULL)
	{
		*pCurlRetCode = CURLE_OK;
	}

	// 参数有效性
	string strUrlUtf8 = STRF_UnicodeToUtf8(lpURL);
	if (   strUrlUtf8.length() == 0
		|| strPostData.length() == 0
		)
	{
		return XHTTPRET_ERROR_PARAMETER;
	}

	// 申请句柄
	CURL *pcurl = curl_easy_init();
	if (pcurl == NULL)
	{
		return XHTTPRET_ERROR_CURLEASYINIT;
	}

	// 设置Headers
	curl_slist *pHeaderList = NULL;
	string strHeaderUtf8 = STRF_UnicodeToUtf8(lpHeaders);
	if (strHeaderUtf8.length() > 0)
	{
		pHeaderList = curl_slist_append(pHeaderList, strHeaderUtf8.c_str()); 
		curl_easy_setopt(pcurl, CURLOPT_HTTPHEADER, pHeaderList); 		
	}

	// 设置POST数据
	curl_easy_setopt(pcurl, CURLOPT_POST, 1L);
	curl_easy_setopt(pcurl, CURLOPT_POSTFIELDS, strPostData.c_str());  
	curl_easy_setopt(pcurl, CURLOPT_POSTFIELDSIZE, strPostData.size());

	// 设置返回结果写入string
	if (pRetBuf != NULL)
	{
		curl_easy_setopt(pcurl, CURLOPT_WRITEFUNCTION, XCURLIN_WriteDataToStringFunctionCallback); 
		curl_easy_setopt(pcurl, CURLOPT_WRITEDATA, pRetBuf);  
	}

	// 设置超时时间
	if (lTimeOutSeconds > 0)
	{
		curl_easy_setopt(pcurl, CURLOPT_TIMEOUT, lTimeOutSeconds);
	}
	
	// 设置其他参数
	curl_easy_setopt(pcurl, CURLOPT_CONNECTTIMEOUT, 10L);
	curl_easy_setopt(pcurl, CURLOPT_NOSIGNAL, 1L);
	curl_easy_setopt(pcurl, CURLOPT_NOPROGRESS, 1L);
	curl_easy_setopt(pcurl, CURLOPT_HEADER, 0L);	
	curl_easy_setopt(pcurl, CURLOPT_FOLLOWLOCATION, 1L);	
	curl_easy_setopt(pcurl, CURLOPT_SSL_VERIFYPEER, 0L);
	curl_easy_setopt(pcurl, CURLOPT_SSL_VERIFYHOST, 2L);
	curl_easy_setopt(pcurl, CURLOPT_URL, strUrlUtf8.c_str());

	// 发起请求
	CURLcode curlRetCode = curl_easy_perform(pcurl);

	// 释放句柄
	curl_easy_cleanup(pcurl); 

	// 释放头列表
	if (pHeaderList != NULL)
	{
		curl_slist_free_all(pHeaderList);
	}

	// 得到输出参数
	if (pCurlRetCode != NULL)
	{
		*pCurlRetCode = curlRetCode;
	}	

	// 返回成功
	if (curlRetCode == CURLE_OK)
	{
		return XHTTPRET_SUCCESS;
	}

	// 超时返回单独的值	
	return (curlRetCode == CURLE_OPERATION_TIMEDOUT) ? XHTTPRET_ERROR_PERFORMOPERATIONTIMEDOUT : XHTTPRET_ERROR_CURLEASYPERFORM;
}