[prev in list] [next in list] [prev in thread] [next in thread] 

List:       helix-filesystem-cvs
Subject:    [Filesystem-cvs]  filesystem/httpshim/platform/win WinHttpDriver.cpp, NONE,
From:       qluo () helixcommunity ! org
Date:       2013-04-03 2:23:49
[Download RAW message or body]

Update of /cvsroot/filesystem/filesystem/httpshim/platform/win
In directory cvs01.internal.helixcommunity.org:/tmp/cvs-serv13857/platform/win

Added Files:
	WinHttpDriver.cpp WinHttpDriver.h WinHttpRequest.cpp 
	WinHttpRequest.h WinHttpResponse.cpp WinHttpResponse.h 
	WinInetUtility.cpp WinInetUtility.h 
Log Message:
check-in initial implementation on behalf of Jason Liao and Richard Zhao

--- NEW FILE: WinInetUtility.cpp ---
#include "WinInetUtility.h"
#include <assert.h>

#pragma comment (lib, "wininet.lib")

HINTERNET CWinInetUtility::OpenInternet( LPCTSTR szUserAgent, 
    DWORD dwAccessType /*= INTERNET_OPEN_TYPE_PRECONFIG*/, 
    LPCTSTR szProxyName /*= NULL*/, 
    LPCTSTR szProxyBypass /*= NULL*/)
{
    HINTERNET hInternet = InternetOpen(szUserAgent, dwAccessType, szProxyName, \
szProxyBypass, INTERNET_FLAG_ASYNC);  assert(hInternet != NULL && hInternet != \
INVALID_HANDLE_VALUE);  return hInternet;
}

DWORD CWinInetUtility::GetLastErrorCode()
{
    return GetLastError();
}

void CWinInetUtility::CloseInternet(HINTERNET& hInternet)
{
    _CloseInternetHandler(hInternet);
}

HINTERNET CWinInetUtility::OpenConnection( HINTERNET hInternet, 
    LPCTSTR szServerAddr, 
    DWORD_PTR dwContext,
    INTERNET_PORT nPort /*= INTERNET_DEFAULT_HTTP_PORT*/, 
    LPCTSTR szUsrName /*= NULL*/, 
    LPCTSTR szUsrPwd /*= NULL*/)
{
    assert(hInternet != NULL && hInternet != INVALID_HANDLE_VALUE);
    assert(szServerAddr && *szServerAddr);
    HINTERNET hConnection = InternetConnect(hInternet, szServerAddr, nPort, \
szUsrName, szUsrPwd, INTERNET_SERVICE_HTTP, 0, dwContext);  assert(hConnection != \
NULL && hConnection != INVALID_HANDLE_VALUE);  return hConnection;
}

HINTERNET CWinInetUtility::OpenURL( HINTERNET hInternet, LPCTSTR szURL, DWORD_PTR \
dwContext, DWORD dwFlags  ) {
    HINTERNET hHttpFile = InternetOpenUrl(hInternet, szURL, NULL, 0, dwFlags, \
dwContext);  return hHttpFile;
}

void CWinInetUtility::CloseConnection(HINTERNET& hConnection)
{
    _CloseInternetHandler(hConnection);
}

void CWinInetUtility::_CloseInternetHandler( HINTERNET& hHandler )
{
    if(hHandler != NULL && hHandler != INVALID_HANDLE_VALUE)
    {
        ::InternetCloseHandle(hHandler);
    }

    hHandler = NULL;
}

HINTERNET CWinInetUtility::OpenRequest( HINTERNET hConnection, 
    LPCTSTR szMethod, 
    LPCTSTR szObjectName,
    DWORD_PTR dwContext,
    DWORD dwFlags /*= INTERNET_FLAG_HYPERLINK | INTERNET_FLAG_KEEP_CONNECTION | \
INTERNET_FLAG_NO_UI | INTERNET_FLAG_RESYNCHRONIZE | INTERNET_FLAG_NO_CACHE_WRITE | \
INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_RELOAD*/,   LPCTSTR szReferer /*= \
NULL*/) {
    static LPCTSTR szAcceptedType[] = {_T("*/*"), NULL};
    HINTERNET hRequest = HttpOpenRequest(hConnection, szMethod, szObjectName, NULL, \
szReferer, szAcceptedType, dwFlags, dwContext);  return hRequest;
}

void CWinInetUtility::CloseRequest( HINTERNET& hRequest )
{
    _CloseInternetHandler(hRequest);
}

BOOL CWinInetUtility::AddHeader( HINTERNET hRequest, LPCTSTR szName, LPCTSTR szValue \
) {
    CString strHeader = szName;
    strHeader += _T(": ");
    strHeader += szValue;
    strHeader += _T("\r\n");
    return HttpAddRequestHeaders(hRequest, strHeader, strHeader.GetLength(), \
HTTP_ADDREQ_FLAG_ADD); }

BOOL CWinInetUtility::EndRequest(HINTERNET hRequest)
{
    return HttpEndRequest(hRequest, NULL, 0, 0);
}

BOOL CWinInetUtility::SendRequest( HINTERNET hRequest, LPVOID pPostedBuffer /*= \
NULL*/, DWORD dwBufferSize /*= 0*/ ) {
    return HttpSendRequest(hRequest, NULL, 0, pPostedBuffer, dwBufferSize);
}

BOOL CWinInetUtility::SendRequestEx( HINTERNET hRequest, DWORD dwPostedSize, \
DWORD_PTR dwContext /*= NULL*/ ) {
    INTERNET_BUFFERS bufferIn;
    ZeroMemory(&bufferIn, sizeof(bufferIn));
    bufferIn.dwStructSize = sizeof( INTERNET_BUFFERS );
    bufferIn.dwBufferTotal = dwPostedSize;

    return HttpSendRequestEx(hRequest, &bufferIn, NULL, 0, dwContext);
}

BOOL CWinInetUtility::WriteFile( HINTERNET hRequest, LPVOID pBuffer, DWORD \
dwBufferSize ) {
    BOOL bRet = FALSE;
    DWORD dwTotalWritten = 0;
    DWORD dwWritten = 0;
    while ( dwTotalWritten < dwBufferSize )
    {
        if (!(bRet = InternetWriteFile(hRequest, (BYTE *)pBuffer + dwTotalWritten, \
dwBufferSize - dwTotalWritten, &dwWritten)))  break;

        dwTotalWritten += dwWritten;
    }

    return bRet;
}

