a class do async http post task

参照MS的例子, 封装了一个异步HttpPost的类, 用起来很简单

异步HttpPost的好处是 : 不会在Win32Api中阻塞住, 程序退出时,速度快. 

异步HttpPost主要解决的是程序退出的问题,如果不需要频繁退出的程序,可以使用同步HttpPost操作, 方便易用.


编译环境 : vs2010 vc++ + win32 console

工程下载点: srcAsyncHttpPost_2014_1221_1746.rar


测试程序:

/// @file        srcAsyncHttpPost.cpp
/// @brief      参照MS的例子, 封装了一个异步HttpPost的类, 用起来很简单
///             a class do async http post task

#include "stdafx.h"
#include "./Helper/ThreadManager.h"
#include "./Helper/HttpPostTask.h"
#include "./Helper/StringHelper.h"

int _tmain(int argc, _TCHAR* argv[])
{
    BOOL            bRc = FALSE;
    WCHAR           cUserInput = L'\0';
    std::string     strHttpRecv = "";
    CHttpPostTask   HttpPostTask;

    // http://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=stl&rsv_pq=9d21509800016bd9&rsv_t=7c03V4xpJO40vaY1cVToAMgdr1gNzCHJFmFf6AGMKqjBFuP7De7D3qxTA%2Fc&rsv_enter=1&inputT=2977&rsv_sug1=39&rsv_sug3=21&rsv_sug4=514&rsv_sug2=0
    std::string strServerToPost = "www.baidu.com";
    std::string strPostUrl = "/s";
    std::string strPostName = "ie";
    std::string strPostContent = "utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=stl&rsv_pq=9d21509800016bd9&rsv_t=7c03V4xpJO40vaY1cVToAMgdr1gNzCHJFmFf6AGMKqjBFuP7De7D3qxTA%2Fc&rsv_enter=1&inputT=2977&rsv_sug1=39&rsv_sug3=21&rsv_sug4=514&rsv_sug2=0";
    BOOL bPostDataAsGetType = FALSE;

    bRc = HttpPostTask.PostDataToWeb_async_GET_or_POST(
        strServerToPost, 
        strPostUrl, 
        strPostName, 
        strPostContent, 
        bPostDataAsGetType);
    if (!bRc)
    {
        _tprintf(L"failed HttpPostTask.PostDataToWeb_async_GET_or_POST\r\n");
    }
    _tprintf(L"if want stop http post task, press key 'q' or 'Q', then press ENTER key\r\n");

    do 
    {
        Sleep(0);

        /// 实际的应用中,任务中止的动作是程序退出时发送的 或 自定义超时逻辑发出的
        cUserInput = getwchar();
        if ((L'q' == cUserInput) 
            || (L'Q' == cUserInput))
        {
            _tprintf(L"user send quit command\r\n");
            getwchar(); ///< recive the ENTER key
            break;
        }

        /// @todo 实际工程中,不用轮询任务是否完成
        /// 让 HttpPostTask 和 CHttpPostAsync 等待退出和任务完成事件之一
        /// 这里轮询,是为了Demo写的简明些
        /// 给HttpPostTask增加一个Stop方法, 在另外一个线程中调用, 用于停止HttpPost任务
        /// 给HttpPostTask增加一个waitTaskEnd方法, 阻塞等待完成(成功,失败),退出事件之一, 
        /// 在 PostDataToWeb_async_GET_or_POST 之后阻塞调用
        if (HttpPostTask.IsTaskOver())
        {
            _tprintf(L"ok, HttpPostTask is over\r\n");
            break;
        }
        else
        {
            _tprintf(L"HttpPostTask is running, if need quit, press q or Q key to quit\r\n");
        }
    } while (1);

    if (HttpPostTask.IsTaskOver())
    {
        strHttpRecv = HttpPostTask.GetRecv();
        strHttpRecv = ns_base::UTF8ToGBK(strHttpRecv);
        printf("HttpPostTask.GetErr() = %d\r\nstrHttpRecv = %s\r\n", 
            HttpPostTask.GetErr(), 
            strHttpRecv.c_str());
    }

    _tprintf(L"END, press any key to quit\r\n");
    getwchar();

	return 0;
}


