Leaked source code of windows server 2003
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.

631 lines
18 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. asyncdl.c
  5. Abstract:
  6. Asynchronous download. Tests reading an URL entirely asynchronously
  7. Author:
  8. Richard L Firth (rfirth) 19-Nov-1995
  9. Revision History:
  10. 19-Nov-1995 rfirth
  11. Created
  12. --*/
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <malloc.h>
  17. #include <fcntl.h>
  18. #include <sys\types.h>
  19. #include <sys\stat.h>
  20. #include <io.h>
  21. #include <windows.h>
  22. #include <wininet.h>
  23. #include <catlib.h>
  24. #ifndef _CRTAPI1
  25. #define _CRTAPI1
  26. #endif
  27. #define IS_ARG(c) (((c) == '-') || ((c) == '/'))
  28. #define DEFAULT_URL "http://www.microsoft.com"
  29. #define URL_SIGN (DWORD)'UrlX'
  30. #define DEFAULT_BUFLEN 1024
  31. #define BUFFER_INCREMENT DEFAULT_BUFLEN
  32. typedef enum {
  33. STATE_OPEN,
  34. STATE_READ,
  35. STATE_CLOSE,
  36. STATE_ERROR
  37. } URL_STATE;
  38. typedef struct {
  39. DWORD Signature;
  40. URL_STATE State;
  41. LPVOID Buffer;
  42. DWORD BufferLength;
  43. DWORD BytesRead;
  44. DWORD NumRead;
  45. HINTERNET Handle;
  46. } URL_CONTEXT, * LPURL_CONTEXT;
  47. void _CRTAPI1 main(int, char**);
  48. void usage(void);
  49. void my_callback(HINTERNET, DWORD, DWORD, LPVOID, DWORD);
  50. void data_handler(LPURL_CONTEXT, LPINTERNET_ASYNC_RESULT);
  51. BOOL Verbose = FALSE;
  52. BOOL Completed = FALSE;
  53. BOOL UseQuery = FALSE;
  54. HANDLE AsyncEvent;
  55. DWORD AsyncResult;
  56. DWORD AsyncError;
  57. LPURL_CONTEXT UrlContext;
  58. void _CRTAPI1 main(int argc, char** argv) {
  59. LPSTR url = NULL;
  60. DWORD accessMode = PRE_CONFIG_INTERNET_ACCESS;
  61. LPURL_CONTEXT lpContext;
  62. INTERNET_STATUS_CALLBACK cbres;
  63. HINTERNET hInternet;
  64. HINTERNET hUrl;
  65. BOOL displayData = FALSE;
  66. LPSTR filename = NULL;
  67. DWORD openFlags = 0;
  68. LPSTR proxy = NULL;
  69. BOOL expectingProxy = FALSE;
  70. for (--argc, ++argv; argc; --argc, ++argv) {
  71. if (IS_ARG(**argv)) {
  72. switch (*++*argv) {
  73. case '?':
  74. usage();
  75. break;
  76. case 'a':
  77. switch (*++*argv) {
  78. case 'l':
  79. case 'd':
  80. accessMode = INTERNET_OPEN_TYPE_DIRECT;
  81. break;
  82. case 'p':
  83. accessMode = INTERNET_OPEN_TYPE_PROXY;
  84. proxy = ++*argv;
  85. if (!*proxy) {
  86. expectingProxy = TRUE;
  87. }
  88. break;
  89. default:
  90. printf("error: unrecognized access mode flag: '%c'\n", **argv);
  91. usage();
  92. }
  93. break;
  94. case 'd':
  95. displayData = TRUE;
  96. break;
  97. case 'f':
  98. if (*++*argv) {
  99. filename = *argv;
  100. } else {
  101. printf("error: no filename found for -f flag\n");
  102. usage();
  103. }
  104. break;
  105. case 'n':
  106. openFlags |= INTERNET_FLAG_NO_CACHE_WRITE;
  107. break;
  108. case 'q':
  109. UseQuery = TRUE;
  110. break;
  111. case 'v':
  112. Verbose = TRUE;
  113. break;
  114. default:
  115. printf("error: unrecognized command line flag: '%c'\n", **argv);
  116. usage();
  117. break;
  118. }
  119. } else if (!url) {
  120. url = *argv;
  121. } else if (expectingProxy) {
  122. proxy = *argv;
  123. expectingProxy = FALSE;
  124. } else {
  125. printf("error: unrecognized command line argument: \"%s\"\n", *argv);
  126. usage();
  127. }
  128. }
  129. if (proxy != NULL) {
  130. if (!*proxy) {
  131. printf("error: expecting proxy server name\n");
  132. usage();
  133. }
  134. }
  135. AsyncEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  136. if (!AsyncEvent) {
  137. print_error("asyncdl", "CreateEvent()");
  138. exit(1);
  139. }
  140. lpContext = (LPURL_CONTEXT)calloc(1, sizeof(URL_CONTEXT));
  141. if (!lpContext) {
  142. printf("error: calloc() failed\n");
  143. exit(1);
  144. }
  145. lpContext->Buffer = malloc(DEFAULT_BUFLEN);
  146. if (!lpContext->Buffer) {
  147. printf("error: malloc(%d) failed\n", DEFAULT_BUFLEN);
  148. exit(1);
  149. }
  150. lpContext->BufferLength = DEFAULT_BUFLEN;
  151. lpContext->Signature = URL_SIGN;
  152. lpContext->State = STATE_OPEN;
  153. UrlContext = lpContext;
  154. if (Verbose) {
  155. printf("opening Internet handle\n");
  156. }
  157. hInternet = InternetOpen("Async Read Test",
  158. accessMode,
  159. proxy,
  160. NULL,
  161. INTERNET_FLAG_ASYNC
  162. );
  163. if (!hInternet) {
  164. print_error("asyncdl", "InternetOpen()");
  165. exit(1);
  166. } else if (Verbose) {
  167. printf("InternetOpen() returns handle %x\n", hInternet);
  168. }
  169. if (Verbose) {
  170. printf("installing callback\n");
  171. }
  172. cbres = InternetSetStatusCallback(hInternet, my_callback);
  173. if (cbres == INTERNET_INVALID_STATUS_CALLBACK) {
  174. print_error("asyncdl", "InternetSetStatusCallback()");
  175. exit(1);
  176. }
  177. if (Verbose) {
  178. printf("opening URL %s\n", url);
  179. }
  180. hUrl = InternetOpenUrl(hInternet,
  181. url,
  182. NULL, // lpHeaders
  183. 0, // dwHeadersLength
  184. openFlags,
  185. (DWORD)lpContext
  186. );
  187. if (hUrl == NULL) {
  188. if (GetLastError() != ERROR_IO_PENDING) {
  189. print_error("asyncdl", "InternetOpenUrl()");
  190. exit(1);
  191. }
  192. if (Verbose) {
  193. printf("waiting for async InternetOpenUrl()...\n");
  194. }
  195. WaitForSingleObject(AsyncEvent, INFINITE);
  196. hUrl = (HINTERNET)AsyncResult;
  197. SetLastError(AsyncError);
  198. } else {
  199. printf("warning: InternetOpenUrl() returns synchronous result\n");
  200. }
  201. if (!hUrl) {
  202. if (!Completed) {
  203. print_error("asyncdl", "InternetOpenUrl()");
  204. exit(1);
  205. } else if (Verbose) {
  206. printf("Download completed OK!\n");
  207. }
  208. } else {
  209. printf("error: unexpected hUrl = %x\n", hUrl);
  210. }
  211. if (displayData) {
  212. int fh;
  213. int mode;
  214. if (filename) {
  215. fh = _open(filename, _O_CREAT|_O_TRUNC|_O_WRONLY|_O_BINARY, _S_IREAD|_S_IWRITE);
  216. if (fh == -1) {
  217. printf("error: cannot open file \"%s\" for writing\n", filename);
  218. filename = NULL;
  219. }
  220. }
  221. if (!filename) {
  222. if (Verbose) {
  223. printf("%d bytes data received:\n", lpContext->BytesRead);
  224. }
  225. mode = _setmode(1, _O_BINARY);
  226. fh = 1;
  227. }
  228. _write(fh, lpContext->Buffer, lpContext->BytesRead);
  229. if (filename) {
  230. _close(fh);
  231. } else {
  232. _setmode(1, mode);
  233. }
  234. }
  235. printf("Done.\n");
  236. exit(0);
  237. }
  238. void usage() {
  239. printf("\n"
  240. "usage: asyncdl [-a<l|g|p>[<server>[:<port>]]] [-d] [-f<file>] [-n] [-v] <url>\n"
  241. "\n"
  242. "where: -a = access mode. Default is pre-configured\n"
  243. " -al = local internet access (same as -ad)\n"
  244. " -ap = CERN proxy internet access. <server> is required\n"
  245. " -d = Display received data\n"
  246. " -f = Write data to <file>. Only if -d set\n"
  247. " -n = Don't write data to cache\n"
  248. " -v = Verbose mode\n"
  249. "\n"
  250. "If no URL is supplied, " DEFAULT_URL " will be used\n"
  251. );
  252. exit(1);
  253. }
  254. VOID
  255. my_callback(
  256. HINTERNET Handle,
  257. DWORD Context,
  258. DWORD Status,
  259. LPVOID Info,
  260. DWORD Length
  261. )
  262. {
  263. char* type$;
  264. switch (Status) {
  265. case INTERNET_STATUS_RESOLVING_NAME:
  266. type$ = "RESOLVING NAME";
  267. break;
  268. case INTERNET_STATUS_NAME_RESOLVED:
  269. type$ = "NAME RESOLVED";
  270. break;
  271. case INTERNET_STATUS_CONNECTING_TO_SERVER:
  272. type$ = "CONNECTING TO SERVER";
  273. break;
  274. case INTERNET_STATUS_CONNECTED_TO_SERVER:
  275. type$ = "CONNECTED TO SERVER";
  276. break;
  277. case INTERNET_STATUS_SENDING_REQUEST:
  278. type$ = "SENDING REQUEST";
  279. break;
  280. case INTERNET_STATUS_REQUEST_SENT:
  281. type$ = "REQUEST SENT";
  282. break;
  283. case INTERNET_STATUS_RECEIVING_RESPONSE:
  284. type$ = "RECEIVING RESPONSE";
  285. break;
  286. case INTERNET_STATUS_RESPONSE_RECEIVED:
  287. type$ = "RESPONSE RECEIVED";
  288. break;
  289. case INTERNET_STATUS_CLOSING_CONNECTION:
  290. type$ = "CLOSING CONNECTION";
  291. break;
  292. case INTERNET_STATUS_CONNECTION_CLOSED:
  293. type$ = "CONNECTION CLOSED";
  294. break;
  295. case INTERNET_STATUS_HANDLE_CREATED:
  296. type$ = "HANDLE CREATED";
  297. break;
  298. case INTERNET_STATUS_HANDLE_CLOSING:
  299. type$ = "HANDLE CLOSING";
  300. break;
  301. case INTERNET_STATUS_REQUEST_COMPLETE:
  302. type$ = "REQUEST COMPLETE";
  303. AsyncResult = ((LPINTERNET_ASYNC_RESULT)Info)->dwResult;
  304. AsyncError = ((LPINTERNET_ASYNC_RESULT)Info)->dwError;
  305. break;
  306. default:
  307. type$ = "???";
  308. break;
  309. }
  310. if (Verbose) {
  311. printf("callback: Hndl %x [Ctxt %x [%s]] %s ",
  312. Handle,
  313. Context,
  314. (Context == (DWORD)UrlContext) ? "Url"
  315. : "???",
  316. type$
  317. );
  318. if (Info) {
  319. if ((Status == INTERNET_STATUS_HANDLE_CREATED)
  320. || (Status == INTERNET_STATUS_HANDLE_CLOSING)) {
  321. DWORD handleType;
  322. DWORD handleTypeSize = sizeof(handleType);
  323. LPSTR typeStr;
  324. printf("%x", *(LPHINTERNET)Info);
  325. if (InternetQueryOption(*(LPHINTERNET)Info,
  326. INTERNET_OPTION_HANDLE_TYPE,
  327. &handleType,
  328. &handleTypeSize
  329. )) {
  330. switch (handleType) {
  331. case INTERNET_HANDLE_TYPE_INTERNET:
  332. typeStr = "Internet";
  333. break;
  334. case INTERNET_HANDLE_TYPE_CONNECT_FTP:
  335. typeStr = "FTP Connect";
  336. break;
  337. case INTERNET_HANDLE_TYPE_CONNECT_GOPHER:
  338. typeStr = "Gopher Connect";
  339. break;
  340. case INTERNET_HANDLE_TYPE_CONNECT_HTTP:
  341. typeStr = "HTTP Connect";
  342. break;
  343. case INTERNET_HANDLE_TYPE_FTP_FIND:
  344. typeStr = "FTP Find";
  345. break;
  346. case INTERNET_HANDLE_TYPE_FTP_FIND_HTML:
  347. typeStr = "FTP Find HTML";
  348. break;
  349. case INTERNET_HANDLE_TYPE_FTP_FILE:
  350. typeStr = "FTP File";
  351. break;
  352. case INTERNET_HANDLE_TYPE_FTP_FILE_HTML:
  353. typeStr = "FTP File HTML";
  354. break;
  355. case INTERNET_HANDLE_TYPE_GOPHER_FIND:
  356. typeStr = "Gopher Find";
  357. break;
  358. case INTERNET_HANDLE_TYPE_GOPHER_FIND_HTML:
  359. typeStr = "Gopher Find HTML";
  360. break;
  361. case INTERNET_HANDLE_TYPE_GOPHER_FILE:
  362. typeStr = "Gopher File";
  363. break;
  364. case INTERNET_HANDLE_TYPE_GOPHER_FILE_HTML:
  365. typeStr = "Gopher File HTML";
  366. break;
  367. case INTERNET_HANDLE_TYPE_HTTP_REQUEST:
  368. typeStr = "HTTP Request";
  369. break;
  370. default:
  371. typeStr = "???";
  372. break;
  373. }
  374. ((LPURL_CONTEXT)Context)->Handle = *(LPHINTERNET)Info;
  375. } else {
  376. typeStr = "<error>";
  377. }
  378. printf(" [%s]", typeStr);
  379. } else if (Status == INTERNET_STATUS_REQUEST_COMPLETE) {
  380. //
  381. // nothing
  382. //
  383. } else if (Length == sizeof(DWORD)) {
  384. printf("%d", *(LPDWORD)Info);
  385. } else {
  386. printf(Info);
  387. }
  388. }
  389. putchar('\n');
  390. }
  391. if (Status == INTERNET_STATUS_REQUEST_COMPLETE) {
  392. data_handler((LPURL_CONTEXT)Context,
  393. (LPINTERNET_ASYNC_RESULT)Info
  394. );
  395. }
  396. }
  397. void
  398. data_handler(
  399. LPURL_CONTEXT lpContext,
  400. LPINTERNET_ASYNC_RESULT Results
  401. )
  402. {
  403. BOOL ok;
  404. DWORD len;
  405. int retcode;
  406. DWORD available;
  407. HINTERNET hInternet = lpContext->Handle;
  408. if (lpContext->Signature != URL_SIGN) {
  409. printf("fatal: unrecognized context block %x\n", lpContext);
  410. exit(1);
  411. }
  412. while (1) {
  413. switch (lpContext->State) {
  414. case STATE_OPEN:
  415. if (!Results->dwResult) {
  416. SetLastError(Results->dwError);
  417. print_error("data_handler", "async InternetOpenUrl()");
  418. exit(1);
  419. }
  420. len = sizeof(retcode);
  421. ok = HttpQueryInfo(hInternet,
  422. HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
  423. (LPVOID)&retcode,
  424. &len,
  425. NULL
  426. );
  427. if (!ok) {
  428. print_error("data_handler", "HttpQueryInfo()");
  429. goto error_exit;
  430. }
  431. if (retcode != 200) {
  432. printf("error: server returns error %d\n", retcode);
  433. goto error_exit;
  434. } else if (Verbose) {
  435. printf("async InternetOpenUrl(): HTTP result code %d\n", retcode);
  436. }
  437. do {
  438. if (UseQuery) {
  439. ok = InternetQueryDataAvailable(
  440. hInternet,
  441. &available,
  442. 0,
  443. 0
  444. );
  445. } else {
  446. ok = InternetReadFile(
  447. hInternet,
  448. (LPBYTE)lpContext->Buffer + lpContext->BytesRead,
  449. lpContext->BufferLength - lpContext->BytesRead,
  450. &lpContext->NumRead
  451. );
  452. }
  453. } while (ok);
  454. if (!ok) {
  455. if (GetLastError() == ERROR_IO_PENDING) {
  456. if (Verbose) {
  457. printf("initial read started...\n");
  458. }
  459. lpContext->State = STATE_READ;
  460. return;
  461. } else {
  462. print_error("data_handler", "InternetReadFile()");
  463. exit(1);
  464. }
  465. }
  466. return;
  467. case STATE_READ:
  468. if (!Results->dwResult) {
  469. SetLastError(Results->dwError);
  470. print_error("data_handler", "async InternetReadFile()");
  471. exit(1);
  472. }
  473. if (lpContext->NumRead == 0) {
  474. if (Verbose) {
  475. printf("finished\n");
  476. lpContext->State = STATE_CLOSE;
  477. continue;
  478. }
  479. } else if (Verbose) {
  480. printf("InternetReadFile() returns %d bytes\n", lpContext->NumRead);
  481. }
  482. lpContext->BytesRead += lpContext->NumRead;
  483. if (Verbose) {
  484. printf("reallocating buffer %x from %d (%x) to %d (%x)\n",
  485. lpContext->Buffer,
  486. lpContext->BufferLength,
  487. lpContext->BufferLength,
  488. lpContext->BufferLength + BUFFER_INCREMENT,
  489. lpContext->BufferLength + BUFFER_INCREMENT
  490. );
  491. }
  492. lpContext->Buffer = realloc(lpContext->Buffer,
  493. lpContext->BufferLength + BUFFER_INCREMENT
  494. );
  495. if (lpContext->Buffer == NULL) {
  496. printf("error: data_handler: realloc() failed\n");
  497. exit(1);
  498. }
  499. lpContext->BufferLength += BUFFER_INCREMENT;
  500. ok = InternetReadFile(hInternet,
  501. (LPBYTE)lpContext->Buffer + lpContext->BytesRead,
  502. lpContext->BufferLength - lpContext->BytesRead,
  503. &lpContext->NumRead
  504. );
  505. if (!ok) {
  506. if (GetLastError() == ERROR_IO_PENDING) {
  507. return;
  508. } else {
  509. print_error("data_handler", "InternetReadFile()");
  510. exit(1);
  511. }
  512. }
  513. return;
  514. case STATE_CLOSE:
  515. InternetCloseHandle(hInternet);
  516. AsyncResult = 0;
  517. AsyncError = 0;
  518. Completed = TRUE;
  519. SetEvent(AsyncEvent);
  520. return;
  521. case STATE_ERROR:
  522. return;
  523. default:
  524. printf("fatal: unrecognized state %x in context %x\n",
  525. lpContext->State,
  526. lpContext
  527. );
  528. exit(1);
  529. }
  530. }
  531. printf("\aerror: data_handler: didn't expect to reach here\n");
  532. return;
  533. error_exit:
  534. AsyncResult = Results->dwResult;
  535. AsyncError = Results->dwError;
  536. InternetCloseHandle(hInternet);
  537. SetEvent(AsyncEvent);
  538. }