BOOL CWinInetUtility::GetStatusText( HINTERNET hRequest, CString& strStatusText )
{
    BOOL bRet = TRUE;
    DWORD dwBufSize = 0 ;
    LPVOID pBuffer = NULL;

    // Get required buffer size
    if (!QueryInfo(hRequest, HTTP_QUERY_STATUS_TEXT, pBuffer, dwBufSize, NULL))
    {
        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
        {
            bRet = FALSE;
        }
    }

    if(bRet)
    {
        assert(dwBufSize > 0);
        pBuffer = (LPVOID)malloc(dwBufSize + sizeof(TCHAR));
        ZeroMemory(pBuffer, dwBufSize + sizeof(TCHAR));

        // Get the status text
        bRet = QueryInfo(hRequest, HTTP_QUERY_STATUS_TEXT, pBuffer, dwBufSize, NULL);
        strStatusText = (TCHAR *)pBuffer;
        free(pBuffer);
    }   

    return bRet;
}

BOOL CWinInetUtility::GetHeader( HINTERNET hRequest, CString& strHeader, LPCTSTR \
szName, DWORD* pdwIndex /*= NULL*/ ) {
    BOOL bRet = TRUE;
    DWORD dwOriginalIndex = 0;
    if(pdwIndex)	
    {
        dwOriginalIndex = *pdwIndex;
    }

    DWORD dwBufSize = (_tcslen(szName) + 1) * sizeof(TCHAR);
    LPVOID pBuffer = (LPVOID)malloc(dwBufSize);
    ZeroMemory(pBuffer, dwBufSize);
    memcpy(pBuffer, szName, _tcslen(szName) * sizeof(TCHAR));

    if(!(bRet = QueryInfo(hRequest, HTTP_QUERY_CUSTOM, pBuffer, dwBufSize, \
pdwIndex)))  {
        if(GetLastError () == ERROR_INSUFFICIENT_BUFFER)
        {
            free(pBuffer);
            pBuffer = (LPVOID)malloc(dwBufSize + sizeof(TCHAR));
            ZeroMemory(pBuffer, dwBufSize + sizeof(TCHAR));
            memcpy(pBuffer, szName, _tcslen(szName) * sizeof(TCHAR));

            if(pdwIndex)
            {
                *pdwIndex = dwOriginalIndex;
            }

            bRet = QueryInfo(hRequest, HTTP_QUERY_CUSTOM, pBuffer, dwBufSize, \
pdwIndex);  }          
    }

    if(bRet)
    {
        strHeader = (TCHAR *)pBuffer;
    }

    free(pBuffer);
    return bRet;
}

BOOL CWinInetUtility::SetInternetOption( HINTERNET hInternet, DWORD dwOption, LPVOID \
lpBuffer, DWORD dwBufferLength ) {
    return InternetSetOption(hInternet, dwOption, lpBuffer, dwBufferLength);
}

BOOL CWinInetUtility::ReadFile( HINTERNET hRequest, LPVOID pBuffer, DWORD \
dwBytesToRead, LPDWORD pdwBytesRead) {
    return InternetReadFile(hRequest, pBuffer, dwBytesToRead, pdwBytesRead);
}

BOOL CWinInetUtility::ReadFileEx( HINTERNET hRequest, LPVOID pBuffer, DWORD \
dwBytesToRead, LPDWORD pdwRead, DWORD_PTR dwContext /*= NULL*/ ) {
    INTERNET_BUFFERS ib;
    ZeroMemory(&ib, sizeof(ib));
    ib.lpvBuffer = pBuffer;
    ib.dwStructSize = sizeof(INTERNET_BUFFERS);
    ib.dwBufferLength = dwBytesToRead;

    BOOL bRet = InternetReadFileEx(hRequest, &ib, IRF_ASYNC, dwContext);
    if(pdwRead)
    {
        *pdwRead = ib.dwBufferLength;
    }

    return bRet;
}

BOOL CWinInetUtility::GetContentLength( HINTERNET hRequest, DWORD& dwContentLength )
{
    DWORD dwBufferSize = sizeof(DWORD);
    return QueryInfo(hRequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, \
(LPVOID)(&dwContentLength), dwBufferSize, NULL); }

void CWinInetUtility::SetStatusCallback( HINTERNET hInternet, \
INTERNET_STATUS_CALLBACK lpCallback /*= NULL*/) {
    InternetSetStatusCallback(hInternet, lpCallback);
}

BOOL CWinInetUtility::GetStatus( HINTERNET hRequest, DWORD& dwStatus )
{
    DWORD dwBufferSize = sizeof(DWORD);
    return QueryInfo(hRequest, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, \
(LPVOID)(&dwStatus), dwBufferSize, NULL); }

BOOL CWinInetUtility::QueryInfo( HINTERNET hRequest, DWORD dwQueryFlag, LPVOID \
pBuffer, DWORD& dwBufferSize, DWORD* pdwIndex /*= NULL*/ ) {
    return HttpQueryInfo(hRequest, dwQueryFlag, pBuffer, &dwBufferSize, pdwIndex);
}

BOOL CWinInetUtility::WriteFileEx( HINTERNET hRequest, LPVOID pBuffer, DWORD \
dwBufferSize, LPDWORD pdwWritten ) {
    BOOL bRet = InternetWriteFile(hRequest, pBuffer, dwBufferSize, pdwWritten);
    return bRet;
}

#define DEFAULT_HEADERS_SIZE 4096

BOOL CWinInetUtility::GetHeaders( HINTERNET hRequest, CString& strHeaders )
{
    BOOL bRet = TRUE;
    DWORD dwBufSize = DEFAULT_HEADERS_SIZE;
    LPVOID pBuffer = (LPVOID)malloc(dwBufSize);
    ZeroMemory(pBuffer, dwBufSize);

    if(!(bRet = QueryInfo(hRequest, HTTP_QUERY_RAW_HEADERS, pBuffer, dwBufSize)))
    {
        if(GetLastError () == ERROR_INSUFFICIENT_BUFFER)
        {
            free(pBuffer);
            pBuffer = (LPVOID)malloc(dwBufSize);
            ZeroMemory(pBuffer, dwBufSize);

            bRet = QueryInfo(hRequest, HTTP_QUERY_RAW_HEADERS, pBuffer, dwBufSize);
        }          
    }

    if(bRet)
    {
        strHeaders = (TCHAR *)pBuffer;
    }

    free(pBuffer);
    return bRet;
}

--- NEW FILE: WinHttpResponse.cpp ---
#include "WinHttpResponse.h"
#include "WinHttpRequest.h"
#include "WinInetUtility.h"

#define DEFAULT_CHUNK_SIZE 4096

CWinHttpResponse::CWinHttpResponse(CWinHttpRequest* pRequest, unsigned long \
ulSizePerTimeToReceive)  :m_request(pRequest),
    m_dwStatusCode(0),
    m_dwSizeReceived(0),
    m_dwSizeReceivedTotal(0),
    m_dwSizeToReceivePerTime(ulSizePerTimeToReceive),
    m_pContent(NULL),
    m_dwContentLength(0),
    m_strHeaders(_T("")),
    m_strStatusText(_T("")),
    m_bIsChunked(FALSE)
{
    m_mapHeaders.clear();
}