HttpPost任务类 .h

/// @file       HttpPostTask.h
/// @brief      HttpPost任务类, 调用HttpPostAsync干活

#ifndef __HTTP_POST_TASK_H__
#define __HTTP_POST_TASK_H__

#include "HttpPostAsync.h"

class CHttpPostTask
{
public:
    CHttpPostTask();
    virtual ~CHttpPostTask();

    BOOL PostDataToWeb_async_GET_or_POST(
        IN std::string& strServerToPost, 
        IN std::string& strPostUrl,
        IN std::string& strPostName,
        IN std::string& strPostContent, 
        IN BOOL bPostDataAsGetType);

    BOOL IsTaskOver();
    CHttpPostAsync::eHttpError GetErr() {return m_httpPostAsync.GetErr();}
    std::string GetRecv();

    static UINT WINAPI ThreadProc_HttpPost(void* pParam);
    UINT ThreadProc_HttpPost();

private:
    void DataInit();

private:
    CHttpPostAsync  m_httpPostAsync;

    std::string m_strServerToPost;
    std::string m_strPostUrl;
    std::string m_strPostName;
    std::string m_strPostContent;
    BOOL        m_bPostDataAsGetType;
    std::string m_strRecv;
};

#endif // #ifndef __HTTP_POST_TASK_H__

HttpPost实现类

/// @file       HttpPostAsync.h
/// @brief      异步HttpPost类

#ifndef __HTTP_POST_EX_H__
#define __HTTP_POST_EX_H__

#include "EventManager.h"
#include "ThreadManager.h"

typedef struct _tag_cbContext_HttpPostEx TAG_CB_CONTEXT_HTTP_POST_EX;

class CHttpPostAsync
{
public:
    CHttpPostAsync();
    virtual ~CHttpPostAsync();

public:
    enum eHttpContext
    {
        eHttpCtx_unknown = -1,  // 不处理的回调状态
        eHttpCtx_Connection,    // 以下是需要处理的回调状态
        eHttpCtx_OpenRequest,   
        eHttpCtx_SendRequestHeader,
        eHttpCtx_SendRequestHeaderData,
        eHttpCtx_GetRemoteResponse,
    };

    enum eHttpError
    {
         eHttpError_unknown = -1,
         eHttpError_no,              ///< 没有错误
         eHttpError_CreateWorkerThread,
         eHttpError_Param,
         eHttpError_InternetOpen,
         eHttpError_SetCallBack,
         eHttpError_SendRequestHeader,
         eHttpError_InternetReadFileEx,
         eHttpError_HttpEndRequest,
         eHttpError_InternetWriteFile,
         eHttpError_InternetConnect,
         eHttpError_HttpOpenRequest,
    };

public:
    void SetErr(eHttpError err) {m_HttpError = err;}
    CHttpPostAsync::eHttpError GetErr() {return m_HttpError;}

    BOOL PostUrl(const char* pcServerName, const char* pcUrl, const char* pcPostText);
    BOOL GetRecvData(std::string& strRecv);
    BOOL IsTaskEnd();
    BOOL Stop();
    void SetNeedStop(BOOL bNeedStop)
    {
        m_bCmdStop = bNeedStop;
        m_Event_CmdStop.SetEvent();
    }
    BOOL IsNeedStop() {return m_bCmdStop;}

    static UINT WINAPI ThreadProc_HttpPostAsync(void* pParam);
    UINT ThreadProc_HttpPostAsync();

    void __stdcall CallbackProc_HttpPostEx_Connection(HINTERNET hInternet,
        DWORD dwContext,
        DWORD dwInternetStatus,
        LPVOID lpStatusInfo,
        DWORD dwStatusInfoLen);

    void __stdcall CallbackProc_HttpPostEx_OpenRequest(HINTERNET hInternet,
        DWORD dwContext,
        DWORD dwInternetStatus,
        LPVOID lpStatusInfo,
        DWORD dwStatusInfoLen);

