929 lines
35 KiB
C++
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;
|
|
}
|