CWinHttpResponse::~CWinHttpResponse(void)
{
    free(m_pContent);
}

BOOL CWinHttpResponse::GetHeaders( CString& strHeaders ) const
{
    strHeaders = m_strHeaders;
    return TRUE;
}

BOOL CWinHttpResponse::GetContentLength( unsigned long& ulLength ) const
{
    ulLength = m_dwContentLength;
    return TRUE;
}

BOOL CWinHttpResponse::GetContent( BYTE *pBuffer, unsigned long ulBufferSize ) const
{
    memcpy(pBuffer, m_pContent, ulBufferSize);
    return TRUE;
}

BOOL CWinHttpResponse::GetStatusCode( unsigned long& ulStatus ) const
{    
    ulStatus = m_dwStatusCode;
    return TRUE;
}

BOOL CWinHttpResponse::GetStatusText( CString& strStatus ) const
{
    strStatus = m_strStatusText;
    return TRUE;
}

BOOL CWinHttpResponse::GetHeader( const CString& strName, CString& strHeader) const
{
    std::map<CString, CString>::const_iterator it = m_mapHeaders.find(strName);
    if(it != m_mapHeaders.end())
    {		
        strHeader = it->second;
        return TRUE;
    }

    return FALSE;
}

int CWinHttpResponse::GetHeadersCount() const
{
    return m_mapHeaders.size();
}

unsigned long CWinHttpResponse::ReceiveData()
{
    CWinInetUtility::GetStatus(m_request->GetRequestHandle(), m_dwStatusCode);
    CWinInetUtility::GetStatusText(m_request->GetRequestHandle(), m_strStatusText);
    CWinInetUtility::GetHeaders(m_request->GetRequestHandle(), m_strHeaders);

    // headers -> header-value map

    // try to get content length
    if(CWinInetUtility::GetContentLength(m_request->GetRequestHandle(), \
m_dwContentLength))  {
        if(m_dwContentLength > 0)
        {
            m_pContent = (byte*)malloc(m_dwContentLength);
            ZeroMemory(m_pContent, m_dwContentLength);
        }        
    }
    else
    {
        CString strHeader;
        if(CWinInetUtility::GetHeader(m_request->GetRequestHandle(), strHeader, \
_T("Transfer-Encoding")) && strHeader.CompareNoCase(_T("chunked")) == 0)  {
            m_bIsChunked = TRUE;
            m_pContent = (byte*)malloc(DEFAULT_CHUNK_SIZE);
            ZeroMemory(m_pContent, DEFAULT_CHUNK_SIZE);
            m_dwContentLength = DEFAULT_CHUNK_SIZE;
        }
    }

    DWORD dwRet = NO_ERROR;
    if(!m_bIsChunked && m_dwContentLength > 0)
    {
        while(m_dwSizeReceivedTotal < m_dwContentLength && 
            CWinInetUtility::ReadFile(m_request->GetRequestHandle(), m_pContent + \
m_dwSizeReceivedTotal, m_dwSizeToReceivePerTime, &m_dwSizeReceived) &&  \
m_dwSizeReceived > 0)  {
            m_dwSizeReceivedTotal += m_dwSizeReceived;
        }
    }
    else if(m_bIsChunked)
    {
        byte* pBuffer = (byte*)malloc(m_dwSizeToReceivePerTime);
        while(CWinInetUtility::ReadFile(m_request->GetRequestHandle(), pBuffer, \
m_dwSizeToReceivePerTime, &m_dwSizeReceived) && m_dwSizeReceived > 0)  {			
            if(m_dwSizeReceivedTotal +  m_dwSizeReceived > m_dwContentLength)
            {
                m_dwContentLength *= 2;
                m_pContent = (byte *)realloc(m_pContent, m_dwContentLength);
                ZeroMemory(m_pContent + m_dwSizeReceivedTotal, m_dwContentLength - \
m_dwSizeReceivedTotal);  }

            memcpy(m_pContent + m_dwSizeReceivedTotal, pBuffer, m_dwSizeReceived);    \
  m_dwSizeReceivedTotal += m_dwSizeReceived;
        }

        m_dwContentLength = m_dwSizeReceivedTotal;        
    }

    return dwRet;
}

--- NEW FILE: WinHttpRequest.h ---
#pragma once

#include "HttpDriver.h"
#include "WinHttpResponse.h"
#include <wininet.h>
#include <vector>
#include <list>
#include <map>

class CWinHttpRequest : public IHttpRequest
{
private:
    enum Request_Status
    {
        ReqStatus_SendReq = 0,
        ReqStatus_SendReqWithContent,
        ReqStatus_PostSendData,
        ReqStatus_PostComplete,
        ReqStatus_ResponseRecvData,
        ReqStatus_Complete
    };

public:
    CWinHttpRequest(HINTERNET hInternet, LPVOID pContext);
    ~CWinHttpRequest(void);

    // IHttpRequest methods
    virtual unsigned long Initialize( HTTPVerb verb,      
        const CString& strHost,
        const CString& strObjectName,
        int nPort,
        const CString& strUserName, 
        const CString& strPassword,
        BOOL bSecure = FALSE );
    virtual unsigned long Initialize(const CString& strURL);
    virtual void AppendByteRange( unsigned long ulStart, unsigned long ulEnd );
    virtual void AppendLastBytes( unsigned long ulBytesCount );
    virtual void AppendBytesFrom( unsigned long ulStartFrom );
    virtual void AppendCookie( const CString& strCookieName, const CString& \
strCookieValue );  virtual void AppendCookies( const CString& strCookies );
    virtual void AppendCustomHeader( const CString& strHeaderName, const CString& \
strHeaderValue );  virtual void AppendCustomHeaders( const CString& strHeaders );
    virtual void SetTransferRate(unsigned long ulSizePerTimeToPost, unsigned long \
ulSizePerTimeToReceive);  virtual void SetContent( const byte* pBuffer, unsigned long \
ulBufferSize );  virtual void SetRequestCallback( HttpRequestCallback fnCallback );
    virtual IHttpResponse* GetResponse();
    virtual void SetPostMultipart( BOOL bMultipart );
    virtual void SetBoundary( const CString& strBoundary );
    virtual void Execute();
    virtual void UnInitialize();
    virtual BOOL IsInitialized() const;  
    virtual LPVOID GetContext() { return m_pContext; }

public:
    void OnStatusNofified(__in DWORD dwInternetStatus,
        __in_bcount(dwStatusInformationLength) LPVOID lpvStatusInformation,
        __in DWORD dwStatusInformationLength);
    HINTERNET GetRequestHandle() const { return m_hRequest; } 

private:
    struct _InternetStatus
    {
        DWORD dwInternetStatus;
        LPVOID lpvStatusInformation;
        DWORD dwStatusInformationLength;