    void __stdcall CallbackProc_HttpPostEx_SendRequestHeader(HINTERNET hInternet,
        DWORD dwContext,
        DWORD dwInternetStatus,
        LPVOID lpStatusInfo,
        DWORD dwStatusInfoLen);

    void __stdcall CallbackProc_HttpPostEx_GetRemoteResponse(HINTERNET hInternet,
        DWORD dwContext,
        DWORD dwInternetStatus,
        LPVOID lpStatusInfo,
        DWORD dwStatusInfoLen);
private:
    void DataInit();
    BOOL CreateWorkerThread();

    BOOL DoInternetOpen(HINTERNET& hSession);
    BOOL DoSetCallback(HINTERNET& hHandle, INTERNET_STATUS_CALLBACK pcbfn);
    BOOL DoConnect(HINTERNET& hConnect);
    BOOL DoOpenRequest();
    BOOL DoSendRequest();
    BOOL DoGetRemoteResponse();
    void DoCloseConnect();
    void DoResetAllEventOnWait();

private:
    std::string m_strServerName;
    std::string m_strUrl;
    std::string m_strPostContent;
    std::string m_strRecvContent;

    ns_base::CThreadManager m_ThreadManager_WorkerThread;

    ns_base::CEventManager  m_Event_ConnectedOver;
    ns_base::CEventManager  m_Event_OpenRequestOver;
    ns_base::CEventManager  m_Event_SendRequestOver;
    ns_base::CEventManager  m_Event_GetRemoteResponseOver;
    ns_base::CEventManager  m_Event_CmdStop;

    HINTERNET   m_hSession;
    HINTERNET   m_hConnect;
    HINTERNET   m_hOpenRequest;
    BOOL        m_bAllDone;
    eHttpError  m_HttpError;    ///< http操作中的错误码
    BOOL        m_bCmdStop;     ///< 外部发出的停止命令
    TAG_CB_CONTEXT_HTTP_POST_EX* m_pHttpPostContext;
};

typedef struct _tag_cbContext_HttpPostEx
{
    CHttpPostAsync*    pOnwer;
    CHttpPostAsync::eHttpContext    ContextCode;

    _tag_cbContext_HttpPostEx()
    {
        pOnwer = NULL;
        ContextCode = CHttpPostAsync::eHttpCtx_unknown;
    }

    void SetParam(CHttpPostAsync* pOnwer, CHttpPostAsync::eHttpContext ContextCode)
    {
        this->pOnwer = pOnwer;
        this->ContextCode = ContextCode;
    }
}TAG_CB_CONTEXT_HTTP_POST_EX;

#endif // #ifndef __HTTP_POST_EX_H__

类实现:

/// @file       HttpPostTask.cpp
/// @brief      ...

#include "stdafx.h"
#include "constDefine.h"
#include "HttpPostTask.h"
#include "StringHelper.h"

CHttpPostTask::CHttpPostTask()
{
    DataInit();
}

CHttpPostTask::~CHttpPostTask()
{
}

void CHttpPostTask::DataInit()
{
    m_strServerToPost = "";
    m_strPostUrl = "";
    m_strPostName = "";
    m_strPostContent = "";
    m_bPostDataAsGetType = FALSE;
    m_strRecv = "";
}

BOOL CHttpPostTask::PostDataToWeb_async_GET_or_POST(
    IN std::string& strServerToPost, 
    IN std::string& strPostUrl,
    IN std::string& strPostName,
    IN std::string& strPostContent, 
    IN BOOL bPostDataAsGetType)
{
    USES_CONVERSION;
    BOOL        bRc = FALSE;
    std::string strPostUrlIn = "";
    std::string strPostTextIn = "";
    std::string strPostUrlInUtf8 = "";
    std::string strPostTextInUtf8 = "";


    m_strServerToPost = strServerToPost;
    m_strPostUrl = strPostUrl;
    m_strPostName = strPostName;
    m_strPostContent = strPostContent;
    m_bPostDataAsGetType = bPostDataAsGetType;
    m_strRecv = "";
    strPostUrlIn = strPostUrl.c_str();
    strPostTextIn = ns_base::StringFormatVA("%s=%s",
        strPostName.c_str(), 
        strPostContent.c_str());

    if (bPostDataAsGetType)
    {
        strPostUrlIn += "&";
        strPostUrlIn += strPostTextIn.c_str();
        strPostTextIn = "";
    }

    // if strPostUrlIn or strPostTextIn include chinese word, need convert to utf8
    // then call http post

    strPostUrlIn = ns_base::GBK2UTF8(strPostUrlIn);
    strPostTextIn = ns_base::GBK2UTF8(strPostTextIn);

    return m_httpPostAsync.PostUrl(strServerToPost.c_str(), strPostUrlIn.c_str(), strPostTextIn.c_str());
}

