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.

760 lines
22 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. w3test.c
  5. Abstract:
  6. This module tests the web server's server extension interface
  7. Author:
  8. John Ludeman (johnl) 13-Oct-1994
  9. Revision History:
  10. Tony Godfrey (tonygod) 15-Sep-1997 - fixed TerminateExtension
  11. --*/
  12. #include <windows.h>
  13. //#include <httpext.h>
  14. #include <iisext.h>
  15. // Global variable used to track outstanding threads
  16. DWORD g_dwThreadCount;
  17. #define BUFFER_LENGTH 4096
  18. // Debug macro
  19. CHAR g_szDebug[256];
  20. #define DEBUG(DebugString, Param)\
  21. {\
  22. wsprintf( g_szDebug, DebugString, Param );\
  23. OutputDebugString( g_szDebug );\
  24. }
  25. // Prototypes
  26. DWORD WINAPI SimulatePendIOThread( LPDWORD lpParams );
  27. BOOL WINAPI DllMain( HANDLE hInst, ULONG Reason, LPVOID Reserved );
  28. BOOL WINAPI DoAction(
  29. EXTENSION_CONTROL_BLOCK * pecb,
  30. char * pszAction,
  31. BOOL * pfKeepConn
  32. );
  33. DWORD WINAPI HttpExtensionProc( EXTENSION_CONTROL_BLOCK * pecb )
  34. {
  35. BOOL fKeepConn = FALSE;
  36. DWORD dwThreadId;
  37. HANDLE hThread;
  38. if ( !_strnicmp( pecb->lpszQueryString,
  39. "SimulatePendingIO",
  40. 17))
  41. {
  42. InterlockedIncrement( &g_dwThreadCount );
  43. hThread = CreateThread(
  44. NULL,
  45. 0,
  46. (LPTHREAD_START_ROUTINE) SimulatePendIOThread,
  47. pecb,
  48. 0,
  49. &dwThreadId
  50. );
  51. if ( hThread == NULL ) {
  52. InterlockedDecrement( &g_dwThreadCount );
  53. } else {
  54. CloseHandle( hThread );
  55. }
  56. return HSE_STATUS_PENDING;
  57. }
  58. else
  59. {
  60. if ( !DoAction( pecb,
  61. pecb->lpszQueryString,
  62. &fKeepConn ))
  63. {
  64. return HSE_STATUS_ERROR;
  65. }
  66. }
  67. return fKeepConn ? HSE_STATUS_SUCCESS_AND_KEEP_CONN :
  68. HSE_STATUS_SUCCESS;
  69. }
  70. BOOL WINAPI DoAction(
  71. EXTENSION_CONTROL_BLOCK * pecb,
  72. char * pszAction,
  73. BOOL * pfKeepConn
  74. )
  75. {
  76. char *buff;
  77. int ret;
  78. int i;
  79. int cb;
  80. buff = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, BUFFER_LENGTH + 1 );
  81. if ( buff == NULL ) {
  82. return FALSE;
  83. }
  84. //
  85. // Log the request here
  86. //
  87. strcpy( pecb->lpszLogData, ", ISAPI Data->" );
  88. strcat( pecb->lpszLogData, pszAction );
  89. if ( !_stricmp( pszAction,
  90. "HSE_REQ_SEND_URL_REDIRECT_RESP" ))
  91. {
  92. //
  93. // pecb->pszPathInfo is the URL to redirect to
  94. //
  95. HeapFree( GetProcessHeap(), 0, buff );
  96. return pecb->ServerSupportFunction(
  97. pecb->ConnID,
  98. HSE_REQ_SEND_URL_REDIRECT_RESP,
  99. pecb->lpszPathInfo,
  100. NULL,
  101. NULL );
  102. }
  103. else if ( !_stricmp( pszAction,
  104. "HSE_REQ_SEND_URL" ))
  105. {
  106. //
  107. // pecbb->lpszPathInfo is the URL to send
  108. //
  109. HeapFree( GetProcessHeap(), 0, buff );
  110. return pecb->ServerSupportFunction(
  111. pecb->ConnID,
  112. HSE_REQ_SEND_URL,
  113. pecb->lpszPathInfo,
  114. 0,
  115. 0 );
  116. }
  117. else if ( !_stricmp( pszAction,
  118. "HSE_REQ_SEND_RESPONSE_HEADER" ))
  119. {
  120. wsprintf( buff,
  121. "Content-type: text/html\r\n"
  122. "\r\n"
  123. "<head><title>Response header test</title></head>\n"
  124. "<body><h1>HTTP status code supplied in the path info was \"%s\"</h1></body>\n",
  125. pecb->lpszPathInfo );
  126. ret = pecb->ServerSupportFunction(
  127. pecb->ConnID,
  128. HSE_REQ_SEND_RESPONSE_HEADER,
  129. pecb->lpszPathInfo, // HTTP status code
  130. NULL,
  131. (LPDWORD) buff );
  132. if ( !ret ) {
  133. HeapFree( GetProcessHeap(), 0, buff );
  134. return FALSE;
  135. }
  136. cb = wsprintf( buff,
  137. "Content-Type: text/html\r\n"
  138. "\r\n"
  139. "<head><title>Response header test</title></head>\n"
  140. "<body><h1>Specified status code was %s</h1></body>\n",
  141. pecb->lpszPathInfo );
  142. ret = pecb->WriteClient( pecb->ConnID,
  143. buff,
  144. &cb,
  145. 0 );
  146. HeapFree( GetProcessHeap(), 0, buff );
  147. return ret;
  148. }
  149. else if ( !_strnicmp( pszAction,
  150. "GET_VAR",
  151. 7 ))
  152. {
  153. CHAR * pch;
  154. ret = pecb->ServerSupportFunction(
  155. pecb->ConnID,
  156. HSE_REQ_SEND_RESPONSE_HEADER,
  157. NULL,
  158. NULL,
  159. (LPDWORD) "Content-Type: text/html\r\n"
  160. "\r\n" );
  161. if ( !ret ) {
  162. HeapFree( GetProcessHeap(), 0, buff );
  163. return FALSE;
  164. }
  165. cb = BUFFER_LENGTH;
  166. if ( !(pch = strchr( pszAction, '&' )) )
  167. {
  168. pch = "ALL_HTTP";
  169. }
  170. else
  171. {
  172. pch++;
  173. }
  174. ret = pecb->GetServerVariable( pecb->ConnID,
  175. pch,
  176. buff,
  177. &cb );
  178. if ( !ret ) {
  179. HeapFree( GetProcessHeap(), 0, buff );
  180. return FALSE;
  181. }
  182. strcat( buff, "\r\n" );
  183. cb = strlen( buff );
  184. ret = pecb->WriteClient( pecb->ConnID,
  185. buff,
  186. &cb,
  187. 0 );
  188. HeapFree( GetProcessHeap(), 0, buff );
  189. return ret;
  190. }
  191. else if ( !_stricmp( pszAction,
  192. "HSE_REQ_MAP_URL_TO_PATH" ))
  193. {
  194. char Path[MAX_PATH + 1];
  195. DWORD cbPath = sizeof( Path );
  196. strcpy( Path, pecb->lpszPathInfo );
  197. ret = pecb->ServerSupportFunction( pecb->ConnID,
  198. HSE_REQ_MAP_URL_TO_PATH,
  199. Path,
  200. &cbPath,
  201. NULL );
  202. if ( !ret ) {
  203. HeapFree( GetProcessHeap(), 0, buff );
  204. return FALSE;
  205. }
  206. wsprintf( buff,
  207. "Content-type: text/html\r\n"
  208. "\r\n"
  209. "<head><title>URL map test</title></head>\n"
  210. "<body><h1>URL \"%s\" maps to \"%s\""
  211. "cbPath is %d</h1></body>\n",
  212. pecb->lpszPathInfo,
  213. Path,
  214. cbPath );
  215. ret = pecb->ServerSupportFunction(
  216. pecb->ConnID,
  217. HSE_REQ_SEND_RESPONSE_HEADER,
  218. NULL,
  219. NULL,
  220. (LPDWORD) buff );
  221. HeapFree( GetProcessHeap(), 0, buff );
  222. return ret;
  223. }
  224. else if ( !_stricmp( pszAction,
  225. "HSE_REQ_MAP_URL_TO_PATH_EX" ))
  226. {
  227. HSE_URL_MAPEX_INFO mapinfo;
  228. ret = pecb->ServerSupportFunction( pecb->ConnID,
  229. HSE_REQ_MAP_URL_TO_PATH_EX,
  230. pecb->lpszPathInfo,
  231. NULL,
  232. (DWORD *) &mapinfo );
  233. if ( !ret ) {
  234. HeapFree( GetProcessHeap(), 0, buff );
  235. return FALSE;
  236. }
  237. wsprintf( buff,
  238. "Content-type: text/html\r\n"
  239. "\r\n"
  240. "<head><title>URL map_ex test</title></head>\n"
  241. "<body><h1>URL \"%s\" maps to \"%s\""
  242. "dwFlags = 0x%08x\n"
  243. "cchMatchingPath = %d\n"
  244. "cchMatchingURL = %d\n</h1></body>",
  245. pecb->lpszPathInfo,
  246. mapinfo.lpszPath,
  247. mapinfo.dwFlags,
  248. mapinfo.cchMatchingPath,
  249. mapinfo.cchMatchingURL );
  250. ret = pecb->ServerSupportFunction(
  251. pecb->ConnID,
  252. HSE_REQ_SEND_RESPONSE_HEADER,
  253. NULL,
  254. NULL,
  255. (LPDWORD) buff );
  256. HeapFree( GetProcessHeap(), 0, buff );
  257. return ret;
  258. }
  259. else if ( !_stricmp( pszAction,
  260. "Keep_Alive" ))
  261. {
  262. DWORD cbBuff = BUFFER_LENGTH;
  263. DWORD cbDoc;
  264. CHAR achDoc[4096];
  265. BOOL fKeepAlive = FALSE;
  266. if ( !pecb->GetServerVariable( pecb->ConnID,
  267. "HTTP_CONNECTION",
  268. buff,
  269. &cbBuff ))
  270. {
  271. *buff = '\0';
  272. }
  273. cbDoc = wsprintf( achDoc,
  274. "<head><title>Keep alive test</title></head>\n"
  275. "This document is being kept alive."
  276. );
  277. //
  278. // This assumes keep-alive comes first in the list
  279. //
  280. if ( !_strnicmp( buff, "keep-alive", 10 ))
  281. {
  282. fKeepAlive = TRUE;
  283. wsprintf( buff,
  284. "Content-type: text/html\r\n"
  285. "Connection: keep-alive\r\n"
  286. "Content-Length: %d\r\n"
  287. "\r\n",
  288. cbDoc );
  289. }
  290. else
  291. {
  292. wsprintf( buff,
  293. "Content-type: text/html\r\n"
  294. "\r\n"
  295. "<head><title>Keep alive test</title></head>\n"
  296. "Client did not specify keep alive!"
  297. );
  298. }
  299. ret = pecb->ServerSupportFunction(
  300. pecb->ConnID,
  301. HSE_REQ_SEND_RESPONSE_HEADER,
  302. NULL,
  303. NULL,
  304. (LPDWORD) buff ) &&
  305. pecb->WriteClient( pecb->ConnID,
  306. achDoc,
  307. &cbDoc,
  308. 0 );
  309. if ( !ret ) {
  310. HeapFree( GetProcessHeap(), 0, buff );
  311. return FALSE;
  312. }
  313. if ( fKeepAlive ) {
  314. *pfKeepConn = TRUE;
  315. }
  316. HeapFree( GetProcessHeap(), 0, buff );
  317. return TRUE;
  318. }
  319. else if ( !strncmp( pszAction,
  320. "Open_Reg",
  321. 7 ))
  322. {
  323. CHAR * pch;
  324. DWORD err;
  325. HKEY hKey;
  326. HKEY hSubKey;
  327. HANDLE hFile;
  328. ret = pecb->ServerSupportFunction(
  329. pecb->ConnID,
  330. HSE_REQ_SEND_RESPONSE_HEADER,
  331. NULL,
  332. NULL,
  333. (LPDWORD) "Content-Type: text/html\r\n"
  334. "\r\n" );
  335. if ( !ret ) {
  336. HeapFree( GetProcessHeap(), 0, buff );
  337. return FALSE;
  338. }
  339. //
  340. // The path info begins with the portion of the registry to open
  341. //
  342. if ( !_strnicmp( pecb->lpszPathInfo + 1,
  343. "HKEY_CLASSES_ROOT",
  344. 17 ))
  345. {
  346. pch = pecb->lpszPathInfo + 19;
  347. hKey = HKEY_CLASSES_ROOT;
  348. }
  349. else if ( !_strnicmp( pecb->lpszPathInfo + 1,
  350. "HKEY_CURRENT_USER",
  351. 17 ))
  352. {
  353. pch = pecb->lpszPathInfo + 19;
  354. hKey = HKEY_CURRENT_USER;
  355. }
  356. else if ( !_strnicmp( pecb->lpszPathInfo + 1,
  357. "HKEY_LOCAL_MACHINE",
  358. 18 ))
  359. {
  360. pch = pecb->lpszPathInfo + 20;
  361. hKey = HKEY_LOCAL_MACHINE;
  362. }
  363. else if ( !_strnicmp( pecb->lpszPathInfo + 1,
  364. "HKEY_USERS",
  365. 10 ))
  366. {
  367. pch = pecb->lpszPathInfo + 12;
  368. hKey = HKEY_USERS;
  369. }
  370. err = RegOpenKey( hKey,
  371. pch,
  372. &hSubKey );
  373. if ( err )
  374. {
  375. cb = wsprintf( buff,
  376. "Failed to open registry key %s, error %d\n",
  377. pecb->lpszPathInfo,
  378. err );
  379. }
  380. else
  381. {
  382. cb = wsprintf( buff,
  383. "Successfully opened registry key %s\n",
  384. pecb->lpszPathInfo );
  385. RegCloseKey( hSubKey );
  386. }
  387. pecb->WriteClient( pecb->ConnID,
  388. buff,
  389. &cb,
  390. 0 );
  391. HeapFree( GetProcessHeap(), 0, buff );
  392. return TRUE;
  393. }
  394. else if ( !_stricmp( pszAction,
  395. "Open_File" ))
  396. {
  397. CHAR *pch;
  398. DWORD err;
  399. HKEY hKey;
  400. HKEY hSubKey;
  401. HANDLE hFile;
  402. DWORD dwBytesRead;
  403. DWORD dwFileSize = 0;
  404. DWORD dwError;
  405. //
  406. // The path translated is the filename to open
  407. //
  408. hFile = CreateFile(
  409. pecb->lpszPathTranslated,
  410. GENERIC_READ,
  411. FILE_SHARE_READ,
  412. NULL,
  413. OPEN_EXISTING,
  414. FILE_ATTRIBUTE_NORMAL,
  415. NULL
  416. );
  417. if ( hFile == INVALID_HANDLE_VALUE ) {
  418. dwError = GetLastError();
  419. wsprintf(
  420. buff,
  421. "Content-Type: text/html\r\n\r\n"
  422. );
  423. ret = pecb->ServerSupportFunction(
  424. pecb->ConnID,
  425. HSE_REQ_SEND_RESPONSE_HEADER,
  426. "200 OK",
  427. NULL,
  428. (LPDWORD) buff );
  429. if ( !ret ) {
  430. HeapFree( GetProcessHeap(), 0, buff );
  431. return FALSE;
  432. }
  433. cb = wsprintf(
  434. buff,
  435. "<head><title>Unable to open file</title></head>\r\n"
  436. "<body><h1>Unable to open file</h1>\r\n"
  437. "CreateFile failed: %ld\r\n<p>"
  438. "Filename: %s<p></body>",
  439. dwError,
  440. pecb->lpszPathTranslated
  441. );
  442. pecb->WriteClient(
  443. pecb->ConnID,
  444. buff,
  445. &cb,
  446. 0
  447. );
  448. HeapFree( GetProcessHeap(), 0, buff );
  449. return TRUE;
  450. }
  451. dwFileSize = GetFileSize( hFile, NULL );
  452. pch = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwFileSize + 1 );
  453. ret = ReadFile(
  454. hFile,
  455. pch,
  456. dwFileSize,
  457. &dwBytesRead,
  458. NULL
  459. );
  460. if ( !ret ) {
  461. dwError = GetLastError();
  462. }
  463. pch[dwBytesRead] = 0;
  464. CloseHandle( hFile );
  465. if ( !ret ) {
  466. wsprintf(
  467. buff,
  468. "Content-Type: text/html\r\n\r\n"
  469. );
  470. ret = pecb->ServerSupportFunction(
  471. pecb->ConnID,
  472. HSE_REQ_SEND_RESPONSE_HEADER,
  473. "200 OK",
  474. NULL,
  475. (LPDWORD) buff );
  476. if ( !ret ) {
  477. HeapFree( GetProcessHeap(), 0, buff );
  478. return FALSE;
  479. }
  480. cb = wsprintf(
  481. buff,
  482. "<head><title>Unable to Read File</title></head>\r\n"
  483. "<body><h1>Unable to Read File</h1>\r\n"
  484. "ReadFile failed: %ld<p>\r\n"
  485. "Filename: %s</body>",
  486. dwError,
  487. pecb->lpszPathTranslated
  488. );
  489. pecb->WriteClient(
  490. pecb->ConnID,
  491. buff,
  492. &cb,
  493. 0
  494. );
  495. HeapFree( GetProcessHeap(), 0, buff );
  496. return TRUE;
  497. }
  498. wsprintf(
  499. buff,
  500. "Content-Type: text/html\r\n\r\n"
  501. );
  502. ret = pecb->ServerSupportFunction(
  503. pecb->ConnID,
  504. HSE_REQ_SEND_RESPONSE_HEADER,
  505. "200 OK",
  506. NULL,
  507. (LPDWORD) buff );
  508. if ( !ret ) {
  509. HeapFree( GetProcessHeap(), 0, buff );
  510. return FALSE;
  511. }
  512. pecb->WriteClient(
  513. pecb->ConnID,
  514. pch,
  515. &dwBytesRead,
  516. 0
  517. );
  518. HeapFree( GetProcessHeap(), 0, buff );
  519. HeapFree( GetProcessHeap(), 0, pch );
  520. return TRUE;
  521. }
  522. else if ( !_stricmp( pszAction,
  523. "SimulateFault" ))
  524. {
  525. *((CHAR *)0xffffffff) = 'a';
  526. HeapFree( GetProcessHeap(), 0, buff );
  527. return FALSE;
  528. }
  529. wsprintf( buff,
  530. "Content-Type: text/html\r\n\r\n"
  531. "<head><title>Unknown Test command</title></head>\n"
  532. "<body><h1>Unknown Test Command</h1>\n"
  533. "<p>Usage:"
  534. "<p>Query string contains one of the following:"
  535. "<p>"
  536. "<p> HSE_REQ_SEND_URL_REDIRECT_RESP"
  537. "<p> HSE_REQ_SEND_URL"
  538. "<p> HSE_REQ_SEND_RESPONSE_HEADER"
  539. "<p> HSE_REQ_MAP_URL_TO_PATH"
  540. "<p> GET_VAR&var_to_get"
  541. "<p> SimulateFault"
  542. "<p> Keep_Alive"
  543. "<p> Open_Reg"
  544. "<p> Open_File"
  545. "<p>"
  546. "<p> For example:"
  547. "<p>"
  548. "<p> http://computer/scripts/w3test.dll?CGI_VAR"
  549. "<p>"
  550. "<p> or SimulatePendingIO with one of the above action strings"
  551. "<p>"
  552. "<p> such as:"
  553. "<p>"
  554. "<p> http://computer/scripts/w3test.dll?SimulatePendingIO&HSE_REQ_SEND_URL"
  555. "<p>"
  556. "<p> The Path info generally contains the URL or response to use"
  557. "</body>\n");
  558. ret = pecb->ServerSupportFunction(
  559. pecb->ConnID,
  560. HSE_REQ_SEND_RESPONSE_HEADER,
  561. "200 OK",
  562. NULL,
  563. (LPDWORD) buff );
  564. cb = wsprintf( buff,
  565. "<p>cbTotalBytes = %d<p> cbAvailable = %d<p>"
  566. "lpszContentType = %s<p> lpszPathInfo = %s<p>"
  567. "lpszPathTranslated = %s",
  568. pecb->cbTotalBytes,
  569. pecb->cbAvailable,
  570. pecb->lpszContentType,
  571. pecb->lpszPathInfo,
  572. pecb->lpszPathTranslated );
  573. pecb->WriteClient( pecb->ConnID,
  574. buff,
  575. &cb,
  576. 0 );
  577. cb = pecb->cbAvailable;
  578. pecb->WriteClient( pecb->ConnID,
  579. pecb->lpbData,
  580. &cb,
  581. 0 );
  582. while ( pecb->cbAvailable < pecb->cbTotalBytes )
  583. {
  584. cb = min( pecb->cbTotalBytes - pecb->cbAvailable, BUFFER_LENGTH );
  585. if ( !pecb->ReadClient( pecb->ConnID,
  586. buff,
  587. &cb ) ||
  588. !cb )
  589. {
  590. break;
  591. }
  592. pecb->cbAvailable += cb;
  593. pecb->WriteClient( pecb->ConnID,
  594. buff,
  595. &cb,
  596. 0 );
  597. }
  598. HeapFree( GetProcessHeap(), 0, buff );
  599. return TRUE;
  600. }
  601. DWORD WINAPI SimulatePendIOThread( LPDWORD lpParams )
  602. {
  603. EXTENSION_CONTROL_BLOCK * pecb = (EXTENSION_CONTROL_BLOCK *) lpParams;
  604. char *psz;
  605. DWORD dwStatus;
  606. BOOL fKeepConn = FALSE;
  607. Sleep( 5000 );
  608. psz = strchr( pecb->lpszQueryString, '&' );
  609. if ( psz )
  610. psz++;
  611. else
  612. psz = "No action string specified";
  613. DoAction( pecb,
  614. psz,
  615. &fKeepConn );
  616. dwStatus = fKeepConn ? HSE_STATUS_SUCCESS_AND_KEEP_CONN :
  617. HSE_STATUS_SUCCESS;
  618. pecb->ServerSupportFunction( pecb,
  619. HSE_REQ_DONE_WITH_SESSION,
  620. &dwStatus,
  621. 0,
  622. 0 );
  623. InterlockedDecrement( &g_dwThreadCount );
  624. return 0;
  625. }
  626. BOOL GetExtensionVersion( HSE_VERSION_INFO * pver )
  627. {
  628. pver->dwExtensionVersion = MAKELONG( 0, 1 );
  629. strcpy( pver->lpszExtensionDesc, "Extension test example" );
  630. return TRUE;
  631. }
  632. BOOL TerminateExtension( DWORD dwFlags )
  633. {
  634. DEBUG( "[W3Test.TerminateExtension] Extension terminating!\r\n", 0 );
  635. while ( g_dwThreadCount > 0 ) {
  636. DEBUG( "[W3Test.TerminateExtension] Thread Count: %ld\r\n", g_dwThreadCount );
  637. SleepEx( 1000, FALSE );
  638. }
  639. SleepEx( 1000, FALSE );
  640. return TRUE;
  641. }
  642. BOOL WINAPI DllMain( HANDLE hInst, ULONG Reason, LPVOID Reserved )
  643. {
  644. switch( Reason ) {
  645. case DLL_PROCESS_ATTACH:
  646. g_dwThreadCount = 0;
  647. break;
  648. case DLL_PROCESS_DETACH:
  649. break;
  650. }
  651. return TRUE;
  652. }