        _InternetStatus()
        {
            dwInternetStatus = 0;
            lpvStatusInformation = NULL;
            dwStatusInformationLength = 0;
        }
    };

    // working threads
    static unsigned __stdcall _ProcessNotificationThread( void* pArguments );
    static unsigned __stdcall _TriggerCallbackThread( void* pArguments );

    void _ProcessNotification(DWORD dwInternetStatus, LPVOID lpvStatusInformation, \
DWORD dwStatusInformationLength);  void _ProcessRequest(DWORD dwCode);
    BOOL _PopFrontCallbackStatus(HTTPRequestStatus& status);
    BOOL _PopFrontInternetStatus(_InternetStatus& status);

private:
    HINTERNET m_hInternet;
    LPVOID m_pContext;
    BOOL m_bInitialized;
    Request_Status m_currentStatus;

    // connection information
    HTTPVerb m_verb;
    HINTERNET m_hConnection;

    // write & post
    DWORD m_dwSizePosted;
    DWORD m_dwSizeToPostPerTime;    
    DWORD m_dwSizePostedTotal;
    DWORD m_dwSizeToReceivePerTime;
    BOOL m_bMultiPart;

    // content
    byte* m_pContentToPost;
    DWORD m_dwContentLengthToPost;

    // http request file handle
    HINTERNET m_hRequest;
    CString m_strObject;
    CString m_strURL;

    // byte-range
    std::vector<CString> m_vecByteRanges;

    // cookies
    CString m_strCookies;
    std::map<CString, CString> m_mapCookies;

    // headers
    CString m_strHeaders;
    std::map<CString, CString> m_mapHeaders;

    // boundary
    CString m_strBoundary;

    // response
    CWinHttpResponse *m_response;    

    // callback
    HttpRequestCallback m_hResonseCallback;

    // threads
    unsigned m_uThreadProcessNotify;
    unsigned m_uThreadTriggerCallback;
    HANDLE m_hThreadProcessNotify;
    HANDLE m_hThreadTriggerCallback;
    std::list<_InternetStatus> m_listInternetStatus;
    std::list<HTTPRequestStatus> m_listCallbackStatus;
    HANDLE m_hEventExit;
    HANDLE m_hEventInternetStatusUpdated;
    HANDLE m_hEventCallbackUpdated;

    // lockers
    CRITICAL_SECTION m_csInternetStatus;
    CRITICAL_SECTION m_csCallbackStatus;
    CRITICAL_SECTION m_csInitialize;
};

--- NEW FILE: WinHttpDriver.cpp ---
#include "WinHttpDriver.h"
#include "WinInetUtility.h"
#include "WinHttpRequest.h"

BOOL s_bIsUnInitialized = FALSE;

CWinHttpDriver::CWinHttpDriver(void)
    :m_hInternet(NULL)
{
}

CWinHttpDriver::~CWinHttpDriver(void)
{    
}

unsigned long CWinHttpDriver::Initialize( const CString& strName )
{
    return Initialize(strName, INTERNET_OPEN_TYPE_PRECONFIG, _T(""), _T(""));
}

unsigned long CWinHttpDriver::Initialize( const CString& strName, unsigned long \
ulAccessType, const CString& strProxyName, const CString& strProxyByPass ) {
    DWORD dwRet = NO_ERROR;    
    const TCHAR* szProxyName = NULL;
    if(!strProxyName.IsEmpty())
        szProxyName = strProxyName;

    const TCHAR* szProxyByPass = NULL;
    if(!strProxyName.IsEmpty())
        szProxyName = strProxyName;

    m_hInternet = CWinInetUtility::OpenInternet(strName, ulAccessType, szProxyName, \
szProxyByPass);

    if(m_hInternet == NULL || m_hInternet == INVALID_HANDLE_VALUE)
        dwRet = GetLastError();
    else
    {
        s_bIsUnInitialized = FALSE;
        CWinInetUtility::SetStatusCallback(m_hInternet, StatusNotifyCallback);
    }

    return dwRet;
}

IHttpRequest* CWinHttpDriver::CreateRequest(LPVOID pContext)
{
    IHttpRequest* pRequest = new CWinHttpRequest(m_hInternet, pContext);
    return pRequest;
}

void CWinHttpDriver::ReleaseRequest( IHttpRequest* pRequest)
{
    pRequest->UnInitialize();
    delete pRequest;
}

void CWinHttpDriver::UnInitialize()
{
    OutputDebugString(_T("void CWinHttpDriver::UnInitialize\n"));
    if(m_hInternet != NULL && m_hInternet != INVALID_HANDLE_VALUE)        
    {
        s_bIsUnInitialized = TRUE;
        CWinInetUtility::SetStatusCallback(m_hInternet, NULL);
        CWinInetUtility::CloseInternet(m_hInternet);
    }

    m_hInternet = NULL;
}

void WINAPI CWinHttpDriver::StatusNotifyCallback( __in HINTERNET hInternet,
    __in DWORD_PTR dwContext, 
    __in DWORD dwInternetStatus, 
    __in_bcount(dwStatusInformationLength) LPVOID lpvStatusInformation,
    __in DWORD dwStatusInformationLength )
{
    if(s_bIsUnInitialized)
    {
        return;
    }

    CWinHttpRequest* pRequest = (CWinHttpRequest*)dwContext;
    pRequest->OnStatusNofified(dwInternetStatus, lpvStatusInformation, \
dwStatusInformationLength); }

--- NEW FILE: WinHttpRequest.cpp ---
#include "WinHttpRequest.h"
#include "WinInetUtility.h"
#include <assert.h>

using namespace std;

class CWinLocker
{
public:
    CWinLocker(LPCRITICAL_SECTION cs)
        :m_cs(cs)
    {
        EnterCriticalSection(cs);
    }

    ~CWinLocker()
    {
        LeaveCriticalSection(m_cs);
    }

private:
    LPCRITICAL_SECTION m_cs;
};

CWinHttpRequest::CWinHttpRequest(HINTERNET hInternet, LPVOID pContext)
    :m_bInitialized(FALSE),
    m_hInternet(hInternet),
    m_hConnection(NULL),
    m_verb(Verb_Unknown),
    m_hRequest(NULL),
    m_strObject(_T("")),
    m_strCookies(_T("")),
    m_pContentToPost(NULL),
    m_dwContentLengthToPost(0),
    m_dwSizeToPostPerTime(DEFAULT_TRANSFER_SIZE),
    m_dwSizeToReceivePerTime(DEFAULT_TRANSFER_SIZE),
    m_dwSizePostedTotal(0),
    m_response(NULL),
    m_pContext(pContext)
{
    m_vecByteRanges.clear();
    m_mapCookies.clear();
    m_mapHeaders.clear();
    m_listInternetStatus.clear();

    InitializeCriticalSection(&m_csCallbackStatus);
    InitializeCriticalSection(&m_csInternetStatus);
    InitializeCriticalSection(&m_csInitialize);

    m_hEventExit = CreateEvent(NULL, TRUE, FALSE, NULL);
    m_hEventInternetStatusUpdated = CreateEvent(NULL, FALSE, FALSE, NULL);
    m_hEventCallbackUpdated = CreateEvent(NULL, FALSE, FALSE, NULL);

    m_hThreadProcessNotify = (HANDLE)_beginthreadex(NULL, 0, \
&_ProcessNotificationThread, this, 0, &m_uThreadProcessNotify);  \
m_hThreadTriggerCallback = (HANDLE)_beginthreadex(NULL, 0, &_TriggerCallbackThread, \
this, 0, &m_uThreadTriggerCallback); }