BOOL CHttpPostTask::IsTaskOver()
{
    return m_httpPostAsync.IsTaskEnd();
}

UINT WINAPI CHttpPostTask::ThreadProc_HttpPost(void* pParam)
{
    if (NULL == pParam)
        return S_FALSE;

    return ((CHttpPostTask*)pParam)->ThreadProc_HttpPost();
}

UINT CHttpPostTask::ThreadProc_HttpPost()
{
    return S_OK;
}

std::string CHttpPostTask::GetRecv()
{
    m_httpPostAsync.GetRecvData(m_strRecv);
    return m_strRecv;
}


/// @file       HttpPostAsync.cpp
/// @brief      ...

#include <stdafx.h>
#include "constDefine.h"
#include "HttpPostAsync.h"

void __stdcall Callback_HttpPostEx(
    HINTERNET hInternet,
    DWORD dwContext,
    DWORD dwInternetStatus,
    LPVOID lpStatusInfo,
    DWORD dwStatusInfoLen)
{
    TAG_CB_CONTEXT_HTTP_POST_EX* pcbContext = (TAG_CB_CONTEXT_HTTP_POST_EX*)dwContext;

    if (NULL == pcbContext)
        return;

    if (NULL == pcbContext->pOnwer)
        return;

    switch (pcbContext->ContextCode)
    {
    case CHttpPostAsync::eHttpCtx_Connection:
        {
            pcbContext->pOnwer->CallbackProc_HttpPostEx_Connection(
                hInternet, 
                dwContext, 
                dwInternetStatus, 
                lpStatusInfo, 
                dwStatusInfoLen);
        }
        break;

    case CHttpPostAsync::eHttpCtx_OpenRequest:
        {
            pcbContext->pOnwer->CallbackProc_HttpPostEx_OpenRequest(
                hInternet, 
                dwContext, 
                dwInternetStatus, 
                lpStatusInfo, 
                dwStatusInfoLen);
        }
        break;

    case CHttpPostAsync::eHttpCtx_SendRequestHeader:
        {
            pcbContext->pOnwer->CallbackProc_HttpPostEx_SendRequestHeader(
                hInternet, 
                dwContext, 
                dwInternetStatus, 
                lpStatusInfo, 
                dwStatusInfoLen);
        }
        break;

    case CHttpPostAsync::eHttpCtx_GetRemoteResponse:
        {
            pcbContext->pOnwer->CallbackProc_HttpPostEx_GetRemoteResponse(
                hInternet, 
                dwContext, 
                dwInternetStatus, 
                lpStatusInfo, 
                dwStatusInfoLen);
        }
        break;

    case CHttpPostAsync::eHttpCtx_unknown:
    default:
        {
            /// SendRequest没有指定回调时,会进这里. 不能做任何处理
            /// pcbContext->pOnwer是无效的
        }
        break;
    }
}

void __stdcall CHttpPostAsync::CallbackProc_HttpPostEx_Connection(
    HINTERNET hInternet,
    DWORD dwContext,
    DWORD dwInternetStatus,
    LPVOID lpStatusInfo,
    DWORD dwStatusInfoLen)
{
    if (IsNeedStop())
        return;

    switch (dwInternetStatus)
    {
    case INTERNET_STATUS_HANDLE_CREATED:
        {
            m_Event_ConnectedOver.SetEvent();
        }
        break;

    default:
        break;
    }
}

