Source code of Windows XP (NT5)
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.

1397 lines
35 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. thttp.c
  5. Abstract:
  6. Simple test program for the HTTP API.
  7. Author:
  8. Keith Moore (keithmo) 16-Nov-1994
  9. Revision History:
  10. --*/
  11. #include <windows.h>
  12. #include <wininet.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <fcntl.h>
  17. #include <io.h>
  18. //
  19. // macros
  20. //
  21. #define IS_ARG(c) ((c) == '-')
  22. //
  23. // Private constants.
  24. //
  25. #define DEFAULT_CONTEXT 1
  26. #define OPEN_CONTEXT 2
  27. #define CONNECT_CONTEXT 3
  28. #define REQUEST_CONTEXT 4
  29. #define LOAD_ENTRY( hMod, Name ) \
  30. (p##Name = (pfn##Name) GetProcAddress( (hMod), #Name ))
  31. //
  32. // Private types.
  33. //
  34. typedef struct _QUERY_LEVEL
  35. {
  36. DWORD QueryType;
  37. CHAR * QueryName;
  38. } QUERY_LEVEL;
  39. #define MK_QUERY(x) { HTTP_QUERY_ ## x, #x }
  40. typedef
  41. INTERNETAPI
  42. HINTERNET
  43. (WINAPI *
  44. pfnInternetOpenA)(
  45. IN LPCSTR lpszAgent,
  46. IN DWORD dwAccessType,
  47. IN LPCSTR lpszProxy OPTIONAL,
  48. IN LPCSTR lpszProxyBypass OPTIONAL,
  49. IN DWORD dwFlags
  50. );
  51. typedef
  52. INTERNETAPI
  53. INTERNET_STATUS_CALLBACK
  54. (WINAPI *
  55. pfnInternetSetStatusCallback)(
  56. IN HINTERNET hInternet,
  57. IN INTERNET_STATUS_CALLBACK lpfnInternetCallback
  58. );
  59. typedef
  60. INTERNETAPI
  61. HINTERNET
  62. (WINAPI *
  63. pfnInternetConnectA)(
  64. IN HINTERNET hInternet,
  65. IN LPCSTR lpszServerName,
  66. IN INTERNET_PORT nServerPort,
  67. IN LPCSTR lpszUserName OPTIONAL,
  68. IN LPCSTR lpszPassword OPTIONAL,
  69. IN DWORD dwService,
  70. IN DWORD dwFlags,
  71. IN DWORD dwContext
  72. );
  73. typedef
  74. INTERNETAPI
  75. HINTERNET
  76. (WINAPI *
  77. pfnHttpOpenRequestA)(
  78. IN HINTERNET hConnect,
  79. IN LPCSTR lpszVerb,
  80. IN LPCSTR lpszObjectName,
  81. IN LPCSTR lpszVersion,
  82. IN LPCSTR lpszReferrer OPTIONAL,
  83. IN LPCSTR FAR * lplpszAcceptTypes OPTIONAL,
  84. IN DWORD dwFlags,
  85. IN DWORD dwContext
  86. );
  87. typedef
  88. INTERNETAPI
  89. BOOL
  90. (WINAPI *
  91. pfnHttpAddRequestHeadersA)(
  92. IN HINTERNET hRequest,
  93. IN LPCSTR lpszHeaders,
  94. IN DWORD dwHeadersLength,
  95. IN DWORD dwModifiers
  96. );
  97. typedef
  98. INTERNETAPI
  99. BOOL
  100. (WINAPI *
  101. pfnHttpSendRequestA)(
  102. IN HINTERNET hRequest,
  103. IN LPCSTR lpszHeaders OPTIONAL,
  104. IN DWORD dwHeadersLength,
  105. IN LPVOID lpOptional OPTIONAL,
  106. IN DWORD dwOptionalLength
  107. );
  108. typedef
  109. INTERNETAPI
  110. BOOL
  111. (WINAPI *
  112. pfnHttpQueryInfoA)(
  113. IN HINTERNET hRequest,
  114. IN DWORD dwInfoLevel,
  115. IN OUT LPVOID lpBuffer OPTIONAL,
  116. IN OUT LPDWORD lpdwBufferLength,
  117. IN OUT LPDWORD lpdwIndex OPTIONAL
  118. );
  119. typedef
  120. INTERNETAPI
  121. BOOL
  122. (WINAPI *
  123. pfnInternetCloseHandle)(
  124. IN HINTERNET hInternet
  125. );
  126. typedef
  127. INTERNETAPI
  128. BOOL
  129. (WINAPI *
  130. pfnInternetReadFile)(
  131. IN HINTERNET hFile,
  132. IN LPVOID lpBuffer,
  133. IN DWORD dwNumberOfBytesToRead,
  134. OUT LPDWORD lpdwNumberOfBytesRead
  135. );
  136. //
  137. // Private globals.
  138. //
  139. CHAR MoreHeaders[] = "Pragma: This is garbage!\r\n";
  140. HMODULE hWininet;
  141. LPTSTR AcceptTypes[] =
  142. {
  143. "*/*",
  144. NULL
  145. };
  146. QUERY_LEVEL QueryLevels[] =
  147. {
  148. MK_QUERY( STATUS_CODE ),
  149. MK_QUERY( STATUS_TEXT ),
  150. MK_QUERY( VERSION ),
  151. MK_QUERY( MIME_VERSION ),
  152. MK_QUERY( CONTENT_TYPE ),
  153. MK_QUERY( CONTENT_TRANSFER_ENCODING ),
  154. MK_QUERY( CONTENT_ID ),
  155. MK_QUERY( CONTENT_DESCRIPTION ),
  156. MK_QUERY( CONTENT_LENGTH ),
  157. MK_QUERY( CONTENT_LANGUAGE ),
  158. MK_QUERY( ALLOW ),
  159. MK_QUERY( PUBLIC ),
  160. MK_QUERY( DATE ),
  161. MK_QUERY( EXPIRES ),
  162. MK_QUERY( LAST_MODIFIED ),
  163. MK_QUERY( MESSAGE_ID ),
  164. MK_QUERY( URI ),
  165. MK_QUERY( DERIVED_FROM ),
  166. MK_QUERY( COST ),
  167. MK_QUERY( LINK ),
  168. MK_QUERY( PRAGMA ),
  169. MK_QUERY( CONNECTION ),
  170. MK_QUERY( RAW_HEADERS_CRLF )
  171. };
  172. #define NUM_LEVELS (sizeof(QueryLevels) / sizeof(QueryLevels[0]))
  173. BOOL Verbose = FALSE;
  174. BOOL Quiet = FALSE; // Don't print failed headers and content
  175. BOOL Recurse = FALSE; // Follow links
  176. BOOL Cache = FALSE; // Don't allow caching (i.e., force reload)
  177. BOOL Stats = FALSE; // Print stats
  178. BOOL Logs = FALSE; // Print log
  179. BOOL LargeBuf= TRUE; // Use 8k reads rather then 512 byte
  180. BOOL KeepAlive = FALSE;
  181. DWORD AccessType = PRE_CONFIG_INTERNET_ACCESS;
  182. BOOL EnableCallbacks = FALSE;
  183. BOOL UserSuppliedContext = FALSE;
  184. INTERNET_STATUS_CALLBACK PreviousCallback;
  185. DWORD cLevel = 0; // Current recurse level
  186. DWORD cMaxLevel = 10; // Max Recurse level
  187. DWORD cbReceived = 0;
  188. DWORD cmsecStart = 0;
  189. DWORD cFiles = 0;
  190. DWORD cIterations= 1; // Total iterations to perform request
  191. LPSTR GatewayServer = NULL;
  192. INTERNET_PORT nServerPort = 0;
  193. DWORD LogError = ERROR_SUCCESS;
  194. HANDLE AsyncEvent = NULL;
  195. BOOL AsyncMode = FALSE;
  196. DWORD AsyncResult;
  197. DWORD AsyncError;
  198. DWORD Context = 0;
  199. pfnInternetOpenA pInternetOpenA;
  200. pfnInternetSetStatusCallback pInternetSetStatusCallback;
  201. pfnInternetConnectA pInternetConnectA;
  202. pfnHttpOpenRequestA pHttpOpenRequestA;
  203. pfnHttpAddRequestHeadersA pHttpAddRequestHeadersA;
  204. pfnHttpSendRequestA pHttpSendRequestA;
  205. pfnHttpQueryInfoA pHttpQueryInfoA;
  206. pfnInternetCloseHandle pInternetCloseHandle;
  207. pfnInternetReadFile pInternetReadFile;
  208. //
  209. // Private prototypes.
  210. //
  211. void usage(void);
  212. DWORD
  213. DoTest(
  214. LPSTR Host,
  215. LPSTR Verb,
  216. LPSTR Object
  217. );
  218. BOOL
  219. add_headers(
  220. HINTERNET hHttpRequest,
  221. LPSTR lpszHeaders,
  222. DWORD dwHeadersLength
  223. );
  224. void my_callback(HINTERNET, DWORD, DWORD, LPVOID, DWORD);
  225. VOID
  226. FindLink(
  227. LPSTR Host,
  228. LPSTR Verb,
  229. CHAR * buf,
  230. DWORD len,
  231. CHAR * pchLink,
  232. BOOL * pfCopyingLink,
  233. CHAR * pchReferer
  234. );
  235. DWORD ReadHtml(HINTERNET hInternet, LPVOID buf, DWORD len, LPDWORD pRead);
  236. BOOL
  237. LoadWininet(
  238. VOID
  239. );
  240. //
  241. // Public functions.
  242. //
  243. int
  244. __cdecl
  245. main(
  246. int argc,
  247. char * argv[]
  248. )
  249. {
  250. LPSTR host = NULL;
  251. LPSTR verb = NULL;
  252. LPSTR object = NULL;
  253. if ( !LoadWininet() )
  254. {
  255. printf(" Unable to load wininet.dll, error %d\n", GetLastError() );
  256. return GetLastError();
  257. }
  258. for (--argc, ++argv; argc; --argc, ++argv) {
  259. if (IS_ARG(**argv)) {
  260. switch (*++*argv) {
  261. case '?':
  262. usage();
  263. break;
  264. case 'c':
  265. EnableCallbacks = TRUE;
  266. break;
  267. case 'C':
  268. Cache = TRUE;
  269. break;
  270. case 'G':
  271. printf("'G' flag is not supported at this time\n");
  272. GatewayServer = ++*argv;
  273. //AccessType = GATEWAY_INTERNET_ACCESS;
  274. break;
  275. case 'i':
  276. if ( isdigit( argv[0][1] ))
  277. {
  278. cIterations = atoi( ++*argv );
  279. while ( isdigit( *(*argv)++ ))
  280. ;
  281. }
  282. break;
  283. case 'k':
  284. KeepAlive = TRUE;
  285. break;
  286. case 'l':
  287. LargeBuf = TRUE;
  288. break;
  289. case 'L':
  290. AccessType = LOCAL_INTERNET_ACCESS;
  291. break;
  292. case 'p':
  293. object = ++*argv;
  294. break;
  295. case 'P':
  296. if ( isdigit( argv[0][1] ))
  297. {
  298. nServerPort = (INTERNET_PORT)atoi( ++*argv );
  299. while ( isdigit( *(*argv)++ ))
  300. ;
  301. }
  302. break;
  303. case 'q':
  304. Quiet = TRUE;
  305. break;
  306. case 'r':
  307. Recurse = TRUE;
  308. if ( isdigit( argv[0][1] ))
  309. {
  310. cMaxLevel = atoi( ++*argv );
  311. while ( isdigit( *(*argv)++ ))
  312. ;
  313. }
  314. break;
  315. case 's':
  316. Stats = TRUE;
  317. cmsecStart = GetTickCount();
  318. break;
  319. case 'v':
  320. Verbose = TRUE;
  321. break;
  322. case 'x':
  323. ++*argv;
  324. if (!**argv) {
  325. Context = DEFAULT_CONTEXT;
  326. } else {
  327. Context = (DWORD)strtoul(*argv, NULL, 0);
  328. UserSuppliedContext = TRUE;
  329. }
  330. break;
  331. case 'y':
  332. AsyncMode = TRUE;
  333. break;
  334. case 'z':
  335. Logs = TRUE;
  336. cmsecStart = GetTickCount();
  337. break;
  338. default:
  339. printf("error: unrecognized command line flag: '%c'\n", **argv);
  340. usage();
  341. }
  342. } else if (!host) {
  343. host = *argv;
  344. } else if (!verb) {
  345. verb = *argv;
  346. } else if (!object) {
  347. object = *argv;
  348. } else {
  349. printf("error: unrecognized command line argument: \"%s\"\n", *argv);
  350. usage();
  351. }
  352. }
  353. if (!verb) {
  354. verb = "GET";
  355. }
  356. if (!object) {
  357. object = "\r\n";
  358. }
  359. if (!(host && verb && object)) {
  360. printf("error: missing command-line argument\n");
  361. usage();
  362. }
  363. if (AsyncMode) {
  364. //
  365. // create an auto-reset event
  366. //
  367. AsyncEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  368. }
  369. //
  370. // Make stdout "binary" so we can retrieve GIFs, JPEGs, etc.
  371. //
  372. _setmode( _fileno( stdout ), _O_BINARY );
  373. //
  374. // Perform some tests.
  375. //
  376. while ( cIterations-- )
  377. {
  378. DWORD Error;
  379. Error = DoTest(host, verb, object );
  380. if( Error != ERROR_SUCCESS ) {
  381. LogError = Error;
  382. }
  383. }
  384. if ( Stats )
  385. {
  386. DWORD csecTotal = (GetTickCount() - cmsecStart) / 1000;
  387. DWORD cMin = csecTotal / 60;
  388. DWORD cSec = csecTotal % 60;
  389. fprintf( stderr,
  390. "=====================================\n"
  391. "Total data bytes received: %ld\n"
  392. "Total files retrieved: %ld\n"
  393. "Total time: %d:%d\n"
  394. "=====================================\n",
  395. cbReceived,
  396. cFiles,
  397. cMin,
  398. cSec );
  399. }
  400. if ( Logs )
  401. {
  402. DWORD csecTotal = (GetTickCount() - cmsecStart) ;
  403. SYSTEMTIME SystemTime;
  404. GetLocalTime( &SystemTime );
  405. fprintf( stderr,
  406. "LOG: [%02u/%02u %02u:%02u:%02u] "
  407. "%-10s %-32s %4s %8d %8d\n",
  408. SystemTime.wMonth,
  409. SystemTime.wDay,
  410. SystemTime.wHour,
  411. SystemTime.wMinute,
  412. SystemTime.wSecond,
  413. GatewayServer,
  414. host,
  415. object,
  416. LogError,
  417. csecTotal );
  418. }
  419. return 0;
  420. } // main
  421. void usage() {
  422. printf("usage: thttp [-c] [-C] [-l] [-L] [-k] [-p<path>] [-q] [-r] [-s] [-v] [-P]\n"
  423. " [-x$] [-y] [-z] [-G<servername>] <host> [<verb>] [<object>]\n"
  424. "\n"
  425. "where: -c = Enable call-backs\n"
  426. " -C = Enable caching\n"
  427. " -i[n] = Iterate n times\n"
  428. " -l = Large network buffer\n"
  429. " -L = Force local access (i.e., do not use gateway)\n"
  430. " -k = Use Keep-Alive\n"
  431. " -p = path (e.g. if path starts with '/')\n"
  432. " -q = Quiet mode, no failed headers, no content\n"
  433. " -r[n] = Recurse into links, n = max recurse level\n"
  434. " -s = Print network statistics\n"
  435. " -v = Verbose mode\n"
  436. " -G = specific gateway server\n"
  437. " -P[n] = Use port n; default = 80\n"
  438. " -x = Context value. $ is number string (binary, hex, decimal)\n"
  439. " -y = Async mode\n"
  440. " -z = print log\n"
  441. "Verb defaults to \"GET\"\n"
  442. "Object defaults to \"\\r\\n\"\n"
  443. );
  444. exit(1);
  445. }
  446. BOOL
  447. LoadWininet(
  448. VOID
  449. )
  450. {
  451. if ( !(hWininet = LoadLibrary( "wininet.dll" )) )
  452. {
  453. printf("Failed to load wininet.dll\n" );
  454. return FALSE;
  455. }
  456. if ( !LOAD_ENTRY( hWininet, InternetOpenA ) ||
  457. !LOAD_ENTRY( hWininet, InternetSetStatusCallback ) ||
  458. !LOAD_ENTRY( hWininet, InternetConnectA ) ||
  459. !LOAD_ENTRY( hWininet, HttpOpenRequestA ) ||
  460. !LOAD_ENTRY( hWininet, HttpAddRequestHeadersA ) ||
  461. !LOAD_ENTRY( hWininet, HttpSendRequestA ) ||
  462. !LOAD_ENTRY( hWininet, HttpQueryInfoA ) ||
  463. !LOAD_ENTRY( hWininet, InternetCloseHandle ) ||
  464. !LOAD_ENTRY( hWininet, InternetReadFile ) )
  465. {
  466. return FALSE;
  467. }
  468. return TRUE;
  469. }
  470. DWORD
  471. DoTest(
  472. LPSTR Host,
  473. LPSTR Verb,
  474. LPSTR Object
  475. )
  476. {
  477. DWORD Error = ERROR_SUCCESS;
  478. HINTERNET InternetHandle = NULL;
  479. HINTERNET InternetConnectHandle = NULL;
  480. HINTERNET hhttp = NULL;
  481. DWORD len;
  482. int i;
  483. CHAR buf[8192];
  484. CHAR bufLink[512];
  485. BOOL fCopyingLink = FALSE;
  486. *bufLink = '\0';
  487. //
  488. // open internet.
  489. //
  490. if (Verbose) {
  491. printf("calling InternetOpen()...\n");
  492. }
  493. InternetHandle = pInternetOpenA(
  494. "THTTP: HTTP API Test Application", // lpszCallerName
  495. AccessType, // dwAccessType
  496. GatewayServer, // lpszProxyName
  497. INTERNET_INVALID_PORT_NUMBER, // nProxyPort
  498. AsyncMode ? INTERNET_FLAG_ASYNC : 0 // dwFlags (async)
  499. );
  500. if (InternetHandle == NULL) {
  501. if (AsyncMode) {
  502. Error = GetLastError();
  503. if (Error == ERROR_IO_PENDING) {
  504. if (Verbose) {
  505. fprintf(stderr, "error: InternetOpen() is async (spanish inquisition mode)\n");
  506. printf("waiting for async InternetOpen()...\n");
  507. }
  508. WaitForSingleObject(AsyncEvent, INFINITE);
  509. if (AsyncResult == 0) {
  510. fprintf(stderr, "error: async InternetOpen() returns %d\n",
  511. AsyncError);
  512. goto Cleanup;
  513. } else {
  514. InternetHandle = (HINTERNET)AsyncResult;
  515. }
  516. } else {
  517. fprintf(stderr, "error: async InternetOpen() returns %d\n", Error);
  518. goto Cleanup;
  519. }
  520. } else {
  521. fprintf( stderr,
  522. "InternetOpen() failed, error %d\n",
  523. Error = GetLastError() );
  524. goto Cleanup;
  525. }
  526. }
  527. if (Verbose) {
  528. printf("InternetOpen() returns %x\n", InternetHandle);
  529. }
  530. if (EnableCallbacks) {
  531. //
  532. // let's have a status callback
  533. //
  534. // Note that call-backs can be set even before we have opened a handle
  535. // to the internet/gateway
  536. //
  537. PreviousCallback = pInternetSetStatusCallback(InternetHandle, my_callback);
  538. if (Verbose) {
  539. printf("previous Internet callback = %x\n", PreviousCallback);
  540. }
  541. }
  542. //
  543. // Call internet connect to connect to the http server.
  544. //
  545. if (Verbose) {
  546. printf("calling InternetConnect()...\n");
  547. }
  548. InternetConnectHandle = pInternetConnectA(
  549. InternetHandle, // hInternetSession
  550. Host, // lpszServerName
  551. nServerPort, // nServerPort
  552. NULL, // lpszUserName
  553. NULL, // lpszPassword
  554. INTERNET_SERVICE_HTTP, // dwService
  555. 0, // dwFlags
  556. UserSuppliedContext ? Context : CONNECT_CONTEXT
  557. );
  558. if( InternetConnectHandle == NULL )
  559. {
  560. if (AsyncMode) {
  561. Error = GetLastError();
  562. if (Error == ERROR_IO_PENDING) {
  563. if (Verbose) {
  564. fprintf(stderr, "error: InternetConnect() is async (spanish inquisition mode)\n");
  565. printf("waiting for async InternetConnect()...\n");
  566. }
  567. WaitForSingleObject(AsyncEvent, INFINITE);
  568. if (AsyncResult == 0) {
  569. fprintf(stderr, "error: async InternetConnect() returns %d\n",
  570. AsyncError);
  571. goto Cleanup;
  572. } else {
  573. InternetConnectHandle = (HINTERNET)AsyncResult;
  574. }
  575. } else {
  576. fprintf(stderr, "error: async InternetConnect() returns %d\n", Error);
  577. goto Cleanup;
  578. }
  579. } else {
  580. fprintf( stderr,
  581. "InternetConnect() failed, error %d\n",
  582. Error = GetLastError() );
  583. goto Cleanup;
  584. }
  585. }
  586. if (Verbose) {
  587. printf("InternetConnect() returns %x\n", InternetConnectHandle);
  588. }
  589. //
  590. // Open a request handle.
  591. //
  592. if (Verbose) {
  593. printf("calling HttpOpenRequest()...\n");
  594. }
  595. hhttp = pHttpOpenRequestA(
  596. InternetConnectHandle, // hHttpSession
  597. Verb, // lpszVerb
  598. Object, // lpszObjectName
  599. NULL, // lpszVersion
  600. NULL, // lpszReferer
  601. AcceptTypes, // lplpszAcceptTypes
  602. (Cache ? 0 :
  603. INTERNET_FLAG_RELOAD),
  604. UserSuppliedContext ? Context : REQUEST_CONTEXT
  605. );
  606. if( hhttp == NULL )
  607. {
  608. if (AsyncMode) {
  609. Error = GetLastError();
  610. if (Error == ERROR_IO_PENDING) {
  611. if (Verbose) {
  612. fprintf(stderr, "error: HttpOpenRequest() is async (spanish inquisition mode)\n");
  613. printf("waiting for async HttpOpenRequest()...\n");
  614. }
  615. WaitForSingleObject(AsyncEvent, INFINITE);
  616. if (AsyncResult == 0) {
  617. fprintf(stderr, "error: async HttpOpenRequest() returns %d\n",
  618. AsyncError);
  619. goto Cleanup;
  620. } else {
  621. hhttp = (HINTERNET)AsyncResult;
  622. }
  623. } else {
  624. fprintf(stderr, "error: async HttpOpenRequest() returns %d\n", Error);
  625. goto Cleanup;
  626. }
  627. } else {
  628. fprintf( stderr,
  629. "HttpOpenRequest() failed, error %d\n",
  630. Error = GetLastError() );
  631. goto Cleanup;
  632. }
  633. }
  634. if (Verbose) {
  635. printf("HttpOpenRequest() returns %x\n", hhttp);
  636. }
  637. //
  638. // add keep-alive header if requested
  639. //
  640. if (KeepAlive) {
  641. if (!add_headers(hhttp, "Connection: Keep-Alive\r\n", (DWORD)-1)) {
  642. fprintf(stderr, "HttpAddRequestHeaders() returns %d\n", GetLastError());
  643. }
  644. }
  645. //
  646. // Add additional request headers.
  647. //
  648. if( !add_headers(
  649. hhttp,
  650. "Pragma: bite-me\r\n",
  651. (DWORD)-1L ) )
  652. {
  653. fprintf( stderr,
  654. "HttpAddRequestHeaders() failed, error %d\n",
  655. GetLastError() );
  656. }
  657. if( !add_headers(
  658. hhttp,
  659. "Pragma: bite-me-again\r\n",
  660. (DWORD)-1L ) )
  661. {
  662. fprintf( stderr,
  663. "HttpAddRequestHeaders() failed, error %d\n",
  664. GetLastError() );
  665. }
  666. if( !add_headers(
  667. hhttp,
  668. "Pragma: bite-me-a-third-time\r\n",
  669. (DWORD)-1L ) )
  670. {
  671. fprintf( stderr,
  672. "HttpAddRequestHeaders() failed, error %d\n",
  673. GetLastError() );
  674. }
  675. //
  676. // Send the request.
  677. //
  678. if (Verbose) {
  679. printf("calling HttpSendRequest()...\n");
  680. }
  681. if( !pHttpSendRequestA(
  682. hhttp, // hHttpRequest
  683. MoreHeaders, // lpszHeaders
  684. (DWORD)-1L, // dwHeadersLength
  685. NULL, // lpOptional
  686. 0 ) ) // dwOptionalLength
  687. {
  688. if (AsyncMode) {
  689. Error = GetLastError();
  690. if (Error == ERROR_IO_PENDING) {
  691. if (Verbose) {
  692. printf("HttpSendRequest() waiting for async completion\n");
  693. }
  694. WaitForSingleObject(AsyncEvent, INFINITE);
  695. Error = AsyncError;
  696. if (!AsyncResult) {
  697. printf("error: ASYNC HttpSendRequest() returns FALSE\n");
  698. if (Error == ERROR_SUCCESS) {
  699. printf("error: ASYNC HttpSendRequest() (FALSE) returns ERROR_SUCCESS!\n");
  700. } else {
  701. printf("ASYNC HttpSendRequest() returns %d\n", Error);
  702. }
  703. } else if (Verbose) {
  704. printf("ASYNC HttpSendRequest() success\n");
  705. }
  706. } else {
  707. printf("error: ASYNC HttpSendRequest() returns %d\n", Error);
  708. }
  709. } else {
  710. fprintf( stderr,
  711. "HttpSendRequest() failed, error %d\n",
  712. Error = GetLastError() );
  713. }
  714. } else if (AsyncMode) {
  715. //
  716. // we expect async HttpSendRequest() to always return FALSE w/ error
  717. // or ERROR_IO_PENDING
  718. //
  719. printf("ASYNC HttpSendRequest() returns TRUE\n");
  720. // } else {
  721. //
  722. // Error is still ERROR_SUCCESS from initialization
  723. //
  724. }
  725. if (Error == ERROR_SUCCESS) {
  726. //
  727. // Process the queries.
  728. //
  729. if ( Quiet )
  730. {
  731. len = sizeof(buf);
  732. //
  733. // Only look for failures to retrieve if we're in quiet mode
  734. //
  735. if ( !pHttpQueryInfoA(
  736. hhttp,
  737. HTTP_QUERY_STATUS_CODE,
  738. buf,
  739. &len,
  740. NULL ))
  741. {
  742. fprintf( stderr,
  743. "HttpQueryInfo( HTTP_QUERY_STATUS_CODE ) failed, error %d\n",
  744. GetLastError() );
  745. }
  746. if ( *buf != '2' )
  747. {
  748. Error = atoi(buf);
  749. goto PrintAllHeaders;
  750. }
  751. cFiles++;
  752. }
  753. else
  754. {
  755. PrintAllHeaders:
  756. if( !Logs ) {
  757. for( i = 0 ; i < NUM_LEVELS ; i++ )
  758. {
  759. len = sizeof(buf);
  760. if( !pHttpQueryInfoA(
  761. hhttp,
  762. QueryLevels[i].QueryType,
  763. buf,
  764. &len,
  765. NULL ) )
  766. {
  767. if ( QueryLevels[i].QueryType == HTTP_QUERY_STATUS_CODE &&
  768. *buf == '2' )
  769. {
  770. cFiles++;
  771. }
  772. if ( !Quiet && GetLastError() != ERROR_HTTP_HEADER_NOT_FOUND )
  773. {
  774. fprintf( stderr,
  775. "HttpQueryInfo( %s ) failed, error %d\n",
  776. QueryLevels[i].QueryName,
  777. GetLastError() );
  778. }
  779. }
  780. else
  781. {
  782. fprintf( stderr,
  783. "%s = %s\n",
  784. QueryLevels[i].QueryName,
  785. buf );
  786. }
  787. }
  788. }
  789. }
  790. //
  791. // Read the data.
  792. //
  793. for( ; ; )
  794. {
  795. len = LargeBuf ? sizeof(buf) : 512;
  796. Error = ReadHtml(hhttp, buf, len, &len);
  797. if (Error != ERROR_SUCCESS) {
  798. fprintf( stderr,
  799. "InternetReadFile() failed, error %d\n",
  800. Error = GetLastError() );
  801. break;
  802. }
  803. cbReceived += len;
  804. if( len == 0 )
  805. {
  806. if ( !Quiet )
  807. {
  808. fprintf( stderr,
  809. "EOF\n" );
  810. }
  811. break;
  812. }
  813. if ( !Quiet )
  814. {
  815. fwrite( buf, 1, (size_t)len, stdout );
  816. }
  817. if ( Recurse && cLevel < cMaxLevel )
  818. {
  819. CHAR ContentType[50];
  820. DWORD cbContentType = sizeof( ContentType );
  821. //
  822. // Only look for links if the content type is text/html
  823. //
  824. if( pHttpQueryInfoA(
  825. hhttp,
  826. HTTP_QUERY_CONTENT_TYPE,
  827. ContentType,
  828. &cbContentType,
  829. NULL ) &&
  830. !_stricmp( ContentType,
  831. "text/html" ))
  832. {
  833. FindLink( Host,
  834. Verb,
  835. buf,
  836. len,
  837. bufLink,
  838. &fCopyingLink,
  839. Object );
  840. }
  841. }
  842. }
  843. //
  844. // Perform an extraneous read.
  845. //
  846. len = sizeof(buf);
  847. Error = ReadHtml(hhttp, buf, len, &len);
  848. if (Error != ERROR_SUCCESS) {
  849. fprintf( stderr,
  850. "InternetReadFile() failed, error %d\n",
  851. Error = GetLastError() );
  852. }
  853. else
  854. if( len != 0 )
  855. {
  856. fprintf( stderr,
  857. "BOGUS EXTRANEOUS READ: %d\n",
  858. len );
  859. }
  860. }
  861. Cleanup:
  862. //
  863. // Close handles.
  864. //
  865. if( hhttp != NULL )
  866. {
  867. if( !pInternetCloseHandle( hhttp ) )
  868. {
  869. fprintf( stderr,
  870. "InternetCloseHandle() failed, error %d\n",
  871. GetLastError() );
  872. }
  873. }
  874. if( InternetConnectHandle != NULL )
  875. {
  876. if( !pInternetCloseHandle( InternetConnectHandle ) )
  877. {
  878. fprintf( stderr,
  879. "InternetCloseHandle() failed, error %d\n",
  880. GetLastError() );
  881. }
  882. }
  883. if( InternetHandle != NULL )
  884. {
  885. if( !pInternetCloseHandle( InternetHandle ) )
  886. {
  887. fprintf( stderr,
  888. "InternetCloseHandle() failed, error %d\n",
  889. GetLastError() );
  890. }
  891. }
  892. cLevel--;
  893. return( Error );
  894. } // DoTest
  895. BOOL
  896. add_headers(
  897. HINTERNET hHttpRequest,
  898. LPSTR lpszHeaders,
  899. DWORD dwHeadersLength
  900. )
  901. {
  902. BOOL ok;
  903. ok = pHttpAddRequestHeadersA(hHttpRequest, lpszHeaders, dwHeadersLength, 0);
  904. if (AsyncMode) {
  905. if (!ok) {
  906. DWORD err;
  907. err = GetLastError();
  908. if (err == ERROR_IO_PENDING) {
  909. if (Verbose) {
  910. printf("warning: HttpAddRequestHeaders() is async - unexpected\n");
  911. printf("waiting for async HttpAddRequestHeaders()...\n");
  912. }
  913. WaitForSingleObject(AsyncEvent, INFINITE);
  914. ok = (BOOL)AsyncResult;
  915. if (!ok) {
  916. printf("error: async HttpAddRequestHeaders() returns %d\n",
  917. AsyncError);
  918. }
  919. } else {
  920. printf("error: async HttpAddRequestHeaders() returns %d\n", err);
  921. }
  922. }
  923. }
  924. return ok;
  925. }
  926. VOID
  927. my_callback(
  928. HINTERNET hInternet,
  929. DWORD Context,
  930. DWORD Status,
  931. LPVOID Info,
  932. DWORD Length
  933. )
  934. {
  935. char* type$;
  936. BOOL unknown = FALSE;
  937. switch (Status) {
  938. case INTERNET_STATUS_RESOLVING_NAME:
  939. type$ = "RESOLVING NAME";
  940. break;
  941. case INTERNET_STATUS_NAME_RESOLVED:
  942. type$ = "NAME RESOLVED";
  943. break;
  944. case INTERNET_STATUS_CONNECTING_TO_SERVER:
  945. type$ = "CONNECTING TO SERVER";
  946. break;
  947. case INTERNET_STATUS_CONNECTED_TO_SERVER:
  948. type$ = "CONNECTED TO SERVER";
  949. break;
  950. case INTERNET_STATUS_SENDING_REQUEST:
  951. type$ = "SENDING REQUEST";
  952. break;
  953. case INTERNET_STATUS_REQUEST_SENT:
  954. type$ = "REQUEST SENT";
  955. break;
  956. case INTERNET_STATUS_RECEIVING_RESPONSE:
  957. type$ = "RECEIVING RESPONSE";
  958. break;
  959. case INTERNET_STATUS_RESPONSE_RECEIVED:
  960. type$ = "RESPONSE RECEIVED";
  961. break;
  962. case INTERNET_STATUS_CLOSING_CONNECTION:
  963. type$ = "CLOSING CONNECTION";
  964. break;
  965. case INTERNET_STATUS_CONNECTION_CLOSED:
  966. type$ = "CONNECTION CLOSED";
  967. break;
  968. case INTERNET_STATUS_REQUEST_COMPLETE:
  969. type$ = "REQUEST COMPLETE";
  970. if (AsyncMode) {
  971. AsyncResult = ((LPINTERNET_ASYNC_RESULT)Info)->dwResult;
  972. AsyncError = ((LPINTERNET_ASYNC_RESULT)Info)->dwError;
  973. SetEvent(AsyncEvent);
  974. } else {
  975. printf("error: REQUEST_COMPLETE not expected - not async\n");
  976. }
  977. break;
  978. default:
  979. type$ = "???";
  980. unknown = TRUE;
  981. break;
  982. }
  983. if (Verbose) {
  984. printf("callback: handle %x [context %x [%s]] %s ",
  985. hInternet,
  986. Context,
  987. UserSuppliedContext ? "User"
  988. : (Context == DEFAULT_CONTEXT) ? "Default"
  989. : (Context == OPEN_CONTEXT) ? "Open"
  990. : (Context == CONNECT_CONTEXT) ? "Connect"
  991. : (Context == REQUEST_CONTEXT) ? "Request"
  992. : "???",
  993. type$
  994. );
  995. if (Info && !unknown) {
  996. if (Status == INTERNET_STATUS_REQUEST_COMPLETE) {
  997. if (Verbose) {
  998. printf("dwResult = %x, dwError = %d\n",
  999. ((LPINTERNET_ASYNC_RESULT)Info)->dwResult,
  1000. ((LPINTERNET_ASYNC_RESULT)Info)->dwError
  1001. );
  1002. }
  1003. } else {
  1004. printf(Info);
  1005. }
  1006. }
  1007. putchar('\n');
  1008. }
  1009. }
  1010. VOID
  1011. FindLink(
  1012. LPSTR Host,
  1013. LPSTR Verb,
  1014. CHAR * buf,
  1015. DWORD len,
  1016. CHAR * pchLink,
  1017. BOOL * pfCopyingLink,
  1018. CHAR * pchReferer
  1019. )
  1020. {
  1021. DWORD Error;
  1022. CHAR * pchEnd = buf + len;
  1023. CHAR * pch = buf;
  1024. DWORD cchLink = strlen( pchLink );
  1025. while ( TRUE )
  1026. {
  1027. if ( *pfCopyingLink )
  1028. {
  1029. FindEOT:
  1030. //
  1031. // Look for end of href
  1032. //
  1033. while ( pch < pchEnd )
  1034. {
  1035. if ( *pch == '"' )
  1036. goto FoundEOT;
  1037. pchLink[cchLink++] = *pch;
  1038. pch++;
  1039. }
  1040. //
  1041. // Used up all of the buffer and we didn't find the end of the tag,
  1042. // get some more data
  1043. //
  1044. pchLink[cchLink] = '\0';
  1045. return;
  1046. FoundEOT:
  1047. pchLink[cchLink] = '\0';
  1048. *pfCopyingLink = FALSE;
  1049. //
  1050. // We only traverse URLs of the form '/dir/bar/doc.htm'
  1051. //
  1052. if ( pchLink[0] != '/' )
  1053. {
  1054. CHAR * pchLastSlash;
  1055. CHAR achTemp[512];
  1056. //
  1057. // If it's relative, use the referer to make it absolute
  1058. //
  1059. // Note we don't process /dir/bar/doc.htm#GoHere tags
  1060. //
  1061. if ( (pchLastSlash = strrchr( pchReferer, '/' )) &&
  1062. strncmp( pchLink, "ftp:", 4 ) &&
  1063. strncmp( pchLink, "http:", 5 ) &&
  1064. strncmp( pchLink, "gopher:", 7 ) &&
  1065. strncmp( pchLink, "mailto:", 7 ) &&
  1066. !strchr( pchLink, '#' ))
  1067. {
  1068. *(pchLastSlash + 1) = '\0';
  1069. strcpy( achTemp, pchReferer );
  1070. strcat( achTemp, pchLink );
  1071. strcpy( pchLink, achTemp );
  1072. }
  1073. else
  1074. {
  1075. fprintf( stderr,
  1076. "Ignoring %s\n",
  1077. pchLink );
  1078. return;
  1079. }
  1080. }
  1081. fprintf( stderr,
  1082. "Traversing %s\n",
  1083. pchLink );
  1084. cLevel++;
  1085. Error = DoTest(
  1086. Host,
  1087. Verb,
  1088. pchLink );
  1089. if( Error != ERROR_SUCCESS ) {
  1090. LogError = Error;
  1091. }
  1092. }
  1093. else
  1094. {
  1095. *pchLink = '\0';
  1096. //
  1097. // Scan for the beginning of an href tag
  1098. //
  1099. while ( pch < pchEnd )
  1100. {
  1101. if ( *pch == '<' )
  1102. {
  1103. //
  1104. // Look for "<A HREF="", note we aren't flexible about spacing
  1105. //
  1106. if ( !_strnicmp( pch, "<A HREF=\"", 9 ) ||
  1107. !_strnicmp( pch, "<IMG SRC=\"", 10 ))
  1108. {
  1109. pch += (toupper(pch[1]) == 'A' ? 9 : 10);
  1110. *pfCopyingLink = TRUE;
  1111. cchLink = 0;
  1112. goto FindEOT;
  1113. }
  1114. }
  1115. pch++;
  1116. }
  1117. //
  1118. // No tag found, return
  1119. //
  1120. return;
  1121. }
  1122. }
  1123. }
  1124. DWORD ReadHtml(HINTERNET hInternet, LPVOID buf, DWORD len, LPDWORD pRead) {
  1125. DWORD error = ERROR_SUCCESS;
  1126. if (!pInternetReadFile(hInternet, buf, len, pRead)) {
  1127. if (AsyncMode) {
  1128. error = GetLastError();
  1129. if (error == ERROR_IO_PENDING) {
  1130. if (Verbose) {
  1131. printf("ASYNC InternetReadFile() waiting for async completion\n");
  1132. }
  1133. WaitForSingleObject(AsyncEvent, INFINITE);
  1134. error = AsyncError;
  1135. if (!AsyncResult) {
  1136. printf("error: ASYNC InternetReadFile() returns FALSE\n");
  1137. if (error == ERROR_SUCCESS) {
  1138. printf("error: ASYNC InternetReadFile() (FALSE) returns ERROR_SUCCESS!\n");
  1139. } else {
  1140. printf("ASYNC InternetReadFile() returns %d\n", error);
  1141. }
  1142. } else if (Verbose) {
  1143. printf("ASYNC InternetReadFile() success\n");
  1144. //
  1145. // error should be ERROR_SUCCESS from callback
  1146. //
  1147. if (error != ERROR_SUCCESS) {
  1148. printf("error: async error = %d. Expected ERROR_SUCCESS\n", error);
  1149. }
  1150. }
  1151. } else {
  1152. printf("error: ASYNC InternetReadFile() returns %d\n", error);
  1153. }
  1154. } else {
  1155. error = GetLastError();
  1156. printf("error: SYNC InternetReadFile() returns %d\n", error);
  1157. }
  1158. } else if (AsyncMode) {
  1159. //
  1160. // we expect async InternetReadFile() to always return FALSE w/ error
  1161. // or ERROR_IO_PENDING
  1162. //
  1163. if (Verbose) {
  1164. printf("ASYNC InternetReadFile() returns TRUE\n");
  1165. }
  1166. } else {
  1167. //
  1168. // error is still ERROR_SUCCESS from initialization
  1169. //
  1170. if (Verbose) {
  1171. printf("SYNC InternetReadFile() returns TRUE\n");
  1172. }
  1173. }
  1174. return error;
  1175. }