CWinHttpRequest::~CWinHttpRequest(void)
{
    UnInitialize();

    // stop threads
    SetEvent(m_hEventExit);
    WaitForSingleObject(m_hThreadProcessNotify, INFINITE);
    WaitForSingleObject(m_hThreadTriggerCallback, INFINITE);
    CloseHandle(m_hThreadProcessNotify);
    CloseHandle(m_hThreadTriggerCallback);

    // release objects
    CloseHandle(m_hEventExit);
    CloseHandle(m_hEventInternetStatusUpdated);
    CloseHandle(m_hEventCallbackUpdated);
    DeleteCriticalSection(&m_csCallbackStatus);
    DeleteCriticalSection(&m_csInternetStatus);
    DeleteCriticalSection(&m_csInitialize);
}

#pragma region "initialize and uninitialize"

unsigned long CWinHttpRequest::Initialize( HTTPVerb verb, const CString& strHost, \
const CString& strObjectName, int nPort, const CString& strUserName, const CString& \
strPassword, BOOL bSecure /*= FALSE */ ) {
    CWinLocker locker(&m_csInitialize);
    DWORD dwRet = NO_ERROR;
    if(!m_bInitialized)
    {
        m_hConnection = CWinInetUtility::OpenConnection(m_hInternet, strHost, \
(DWORD_PTR)this, nPort, strUserName, strPassword);  if(m_hConnection == NULL || \
m_hConnection == INVALID_HANDLE_VALUE)  {
            dwRet = GetLastError();
        }
        else
        {
            m_bInitialized = TRUE;
            m_verb = verb;
            m_strObject = strObjectName;
        }
    }

    return dwRet;
}

unsigned long CWinHttpRequest::Initialize( const CString& strURL )
{
    CWinLocker locker(&m_csInitialize);
    DWORD dwRet = NO_ERROR;
    if(!m_bInitialized)
    {
        m_strURL = strURL;    
        m_bInitialized = TRUE;
    }

    return dwRet;
}

void CWinHttpRequest::UnInitialize()
{
    CWinLocker locker(&m_csInitialize);
    if(m_bInitialized)
    {
        CWinInetUtility::CloseRequest(m_hRequest);
        CWinInetUtility::CloseConnection(m_hConnection);
        m_verb = Verb_Unknown;
        m_strObject.Empty();
        m_vecByteRanges.clear();
        m_mapCookies.clear();
        m_mapHeaders.clear();
        m_strCookies.Empty();
        m_strHeaders.Empty();
        m_strBoundary.Empty();
        m_bMultiPart = FALSE;
        free(m_pContentToPost);
        m_pContentToPost = NULL;
        m_dwContentLengthToPost = 0;
        m_dwSizePostedTotal = 0;
        m_dwSizeToPostPerTime = DEFAULT_TRANSFER_SIZE;
        m_dwSizeToReceivePerTime = DEFAULT_TRANSFER_SIZE;
        delete m_response;
        m_response = NULL;
        m_hResonseCallback = NULL;
        ResetEvent(m_hEventInternetStatusUpdated);
        ResetEvent(m_hEventCallbackUpdated);

        _InternetStatus status;
        while(_PopFrontInternetStatus(status))
        {
            free(status.lpvStatusInformation);
        }

        {
            CWinLocker locker(&m_csCallbackStatus);
            m_listCallbackStatus.clear();
        }       

        m_bInitialized = FALSE;
    }
}

BOOL CWinHttpRequest::IsInitialized() const
{
    CWinLocker locker((LPCRITICAL_SECTION)&m_csInitialize);
    return m_bInitialized;
}

#pragma endregion

#pragma region "byte-range settings"

void CWinHttpRequest::AppendByteRange( unsigned long ulStart, unsigned long ulEnd )
{
    if(ulStart <= ulEnd && ulStart >= 0)
    {
        CString strRangeItem;
        strRangeItem.Format(_T("%d-%d"), ulStart, ulEnd);
        m_vecByteRanges.push_back(strRangeItem);
    }
}

void CWinHttpRequest::AppendLastBytes( unsigned long ulBytesCount )
{
    if(ulBytesCount >= 0)
    {
        CString strRangeItem;
        strRangeItem.Format(_T("-%d"), ulBytesCount);
        m_vecByteRanges.push_back(strRangeItem);
    }
}

void CWinHttpRequest::AppendBytesFrom( unsigned long ulStartFrom )
{
    if(ulStartFrom >= 0)
    {
        CString strRangeItem;
        strRangeItem.Format(_T("%d-%d"), ulStartFrom);
        m_vecByteRanges.push_back(strRangeItem);
    }
}

#pragma endregion

#pragma region "cookie settings"

void CWinHttpRequest::AppendCookie( const CString& strCookieName, const CString& \
strCookieValue ) {
    if(!strCookieName.IsEmpty())
    {
        m_mapCookies[strCookieName] = strCookieValue;
    }
}

void CWinHttpRequest::AppendCookies( const CString& strCookies )
{
    m_strCookies = strCookies;
}

#pragma endregion

#pragma region "header settings"

// Append one specific header
void CWinHttpRequest::AppendCustomHeader( const CString& strHeaderName, const \
CString& strHeaderValue ) {
    if(!strHeaderName.IsEmpty())
    {
        m_mapHeaders[strHeaderName] = strHeaderValue;
    }
}

// append headers
void CWinHttpRequest::AppendCustomHeaders( const CString& strHeaders )
{
    m_strHeaders = strHeaders;
}

#pragma endregion

void CWinHttpRequest::SetTransferRate(unsigned long ulSizePerTimeToPost, unsigned \
long ulSizePerTimeToReceive) {
    m_dwSizeToPostPerTime = ulSizePerTimeToPost;
    m_dwSizeToReceivePerTime = ulSizePerTimeToReceive;
}

