|
|
/*++
Copyright (c) 1994 Microsoft Corporation
Module Name:
thttp.c
Abstract:
Simple test program for the HTTP API.
Author:
Keith Moore (keithmo) 16-Nov-1994
Revision History:
--*/
#include <windows.h>
#include <wininet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <io.h>
//
// macros
//
#define IS_ARG(c) ((c) == '-')
//
// Private constants.
//
#define DEFAULT_CONTEXT 1
#define OPEN_CONTEXT 2
#define CONNECT_CONTEXT 3
#define REQUEST_CONTEXT 4
#define LOAD_ENTRY( hMod, Name ) \
(p##Name = (pfn##Name) GetProcAddress( (hMod), #Name ))
//
// Private types.
//
typedef struct _QUERY_LEVEL { DWORD QueryType; CHAR * QueryName;
} QUERY_LEVEL;
#define MK_QUERY(x) { HTTP_QUERY_ ## x, #x }
typedef INTERNETAPI HINTERNET (WINAPI * pfnInternetOpenA)( IN LPCSTR lpszAgent, IN DWORD dwAccessType, IN LPCSTR lpszProxy OPTIONAL, IN LPCSTR lpszProxyBypass OPTIONAL, IN DWORD dwFlags );
typedef INTERNETAPI INTERNET_STATUS_CALLBACK (WINAPI * pfnInternetSetStatusCallback)( IN HINTERNET hInternet, IN INTERNET_STATUS_CALLBACK lpfnInternetCallback );
typedef INTERNETAPI HINTERNET (WINAPI * pfnInternetConnectA)( IN HINTERNET hInternet, IN LPCSTR lpszServerName, IN INTERNET_PORT nServerPort, IN LPCSTR lpszUserName OPTIONAL, IN LPCSTR lpszPassword OPTIONAL, IN DWORD dwService, IN DWORD dwFlags, IN DWORD dwContext );
typedef INTERNETAPI HINTERNET (WINAPI * pfnHttpOpenRequestA)( IN HINTERNET hConnect, IN LPCSTR lpszVerb, IN LPCSTR lpszObjectName, IN LPCSTR lpszVersion, IN LPCSTR lpszReferrer OPTIONAL, IN LPCSTR FAR * lplpszAcceptTypes OPTIONAL, IN DWORD dwFlags, IN DWORD dwContext );
typedef INTERNETAPI BOOL (WINAPI * pfnHttpAddRequestHeadersA)( IN HINTERNET hRequest, IN LPCSTR lpszHeaders, IN DWORD dwHeadersLength, IN DWORD dwModifiers );
typedef INTERNETAPI BOOL (WINAPI * pfnHttpSendRequestA)( IN HINTERNET hRequest, IN LPCSTR lpszHeaders OPTIONAL, IN DWORD dwHeadersLength, IN LPVOID lpOptional OPTIONAL, IN DWORD dwOptionalLength );
typedef INTERNETAPI BOOL (WINAPI * pfnHttpQueryInfoA)( IN HINTERNET hRequest, IN DWORD dwInfoLevel, IN OUT LPVOID lpBuffer OPTIONAL, IN OUT LPDWORD lpdwBufferLength, IN OUT LPDWORD lpdwIndex OPTIONAL );
typedef INTERNETAPI BOOL (WINAPI * pfnInternetCloseHandle)( IN HINTERNET hInternet );
typedef INTERNETAPI BOOL (WINAPI * pfnInternetReadFile)( IN HINTERNET hFile, IN LPVOID lpBuffer, IN DWORD dwNumberOfBytesToRead, OUT LPDWORD lpdwNumberOfBytesRead );
//
// Private globals.
//
CHAR MoreHeaders[] = "Pragma: This is garbage!\r\n";
HMODULE hWininet;
LPTSTR AcceptTypes[] = { "*/*", NULL };
QUERY_LEVEL QueryLevels[] = { MK_QUERY( STATUS_CODE ), MK_QUERY( STATUS_TEXT ), MK_QUERY( VERSION ), MK_QUERY( MIME_VERSION ),
MK_QUERY( CONTENT_TYPE ), MK_QUERY( CONTENT_TRANSFER_ENCODING ), MK_QUERY( CONTENT_ID ), MK_QUERY( CONTENT_DESCRIPTION ), MK_QUERY( CONTENT_LENGTH ), MK_QUERY( CONTENT_LANGUAGE ), MK_QUERY( ALLOW ), MK_QUERY( PUBLIC ), MK_QUERY( DATE ), MK_QUERY( EXPIRES ), MK_QUERY( LAST_MODIFIED ), MK_QUERY( MESSAGE_ID ), MK_QUERY( URI ), MK_QUERY( DERIVED_FROM ), MK_QUERY( COST ), MK_QUERY( LINK ), MK_QUERY( PRAGMA ), MK_QUERY( CONNECTION ), MK_QUERY( RAW_HEADERS_CRLF ) }; #define NUM_LEVELS (sizeof(QueryLevels) / sizeof(QueryLevels[0]))
BOOL Verbose = FALSE; BOOL Quiet = FALSE; // Don't print failed headers and content
BOOL Recurse = FALSE; // Follow links
BOOL Cache = FALSE; // Don't allow caching (i.e., force reload)
BOOL Stats = FALSE; // Print stats
BOOL Logs = FALSE; // Print log
BOOL LargeBuf= TRUE; // Use 8k reads rather then 512 byte
BOOL KeepAlive = FALSE; DWORD AccessType = PRE_CONFIG_INTERNET_ACCESS; BOOL EnableCallbacks = FALSE; BOOL UserSuppliedContext = FALSE;
INTERNET_STATUS_CALLBACK PreviousCallback;
DWORD cLevel = 0; // Current recurse level
DWORD cMaxLevel = 10; // Max Recurse level
DWORD cbReceived = 0; DWORD cmsecStart = 0; DWORD cFiles = 0; DWORD cIterations= 1; // Total iterations to perform request
LPSTR GatewayServer = NULL;
INTERNET_PORT nServerPort = 0;
DWORD LogError = ERROR_SUCCESS;
HANDLE AsyncEvent = NULL; BOOL AsyncMode = FALSE; DWORD AsyncResult; DWORD AsyncError; DWORD Context = 0;
pfnInternetOpenA pInternetOpenA; pfnInternetSetStatusCallback pInternetSetStatusCallback; pfnInternetConnectA pInternetConnectA; pfnHttpOpenRequestA pHttpOpenRequestA; pfnHttpAddRequestHeadersA pHttpAddRequestHeadersA; pfnHttpSendRequestA pHttpSendRequestA; pfnHttpQueryInfoA pHttpQueryInfoA; pfnInternetCloseHandle pInternetCloseHandle; pfnInternetReadFile pInternetReadFile;
//
// Private prototypes.
//
void usage(void);
DWORD DoTest( LPSTR Host, LPSTR Verb, LPSTR Object );
BOOL add_headers( HINTERNET hHttpRequest, LPSTR lpszHeaders, DWORD dwHeadersLength );
void my_callback(HINTERNET, DWORD, DWORD, LPVOID, DWORD);
VOID FindLink( LPSTR Host, LPSTR Verb, CHAR * buf, DWORD len, CHAR * pchLink, BOOL * pfCopyingLink, CHAR * pchReferer );
DWORD ReadHtml(HINTERNET hInternet, LPVOID buf, DWORD len, LPDWORD pRead);
BOOL LoadWininet( VOID );
//
// Public functions.
//
int __cdecl main( int argc, char * argv[] ) { LPSTR host = NULL; LPSTR verb = NULL; LPSTR object = NULL;
if ( !LoadWininet() ) { printf(" Unable to load wininet.dll, error %d\n", GetLastError() ); return GetLastError(); }
for (--argc, ++argv; argc; --argc, ++argv) { if (IS_ARG(**argv)) { switch (*++*argv) { case '?': usage(); break;
case 'c': EnableCallbacks = TRUE; break;
case 'C': Cache = TRUE; break;
case 'G': printf("'G' flag is not supported at this time\n"); GatewayServer = ++*argv; //AccessType = GATEWAY_INTERNET_ACCESS;
break;
case 'i':
if ( isdigit( argv[0][1] )) { cIterations = atoi( ++*argv );
while ( isdigit( *(*argv)++ )) ; } break;
case 'k': KeepAlive = TRUE; break;
case 'l': LargeBuf = TRUE; break;
case 'L': AccessType = LOCAL_INTERNET_ACCESS; break;
case 'p': object = ++*argv; break;
case 'P':
if ( isdigit( argv[0][1] )) { nServerPort = (INTERNET_PORT)atoi( ++*argv );
while ( isdigit( *(*argv)++ )) ; } break;
case 'q': Quiet = TRUE; break;
case 'r': Recurse = TRUE;
if ( isdigit( argv[0][1] )) { cMaxLevel = atoi( ++*argv );
while ( isdigit( *(*argv)++ )) ; } break;
case 's': Stats = TRUE; cmsecStart = GetTickCount(); break;
case 'v': Verbose = TRUE; break;
case 'x': ++*argv; if (!**argv) { Context = DEFAULT_CONTEXT; } else { Context = (DWORD)strtoul(*argv, NULL, 0); UserSuppliedContext = TRUE; } break;
case 'y': AsyncMode = TRUE; break;
case 'z': Logs = TRUE; cmsecStart = GetTickCount(); break;
default: printf("error: unrecognized command line flag: '%c'\n", **argv); usage(); } } else if (!host) { host = *argv; } else if (!verb) { verb = *argv; } else if (!object) { object = *argv; } else { printf("error: unrecognized command line argument: \"%s\"\n", *argv); usage(); } }
if (!verb) { verb = "GET"; }
if (!object) { object = "\r\n"; }
if (!(host && verb && object)) { printf("error: missing command-line argument\n"); usage(); }
if (AsyncMode) {
//
// create an auto-reset event
//
AsyncEvent = CreateEvent(NULL, FALSE, FALSE, NULL); }
//
// Make stdout "binary" so we can retrieve GIFs, JPEGs, etc.
//
_setmode( _fileno( stdout ), _O_BINARY );
//
// Perform some tests.
//
while ( cIterations-- ) { DWORD Error;
Error = DoTest(host, verb, object );
if( Error != ERROR_SUCCESS ) { LogError = Error; } }
if ( Stats ) { DWORD csecTotal = (GetTickCount() - cmsecStart) / 1000; DWORD cMin = csecTotal / 60; DWORD cSec = csecTotal % 60;
fprintf( stderr, "=====================================\n" "Total data bytes received: %ld\n" "Total files retrieved: %ld\n" "Total time: %d:%d\n" "=====================================\n", cbReceived, cFiles, cMin, cSec ); }
if ( Logs ) { DWORD csecTotal = (GetTickCount() - cmsecStart) ; SYSTEMTIME SystemTime;
GetLocalTime( &SystemTime );
fprintf( stderr, "LOG: [%02u/%02u %02u:%02u:%02u] " "%-10s %-32s %4s %8d %8d\n", SystemTime.wMonth, SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond, GatewayServer, host, object, LogError, csecTotal ); }
return 0;
} // main
void usage() { printf("usage: thttp [-c] [-C] [-l] [-L] [-k] [-p<path>] [-q] [-r] [-s] [-v] [-P]\n" " [-x$] [-y] [-z] [-G<servername>] <host> [<verb>] [<object>]\n" "\n" "where: -c = Enable call-backs\n" " -C = Enable caching\n" " -i[n] = Iterate n times\n" " -l = Large network buffer\n" " -L = Force local access (i.e., do not use gateway)\n" " -k = Use Keep-Alive\n" " -p = path (e.g. if path starts with '/')\n" " -q = Quiet mode, no failed headers, no content\n" " -r[n] = Recurse into links, n = max recurse level\n" " -s = Print network statistics\n" " -v = Verbose mode\n" " -G = specific gateway server\n" " -P[n] = Use port n; default = 80\n" " -x = Context value. $ is number string (binary, hex, decimal)\n" " -y = Async mode\n" " -z = print log\n" "Verb defaults to \"GET\"\n" "Object defaults to \"\\r\\n\"\n" ); exit(1); }
BOOL LoadWininet( VOID ) { if ( !(hWininet = LoadLibrary( "wininet.dll" )) ) { printf("Failed to load wininet.dll\n" ); return FALSE; }
if ( !LOAD_ENTRY( hWininet, InternetOpenA ) || !LOAD_ENTRY( hWininet, InternetSetStatusCallback ) || !LOAD_ENTRY( hWininet, InternetConnectA ) || !LOAD_ENTRY( hWininet, HttpOpenRequestA ) || !LOAD_ENTRY( hWininet, HttpAddRequestHeadersA ) || !LOAD_ENTRY( hWininet, HttpSendRequestA ) || !LOAD_ENTRY( hWininet, HttpQueryInfoA ) || !LOAD_ENTRY( hWininet, InternetCloseHandle ) || !LOAD_ENTRY( hWininet, InternetReadFile ) ) { return FALSE; }
return TRUE; }
DWORD DoTest( LPSTR Host, LPSTR Verb, LPSTR Object ) { DWORD Error = ERROR_SUCCESS; HINTERNET InternetHandle = NULL; HINTERNET InternetConnectHandle = NULL; HINTERNET hhttp = NULL; DWORD len; int i; CHAR buf[8192]; CHAR bufLink[512]; BOOL fCopyingLink = FALSE;
*bufLink = '\0';
//
// open internet.
//
if (Verbose) { printf("calling InternetOpen()...\n"); }
InternetHandle = pInternetOpenA( "THTTP: HTTP API Test Application", // lpszCallerName
AccessType, // dwAccessType
GatewayServer, // lpszProxyName
INTERNET_INVALID_PORT_NUMBER, // nProxyPort
AsyncMode ? INTERNET_FLAG_ASYNC : 0 // dwFlags (async)
); if (InternetHandle == NULL) { if (AsyncMode) { Error = GetLastError(); if (Error == ERROR_IO_PENDING) { if (Verbose) { fprintf(stderr, "error: InternetOpen() is async (spanish inquisition mode)\n"); printf("waiting for async InternetOpen()...\n"); } WaitForSingleObject(AsyncEvent, INFINITE); if (AsyncResult == 0) { fprintf(stderr, "error: async InternetOpen() returns %d\n", AsyncError); goto Cleanup; } else { InternetHandle = (HINTERNET)AsyncResult; } } else { fprintf(stderr, "error: async InternetOpen() returns %d\n", Error); goto Cleanup; } } else { fprintf( stderr, "InternetOpen() failed, error %d\n", Error = GetLastError() );
goto Cleanup; } }
if (Verbose) { printf("InternetOpen() returns %x\n", InternetHandle); }
if (EnableCallbacks) {
//
// let's have a status callback
//
// Note that call-backs can be set even before we have opened a handle
// to the internet/gateway
//
PreviousCallback = pInternetSetStatusCallback(InternetHandle, my_callback); if (Verbose) { printf("previous Internet callback = %x\n", PreviousCallback); } }
//
// Call internet connect to connect to the http server.
//
if (Verbose) { printf("calling InternetConnect()...\n"); }
InternetConnectHandle = pInternetConnectA( InternetHandle, // hInternetSession
Host, // lpszServerName
nServerPort, // nServerPort
NULL, // lpszUserName
NULL, // lpszPassword
INTERNET_SERVICE_HTTP, // dwService
0, // dwFlags
UserSuppliedContext ? Context : CONNECT_CONTEXT );
if( InternetConnectHandle == NULL ) { if (AsyncMode) { Error = GetLastError(); if (Error == ERROR_IO_PENDING) { if (Verbose) { fprintf(stderr, "error: InternetConnect() is async (spanish inquisition mode)\n"); printf("waiting for async InternetConnect()...\n"); } WaitForSingleObject(AsyncEvent, INFINITE); if (AsyncResult == 0) { fprintf(stderr, "error: async InternetConnect() returns %d\n", AsyncError); goto Cleanup; } else { InternetConnectHandle = (HINTERNET)AsyncResult; } } else { fprintf(stderr, "error: async InternetConnect() returns %d\n", Error); goto Cleanup; } } else { fprintf( stderr, "InternetConnect() failed, error %d\n", Error = GetLastError() );
goto Cleanup; } }
if (Verbose) { printf("InternetConnect() returns %x\n", InternetConnectHandle); }
//
// Open a request handle.
//
if (Verbose) { printf("calling HttpOpenRequest()...\n"); }
hhttp = pHttpOpenRequestA( InternetConnectHandle, // hHttpSession
Verb, // lpszVerb
Object, // lpszObjectName
NULL, // lpszVersion
NULL, // lpszReferer
AcceptTypes, // lplpszAcceptTypes
(Cache ? 0 : INTERNET_FLAG_RELOAD), UserSuppliedContext ? Context : REQUEST_CONTEXT );
if( hhttp == NULL ) { if (AsyncMode) { Error = GetLastError(); if (Error == ERROR_IO_PENDING) { if (Verbose) { fprintf(stderr, "error: HttpOpenRequest() is async (spanish inquisition mode)\n"); printf("waiting for async HttpOpenRequest()...\n"); } WaitForSingleObject(AsyncEvent, INFINITE); if (AsyncResult == 0) { fprintf(stderr, "error: async HttpOpenRequest() returns %d\n", AsyncError); goto Cleanup; } else { hhttp = (HINTERNET)AsyncResult; } } else { fprintf(stderr, "error: async HttpOpenRequest() returns %d\n", Error); goto Cleanup; } } else { fprintf( stderr, "HttpOpenRequest() failed, error %d\n", Error = GetLastError() );
goto Cleanup; } }
if (Verbose) { printf("HttpOpenRequest() returns %x\n", hhttp); }
//
// add keep-alive header if requested
//
if (KeepAlive) { if (!add_headers(hhttp, "Connection: Keep-Alive\r\n", (DWORD)-1)) { fprintf(stderr, "HttpAddRequestHeaders() returns %d\n", GetLastError()); } }
//
// Add additional request headers.
//
if( !add_headers( hhttp, "Pragma: bite-me\r\n", (DWORD)-1L ) ) { fprintf( stderr, "HttpAddRequestHeaders() failed, error %d\n", GetLastError() ); }
if( !add_headers( hhttp, "Pragma: bite-me-again\r\n", (DWORD)-1L ) ) { fprintf( stderr, "HttpAddRequestHeaders() failed, error %d\n", GetLastError() ); }
if( !add_headers( hhttp, "Pragma: bite-me-a-third-time\r\n", (DWORD)-1L ) ) { fprintf( stderr, "HttpAddRequestHeaders() failed, error %d\n", GetLastError() ); }
//
// Send the request.
//
if (Verbose) { printf("calling HttpSendRequest()...\n"); }
if( !pHttpSendRequestA( hhttp, // hHttpRequest
MoreHeaders, // lpszHeaders
(DWORD)-1L, // dwHeadersLength
NULL, // lpOptional
0 ) ) // dwOptionalLength
{ if (AsyncMode) { Error = GetLastError(); if (Error == ERROR_IO_PENDING) { if (Verbose) { printf("HttpSendRequest() waiting for async completion\n"); } WaitForSingleObject(AsyncEvent, INFINITE); Error = AsyncError; if (!AsyncResult) { printf("error: ASYNC HttpSendRequest() returns FALSE\n"); if (Error == ERROR_SUCCESS) { printf("error: ASYNC HttpSendRequest() (FALSE) returns ERROR_SUCCESS!\n"); } else { printf("ASYNC HttpSendRequest() returns %d\n", Error); } } else if (Verbose) { printf("ASYNC HttpSendRequest() success\n"); } } else { printf("error: ASYNC HttpSendRequest() returns %d\n", Error); } } else { fprintf( stderr, "HttpSendRequest() failed, error %d\n", Error = GetLastError() ); } } else if (AsyncMode) {
//
// we expect async HttpSendRequest() to always return FALSE w/ error
// or ERROR_IO_PENDING
//
printf("ASYNC HttpSendRequest() returns TRUE\n"); // } else {
//
// Error is still ERROR_SUCCESS from initialization
//
}
if (Error == ERROR_SUCCESS) {
//
// Process the queries.
//
if ( Quiet ) { len = sizeof(buf);
//
// Only look for failures to retrieve if we're in quiet mode
//
if ( !pHttpQueryInfoA( hhttp, HTTP_QUERY_STATUS_CODE, buf, &len, NULL )) { fprintf( stderr, "HttpQueryInfo( HTTP_QUERY_STATUS_CODE ) failed, error %d\n", GetLastError() ); }
if ( *buf != '2' ) { Error = atoi(buf); goto PrintAllHeaders; }
cFiles++; } else { PrintAllHeaders:
if( !Logs ) { for( i = 0 ; i < NUM_LEVELS ; i++ ) { len = sizeof(buf);
if( !pHttpQueryInfoA( hhttp, QueryLevels[i].QueryType, buf, &len, NULL ) ) { if ( QueryLevels[i].QueryType == HTTP_QUERY_STATUS_CODE && *buf == '2' ) { cFiles++; }
if ( !Quiet && GetLastError() != ERROR_HTTP_HEADER_NOT_FOUND ) { fprintf( stderr, "HttpQueryInfo( %s ) failed, error %d\n", QueryLevels[i].QueryName, GetLastError() ); } } else { fprintf( stderr, "%s = %s\n", QueryLevels[i].QueryName, buf ); } } } }
//
// Read the data.
//
for( ; ; ) { len = LargeBuf ? sizeof(buf) : 512;
Error = ReadHtml(hhttp, buf, len, &len); if (Error != ERROR_SUCCESS) { fprintf( stderr, "InternetReadFile() failed, error %d\n", Error = GetLastError() );
break; }
cbReceived += len;
if( len == 0 ) { if ( !Quiet ) { fprintf( stderr, "EOF\n" ); }
break; }
if ( !Quiet ) { fwrite( buf, 1, (size_t)len, stdout ); }
if ( Recurse && cLevel < cMaxLevel ) { CHAR ContentType[50]; DWORD cbContentType = sizeof( ContentType );
//
// Only look for links if the content type is text/html
//
if( pHttpQueryInfoA( hhttp, HTTP_QUERY_CONTENT_TYPE, ContentType, &cbContentType, NULL ) && !_stricmp( ContentType, "text/html" )) { FindLink( Host, Verb, buf, len, bufLink, &fCopyingLink, Object ); } } }
//
// Perform an extraneous read.
//
len = sizeof(buf);
Error = ReadHtml(hhttp, buf, len, &len); if (Error != ERROR_SUCCESS) { fprintf( stderr, "InternetReadFile() failed, error %d\n", Error = GetLastError() ); } else if( len != 0 ) { fprintf( stderr, "BOGUS EXTRANEOUS READ: %d\n", len ); } }
Cleanup:
//
// Close handles.
//
if( hhttp != NULL ) { if( !pInternetCloseHandle( hhttp ) ) { fprintf( stderr, "InternetCloseHandle() failed, error %d\n", GetLastError() ); } }
if( InternetConnectHandle != NULL ) { if( !pInternetCloseHandle( InternetConnectHandle ) ) { fprintf( stderr, "InternetCloseHandle() failed, error %d\n", GetLastError() ); } }
if( InternetHandle != NULL ) { if( !pInternetCloseHandle( InternetHandle ) ) { fprintf( stderr, "InternetCloseHandle() failed, error %d\n", GetLastError() ); } }
cLevel--; return( Error ); } // DoTest
BOOL add_headers( HINTERNET hHttpRequest, LPSTR lpszHeaders, DWORD dwHeadersLength ) { BOOL ok;
ok = pHttpAddRequestHeadersA(hHttpRequest, lpszHeaders, dwHeadersLength, 0); if (AsyncMode) { if (!ok) {
DWORD err;
err = GetLastError(); if (err == ERROR_IO_PENDING) { if (Verbose) { printf("warning: HttpAddRequestHeaders() is async - unexpected\n"); printf("waiting for async HttpAddRequestHeaders()...\n"); } WaitForSingleObject(AsyncEvent, INFINITE); ok = (BOOL)AsyncResult; if (!ok) { printf("error: async HttpAddRequestHeaders() returns %d\n", AsyncError); } } else { printf("error: async HttpAddRequestHeaders() returns %d\n", err); } } } return ok; }
VOID my_callback( HINTERNET hInternet, DWORD Context, DWORD Status, LPVOID Info, DWORD Length ) { char* type$; BOOL unknown = FALSE;
switch (Status) { case INTERNET_STATUS_RESOLVING_NAME: type$ = "RESOLVING NAME"; break;
case INTERNET_STATUS_NAME_RESOLVED: type$ = "NAME RESOLVED"; break;
case INTERNET_STATUS_CONNECTING_TO_SERVER: type$ = "CONNECTING TO SERVER"; break;
case INTERNET_STATUS_CONNECTED_TO_SERVER: type$ = "CONNECTED TO SERVER"; break;
case INTERNET_STATUS_SENDING_REQUEST: type$ = "SENDING REQUEST"; break;
case INTERNET_STATUS_REQUEST_SENT: type$ = "REQUEST SENT"; break;
case INTERNET_STATUS_RECEIVING_RESPONSE: type$ = "RECEIVING RESPONSE"; break;
case INTERNET_STATUS_RESPONSE_RECEIVED: type$ = "RESPONSE RECEIVED"; break;
case INTERNET_STATUS_CLOSING_CONNECTION: type$ = "CLOSING CONNECTION"; break;
case INTERNET_STATUS_CONNECTION_CLOSED: type$ = "CONNECTION CLOSED"; break;
case INTERNET_STATUS_REQUEST_COMPLETE: type$ = "REQUEST COMPLETE"; if (AsyncMode) { AsyncResult = ((LPINTERNET_ASYNC_RESULT)Info)->dwResult; AsyncError = ((LPINTERNET_ASYNC_RESULT)Info)->dwError; SetEvent(AsyncEvent); } else { printf("error: REQUEST_COMPLETE not expected - not async\n"); } break;
default: type$ = "???"; unknown = TRUE; break; } if (Verbose) { printf("callback: handle %x [context %x [%s]] %s ", hInternet, Context, UserSuppliedContext ? "User" : (Context == DEFAULT_CONTEXT) ? "Default" : (Context == OPEN_CONTEXT) ? "Open" : (Context == CONNECT_CONTEXT) ? "Connect" : (Context == REQUEST_CONTEXT) ? "Request" : "???", type$ ); if (Info && !unknown) { if (Status == INTERNET_STATUS_REQUEST_COMPLETE) { if (Verbose) { printf("dwResult = %x, dwError = %d\n", ((LPINTERNET_ASYNC_RESULT)Info)->dwResult, ((LPINTERNET_ASYNC_RESULT)Info)->dwError ); } } else { printf(Info); } } putchar('\n'); } }
VOID FindLink( LPSTR Host, LPSTR Verb, CHAR * buf, DWORD len, CHAR * pchLink, BOOL * pfCopyingLink, CHAR * pchReferer ) { DWORD Error; CHAR * pchEnd = buf + len; CHAR * pch = buf; DWORD cchLink = strlen( pchLink );
while ( TRUE ) { if ( *pfCopyingLink ) { FindEOT: //
// Look for end of href
//
while ( pch < pchEnd ) { if ( *pch == '"' ) goto FoundEOT;
pchLink[cchLink++] = *pch;
pch++; }
//
// Used up all of the buffer and we didn't find the end of the tag,
// get some more data
//
pchLink[cchLink] = '\0';
return;
FoundEOT: pchLink[cchLink] = '\0'; *pfCopyingLink = FALSE;
//
// We only traverse URLs of the form '/dir/bar/doc.htm'
//
if ( pchLink[0] != '/' ) { CHAR * pchLastSlash; CHAR achTemp[512];
//
// If it's relative, use the referer to make it absolute
//
// Note we don't process /dir/bar/doc.htm#GoHere tags
//
if ( (pchLastSlash = strrchr( pchReferer, '/' )) && strncmp( pchLink, "ftp:", 4 ) && strncmp( pchLink, "http:", 5 ) && strncmp( pchLink, "gopher:", 7 ) && strncmp( pchLink, "mailto:", 7 ) && !strchr( pchLink, '#' )) { *(pchLastSlash + 1) = '\0'; strcpy( achTemp, pchReferer ); strcat( achTemp, pchLink ); strcpy( pchLink, achTemp ); } else { fprintf( stderr, "Ignoring %s\n", pchLink ); return; } }
fprintf( stderr, "Traversing %s\n", pchLink );
cLevel++;
Error = DoTest( Host, Verb, pchLink );
if( Error != ERROR_SUCCESS ) { LogError = Error; }
} else { *pchLink = '\0';
//
// Scan for the beginning of an href tag
//
while ( pch < pchEnd ) { if ( *pch == '<' ) { //
// Look for "<A HREF="", note we aren't flexible about spacing
//
if ( !_strnicmp( pch, "<A HREF=\"", 9 ) || !_strnicmp( pch, "<IMG SRC=\"", 10 )) { pch += (toupper(pch[1]) == 'A' ? 9 : 10); *pfCopyingLink = TRUE; cchLink = 0; goto FindEOT; } }
pch++; }
//
// No tag found, return
//
return; } } }
DWORD ReadHtml(HINTERNET hInternet, LPVOID buf, DWORD len, LPDWORD pRead) {
DWORD error = ERROR_SUCCESS;
if (!pInternetReadFile(hInternet, buf, len, pRead)) { if (AsyncMode) { error = GetLastError(); if (error == ERROR_IO_PENDING) { if (Verbose) { printf("ASYNC InternetReadFile() waiting for async completion\n"); } WaitForSingleObject(AsyncEvent, INFINITE); error = AsyncError; if (!AsyncResult) { printf("error: ASYNC InternetReadFile() returns FALSE\n"); if (error == ERROR_SUCCESS) { printf("error: ASYNC InternetReadFile() (FALSE) returns ERROR_SUCCESS!\n"); } else { printf("ASYNC InternetReadFile() returns %d\n", error); } } else if (Verbose) { printf("ASYNC InternetReadFile() success\n");
//
// error should be ERROR_SUCCESS from callback
//
if (error != ERROR_SUCCESS) { printf("error: async error = %d. Expected ERROR_SUCCESS\n", error); } } } else { printf("error: ASYNC InternetReadFile() returns %d\n", error); } } else { error = GetLastError(); printf("error: SYNC InternetReadFile() returns %d\n", error); } } else if (AsyncMode) {
//
// we expect async InternetReadFile() to always return FALSE w/ error
// or ERROR_IO_PENDING
//
if (Verbose) { printf("ASYNC InternetReadFile() returns TRUE\n"); } } else {
//
// error is still ERROR_SUCCESS from initialization
//
if (Verbose) { printf("SYNC InternetReadFile() returns TRUE\n"); } } return error; }
|