void __stdcall CHttpPostAsync::CallbackProc_HttpPostEx_OpenRequest(
    HINTERNET hInternet,
    DWORD dwContext,
    DWORD dwInternetStatus,
    LPVOID lpStatusInfo,
    DWORD dwStatusInfoLen)
{
    if (IsNeedStop())
        return;

    switch (dwInternetStatus)
    {
    case INTERNET_STATUS_HANDLE_CREATED:
        {
            m_Event_OpenRequestOver.SetEvent();
        }
        break;

    default:
        break;
    }
}

void __stdcall CHttpPostAsync::CallbackProc_HttpPostEx_SendRequestHeader(
    HINTERNET hInternet,
    DWORD dwContext,
    DWORD dwInternetStatus,
    LPVOID lpStatusInfo,
    DWORD dwStatusInfoLen)
{
    if (IsNeedStop())
        return;

    switch (dwInternetStatus)
    {
    case INTERNET_STATUS_REQUEST_COMPLETE:
        {
            m_Event_SendRequestOver.SetEvent();
        }
        break;

    default:
        break;
    }
}

void __stdcall CHttpPostAsync::CallbackProc_HttpPostEx_GetRemoteResponse(
    HINTERNET hInternet,
    DWORD dwContext,
    DWORD dwInternetStatus,
    LPVOID lpStatusInfo,
    DWORD dwStatusInfoLen)
{
    if (IsNeedStop())
        return;

    switch (dwInternetStatus)
    {
    case INTERNET_STATUS_REQUEST_COMPLETE:
        {
            m_Event_GetRemoteResponseOver.SetEvent();
        }
        break;
    default:
        break;
    }
}

CHttpPostAsync::CHttpPostAsync()
{
    DataInit();
}

CHttpPostAsync::~CHttpPostAsync()
{
    SAFE_DELETE(m_pHttpPostContext);
}

void CHttpPostAsync::DataInit()
{
    m_strServerName = "";
    m_strUrl = "";
    m_strPostContent = "";
    m_strRecvContent = "";

    m_hSession = NULL;
    m_hConnect = NULL;
    m_hOpenRequest = NULL;
    m_bAllDone = FALSE;
    SetErr(eHttpError_no);    ///< 初始为没有错误
    SetNeedStop(FALSE);
    m_pHttpPostContext = new TAG_CB_CONTEXT_HTTP_POST_EX;
}

void CHttpPostAsync::DoCloseConnect()
{
    /// @todo SAFE_CLOSE_HANDLE 会报错, 不用关闭么?
    DoSetCallback(m_hSession, NULL);

    SAFE_CLOSE_HINTERNET(m_hOpenRequest);
    SAFE_CLOSE_HINTERNET(m_hConnect);
    SAFE_CLOSE_HINTERNET(m_hSession);
}

void CHttpPostAsync::DoResetAllEventOnWait()
{
    SetNeedStop(FALSE);
    SetErr(eHttpError_no);
    m_Event_ConnectedOver.ResetEvent();
    m_Event_OpenRequestOver.ResetEvent();
    m_Event_SendRequestOver.ResetEvent();
    m_Event_GetRemoteResponseOver.ResetEvent();
    m_Event_CmdStop.ResetEvent();
}

BOOL CHttpPostAsync::PostUrl(const char* pcServerName, const char* pcUrl, const char* pcPostText)
{
    BOOL    bRc = FALSE;

    do 
    {
        if ((NULL == pcServerName))
            break;

        m_strServerName = pcServerName;
        if (NULL == pcUrl)
            break;

        m_strUrl = pcUrl;
        m_strPostContent = (NULL == pcPostText) ? "" : pcPostText;

        /// 起一条线程, 执行异步http post任务
        if (!CreateWorkerThread())
            break;

        bRc = TRUE;
    } while (0);

    if (!bRc)
    {
        SetErr(eHttpError_CreateWorkerThread);
    }
    return bRc;
}

