You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
660 lines
18 KiB
660 lines
18 KiB
// ===========================================================================
|
|
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
// PARTICULAR PURPOSE.
|
|
//
|
|
// Copyright 1996 Microsoft Corporation. All Rights Reserved.
|
|
// ===========================================================================
|
|
#include <windows.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <fcntl.h>
|
|
#include <stdlib.h>
|
|
#include <io.h>
|
|
#include <winhttp.h>
|
|
#define _UNICODE
|
|
#include <tchar.h>
|
|
|
|
//==============================================================================
|
|
#define GLOBAL_SESSION 1
|
|
|
|
#ifdef GLOBAL_SESSION
|
|
HINTERNET g_hInternet = NULL;
|
|
#endif
|
|
|
|
#ifndef ASSERT
|
|
#define ASSERT( exp ) \
|
|
((!(exp)) ? \
|
|
DebugBreak() : \
|
|
((void)0))
|
|
#endif
|
|
|
|
typedef enum
|
|
{
|
|
HTTP_INIT = 0,
|
|
HTTP_OPEN = 1,
|
|
HTTP_SEND = 2,
|
|
HTTP_QDA = 3,
|
|
HTTP_READ = 4,
|
|
HTTP_READ_PASS_SYNC = 5,
|
|
HTTP_READ_PASS_ASYNC = 6,
|
|
HTTP_READ_FAIL_SYNC = 7,
|
|
HTTP_READ_FAIL_ASYNC = 8,
|
|
HTTP_SEND_FAIL_SYNC = 9,
|
|
HTTP_SEND_FAIL_ASYNC = 10
|
|
} HTTP_STATE;
|
|
|
|
typedef struct
|
|
{
|
|
HTTP_STATE state;
|
|
BOOL bQDA;
|
|
DWORD dwTotal;
|
|
DWORD_PTR dwResult;
|
|
DWORD dwError;
|
|
HANDLE hEvent;
|
|
DWORD dwSignature;
|
|
BOOL bCallbackDelete;
|
|
DWORD dwRead; //for non-QDA i.e. plain WinHttpReadData
|
|
} TestContext;
|
|
|
|
VOID CALLBACK Callback(IN HINTERNET hInternet, IN DWORD_PTR dwContext,
|
|
IN DWORD dwStatus, IN LPVOID pvInfo, IN DWORD dwStatusLen)
|
|
{
|
|
#if 0
|
|
fprintf(stderr, "callback!!!!!! dwStatus %d\n", dwStatus);
|
|
#endif
|
|
|
|
TestContext* pContext = (TestContext*)dwContext;
|
|
if ((dwStatus == WINHTTP_CALLBACK_STATUS_REQUEST_COMPLETE) && pContext)
|
|
{
|
|
ASSERT (pContext->dwSignature == 0);
|
|
if (pContext->bCallbackDelete)
|
|
{
|
|
delete pContext;
|
|
goto end;
|
|
}
|
|
|
|
DWORD_PTR dwResult = ((LPWINHTTP_ASYNC_RESULT)(pvInfo))->dwResult;
|
|
DWORD dwError = ((LPWINHTTP_ASYNC_RESULT) (pvInfo) )->dwError;
|
|
|
|
pContext->dwResult = dwResult;
|
|
pContext->dwError = dwError;
|
|
SetEvent(pContext->hEvent);
|
|
#if 0
|
|
OutputDebugString("\n\tWINHTTP_CALLBACK_STATUS_REQUEST_COMPLETE for QDA\n");
|
|
fprintf(stderr, "\n\tWINHTTP_CALLBACK_STATUS_REQUEST_COMPLETE for QDA with %d result and %d error.\n", dwResult, dwBytes);
|
|
#endif
|
|
}
|
|
|
|
end:
|
|
return;
|
|
}
|
|
|
|
#define CHECK_ERROR(cond, err) if (!(cond)) {pszErr=(err); goto done;}
|
|
|
|
//==============================================================================
|
|
int RequestLoop (int argc, char **argv)
|
|
{
|
|
#ifndef GLOBAL_SESSION
|
|
HINTERNET g_hInternet = NULL;
|
|
#endif
|
|
HINTERNET hConnect = NULL;
|
|
HINTERNET hRequest = NULL;
|
|
|
|
DWORD dwAccessType = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY;
|
|
WCHAR szProxyServer[256];
|
|
WCHAR szProxyBypass[256];
|
|
|
|
DWORD dwConnectFlags = 0;
|
|
BOOL fPreAuth = FALSE;
|
|
|
|
PSTR pPostData = NULL;
|
|
DWORD cbPostData = 0;
|
|
|
|
PSTR pszErr = NULL;
|
|
BOOL fRet;
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
DWORD dwTarget = WINHTTP_AUTH_TARGET_SERVER;
|
|
LPVOID pAuthParams = NULL;
|
|
|
|
DWORD option = WINHTTP_OPTION_RESOLVE_TIMEOUT;
|
|
DWORD dwTimeout = 10000;
|
|
HANDLE hEvent = NULL;
|
|
|
|
PSTR pszObject = NULL;
|
|
PSTR pszPostFile = NULL;
|
|
char pszHost[128];
|
|
PSTR pszColon = NULL;
|
|
BOOL bDeleteContext = TRUE;
|
|
|
|
TestContext* pContext = new TestContext();
|
|
CHECK_ERROR(pContext, "new TestContext");
|
|
|
|
memset(pContext, 0, sizeof(TestContext));
|
|
|
|
// Parse options.
|
|
while (argc && argv[0][0] == '-')
|
|
{
|
|
switch (tolower(argv[0][1]))
|
|
{
|
|
case 'p':
|
|
dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
|
|
dwTarget = WINHTTP_AUTH_TARGET_PROXY;
|
|
::MultiByteToWideChar(CP_ACP, 0, argv[1], -1, &szProxyServer[0], 256);
|
|
// pszProxyServer = argv[1];
|
|
::MultiByteToWideChar(CP_ACP, 0, "<local>", -1, &szProxyBypass[0], 256);
|
|
// pszProxyBypass = "<local>";
|
|
argv++;
|
|
argc--;
|
|
break;
|
|
|
|
case 's':
|
|
dwConnectFlags = WINHTTP_FLAG_SECURE;
|
|
break;
|
|
|
|
case 'a':
|
|
fPreAuth = TRUE;
|
|
break;
|
|
|
|
default:
|
|
fprintf (stderr, "\nUsage: httpauth [-p <proxy>] [-s] <server> [<object> [<user> [<pass> [<POST-file>]]]]");
|
|
fprintf (stderr, "\n -s: Secure connection (ssl or pct)");
|
|
fprintf (stderr, "\n -p: specify proxy server. (\"<local>\" assumed for bypass.)");
|
|
exit (1);
|
|
}
|
|
|
|
argv++;
|
|
argc--;
|
|
}
|
|
|
|
// Parse host:port
|
|
{
|
|
int nlen = strlen(argv[0]);
|
|
if (nlen > sizeof(pszHost))
|
|
goto done;
|
|
strcpy(pszHost, argv[0]);
|
|
}
|
|
|
|
DWORD dwPort;
|
|
pszColon = strchr(pszHost, ':');
|
|
if (!pszColon)
|
|
dwPort = INTERNET_DEFAULT_PORT;
|
|
else
|
|
{
|
|
*pszColon++ = 0;
|
|
dwPort = atol (pszColon);
|
|
}
|
|
|
|
pszObject = argc >= 2 ? argv[1] : "/";
|
|
pszPostFile = argc >= 3 ? argv[2] : NULL;
|
|
|
|
// Read any POST data into a buffer.
|
|
if (pszPostFile)
|
|
{
|
|
HANDLE hf =
|
|
CreateFile
|
|
(
|
|
pszPostFile,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
|
|
NULL
|
|
);
|
|
if (hf != INVALID_HANDLE_VALUE)
|
|
{
|
|
cbPostData = GetFileSize (hf, NULL);
|
|
pPostData = (PSTR) LocalAlloc (LMEM_FIXED, cbPostData + 1);
|
|
if (pPostData)
|
|
ReadFile (hf, pPostData, cbPostData, &cbPostData, NULL);
|
|
pPostData[cbPostData] = 0;
|
|
CloseHandle (hf);
|
|
}
|
|
}
|
|
|
|
// Initialize wininet.
|
|
#ifdef GLOBAL_SESSION
|
|
if (!g_hInternet)
|
|
#endif
|
|
g_hInternet = WinHttpOpen
|
|
(
|
|
_T("HttpAuth Sample"), // user agent
|
|
// "Mozilla/4.0 (compatible; MSIE 4.0b2; Windows 95",
|
|
dwAccessType, // access type
|
|
szProxyServer, // proxy server
|
|
szProxyBypass, // proxy bypass
|
|
WINHTTP_FLAG_ASYNC // flags
|
|
);
|
|
CHECK_ERROR (g_hInternet, "WinHttpOpen");
|
|
|
|
|
|
WCHAR szHost[256];
|
|
::MultiByteToWideChar(CP_ACP, 0, pszHost, -1, &szHost[0], 256);
|
|
|
|
WinHttpSetStatusCallback(g_hInternet, Callback, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, NULL);
|
|
|
|
WinHttpSetOption(
|
|
g_hInternet,
|
|
option,
|
|
(LPVOID)&dwTimeout,
|
|
sizeof(DWORD)
|
|
);
|
|
|
|
dwTimeout = 10000;
|
|
WinHttpSetOption(
|
|
g_hInternet,
|
|
WINHTTP_OPTION_SEND_TIMEOUT,
|
|
(LPVOID)&dwTimeout,
|
|
sizeof(DWORD)
|
|
);
|
|
|
|
dwTimeout = 10000;
|
|
WinHttpSetOption(
|
|
g_hInternet,
|
|
WINHTTP_OPTION_RECEIVE_TIMEOUT,
|
|
(LPVOID)&dwTimeout,
|
|
sizeof(DWORD)
|
|
);
|
|
|
|
hEvent = CreateEvent(NULL, FALSE /*want auto-reset*/, FALSE /*non-signaled init.*/, NULL);
|
|
|
|
CHECK_ERROR(hEvent, "CreateEvent");
|
|
|
|
pContext->hEvent = hEvent;
|
|
|
|
// Connect to host.
|
|
hConnect = WinHttpConnect
|
|
(
|
|
g_hInternet, // session handle,
|
|
szHost, // host
|
|
(INTERNET_PORT) dwPort, // port
|
|
dwConnectFlags // flags
|
|
);
|
|
CHECK_ERROR (hConnect, "WinHttpConnect");
|
|
|
|
WCHAR szObject[256];
|
|
::MultiByteToWideChar(CP_ACP, 0, pszObject, -1, &szObject[0], 256);
|
|
|
|
// Create request.
|
|
|
|
pContext->state = HTTP_OPEN;
|
|
hRequest = WinHttpOpenRequest
|
|
(
|
|
hConnect, // connect handle
|
|
pszPostFile? _T("POST") : _T("GET"), // request method
|
|
szObject, // object name
|
|
NULL, // version
|
|
NULL, // referer
|
|
NULL, // accept types
|
|
dwConnectFlags // flags
|
|
);
|
|
CHECK_ERROR (hRequest, "WinHttpOpenRequest");
|
|
|
|
// Send request.
|
|
pContext->state = HTTP_SEND;
|
|
fRet = WinHttpSendRequest
|
|
(
|
|
hRequest, // request handle
|
|
_T(""), // header string
|
|
0, // header length
|
|
pPostData, // post data
|
|
cbPostData, // post data length
|
|
cbPostData, // total post length
|
|
(DWORD_PTR)pContext // context
|
|
);
|
|
|
|
if (!fRet)
|
|
{
|
|
dwErr = GetLastError();
|
|
switch (dwErr)
|
|
{
|
|
case ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED:
|
|
break;
|
|
|
|
case ERROR_IO_PENDING:
|
|
fRet = WinHttpReceiveResponse(hRequest, NULL);
|
|
if (!fRet)
|
|
{
|
|
dwErr = GetLastError();
|
|
fprintf (stderr, "WinHttpReceiveResponse failed err=%d\n", dwErr);
|
|
break;
|
|
}
|
|
goto async;
|
|
|
|
default:
|
|
fprintf (stderr, "HttpSendRequest failed err=%d\n", dwErr);
|
|
}
|
|
pContext->state = HTTP_SEND_FAIL_SYNC;
|
|
goto done;
|
|
}
|
|
else
|
|
{
|
|
fRet = WinHttpReceiveResponse(hRequest, NULL);
|
|
if (!fRet)
|
|
{
|
|
dwErr = GetLastError();
|
|
fprintf (stderr, "WinHttpReceiveResponse failed err=%d\n", dwErr);
|
|
pContext->state = HTTP_SEND_FAIL_SYNC;
|
|
}
|
|
goto sync;
|
|
}
|
|
|
|
async:
|
|
#if 0
|
|
fprintf(stderr, "\nERROR_IO_PENDING on HSR...\n");
|
|
#endif
|
|
WaitForSingleObject(hEvent, INFINITE);
|
|
|
|
ASSERT( pContext->state == HTTP_SEND );
|
|
if (! (pContext->dwResult) )
|
|
{
|
|
pContext->state = HTTP_SEND_FAIL_ASYNC;
|
|
SetLastError (pContext->dwError);
|
|
goto done;
|
|
}
|
|
sync:
|
|
|
|
// Get status code.
|
|
DWORD dwStatus, cbStatus;
|
|
cbStatus = sizeof(dwStatus);
|
|
WinHttpQueryHeaders
|
|
(
|
|
hRequest,
|
|
WINHTTP_QUERY_FLAG_NUMBER | WINHTTP_QUERY_STATUS_CODE,
|
|
NULL,
|
|
&dwStatus,
|
|
&cbStatus,
|
|
NULL
|
|
);
|
|
fprintf (stderr, "Status: %d\n", dwStatus);
|
|
|
|
// Dump some bytes.
|
|
BYTE bBuf[1024];
|
|
DWORD cbBuf;
|
|
|
|
//#define QDA 1
|
|
#ifdef QDA
|
|
while (TRUE)
|
|
{
|
|
BOOL bAsyncRead = FALSE;
|
|
pContext->state = HTTP_QDA;
|
|
fRet = WinHttpQueryDataAvailable (hRequest, &(pContext->dwError));//(DWORD_PTR)pContext);
|
|
|
|
if (!fRet)
|
|
{
|
|
if (GetLastError() == ERROR_IO_PENDING)
|
|
{
|
|
#if 0
|
|
OutputDebugString("\nERROR_IO_PENDING on QDA\n");
|
|
fprintf(stderr, "\nERROR_IO_PENDING on QDA...\n");
|
|
#endif
|
|
WaitForSingleObject(hEvent, INFINITE);
|
|
|
|
ASSERT (pContext->state = HTTP_QDA);
|
|
if (!(pContext->dwResult))
|
|
{
|
|
// Done
|
|
pContext->state = HTTP_READ_FAIL_ASYNC;
|
|
SetLastError(pContext->dwError);
|
|
goto done;
|
|
}
|
|
else if (!(pContext->dwError))
|
|
{
|
|
pContext->state = HTTP_READ_PASS_ASYNC;
|
|
goto done;
|
|
}
|
|
bAsyncRead = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pContext->state = HTTP_READ_FAIL_SYNC;
|
|
goto done;
|
|
}
|
|
}
|
|
else if (!(pContext->dwError))
|
|
{
|
|
//Done sync
|
|
pContext->state = HTTP_READ_PASS_SYNC;
|
|
goto done;
|
|
}
|
|
|
|
DWORD dwRead = pContext->dwError;
|
|
DWORD dwActuallyRead = 0;
|
|
while (dwRead > 0)
|
|
{
|
|
cbBuf = (dwRead > sizeof(bBuf)) ? sizeof(bBuf) : dwRead;
|
|
pContext->state = HTTP_READ;
|
|
fRet = WinHttpReadData(hRequest, bBuf, cbBuf, &dwActuallyRead);
|
|
|
|
if (!fRet)
|
|
{
|
|
ASSERT ( GetLastError() != ERROR_IO_PENDING );
|
|
fprintf(stderr, "\nError in WinHttpReadData = %d\n", GetLastError());
|
|
goto done;
|
|
}
|
|
ASSERT((cbBuf == dwActuallyRead));
|
|
#if 0
|
|
ASSERT(fRet);
|
|
fwrite (bBuf, 1, dwActuallyRead, stdout);
|
|
#endif
|
|
pContext->dwTotal += dwActuallyRead;
|
|
dwRead -= dwActuallyRead;
|
|
}
|
|
}
|
|
#else
|
|
/*
|
|
cbBuf = sizeof(bBuf);
|
|
while (WinHttpReadData (hRequest, bBuf, cbBuf, &(pContext->dwRead)) && pContext->dwRead)
|
|
fwrite (bBuf, 1, pContext->dwRead, stdout);
|
|
*/
|
|
cbBuf = sizeof(bBuf);
|
|
|
|
while (TRUE)
|
|
{
|
|
pContext->state = HTTP_READ;
|
|
fRet = WinHttpReadData (hRequest, bBuf, cbBuf, &(pContext->dwRead));
|
|
|
|
if (!fRet)
|
|
{
|
|
if (GetLastError() == ERROR_IO_PENDING)
|
|
{
|
|
#if 0
|
|
OutputDebugString("\nERROR_IO_PENDING on READ\n");
|
|
fprintf(stderr, "\nERROR_IO_PENDING on RD...\n");
|
|
#endif
|
|
WaitForSingleObject(hEvent, INFINITE);
|
|
|
|
ASSERT (pContext->state = HTTP_READ);
|
|
if (!(pContext->dwResult))
|
|
{
|
|
// Done
|
|
pContext->state = HTTP_READ_FAIL_ASYNC;
|
|
SetLastError(pContext->dwError);
|
|
goto done;
|
|
}
|
|
else if (!(pContext->dwRead))
|
|
{
|
|
pContext->state = HTTP_READ_PASS_ASYNC;
|
|
goto done;
|
|
}
|
|
pContext->dwTotal += pContext->dwRead;
|
|
//bAsyncRead = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pContext->state = HTTP_READ_FAIL_SYNC;
|
|
goto done;
|
|
}
|
|
}
|
|
else if (!(pContext->dwError))
|
|
{
|
|
//Done sync
|
|
pContext->dwTotal += pContext->dwRead;
|
|
pContext->state = HTTP_READ_PASS_SYNC;
|
|
goto done;
|
|
}
|
|
else
|
|
{
|
|
//finished this call sync but not done.
|
|
pContext->dwTotal += pContext->dwRead;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
done: // Clean up.
|
|
if (pContext && TRUE)
|
|
{
|
|
fprintf (stderr, "EndOfRequest: pContext=0x%x\n\t:State: %d\n\t:Result: 0x%x\n"
|
|
"\t:Error: 0x%x [%d]\n\t:Total: 0x%x [%d]\n",
|
|
pContext,
|
|
pContext->state,
|
|
pContext->dwResult,
|
|
pContext->dwError, pContext->dwError,
|
|
pContext->dwTotal, pContext->dwTotal
|
|
);
|
|
}
|
|
if (pszErr)
|
|
fprintf (stderr, "Failed on %s, last error %d\n", pszErr, GetLastError());
|
|
if (hRequest)
|
|
WinHttpCloseHandle (hRequest);
|
|
if (hConnect)
|
|
WinHttpCloseHandle (hConnect);
|
|
|
|
#ifndef GLOBAL_SESSION
|
|
if (g_hInternet)
|
|
WinHttpCloseHandle (g_hInternet);
|
|
#endif
|
|
|
|
if (pPostData)
|
|
LocalFree (pPostData);
|
|
if (hEvent)
|
|
CloseHandle(hEvent);
|
|
if (pContext && bDeleteContext)
|
|
{
|
|
pContext->dwSignature = 0x41414141;
|
|
delete pContext;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//==============================================================================
|
|
void ParseArguments
|
|
(
|
|
LPSTR InBuffer,
|
|
LPSTR* CArgv,
|
|
DWORD* CArgc
|
|
)
|
|
{
|
|
LPSTR CurrentPtr = InBuffer;
|
|
DWORD i = 0;
|
|
DWORD Cnt = 0;
|
|
|
|
for ( ;; ) {
|
|
|
|
//
|
|
// skip blanks.
|
|
//
|
|
|
|
while( *CurrentPtr == ' ' ) {
|
|
CurrentPtr++;
|
|
}
|
|
|
|
if( *CurrentPtr == '\0' ) {
|
|
break;
|
|
}
|
|
|
|
CArgv[i++] = CurrentPtr;
|
|
|
|
//
|
|
// go to next space.
|
|
//
|
|
|
|
while( (*CurrentPtr != '\0') &&
|
|
(*CurrentPtr != '\n') ) {
|
|
if( *CurrentPtr == '"' ) { // Deal with simple quoted args
|
|
if( Cnt == 0 )
|
|
CArgv[i-1] = ++CurrentPtr; // Set arg to after quote
|
|
else
|
|
*CurrentPtr = '\0'; // Remove end quote
|
|
Cnt = !Cnt;
|
|
}
|
|
if( (Cnt == 0) && (*CurrentPtr == ' ') || // If we hit a space and no quotes yet we are done with this arg
|
|
(*CurrentPtr == '\0') )
|
|
break;
|
|
CurrentPtr++;
|
|
}
|
|
|
|
if( *CurrentPtr == '\0' ) {
|
|
break;
|
|
}
|
|
|
|
*CurrentPtr++ = '\0';
|
|
}
|
|
|
|
*CArgc = i;
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
int __cdecl main (int argc, char **argv)
|
|
{
|
|
char * port;
|
|
int nCount = 0;
|
|
// Discard program arg.
|
|
argv++;
|
|
argc--;
|
|
|
|
char* argv_large[] = {"dennisch", "venkatk/large.html", 0};
|
|
char* argv_small[] = {"dennisch", "venkatk/small.html", 0};
|
|
char* argv_delay[] = {"venkatk:180", 0};
|
|
|
|
while(nCount++ < 1)
|
|
{
|
|
RequestLoop( 2, argv_large );
|
|
}
|
|
|
|
fprintf (stderr, "\nDone\n", nCount);
|
|
|
|
#if 0
|
|
if (argc)
|
|
RequestLoop (argc, argv);
|
|
|
|
else // Enter command prompt loop
|
|
{
|
|
fprintf (stderr, "\nUsage: [-p <proxy>] [-s] <host>[:port] [<object> [<POST-file>]]");
|
|
fprintf (stderr, "\n -s: use secure sockets layer");
|
|
fprintf (stderr, "\n -p: specify proxy server. (\"<local>\" assumed for bypass.)");
|
|
fprintf (stderr, "\nTo exit input loop, enter no params");
|
|
|
|
while (1)
|
|
{
|
|
char szIn[1024];
|
|
DWORD argcIn;
|
|
LPSTR argvIn[10];
|
|
|
|
fprintf (stderr, "\nhttpauth> ");
|
|
gets (szIn);
|
|
|
|
argcIn = 0;
|
|
ParseArguments (szIn, argvIn, &argcIn);
|
|
if (!argcIn)
|
|
break;
|
|
RequestLoop (argcIn, argvIn);
|
|
//g_cbRead=0;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef GLOBAL_SESSION
|
|
if (g_hInternet)
|
|
WinHttpCloseHandle (g_hInternet);
|
|
g_hInternet = NULL;
|
|
#endif
|
|
}
|
|
|