// set content to post and post size one time
void CWinHttpRequest::SetContent( const byte* pBuffer, unsigned long ulBufferSize )
{
    m_pContentToPost = (byte*)malloc(ulBufferSize);
    memcpy(m_pContentToPost, pBuffer, ulBufferSize);
    m_dwContentLengthToPost = ulBufferSize;    
}

void CWinHttpRequest::SetPostMultipart( BOOL bMultiPart )
{
    m_bMultiPart = bMultiPart;
}

void CWinHttpRequest::SetBoundary( const CString& strBoundary )
{
    m_strBoundary = strBoundary;
}

void CWinHttpRequest::SetRequestCallback( HttpRequestCallback fnCallback )
{
    m_hResonseCallback = fnCallback;
}

IHttpResponse* CWinHttpRequest::GetResponse()
{
    return m_response;
}

// start to execute the request
void CWinHttpRequest::Execute()
{
    static map<HTTPVerb, CString> s_mapVerbNames;
    if(s_mapVerbNames.empty())
    {
        s_mapVerbNames[Verb_Unknown] = _T("Unknow");
        s_mapVerbNames[Verb_Get] = _T("GET");
        s_mapVerbNames[Verb_Post] = _T("POST");
        s_mapVerbNames[Verb_Put] = _T("PUT");
        s_mapVerbNames[Verb_Delete] = _T("DELETE");
        s_mapVerbNames[Verb_More] = _T("More");
    }

    if(m_strURL.IsEmpty())
    {
        m_hRequest = CWinInetUtility::OpenRequest(m_hConnection, \
s_mapVerbNames[m_verb], m_strObject, (DWORD_PTR)this);  }
    else
    {
        m_currentStatus = ReqStatus_ResponseRecvData;
        CWinInetUtility::OpenURL(m_hInternet, m_strURL, (DWORD_PTR)this);
    }    

    // set headers
    if(m_strURL.IsEmpty())
    {
        if(m_pContentToPost != NULL && m_dwContentLengthToPost > 0)
        {
            m_currentStatus = ReqStatus_PostSendData;
            CWinInetUtility::SendRequestEx(m_hRequest, m_dwContentLengthToPost, \
(DWORD_PTR)this);  }
        else
        {
            m_currentStatus = ReqStatus_ResponseRecvData;
            CWinInetUtility::SendRequest(m_hRequest);
        }
    }    
}

#pragma region "Internet status notification"

void CWinHttpRequest::OnStatusNofified( __in DWORD dwInternetStatus, \
__in_bcount(dwStatusInformationLength) LPVOID lpvStatusInformation, __in DWORD \
dwStatusInformationLength ) {
    _InternetStatus status;
    status.dwInternetStatus = dwInternetStatus;
    status.dwStatusInformationLength = dwStatusInformationLength;
    if(dwStatusInformationLength > 0)
    {
        status.lpvStatusInformation = (LPVOID)malloc(dwStatusInformationLength);
        memcpy(status.lpvStatusInformation, lpvStatusInformation, \
dwStatusInformationLength);  }

    // locker
    {
        CWinLocker locker(&m_csInternetStatus);
        m_listInternetStatus.push_back(status);
    }
    
    SetEvent(m_hEventInternetStatusUpdated);
}

// thread to process callback values, so this will not block the raw Internet status \
callback unsigned __stdcall CWinHttpRequest::_ProcessNotificationThread( void* \
pArguments ) {
    CWinHttpRequest *pRequest = (CWinHttpRequest *)pArguments;
    HANDLE handles[2];
    handles[0] = pRequest->m_hEventInternetStatusUpdated;
    handles[1] = pRequest->m_hEventExit;
    list<_InternetStatus> *pListInternetStatus = &pRequest->m_listInternetStatus;

    _InternetStatus status;
    while(WaitForMultipleObjects(2, handles, FALSE, INFINITE) == WAIT_OBJECT_0)
    {
        while(pRequest->_PopFrontInternetStatus(status))
        {
            pRequest->_ProcessNotification(status.dwInternetStatus, \
status.lpvStatusInformation, status.dwStatusInformationLength);  \
free(status.lpvStatusInformation);  }
    }

    _endthreadex(0);
    return 0;
}

// Internet status notified callback procedure
void CWinHttpRequest::_ProcessNotification( DWORD dwInternetStatus, LPVOID \
lpvStatusInformation, DWORD dwStatusInformationLength ) {
    InternetCookieHistory cookieHistory;
    CString strDebugInfo;
    switch(dwInternetStatus)
    {
    case INTERNET_STATUS_COOKIE_SENT:
        OutputDebugString(_T("Status: Cookie found and will be sent with \
request\n"));  break;

    case INTERNET_STATUS_COOKIE_RECEIVED:
        OutputDebugString(_T("Status: Cookie Received\n"));
        break;

    case INTERNET_STATUS_COOKIE_HISTORY:
        OutputDebugString(_T("Status: Cookie History\n"));
        assert(lpvStatusInformation);
        assert(dwStatusInformationLength == sizeof(InternetCookieHistory));

        cookieHistory = *((InternetCookieHistory*)lpvStatusInformation);

        if(cookieHistory.fAccepted)
        {
            OutputDebugString(_T("Cookie Accepted\n"));
        }
        if(cookieHistory.fLeashed)
        {
            OutputDebugString(_T("Cookie Leashed\n"));
        }        
        if(cookieHistory.fDowngraded)
        {
            OutputDebugString(_T("Cookie Downgraded\n"));
        }        
        if(cookieHistory.fRejected)
        {
            OutputDebugString(_T("Cookie Rejected\n"));
        }

        break;

    case INTERNET_STATUS_CLOSING_CONNECTION:
        OutputDebugString(_T("Status: Closing Connection\n"));
        break;

    case INTERNET_STATUS_CONNECTED_TO_SERVER:
        OutputDebugString(_T("Status: Connected to Server\n"));
        break;

    case INTERNET_STATUS_CONNECTING_TO_SERVER:
        OutputDebugString(_T("Status: Connecting to Server\n"));
        break;

    case INTERNET_STATUS_CONNECTION_CLOSED:
        OutputDebugString(_T("Status: Connection Closed\n"));
        break;

    case INTERNET_STATUS_HANDLE_CLOSING:
        OutputDebugString(_T("Status: Handle Closing\n"));            
        break;

    case INTERNET_STATUS_HANDLE_CREATED:
        assert(lpvStatusInformation);
        if(!m_strURL.IsEmpty())
        {
            m_hRequest = \
(HINTERNET)((LPINTERNET_ASYNC_RESULT)lpvStatusInformation)->dwResult;  }

        strDebugInfo.Format(_T("Handle %x created\n"), \
((LPINTERNET_ASYNC_RESULT)lpvStatusInformation)->dwResult);  \
OutputDebugString(strDebugInfo);  break;

    case INTERNET_STATUS_INTERMEDIATE_RESPONSE:
        OutputDebugString(_T("Status: Intermediate response\n"));
        break;

    case INTERNET_STATUS_RECEIVING_RESPONSE:
        OutputDebugString(_T("Status: Receiving Response\n"));    
        break;

    case INTERNET_STATUS_RESPONSE_RECEIVED:
        assert(lpvStatusInformation);
        assert(dwStatusInformationLength == sizeof(DWORD));
        strDebugInfo.Format(_T("Status: Response Received (%d Bytes)\n"), \
*((LPDWORD)lpvStatusInformation));  OutputDebugString(strDebugInfo);
        break;

    case INTERNET_STATUS_REDIRECT:
        OutputDebugString(_T("Status: Redirect\n"));
        break;

    case INTERNET_STATUS_REQUEST_COMPLETE:
        OutputDebugString(_T("Status: Request complete\n"));
        assert(lpvStatusInformation);
        _ProcessRequest(((LPINTERNET_ASYNC_RESULT)lpvStatusInformation)->dwError);
        break;

    case INTERNET_STATUS_REQUEST_SENT:
        assert(lpvStatusInformation);
        assert(dwStatusInformationLength == sizeof(DWORD));
        strDebugInfo.Format(_T("Status: Request sent (%d Bytes)\n"), \
*((LPDWORD)lpvStatusInformation));  OutputDebugString(strDebugInfo);
        break;

    case INTERNET_STATUS_DETECTING_PROXY:
        OutputDebugString(_T("Status: Detecting Proxy\n"));
        break;            

    case INTERNET_STATUS_RESOLVING_NAME:
        OutputDebugString(_T("Status: Resolving Name\n"));
        break;

    case INTERNET_STATUS_NAME_RESOLVED:
        OutputDebugString(_T("Status: Name Resolved\n"));
        break;

    case INTERNET_STATUS_SENDING_REQUEST:
        OutputDebugString(_T("Status: Sending request\n"));
        break;

    case INTERNET_STATUS_STATE_CHANGE:
        OutputDebugString(_T("Status: State Change\n"));
        break;

    case INTERNET_STATUS_P3P_HEADER:
        OutputDebugString(_T("Status: Received P3P header\n"));
        break;

    default:
        strDebugInfo.Format(_T("Status: Unknown (%d)\n"), dwInternetStatus);
        OutputDebugString(strDebugInfo);
        break;
    }
}

