2025-04-27 07:49:33 -04:00

929 lines
35 KiB
C++

// asyncwnt.cpp
#include <windows.h>
#include <wininet.h>
#include <assert.h>
#include <time.h>
#include <stdlib.h> // get rid of this, find a better IntToStr
#include "iasyncwnt.h"
#include "asyncwnt.h"
#include "asyncwnt.clsid.h"
#include "qxml.h"
#include "strutil.h"
#include "mischlpr.h"
#include <stdio.h>
//#define TRACE(a) (fprintf(stderr,"%d %s\n",GetTickCount(),a))
#define TRACE(a)
////////////////////////////////////////////////
//
// Globals
//
static HMODULE g_hModule = NULL;
static long g_cComponents = 0;
static long g_cServerLocks = 0;
const char g_szFriendlyName[] = "ASYNC WININET";
const char g_szVerIndProgID[] = "NeptuneStorage.AsyncWnt";
const char g_szProgID[] = "NeptuneStorage.AsyncWnt.1";
////////////////////////////////////////////////
//
// Class AsyncWnt
//
CAsyncWntImpl::CAsyncWntImpl(): _pwszUserAgent(NULL), _pwszLogFilePath(NULL)
{
TRACE("CAsyncWnt::CAsyncWnt");
}
CAsyncWntImpl::~CAsyncWntImpl()
{
TRACE("CAsyncWnt::~CAsyncWnt");
}
STDMETHODIMP CAsyncWntImpl::Init() {
TRACE("CAsyncWnt::Init");
return S_OK;
}
////////////////////////////////////////////////
STDMETHODIMP CAsyncWntImpl::SetUserAgent (LPCWSTR pwszUserAgent)
{
HRESULT hr = S_OK;
TRACE("CAsyncWnt::SetUserAgent");
if (!pwszUserAgent)
{
hr = E_INVALIDARG;
}
else
{
if (!_pwszUserAgent)
{
free(_pwszUserAgent);
_pwszUserAgent = NULL;
}
_pwszUserAgent = DuplicateStringW(pwszUserAgent);
if (!_pwszUserAgent)
{
hr = E_OUTOFMEMORY;
}
}
return hr;
}
////////////////////////////////////////////////
STDMETHODIMP CAsyncWntImpl::SetLogFilePath (LPCWSTR pwszLogFilePath)
{
HRESULT hr = S_OK;
TRACE("CAsyncWnt::SetLogFilePath");
if (_pwszLogFilePath)
{
free(_pwszLogFilePath);
_pwszLogFilePath = NULL;
}
if (!pwszLogFilePath)
{
// no logging requested
}
else
{
_pwszLogFilePath = DuplicateStringW(pwszLogFilePath);
if (!_pwszLogFilePath)
{
hr = E_OUTOFMEMORY;
}
}
return hr;
}
////////////////////////////////////////////////
STDMETHODIMP CAsyncWntImpl::Request (LPCWSTR pwszURL,
LPCWSTR pwszVerb,
LPCWSTR pwszHeaders,
ULONG nAcceptTypes,
LPCWSTR __RPC_FAR rgwszAcceptTypes[ ],
IAsyncWntCallback* pcallback,
DWORD dwContext)
{
TRACE("CAsyncWnt::Request");
return this->_MasterDriver(pwszURL,
pwszVerb,
pwszHeaders,
nAcceptTypes,
rgwszAcceptTypes,
NULL,
0,
NULL,
pcallback,
dwContext);
}
////////////////////////////////////////////////
STDMETHODIMP CAsyncWntImpl::RequestWithStream (LPCWSTR pwszURL,
LPCWSTR pwszVerb,
LPCWSTR pwszHeaders,
ULONG nAcceptTypes,
LPCWSTR __RPC_FAR rgwszAcceptTypes[ ],
IStream* pStream,
IAsyncWntCallback* pcallback,
DWORD dwContext)
{
TRACE("CAsyncWnt::RequestWithStream");
return this->_MasterDriver(pwszURL,
pwszVerb,
pwszHeaders,
nAcceptTypes,
rgwszAcceptTypes,
NULL,
0,
pStream,
pcallback,
dwContext);
}
////////////////////////////////////////////////
STDMETHODIMP CAsyncWntImpl::RequestWithBuffer (LPCWSTR pwszURL,
LPCWSTR pwszVerb,
LPCWSTR pwszHeaders,
ULONG nAcceptTypes,
LPCWSTR __RPC_FAR rgwszAcceptTypes[ ],
LPBYTE pbBuffer,
UINT cbBuffer,
IAsyncWntCallback* pcallback,
DWORD dwContext)
{
TRACE("CAsyncWnt::RequestWithBuffer");
return this->_MasterDriver(pwszURL,
pwszVerb,
pwszHeaders,
nAcceptTypes,
rgwszAcceptTypes,
pbBuffer,
cbBuffer,
NULL,
pcallback,
dwContext);
}
////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CAsyncWntImpl::_WriteRequestToLog(LPCWSTR pwszURL,
LPCWSTR pwszVerb,
ULONG nAcceptTypes,
LPCWSTR rgwszAcceptTypes[],
LPCWSTR pwszHeaders)
{
HRESULT hr = S_OK;
DWORD dw;
WCHAR wszTime[30];
WCHAR wszDate[20];
TRACE("CAsyncWnt::_WriteRequestToLog");
HANDLE hFile;
hFile = CreateFile(_pwszLogFilePath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
hr = E_FAIL;
}
else
{
if ((SetFilePointer(hFile, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER) && (GetLastError() != ERROR_SUCCESS))
{
hr = E_FAIL;
}
else
{
_wstrtime(wszTime);
_wstrdate(wszDate);
WriteFile(hFile, wszDate, lstrlen(wszDate) * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, L",", lstrlen(L",") * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, wszTime, lstrlen(wszTime) * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, L"\r\n,", lstrlen(L"\r\n") * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, L"Client says:\r\n", lstrlen(L"Client says:\r\n") * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, L"URL:\r\n", lstrlen(L"URL:\r\n") * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, pwszURL, lstrlen(pwszURL) * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, L"\r\n", lstrlen(L"\r\n") * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, L"Verb:\r\n", lstrlen(L"Verb:\r\n") * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, pwszVerb, lstrlen(pwszVerb) * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, L"\r\n", lstrlen(L"\r\n") * sizeof(WCHAR), &dw, NULL);
for (ULONG i = 0; i < nAcceptTypes; i++)
{
WriteFile(hFile, L"Accept:", lstrlen(L"Accept:") * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, rgwszAcceptTypes[i], lstrlen(rgwszAcceptTypes[i]) * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, L"\r\n", lstrlen(L"\r\n") * sizeof(WCHAR), &dw, NULL);
}
WriteFile(hFile, L"Headers:\r\n", lstrlen(L"Headers:\r\n") * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, pwszHeaders, lstrlen(pwszHeaders) * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, L"\r\n", lstrlen(L"\r\n") * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, L"**************************\r\n\r\n", lstrlen(L"**************************\r\n\r\n") * sizeof(WCHAR), &dw, NULL);
}
CloseHandle(hFile);
}
return hr;
}
////////////////////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CAsyncWntImpl::_WriteResponseToLog(LPWSTR pwszVerb,
LPWSTR pwszURL,
UINT cchResponseHeaders,
LPWSTR pwszResponseHeaders,
DWORD dwStatusCode,
LPWSTR pwszStatusMsg,
LPWSTR pwszContentType,
UINT cbSent,
LPVOID UNREF_PARAM(pbResponse),
UINT bytesReadTotal)
{
HRESULT hr = S_OK;
DWORD dw;
WCHAR wszTime[30];
WCHAR wszDate[20];
WCHAR wszCode[20];
TRACE("CAsyncWnt::_WriteResponseToLog");
HANDLE hFile;
hFile = CreateFile(_pwszLogFilePath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
hr = E_FAIL;
}
else
{
if ((SetFilePointer(hFile, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER) && (GetLastError() != ERROR_SUCCESS))
{
hr = E_FAIL;
}
else
{
_wstrtime(wszTime);
_wstrdate(wszDate);
WriteFile(hFile, wszDate, lstrlen(wszDate) * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, L",", lstrlen(L",") * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, wszTime, lstrlen(wszTime) * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, L"\r\n,", lstrlen(L"\r\n") * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, L"Server says:\r\n", lstrlen(L"Client says:\r\n") * sizeof(WCHAR), &dw, NULL);
// begin actual data
WriteFile(hFile, L"URL:\r\n", lstrlen(L"URL:\r\n") * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, pwszURL, lstrlen(pwszURL) * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, L"\r\n", lstrlen(L"\r\n") * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, L"Verb:\r\n", lstrlen(L"Verb:\r\n") * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, pwszVerb, lstrlen(pwszVerb) * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, L"\r\n", lstrlen(L"\r\n") * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, L"Response Headers:\r\n", lstrlen(L"Response Headers:\r\n") * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, pwszResponseHeaders, cchResponseHeaders * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, L"\r\n", lstrlen(L"\r\n") * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, L"Status:\r\n", lstrlen(L"Status:\r\n") * sizeof(WCHAR), &dw, NULL);
_itow(dwStatusCode,wszCode,10);
WriteFile(hFile, wszCode, lstrlen(wszCode) * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, L"-", lstrlen(L"-") * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, pwszStatusMsg, lstrlen(pwszStatusMsg) * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, L"\r\n", lstrlen(L"\r\n") * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, L"Bytes sent:\r\n", lstrlen(L"Bytes sent:\r\n") * sizeof(WCHAR), &dw, NULL);
_itow(cbSent,wszCode,10);
WriteFile(hFile, wszCode, lstrlen(wszCode) * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, L"\r\n", lstrlen(L"\r\n") * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, L"Bytes received:\r\n", lstrlen(L"Bytes received:\r\n") * sizeof(WCHAR), &dw, NULL);
_itow(bytesReadTotal,wszCode,10);
WriteFile(hFile, wszCode, lstrlen(wszCode) * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, L"\r\n", lstrlen(L"\r\n") * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, L"Content-Type:\r\n", lstrlen(L"Content-Type:\r\n") * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, pwszContentType, lstrlen(pwszContentType) * sizeof(WCHAR), &dw, NULL);
WriteFile(hFile, L"\r\n", lstrlen(L"\r\n") * sizeof(WCHAR), &dw, NULL);
// end actual data
WriteFile(hFile, L"**************************\r\n\r\n", lstrlen(L"**************************\r\n\r\n") * sizeof(WCHAR), &dw, NULL);
}
CloseHandle(hFile);
}
return hr;
}
////////////////////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CAsyncWntImpl::_MasterDriver (LPCWSTR pwszURL,
LPCWSTR pwszVerb,
LPCWSTR pwszHeaders,
ULONG nAcceptTypes,
LPCWSTR __RPC_FAR rgwszAcceptTypes[ ],
LPBYTE pbBuffer,
UINT cbBuffer,
IStream* pStream,
IAsyncWntCallback* pcallback,
DWORD dwContext)
{
// locals
HRESULT hr = S_OK;
TRACE("CAsyncWnt::_MasterDriver");
// argument checking
if (((!pbBuffer) && (cbBuffer > 0)) || ((!pbBuffer) && (cbBuffer > 0)))
{
hr = E_INVALIDARG;
}
else if (pbBuffer && pStream) // buffer or stream but not both
{
hr = E_INVALIDARG;
}
else if (!pwszURL || !pwszVerb)
{
hr = E_INVALIDARG;
}
else
{
// code
LPCWSTR pwszLocalHeader = pwszHeaders ? pwszHeaders : L"Content-Type: application/x-www-form-urlencoded\n";
// -- connect to the server
HINTERNET hRequest = NULL;
hr = this->_MasterConnect(pwszURL, pwszVerb, nAcceptTypes, rgwszAcceptTypes,
pcallback, dwContext, &hRequest);
if (SUCCEEDED(hr))
{
DWORD cbSent;
hr = this->_MasterRequest(hRequest, pwszLocalHeader, pbBuffer,
cbBuffer, pStream, &cbSent);
if (SUCCEEDED(hr))
{
// -- request was sent, write to log if appropriate
if (_pwszLogFilePath)
{
hr = this->_WriteRequestToLog(pwszURL, pwszVerb, nAcceptTypes,
rgwszAcceptTypes, pwszHeaders);
}
if (SUCCEEDED(hr))
{
hr = this->_MasterListen(hRequest, pwszURL, pwszVerb,
cbSent, pcallback, dwContext);
}
}
}
}
return hr;
}
/////////////////////////////////////////////////////////
STDMETHODIMP CAsyncWntImpl::_MasterConnect_InternetOpen(HINTERNET* phInternet)
{
TRACE("CAsyncWnt::_MasterConnect_InternetOpen");
*phInternet = InternetOpen(L"AsyncWnt", // agent
INTERNET_OPEN_TYPE_PRECONFIG, // access type
NULL, // proxy name (not used)
NULL, // proxy bypass (not used)
0); // flags
return S_OK;
}
/////////////////////////////////////////////////////////
STDMETHODIMP CAsyncWntImpl::_MasterConnect_InternetConnect(HINTERNET hInternet,
LPCWSTR pwszURL,
IAsyncWntCallback* pcallback,
HINTERNET* phSession,
LPWSTR* ppwszPath)
{
// locals
HRESULT hr = S_OK;
UINT uiOffset = 0;
USHORT port;
LPWSTR pwszSvrHostname = NULL;
WCHAR wszUsername[255]; // we should use a better constant
WCHAR wszPassword[255];
LPWSTR pwszUsername = NULL;
LPWSTR pwszPassword = NULL;
URL_COMPONENTS urlComponents = {0};
TRACE("CAsyncWnt::_MasterConnect_InternetConnect");
// code
// ---- first get the port of the destination
// don't store this in hr, port not required
// -- first parse the URL (server, port, path)
urlComponents.dwStructSize = sizeof(URL_COMPONENTS);
urlComponents.dwHostNameLength = 1;
urlComponents.dwUrlPathLength = 1;
urlComponents.nPort = 1;
if (!InternetCrackUrl(pwszURL, 0, 0, &urlComponents))
{
hr = E_FAIL;
}
else
{
pwszSvrHostname = (LPWSTR)malloc(sizeof(WCHAR) * (1 + urlComponents.dwHostNameLength));
if (!pwszSvrHostname)
{
hr = E_OUTOFMEMORY;
}
else
{
lstrcpyn(pwszSvrHostname, urlComponents.lpszHostName, 1 + urlComponents.dwHostNameLength); // +1 for the final null char
port = urlComponents.nPort;
*ppwszPath = (LPWSTR)malloc(sizeof(WCHAR) * (1 + urlComponents.dwUrlPathLength));
if (!(*ppwszPath))
{
hr = E_OUTOFMEMORY;
}
else
{
lstrcpyn(*ppwszPath, urlComponents.lpszUrlPath, 1 + urlComponents.dwUrlPathLength); // +1 for the final null char
// ---- then get the username, password
pwszUsername = NULL;
pwszPassword = NULL;
if (pcallback)
{
hr = pcallback->OnAuthChallenge(wszUsername, wszPassword);
if (SUCCEEDED(hr))
{
if (lstrlen(wszUsername) > 0)
{
pwszUsername = wszUsername;
}
if (lstrlen(wszPassword) > 0)
{
pwszPassword = wszPassword;
}
}
}
// ---- third actually establish the connection
*phSession = InternetConnect(hInternet, // internet handle
pwszSvrHostname, // hostname of server
port, // port number of server
pwszUsername, // username
pwszPassword, // password
INTERNET_SERVICE_HTTP, // service to use
0, // flags
1); // context info
}
}
}
if (pwszSvrHostname)
{
free(pwszSvrHostname);
}
return hr;
}
/////////////////////////////////////////////////////////
STDMETHODIMP CAsyncWntImpl::_MasterConnect_HttpOpenRequest(HINTERNET hSession,
LPCWSTR pwszVerb,
LPWSTR pwszPath,
UINT nAcceptTypes,
LPCWSTR __RPC_FAR rgwszAcceptTypes[ ],
HINTERNET* phRequest)
{
HRESULT hr = S_OK;
LPCWSTR* acceptAr = NULL;
UINT i;
TRACE("CAsyncWnt::_MasterConnect_HttpOpenRequest");
// ---- first figure out what types are accepted, default is all
if (nAcceptTypes == IASYNCWNT_ACCEPTALL)
{
// if no accept types passed in, assume "Accept: */*"
acceptAr = (LPCWSTR*)malloc(sizeof(LPCWSTR) * 2);
if (!acceptAr)
{
hr = E_OUTOFMEMORY;
}
else
{
acceptAr[0] = L"*/*";
acceptAr[1] = NULL;
}
} else if (nAcceptTypes == 0) {
acceptAr = (LPCWSTR*)malloc(sizeof(LPCWSTR) * 1);
if (!acceptAr)
{
hr = E_OUTOFMEMORY;
}
else
{
acceptAr[0] = NULL;
}
} else {
acceptAr = (LPCWSTR*)malloc(sizeof(LPCWSTR) * (nAcceptTypes + 1));
if (!acceptAr)
{
hr = E_OUTOFMEMORY;
}
else
{
for (i = 0 ; i < nAcceptTypes ; i++)
{
acceptAr[i] = rgwszAcceptTypes[i];
}
acceptAr[nAcceptTypes] = NULL;
}
}
if (SUCCEEDED(hr))
{
// ---- then we can create the request
*phRequest = HttpOpenRequestW(hSession, // connection
pwszVerb, // verb
pwszPath, // objectname
NULL, // HTTP version
NULL, // referrer
acceptAr, // accept types
0, // flags
1); // context
if (!(*phRequest))
{
hr = E_OUTOFMEMORY;
}
}
if (acceptAr)
{
free(acceptAr);
}
return hr;
}
/////////////////////////////////////////////////////////
STDMETHODIMP CAsyncWntImpl::_MasterConnect (LPCWSTR pwszURL,
LPCWSTR pwszVerb,
ULONG nAcceptTypes,
LPCWSTR __RPC_FAR rgwszAcceptTypes[ ],
IAsyncWntCallback* pcallback,
DWORD UNREF_PARAM(dwContext),
HINTERNET* phRequest)
{
// locals
HRESULT hr = S_OK;
HINTERNET hInternet = NULL;
HINTERNET hSession = NULL;
LPWSTR pwszPath = NULL;
TRACE("CAsyncWnt::_MasterConnect");
// code
// -- first establish the internet handle
hr = this->_MasterConnect_InternetOpen(&hInternet);
if (SUCCEEDED(hr))
{
if (!hInternet)
{
hr = E_FAIL;
}
else
{
// -- next connect the internet session
hr = this->_MasterConnect_InternetConnect(hInternet, pwszURL, pcallback, &hSession, &pwszPath);
if (SUCCEEDED(hr))
{
if (!hSession)
{
hr = E_FAIL;
}
else
{
// -- send the request across the connection
hr = this->_MasterConnect_HttpOpenRequest(hSession, pwszVerb, pwszPath, nAcceptTypes, rgwszAcceptTypes, phRequest);
}
}
}
}
if (pwszPath)
{
free(pwszPath);
}
return hr;
}
/////////////////////////////////////////////////////////////
STDMETHODIMP CAsyncWntImpl::_MasterRequest (HINTERNET hRequest,
LPCWSTR pwszHeaders,
LPBYTE pbBuffer,
UINT cbBuffer,
IStream* pStream,
DWORD* pcbSent)
{
// locals
HRESULT hr = S_OK;
STATSTG stats;
LPVOID pbBufferLocal = NULL;
DWORD cbBufferLocal = 0;
LARGE_INTEGER liOffset = {0};
DWORD cchHeaders;
TRACE("CAsyncWnt::_MasterRequest");
// code
*pcbSent = 0;
if (pStream)
{
// ---- use the contents of the file as the body of the request
hr = pStream->Stat(&stats, STATFLAG_NONAME);
if (SUCCEEDED(hr))
{
cbBufferLocal = stats.cbSize.LowPart; // ISSUE: 2000/02/16-aidanl fails for streams > 2gig
pbBufferLocal = (unsigned char *) malloc (cbBufferLocal);
if (!pbBufferLocal)
{
hr = E_OUTOFMEMORY;
}
else
{
hr = pStream->Seek(liOffset,STREAM_SEEK_SET,NULL); // should we seek to start, or should we write what's left of file?
if (SUCCEEDED(hr))
{
hr = pStream->Read(pbBufferLocal, cbBufferLocal, NULL);
}
}
}
}
else
{
// ---- if pStream is null, use the pbBuffer and cbBuffer passed in, which may be NULL, which is fine
pbBufferLocal = pbBuffer;
cbBufferLocal = cbBuffer;
}
if (SUCCEEDED(hr))
{
if (!pwszHeaders)
{
cchHeaders = 0;
}
else
{
cchHeaders = lstrlen(pwszHeaders);
}
TRACE("CAsyncWnt::_MasterRequest - about to send request");
if (!HttpSendRequestW(hRequest,
pwszHeaders,
cchHeaders,
(void*)pbBuffer,
cbBuffer))
{
hr = E_FAIL;
}
TRACE("CAsyncWnt::_MasterRequest - done sending request");
*pcbSent = cbBufferLocal;
}
return hr;
}
/////////////////////////////////////////////////////////
STDMETHODIMP CAsyncWntImpl::_MasterListen (HINTERNET hRequest,
LPCWSTR pwszURL,
LPCWSTR pwszVerb,
DWORD cbSent,
IAsyncWntCallback* pcallback,
DWORD UNREF_PARAM(dwContext))
{
// locals
HRESULT hr = S_OK;
BYTE pbResponse[65000]; // BUGBUG: why did you choose this?
BYTE buffer[1000];// BUGBUG: why did you choose this?
DWORD bytesRead = 0;
DWORD bytesReadTotal = 0;
DWORD dwStatusCode;
LPWSTR pwszStatusMsg = NULL;
LPWSTR pwszContentType = NULL;
DWORD cchTemp;
WCHAR wszTemp[1000];// BUGBUG: why did you choose this?
WCHAR wszResponseHeaders[10000];// BUGBUG: why did you choose this?
DWORD cchResponseHeaders = 0;
LPWSTR pwszResponseHeaders = NULL;
TRACE("CAsyncWnt::_MasterListen");
// code
// for now, do the response synchronously
// -- first, copy the response to buffer, 1000 bytes at a time
// ---- BUGBUG: replace with virtualalloc, this can overflow trivially
LPBYTE pbResponseCursor = pbResponse;
do
{
if (!InternetReadFile(hRequest, // handle to request to get response to
buffer, // buffer to write response into
1000, // size of buffer
&bytesRead))
{
hr = E_FAIL;
}
else
{
if (bytesRead>0)
{
CopyMemory(pbResponseCursor,buffer,bytesRead);
pbResponseCursor+= bytesRead;
bytesReadTotal+=bytesRead;
if (bytesReadTotal > 65000)
{
break; // BUGBUG: we should handle this better.
}
}
}
} while (bytesRead>0 && SUCCEEDED(hr));
if (SUCCEEDED(hr))
{
// now parse the response
// -- get the return code (must be present or else error!)
cchTemp=4;
if (!HttpQueryInfo(hRequest, // handle to request to get info on
HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, // flags
&dwStatusCode, // buffer to write into
&cchTemp, // pointer to size of buffer
NULL)) // pointer to index to grab, unused
{
hr = E_FAIL;
}
else
{
// -- call the pcallback, if appropriate, otherwise return this value as the return value of this function
if (pcallback)
{
// -- get the return message, if present
cchTemp = 1000;
if (HttpQueryInfo(hRequest, // handle to request to get info on
HTTP_QUERY_STATUS_TEXT, // flags
wszTemp, // buffer to write into
&cchTemp, // pointer to size of buffer
NULL)) // pointer to index to grab, unused
{
pwszStatusMsg = DuplicateStringW(wszTemp);
}
// -- get the return message, if present
cchTemp=1000;
if (HttpQueryInfo(hRequest, // handle to request to get info on
HTTP_QUERY_CONTENT_TYPE, // flags
wszTemp, // buffer to write into
&cchTemp, // pointer to size of buffer
NULL)) // pointer to index to grab, unused
{
pwszContentType = DuplicateStringW(wszTemp);
}
// -- get the raw headers
cchTemp=1000;
if (HttpQueryInfo(hRequest, // handle to request to get info on
//HTTP_QUERY_RAW_HEADERS, // flags
HTTP_QUERY_RAW_HEADERS_CRLF, // flags, CRLF just for debugging
wszResponseHeaders, // buffer to write into
&cchTemp, // pointer to size of buffer
NULL)) // pointer to index to grab, unused
{
pwszResponseHeaders = wszResponseHeaders;
cchResponseHeaders = cchTemp;
}
// BUGBUG: cbBuffer needs to be updated, it's really the number of bytes we tried to send, we need to make it
// the number of bytes that we DID send
// write to the log, if appropriate
if (_pwszLogFilePath)
{
hr = this->_WriteResponseToLog((LPWSTR)pwszVerb,
(LPWSTR)pwszURL,
cchResponseHeaders,
pwszResponseHeaders,
dwStatusCode,
pwszStatusMsg,
pwszContentType,
cbSent,
pbResponse,
bytesReadTotal);
}
if (SUCCEEDED(hr))
{
// call the callback
hr = pcallback->Respond((LPWSTR)pwszVerb,
(LPWSTR)pwszURL,
cchResponseHeaders,
pwszResponseHeaders,
dwStatusCode,
pwszStatusMsg,
pwszContentType,
cbSent,
pbResponse,
bytesReadTotal);
}
}
else
{
// no callback, just return the hr based on the HTTP Response Code
if (dwStatusCode <= 99 ) {
hr = E_FAIL; // undefined
}
else if (dwStatusCode <= 199) {
hr = S_OK; // RFC 2616 defines 1?? as "informational", ignore
}
else if (dwStatusCode <= 299) {
hr = S_OK; // RFC 2616 defines 2?? as "OK"
}
else if (dwStatusCode <= 399) {
hr = E_FAIL; // RFC 2616 defines 3?? as "redirection", we can't support this for now
}
else if (dwStatusCode <= 499) {
hr = E_FAIL; // RFC 2616 defines 4?? as "error"
}
else if (dwStatusCode <= 599) {
hr = E_FAIL; // RFC 2616 defines 5?? as "internal server error"
}
else
{
hr = E_FAIL; // undefinfed
}
}
}
}
// release stuff
if (pwszStatusMsg)
{
free(pwszStatusMsg);
}
if (pwszContentType)
{
free(pwszContentType);
}
return hr;
}