BOOL CHttpPostAsync::CreateWorkerThread()
{
    if (!m_ThreadManager_WorkerThread.IsNeedQuitThread()
        && !m_ThreadManager_WorkerThread.IsThreadRunning())
    {
        DoCloseConnect();
        DoResetAllEventOnWait();

        m_ThreadManager_WorkerThread.SetThreadHandle(
            (HANDLE)_beginthreadex(
            NULL, 
            0, 
            &CHttpPostAsync::ThreadProc_HttpPostAsync, 
            (void*)this, 
            0, 
            NULL));
    }

    return TRUE;
}

UINT WINAPI CHttpPostAsync::ThreadProc_HttpPostAsync(void* pParam)
{
    UINT    uRc = S_FALSE;
    CHttpPostAsync* pMe = NULL;

    do 
    {
        if (NULL == pParam)
        {
            pMe->SetErr(eHttpError_Param);
            break;
        }

        pMe = (CHttpPostAsync*)pParam;
        uRc = pMe->ThreadProc_HttpPostAsync();
    } while (0);

    return uRc;
}

BOOL CHttpPostAsync::DoInternetOpen(HINTERNET& hSession)
{
    BOOL        bRc = FALSE;
    DWORD       dwErr = 0;
    const char* pcAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.8888.8888;)";

    do 
    {
        if (IsNeedStop())
            break;

        hSession = InternetOpenA(pcAgent, 
            INTERNET_OPEN_TYPE_PRECONFIG,
            NULL,
            NULL,
            INTERNET_FLAG_ASYNC); // ASYNC Flag

        if (NULL == hSession)
        {
            SetErr(eHttpError_InternetOpen);
            break;
        }

        if (!DoSetCallback(hSession, &Callback_HttpPostEx))
            break;

        bRc = TRUE;
    } while (0);


    return bRc;
}

BOOL CHttpPostAsync::DoSetCallback(HINTERNET& hHandle, INTERNET_STATUS_CALLBACK pcbfn)
{
    BOOL        bRc = FALSE;
    DWORD       dwErr = 0;
    INTERNET_STATUS_CALLBACK    status = INTERNET_INVALID_STATUS_CALLBACK;

    do 
    {
        if (IsNeedStop())
            break;

        if ((NULL == hHandle) || (INVALID_HANDLE_VALUE == hHandle))
            break;

        status = InternetSetStatusCallback(
            hHandle,
            (INTERNET_STATUS_CALLBACK)pcbfn);

        if (INTERNET_INVALID_STATUS_CALLBACK == status)
        {
            SetErr(eHttpError_SetCallBack);
            break;
        }


        bRc = TRUE;
    } while (0);

    return bRc;
}

BOOL CHttpPostAsync::DoConnect(HINTERNET& hConnect)
{
    BOOL        bRc = FALSE;
    DWORD       dwErr = 0;
    HANDLE      ArrEvent[2];  

    ArrEvent[0] = m_Event_CmdStop.GetHandle();
    ArrEvent[1] = m_Event_ConnectedOver.GetHandle();

    do 
    {
        if (IsNeedStop())
            break;

        m_pHttpPostContext->SetParam(this, eHttpCtx_Connection);
        m_hConnect = InternetConnectA(
            m_hSession, 
            m_strServerName.c_str(), 
            INTERNET_DEFAULT_HTTP_PORT, 
            NULL, 
            NULL, 
            INTERNET_SERVICE_HTTP, 
            0, 
            (DWORD_PTR)(m_pHttpPostContext));

        if (NULL == m_hConnect)
        {
            dwErr = ::GetLastError();
            if (ERROR_IO_PENDING != dwErr)
            {
                SetErr(eHttpError_InternetConnect);
                break;
            }

            WaitForMultipleObjects(sizeof(ArrEvent) / sizeof(HANDLE), ArrEvent, FALSE, INFINITE);
        }

        bRc = TRUE;
    } while (0);

    m_Event_ConnectedOver.ResetEvent();

    return bRc;
}

BOOL CHttpPostAsync::DoOpenRequest()
{
    BOOL        bRc = FALSE;
    DWORD       dwErr = 0;
    char*   szAccept[]   = {"Accept: */*", NULL};   //接受文件的类型

    HANDLE      ArrEvent[2];  

    ArrEvent[0] = m_Event_CmdStop.GetHandle();
    ArrEvent[1] = m_Event_OpenRequestOver.GetHandle();

    do 
    {
        if (IsNeedStop())
            break;

        m_pHttpPostContext->SetParam(this, eHttpCtx_OpenRequest);
        m_hOpenRequest = HttpOpenRequestA(
            m_hConnect,
            "POST",
            m_strUrl.c_str(),
            "HTTP/1.1",
            NULL,
            (LPCSTR *)&szAccept,
            INTERNET_FLAG_RELOAD,
            (DWORD_PTR)(m_pHttpPostContext));

        if (NULL == m_hOpenRequest)
        {
            if (GetLastError() != ERROR_IO_PENDING)
            {
                SetErr(eHttpError_HttpOpenRequest);
                dwErr = ::GetLastError();
                break;
            }

            WaitForMultipleObjects(sizeof(ArrEvent) / sizeof(HANDLE), ArrEvent, FALSE, INFINITE);
        }

        if (!DoSetCallback(m_hOpenRequest, &Callback_HttpPostEx))
            break;

        bRc = TRUE;
    } while (0);

    m_Event_OpenRequestOver.ResetEvent();
    return bRc;
}

BOOL CHttpPostAsync::DoSendRequest()
{
    BOOL        bRc = FALSE;
    DWORD       dwErr = 0;
    char strHeaders[] = "Content-Type: application/x-www-form-urlencoded\r\n";

    INTERNET_BUFFERSA   InetBuff;
    HANDLE              ArrEvent[2];  

    DWORD       dwBytesWritten = 0;

    ArrEvent[0] = m_Event_CmdStop.GetHandle();
    ArrEvent[1] = m_Event_SendRequestOver.GetHandle();

    do 
    {
        /// 发送http header
        if (IsNeedStop())
            break;

        m_pHttpPostContext->SetParam(this, eHttpCtx_SendRequestHeader);

        FillMemory(&InetBuff, sizeof(InetBuff), 0);
        InetBuff.dwStructSize= sizeof(InetBuff);
        InetBuff.dwBufferTotal = strlen(m_strPostContent.c_str());
        InetBuff.lpcszHeader = strHeaders;
        InetBuff.dwHeadersLength = strlen(InetBuff.lpcszHeader);

        if (!HttpSendRequestExA(m_hOpenRequest, 
            &InetBuff,
            NULL, 
            INTERNET_KEEP_ALIVE_DISABLED,
            (DWORD_PTR)(m_pHttpPostContext)))
        {
            if (GetLastError() != ERROR_IO_PENDING)
            {
                SetErr(eHttpError_SendRequestHeader);
                break;
            }

            WaitForMultipleObjects(sizeof(ArrEvent) / sizeof(HANDLE), ArrEvent, FALSE, INFINITE);
        }

        /// 发送 post's content
        if (IsNeedStop())
            break;

        m_Event_SendRequestOver.ResetEvent(); ///< !

        if (strlen(m_strPostContent.c_str()) > 0)
        {
            /// 如果 InternetWriteFile 0 长度的数据, 会失败的
            if(!InternetWriteFile(m_hOpenRequest,
                m_strPostContent.c_str(),
                strlen(m_strPostContent.c_str()),
                &dwBytesWritten))
            {
                if (GetLastError() != ERROR_IO_PENDING)
                {
                    SetErr(eHttpError_InternetWriteFile);
                    break;
                }
                else
                {
                    WaitForMultipleObjects(sizeof(ArrEvent) / sizeof(HANDLE), ArrEvent, FALSE, INFINITE);
                }
            }

            m_Event_SendRequestOver.ResetEvent(); ///< !
        }

        /// end request
        if (!HttpEndRequest(m_hOpenRequest, NULL, HSR_INITIATE, (DWORD_PTR)(m_pHttpPostContext)))
        {
            if (GetLastError() == ERROR_IO_PENDING)
            {
                WaitForMultipleObjects(sizeof(ArrEvent) / sizeof(HANDLE), ArrEvent, FALSE, INFINITE);
            }
            else
            {
                SetErr(eHttpError_HttpEndRequest);
                break;
            }
        }

        bRc = TRUE;
    } while (0);

    m_Event_SendRequestOver.ResetEvent();
    return bRc;
}

BOOL CHttpPostAsync::DoGetRemoteResponse()
{
    DWORD       dwErr = 0;
    char        szReadBuff[2048];
    std::string strRecvOnce = "";
    INTERNET_BUFFERS InetBuff;

    HANDLE      ArrEvent[2];  

    ArrEvent[0] = m_Event_CmdStop.GetHandle();
    ArrEvent[1] = m_Event_GetRemoteResponseOver.GetHandle();
    m_strRecvContent = "";
    do
    {
        if (IsNeedStop())
            break;

        FillMemory(&InetBuff, sizeof(InetBuff), 0);
        InetBuff.dwStructSize = sizeof(InetBuff);
        InetBuff.lpvBuffer = szReadBuff;
        InetBuff.dwBufferLength = sizeof(szReadBuff) - 1;

        m_pHttpPostContext->SetParam(this, eHttpCtx_GetRemoteResponse);
        if (!InternetReadFileEx(
            m_hOpenRequest,
            &InetBuff,
            IRF_ASYNC, 
            (DWORD_PTR)(m_pHttpPostContext)))
        {
            dwErr = ::GetLastError();
            if (ERROR_IO_PENDING == dwErr)
            {
                WaitForMultipleObjects(sizeof(ArrEvent) / sizeof(HANDLE), ArrEvent, FALSE, INFINITE);
                m_Event_GetRemoteResponseOver.ResetEvent();
            }
            else
            {
                SetErr(eHttpError_InternetReadFileEx);
                break;
            }
        }

        if (IsNeedStop())
            break;

        szReadBuff[InetBuff.dwBufferLength] = 0;
        if ((InetBuff.dwBufferLength != 0) 
            && (InetBuff.dwBufferLength != (DWORD)(-1)))
        {
            strRecvOnce.resize(InetBuff.dwBufferLength);
            ::memcpy((void*)strRecvOnce.data(), szReadBuff, InetBuff.dwBufferLength);
            m_strRecvContent.append(strRecvOnce);
        }

        if (InetBuff.dwBufferLength == 0) 
            m_bAllDone = TRUE;
    } while (!m_bAllDone);

    m_Event_GetRemoteResponseOver.ResetEvent();

    if (m_bAllDone)
    {
        if ((m_strRecvContent.size() >= 3)
            && ((UCHAR)0xef == (UCHAR)m_strRecvContent[0]) 
            && ((UCHAR)0xbb == (UCHAR)m_strRecvContent[1]) 
            && ((UCHAR)0xbf == (UCHAR)m_strRecvContent[2]))
        {
            m_strRecvContent.erase(0, 3);
        }
    }

    return m_bAllDone;
}

UINT CHttpPostAsync::ThreadProc_HttpPostAsync()
{
    UINT    uRc = S_FALSE;

    do 
    {
        if (!DoInternetOpen(m_hSession))
            break;

        if (!DoConnect(m_hConnect))
            break;

        if (!DoOpenRequest())
            break;

        if (!DoSendRequest())
            break;

        if (!DoGetRemoteResponse())
            break;

        uRc = S_OK;
    } while (0);

    DoSetCallback(m_hSession, NULL);
    return uRc;
}

BOOL CHttpPostAsync::GetRecvData(std::string& strRecv)
{
    strRecv = m_strRecvContent;
    return TRUE;
}

BOOL CHttpPostAsync::IsTaskEnd()
{
    return (m_bAllDone || (eHttpError_no != GetErr()));
}

BOOL CHttpPostAsync::Stop()
{
    SetNeedStop(TRUE);
    m_ThreadManager_WorkerThread.StopThread(L"m_ThreadManager_WorkerThread");
    DoCloseConnect();
    return TRUE;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值