// procedure to send request and receive response
void CWinHttpRequest::_ProcessRequest( DWORD dwCode )
{
    OutputDebugString(_T("CWinHttpRequest::_ProcessRequest!!!!\n"));
    while(dwCode == ERROR_SUCCESS && m_currentStatus != ReqStatus_Complete)
    {
        switch(m_currentStatus)
        {
        case ReqStatus_SendReq:
            // send a simple request
            m_currentStatus = ReqStatus_ResponseRecvData;
            CWinInetUtility::SendRequest(m_hRequest);
            return;

        case ReqStatus_SendReqWithContent: 
            // start send request with content
            m_currentStatus = ReqStatus_PostSendData;
            CWinInetUtility::SendRequestEx(m_hRequest, m_dwContentLengthToPost, \
(DWORD_PTR)this);  return;

        case ReqStatus_PostSendData:
            // send request content
            m_dwSizePosted = 0;
            dwCode = CWinInetUtility::WriteFileEx(m_hRequest, m_pContentToPost + \
m_dwSizePostedTotal, m_dwSizeToPostPerTime, &m_dwSizePosted);  m_dwSizePostedTotal += \
m_dwSizePosted;  if(m_dwSizePostedTotal == m_dwContentLengthToPost)
            {
                m_currentStatus = ReqStatus_PostComplete;
            }

            break;

        case ReqStatus_PostComplete:
            // all bytes are sent, need to end request
            m_currentStatus = ReqStatus_ResponseRecvData;
            dwCode = CWinInetUtility::EndRequest(m_hRequest);
            break;

        case ReqStatus_ResponseRecvData: 
            // start to receive response
            {
                CWinLocker locker(&m_csCallbackStatus);
                m_listCallbackStatus.push_back(Status_Sent);
            }

            SetEvent(m_hEventCallbackUpdated);
            if(m_response == NULL)
                m_response = new CWinHttpResponse(this, m_dwSizeToReceivePerTime);

            if((dwCode = m_response->ReceiveData()) == ERROR_SUCCESS)
            {
                // after all data are received, client callback should be triggered, \
then client can query data via IHttpResponse  m_currentStatus = ReqStatus_Complete;

                {
                    CWinLocker locker(&m_csCallbackStatus);
                    m_listCallbackStatus.push_back(Status_Received); 
                }

                SetEvent(m_hEventCallbackUpdated);
            }

            break;
        default:
            assert(FALSE);
            break;
        }
    }

    // if it's pending, this function should be called in another \
ProcessNotification(INTERNET_STATUS_REQUEST_COMPLETE)  if(dwCode != ERROR_IO_PENDING)
    {
        {
            CWinLocker locker(&m_csCallbackStatus);
            m_listCallbackStatus.push_back(Status_Error);
        }

        SetEvent(m_hEventCallbackUpdated);
    }

    return;
}

#pragma endregion

//  get and pop the first element of Internet status list
BOOL CWinHttpRequest::_PopFrontInternetStatus( _InternetStatus& status )
{
    BOOL bRet = FALSE;
    CWinLocker locker(&m_csInternetStatus);
    if(!m_listInternetStatus.empty())
    {
        status = *(m_listInternetStatus.begin());
        m_listInternetStatus.pop_front();
        bRet = TRUE;
    }

    return bRet;
}

//  get and pop the first element of callback status list
BOOL CWinHttpRequest::_PopFrontCallbackStatus(HTTPRequestStatus& status)
{
    BOOL bRet = FALSE;
    CWinLocker locker(&m_csCallbackStatus);
    if(!m_listCallbackStatus.empty())
    {
        status = *(m_listCallbackStatus.begin());
        m_listCallbackStatus.pop_front();
        bRet = TRUE;
    }

    return bRet;
}

// thread to trigger outer callback, then the callback procedure won't block any \
read/write process of current request unsigned __stdcall \
CWinHttpRequest::_TriggerCallbackThread( void* pArguments ) {
    CWinHttpRequest *pRequest = (CWinHttpRequest *)pArguments;
    HANDLE handles[2];
    handles[0] = pRequest->m_hEventCallbackUpdated;
    handles[1] = pRequest->m_hEventExit;
    list<HTTPRequestStatus> *pListCallbackStatus = &pRequest->m_listCallbackStatus;

    HTTPRequestStatus status = Status_Unknown;
    while(WaitForMultipleObjects(2, handles, FALSE, INFINITE) == WAIT_OBJECT_0)
    { 
        while(pRequest->_PopFrontCallbackStatus(status))
        {
            if(pRequest->m_hResonseCallback)
            {
                pRequest->m_hResonseCallback(status, pRequest);
            }
        }
    }

    _endthreadex(0);
    return 0;
}

--- NEW FILE: WinInetUtility.h ---
#pragma once

#include <Windows.h>
#include <WinInet.h>
#include <atlstr.h>

class CWinInetUtility
{
public:
    // Wininet HTTP methods - asynchronous mode
    static void SetStatusCallback(HINTERNET hInternet, INTERNET_STATUS_CALLBACK \
lpCallback = NULL);  static DWORD GetLastErrorCode();
    static HINTERNET OpenInternet(LPCTSTR szUserAgent, DWORD dwAccessType = \
INTERNET_OPEN_TYPE_PRECONFIG, LPCTSTR szProxyName = NULL, LPCTSTR szProxyBypass = \
NULL);  static void CloseInternet(HINTERNET& hInternet);
    static HINTERNET OpenConnection(HINTERNET hInternet, LPCTSTR szServerAddr, \
DWORD_PTR dwContext, INTERNET_PORT nPort = INTERNET_DEFAULT_HTTP_PORT, LPCTSTR \
szUsrName = NULL, LPCTSTR szUsrPwd = NULL);  static void CloseConnection(HINTERNET& \
hConnection);  static HINTERNET OpenRequest(HINTERNET hConnection, LPCTSTR szMethod, \
LPCTSTR szObjectName, DWORD_PTR dwContext,   DWORD dwFlags = INTERNET_FLAG_HYPERLINK
        | INTERNET_FLAG_KEEP_CONNECTION
        | INTERNET_FLAG_NO_UI
        | INTERNET_FLAG_RESYNCHRONIZE
        | INTERNET_FLAG_NO_CACHE_WRITE
        | INTERNET_FLAG_PRAGMA_NOCACHE
        | INTERNET_FLAG_RELOAD,
        LPCTSTR szReferer = NULL);
    static void CloseRequest(HINTERNET& hRequest);
    static HINTERNET OpenURL(HINTERNET hInternet, LPCTSTR szURL, 
        DWORD_PTR dwContext,
        DWORD dwFlags = INTERNET_FLAG_RELOAD);
    static BOOL AddHeader(HINTERNET hRequest, LPCTSTR szName, LPCTSTR szValue);
    static BOOL SendRequest(HINTERNET hRequest, LPVOID pPostedBuffer = NULL, DWORD \
dwBufferSize = 0);  static BOOL SendRequestEx(HINTERNET hRequest, DWORD dwPostedSize, \
DWORD_PTR dwContext);  static BOOL ReadFile(HINTERNET hRequest, LPVOID pBuffer, DWORD \
dwBytesToRead, LPDWORD pdwRead);  static BOOL ReadFileEx(HINTERNET hRequest, LPVOID \
pBuffer, DWORD dwBytesToRead, LPDWORD pdwRead, DWORD_PTR dwContext);  static BOOL \
WriteFile(HINTERNET hRequest, LPVOID pBuffer, DWORD dwBufferSize);  static BOOL \
WriteFileEx(HINTERNET hRequest, LPVOID pBuffer, DWORD dwBufferSize, LPDWORD \
pdwWritten);  static BOOL EndRequest(HINTERNET hRequest);
    static BOOL GetStatus(HINTERNET hRequest, DWORD& dwStatus);
    static BOOL GetStatusText(HINTERNET hRequest, CString& strStatusText);
    static BOOL GetContentLength(HINTERNET hRequest, DWORD& dwContentLength);
    static BOOL GetHeader(HINTERNET hRequest, CString& strHeader, LPCTSTR szName, \
DWORD* pdwIndex = NULL);  static BOOL GetHeaders(HINTERNET hRequest, CString& \
strHeaders);  static BOOL SetInternetOption(HINTERNET hInternet, DWORD dwOption, \
LPVOID lpBuffer, DWORD dwBufferLength);

private:
    static void _CloseInternetHandler(HINTERNET& hHandler);
    static BOOL QueryInfo(HINTERNET hRequest, DWORD dwQueryFlag, LPVOID pBuffer, \
DWORD& dwBufferSize, DWORD* pdwIndex = NULL); };


--- NEW FILE: WinHttpDriver.h ---
#pragma once
#include "HttpDriver.h"
#include <Wininet.h>

class CWinHttpDriver : public IHttpDriver
{
public:
    CWinHttpDriver(void);
    ~CWinHttpDriver(void);

    virtual unsigned long Initialize( const CString& strName );
    virtual unsigned long Initialize( const CString& strName, unsigned long \
ulAccessType, const CString& strProxyName, const CString& strProxyByPass );  virtual \
IHttpRequest* CreateRequest(LPVOID pContext);  virtual void ReleaseRequest( \
IHttpRequest* );  virtual void UnInitialize();

private:
    static void WINAPI StatusNotifyCallback(__in HINTERNET hInternet,
        __in DWORD_PTR dwContext,
        __in DWORD dwInternetStatus,
        __in_bcount(dwStatusInformationLength) LPVOID lpvStatusInformation,
        __in DWORD dwStatusInformationLength);

private:    
    HINTERNET m_hInternet;
};


--- NEW FILE: WinHttpResponse.h ---
#pragma once
#include "HttpDriver.h"
#include <vector>
#include <map>

class CWinHttpRequest;
class CWinHttpResponse : public IHttpResponse
{
public:
    CWinHttpResponse(CWinHttpRequest* pRequest, unsigned long \
ulSizePerTimeToReceive);  ~CWinHttpResponse(void);

    // IHttpResponse methods
    virtual BOOL GetHeaders( CString& strHeaders ) const;
    virtual int GetHeadersCount() const;
    virtual BOOL GetContentLength( unsigned long& ulLength ) const;
    virtual BOOL GetContent( BYTE *pBuffer, unsigned long ulBufferSize ) const;
    virtual BOOL GetHeader( const CString& strName, CString& strHeader) const;
    virtual BOOL GetStatusCode( unsigned long& ulStatus ) const;
    virtual BOOL GetStatusText( CString& strStatus ) const;

public:
    unsigned long ReceiveData();

private:
    // cached data
    std::map<CString, CString> m_mapHeaders;
    CString m_strHeaders;

    DWORD m_dwSizeToReceivePerTime;
    DWORD m_dwSizeReceived;
    DWORD m_dwSizeReceivedTotal;

    // content
    byte* m_pContent;
    DWORD m_dwContentLength;
    DWORD m_dwStatusCode;
    CString m_strStatusText;
    BOOL m_bIsChunked;

    CWinHttpRequest* m_request; 
};


_______________________________________________
Filesystem-cvs mailing list
Filesystem-cvs@helixcommunity.org
http://lists.helixcommunity.org/mailman/listinfo/filesystem-cvs


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic