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.

4903 lines
118 KiB

  1. /*********************************************************************
  2. * *
  3. * File: specweb99-CAD.cxx *
  4. * ---- *
  5. * *
  6. * *
  7. * Overview: *
  8. * -------- *
  9. * *
  10. * Implementation of the dynamic GET with custom ad rotation *
  11. * operation in the SPECweb99 benchmark. *
  12. * *
  13. * *
  14. * Revision History: *
  15. * ---------------- *
  16. * *
  17. * Date Author Reason *
  18. * ---- ------ ------ *
  19. * *
  20. * 07/28/02 Ankur Upadhyaya Initial Creation. *
  21. * *
  22. *********************************************************************/
  23. /*********************************************************************/
  24. //
  25. // Includes.
  26. //
  27. #include <windows.h>
  28. #include <malloc.h>
  29. #include <stdlib.h>
  30. #include <stdio.h>
  31. #include <time.h>
  32. #include <math.h>
  33. #include "httpextp.h"
  34. /*********************************************************************/
  35. //
  36. // Defines.
  37. //
  38. #define USE_SYNC_IO 1
  39. #define USE_ASYNC_IO 2
  40. #define USE_ADAPTABLE_IO 3
  41. #define INIT_ISAPI_RESPONSE_STACK_SIZE 1024
  42. #define INIT_CLASS1_DATA_BUFFER_STACK_SIZE 1024
  43. #define INIT_CLASS2_DATA_BUFFER_STACK_SIZE 1024
  44. #define NUM_CUSTOM_ADS 360
  45. #define CUSTOM_AD_SIZE 39
  46. #define USER_PROFILE_SIZE 15
  47. #define FREE 0
  48. #define LOCKED -1
  49. #define FILE_DATA_BUFFER_SIZE 8192
  50. #define MAX_COOKIE_STRING_LENGTH 128
  51. #define MAX_FRAGMENT_CACHE_KEY_LENGTH 1024
  52. #define WEIGHTING_MASK 0x0000000f
  53. #define GENDER_MASK 0x30000000
  54. #define AGE_GROUP_MASK 0x0f000000
  55. #define REGION_MASK 0x00f00000
  56. #define INTEREST1_MASK 0x000ffc00
  57. #define INTEREST2_MASK 0x000003ff
  58. /*********************************************************************/
  59. //
  60. // Type definitions.
  61. //
  62. typedef struct class1_data_buffer
  63. {
  64. SINGLE_LIST_ENTRY item_entry;
  65. CHAR buffer[ 10 * 1024 ];
  66. } CLASS1_DATA_BUFFER;
  67. typedef struct class2_data_buffer
  68. {
  69. SINGLE_LIST_ENTRY item_entry;
  70. CHAR buffer[ 100 * 1024 ];
  71. } CLASS2_DATA_BUFFER;
  72. typedef struct isapi_response
  73. {
  74. SINGLE_LIST_ENTRY item_entry;
  75. OVERLAPPED overlapped;
  76. HANDLE hFile;
  77. HSE_VECTOR_ELEMENT vector_element;
  78. DWORD ad_id;
  79. DWORD class_number;
  80. CLASS1_DATA_BUFFER *class1_data_buffer_ptr;
  81. CLASS2_DATA_BUFFER *class2_data_buffer_ptr;
  82. EXTENSION_CONTROL_BLOCK *pECB;
  83. HSE_VECTOR_ELEMENT vector_element_array[ 7 ];
  84. BOOL use_async_vector_send;
  85. HSE_RESPONSE_VECTOR response_vector;
  86. CHAR remote_addr[ 16 ];
  87. CHAR pszHeaders[ 67 + MAX_COOKIE_STRING_LENGTH ];
  88. CHAR set_cookie_string[ MAX_COOKIE_STRING_LENGTH ];
  89. WCHAR unicode_fragment_cache_key[ MAX_FRAGMENT_CACHE_KEY_LENGTH ];
  90. } ISAPI_RESPONSE;
  91. typedef struct custom_ad
  92. {
  93. DWORD ad_id;
  94. DWORD ad_demographics;
  95. DWORD gender_wt;
  96. DWORD age_group_wt;
  97. DWORD region_wt;
  98. DWORD interest1_wt;
  99. DWORD interest2_wt;
  100. DWORD minimum_match_value;
  101. DWORD expiration_time;
  102. } CUSTOM_AD;
  103. typedef struct lock
  104. {
  105. volatile LONG current_state;
  106. volatile LONG num_writers;
  107. } LOCK;
  108. /*********************************************************************/
  109. //
  110. // Global Variables.
  111. //
  112. DWORD g_vector_send_io_mode_config = USE_SYNC_IO;
  113. DWORD g_vector_send_async_range_start = 0;
  114. DWORD g_read_file_io_mode_config = USE_SYNC_IO;
  115. DWORD g_read_file_async_range_start = 0;
  116. CHAR g_root_dir[ MAX_PATH ];
  117. DWORD g_root_dir_length;
  118. CHAR g_app_pool_name[ 1024 ];
  119. DWORD g_app_pool_name_length = 1024;
  120. SLIST_HEADER g_isapi_response_stack;
  121. SLIST_HEADER g_class1_data_buffer_stack;
  122. SLIST_HEADER g_class2_data_buffer_stack;
  123. CUSTOM_AD g_custom_ads_buffer[ NUM_CUSTOM_ADS ];
  124. DWORD *g_user_personalities_buffer = NULL;
  125. LOCK g_user_personalities_buffer_lock;
  126. LOCK g_custom_ads_buffer_lock;
  127. HANDLE g_update_buffers_thread;
  128. CHAR g_fragment_cache_key_base[ MAX_FRAGMENT_CACHE_KEY_LENGTH ];
  129. DWORD g_fragment_cache_key_base_length;
  130. volatile LONG g_fragment_cache_key_base_not_initialized = 1;
  131. DWORD g_num_users;
  132. CHAR *g_pszStatus_200 = "200 OK";
  133. CHAR *g_pszStatus_404 = "404 File Inaccessible";
  134. HSE_VECTOR_ELEMENT g_vector_element_0 = { HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER,
  135. "<html>\n"
  136. "<head><title>SPECweb99 Dynamic GET & POST Test</title></head>\n"
  137. "<body>\n"
  138. "<p>SERVER_SOFTWARE = Microsoft-IIS/6.0\n"
  139. "<p>REMOTE_ADDR = ",
  140. 0,
  141. 132 };
  142. HSE_VECTOR_ELEMENT g_vector_element_2 = { HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER,
  143. "\n<p>SCRIPT_NAME = /specweb99-CAD.dll\n"
  144. "<p>QUERY_STRING = ",
  145. 0,
  146. 55 };
  147. HSE_VECTOR_ELEMENT g_vector_element_4 = { HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER,
  148. "\n<pre>\n",
  149. 0,
  150. 7 };
  151. HSE_VECTOR_ELEMENT g_vector_element_6 = { HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER,
  152. "</pre>\n"
  153. "</body>\n</html>\n",
  154. 0,
  155. 23 };
  156. /*********************************************************************/
  157. //
  158. // Function prototypes.
  159. //
  160. VOID init_lock( LOCK *lock );
  161. VOID acquire_exclusive_lock( LOCK *lock );
  162. VOID release_exclusive_lock( LOCK *lock );
  163. VOID acquire_shared_lock( LOCK *lock );
  164. VOID release_shared_lock( LOCK *lock );
  165. VOID initialize_isapi_response_stack( VOID );
  166. ISAPI_RESPONSE *allocate_isapi_response( VOID );
  167. VOID free_isapi_response( ISAPI_RESPONSE * isapi_response_ptr );
  168. VOID clear_isapi_response_stack( VOID );
  169. VOID initialize_class1_data_buffer_stack( VOID );
  170. CLASS1_DATA_BUFFER *allocate_class1_data_buffer( VOID );
  171. VOID free_class1_data_buffer( CLASS1_DATA_BUFFER *class1_data_buffer_ptr );
  172. VOID clear_class1_data_buffer_stack( VOID );
  173. VOID initialize_class2_data_buffer_stack( VOID );
  174. CLASS2_DATA_BUFFER *allocate_class2_data_buffer( VOID );
  175. VOID free_class2_data_buffer( CLASS2_DATA_BUFFER *class2_data_buffer_ptr );
  176. VOID clear_class2_data_buffer_stack( VOID );
  177. VOID initialize_isapi_response_stack( VOID );
  178. ISAPI_RESPONSE *allocate_isapi_response( VOID );
  179. VOID free_isapi_response( ISAPI_RESPONSE * isapi_response_ptr );
  180. VOID clear_isapi_response_stack( VOID );
  181. BOOL initialize_isapi_response( ISAPI_RESPONSE *isapi_response_ptr,
  182. EXTENSION_CONTROL_BLOCK *pECB,
  183. CHAR *filename,
  184. DWORD filesize,
  185. CHAR *set_cookie_string,
  186. BOOL use_async_vector_send,
  187. DWORD query_string_length );
  188. BOOL load_user_personality_file( VOID );
  189. BOOL load_custom_ads_file( VOID );
  190. DWORD WINAPI update_user_and_ad_buffers( VOID *dummy_parameter );
  191. DWORD send_error_page( EXTENSION_CONTROL_BLOCK *pECB,
  192. CHAR *error_message,
  193. CHAR *status,
  194. DWORD query_string_length );
  195. VOID dword_to_string( DWORD dword,
  196. CHAR *string );
  197. VOID WINAPI vector_send_completion_callback( EXTENSION_CONTROL_BLOCK *pECB,
  198. VOID *pvContext,
  199. DWORD cbIO,
  200. DWORD dwError );
  201. VOID CALLBACK read_file_completion_callback( DWORD dwErrorCode,
  202. DWORD dwNumberOfBytesTransferred,
  203. OVERLAPPED *overlapped );
  204. DWORD determine_set_cookie_string( INT64 user_index,
  205. DWORD last_ad,
  206. CHAR *set_cookie_string );
  207. VOID insert_custom_ad_information( CHAR *buffer, DWORD ad_id );
  208. DWORD handle_class1_or_class2_request( EXTENSION_CONTROL_BLOCK *pECB,
  209. ISAPI_RESPONSE *isapi_response_ptr,
  210. CHAR *filename,
  211. DWORD filesize,
  212. BOOL use_async_vector_send,
  213. DWORD ad_id,
  214. DWORD query_string_length );
  215. BOOL load_registry_data( VOID );
  216. BOOL WINAPI GetExtensionVersion( HSE_VERSION_INFO *pVer );
  217. DWORD WINAPI HttpExtensionProc( EXTENSION_CONTROL_BLOCK *pECB );
  218. BOOL WINAPI TerminateExtension( DWORD dwFlags );
  219. #define LOG_ERROR( text, error ) _LogError(__FUNCTION__, __FILE__, __LINE__, text, error )
  220. void _LogError(const char * function, const char *file, int line, char * text, DWORD error)
  221. {
  222. char buf[1024];
  223. sprintf(buf, "%s(%d) %s - error=0x%x (%d) - %s\n", file, line, function, error, error, text );
  224. OutputDebugStringA(buf);
  225. }
  226. /*********************************************************************/
  227. VOID initialize_isapi_response_stack( VOID )
  228. /*++
  229. Routine Description:
  230. Initializes the stack of free ISAPI_RESPONSE structures on
  231. the heap.
  232. Arguments:
  233. None.
  234. Return Value:
  235. None.
  236. --*/
  237. {
  238. //
  239. // Initialize the SLIST_HEADER head that will be used to implement
  240. // the stack of free ISAPI_RESPONSE structures on the heap.
  241. //
  242. InitializeSListHead( &g_isapi_response_stack );
  243. }
  244. /*********************************************************************/
  245. ISAPI_RESPONSE *allocate_isapi_response( VOID )
  246. /*++
  247. Routine Description:
  248. Pops an element off of the stack of free ISAPI_RESPONSE structures
  249. on the heap.
  250. Arguments:
  251. None.
  252. Return Value:
  253. Returns a pointer to a free ISAPI_RESPONSE structure on the heap.
  254. --*/
  255. {
  256. ISAPI_RESPONSE *isapi_response_ptr;
  257. //
  258. // Attempt to pop a free ISAPI_RESPONSE
  259. // structure off of g_isapi_response_stack.
  260. //
  261. if ( !( isapi_response_ptr =
  262. ( ISAPI_RESPONSE * )InterlockedPopEntrySList( &g_isapi_response_stack ) ) )
  263. {
  264. //
  265. // If g_isapi_response_stack was empty
  266. // allocate a new ISAPI_RESPONSE structure
  267. // off of the heap.
  268. //
  269. isapi_response_ptr = ( ISAPI_RESPONSE * )malloc( sizeof( ISAPI_RESPONSE ) );
  270. }
  271. //
  272. // Return a pointer to the ISAPI_RESPONSE
  273. // structure allocated.
  274. //
  275. return( isapi_response_ptr );
  276. }
  277. /*********************************************************************/
  278. VOID free_isapi_response( ISAPI_RESPONSE *isapi_response_ptr )
  279. /*++
  280. Routine Description:
  281. Pushes an element onto the stack of free ISAPI_RESPONSE structures
  282. on the heap.
  283. Arguments:
  284. isapi_response_ptr - A pointer to a free ISAPI_RESPONSE structure
  285. on the heap.
  286. Return Value:
  287. None.
  288. --*/
  289. {
  290. //
  291. // Pop the input pointer to a free ISAPI_RESPONSE
  292. // structure on the heap onto g_isapi_response_stack.
  293. //
  294. InterlockedPushEntrySList( &g_isapi_response_stack,
  295. ( SINGLE_LIST_ENTRY * )isapi_response_ptr );
  296. }
  297. /*********************************************************************/
  298. VOID clear_isapi_response_stack( VOID )
  299. /*++
  300. Routine Description:
  301. Destroys the stack of free ISAPI_RESPONSE structures on the heap,
  302. freeing all system resources allocated for this data structure.
  303. Arguments:
  304. None.
  305. Return Value:
  306. None.
  307. --*/
  308. {
  309. //
  310. // Flush g_isapi_response_stack of all of
  311. // its elements and set 'curr_struct_ptr'
  312. // to point to a linked list containing
  313. // all of these elements.
  314. //
  315. SINGLE_LIST_ENTRY *curr_struct_ptr = InterlockedFlushSList( &g_isapi_response_stack );
  316. SINGLE_LIST_ENTRY *kill_struct_ptr;
  317. //
  318. // Destroy all elements in the linked
  319. // list initially pointed to by
  320. // 'curr_struct_ptr'.
  321. //
  322. while( curr_struct_ptr )
  323. {
  324. kill_struct_ptr = curr_struct_ptr;
  325. curr_struct_ptr = curr_struct_ptr->Next;
  326. free( ( ISAPI_RESPONSE * )kill_struct_ptr );
  327. }
  328. }
  329. /*********************************************************************/
  330. VOID initialize_class1_data_buffer_stack( VOID )
  331. /*++
  332. Routine Description:
  333. Initializes the stack of free CLASS1_DATA_BUFFER structures on
  334. the heap.
  335. Arguments:
  336. None.
  337. Return Value:
  338. None.
  339. --*/
  340. {
  341. //
  342. // Initialize the SLIST_HEADER head that will be used to implement
  343. // the stack of free CLASS1_DATA_BUFFER structures on the heap.
  344. //
  345. InitializeSListHead( &g_class1_data_buffer_stack );
  346. }
  347. /*********************************************************************/
  348. CLASS1_DATA_BUFFER *allocate_class1_data_buffer( VOID )
  349. /*++
  350. Routine Description:
  351. Pops an element off of the stack of free CLASS1_DATA_BUFFER
  352. structures on the heap.
  353. Arguments:
  354. None.
  355. Return Value:
  356. Returns a pointer to a free CLASS1_DATA_BUFFER structure on
  357. the heap.
  358. --*/
  359. {
  360. CLASS1_DATA_BUFFER *class1_data_buffer_ptr;
  361. //
  362. // Attempt to pop a free CLASS1_DATA_BUFFER
  363. // structure off of g_class1_data_buffer_stack.
  364. //
  365. if ( !( class1_data_buffer_ptr =
  366. ( CLASS1_DATA_BUFFER * )InterlockedPopEntrySList( &g_class1_data_buffer_stack ) ) )
  367. {
  368. //
  369. // If g_class1_data_buffer_stack was empty
  370. // allocate a new CLASS1_DATA_BUFFER structure
  371. // off of the heap.
  372. //
  373. class1_data_buffer_ptr = ( CLASS1_DATA_BUFFER * )malloc( sizeof( CLASS1_DATA_BUFFER ) );
  374. }
  375. //
  376. // Return a pointer to the CLASS1_DATA_BUFFER
  377. // structure allocated.
  378. //
  379. return( class1_data_buffer_ptr );
  380. }
  381. /*********************************************************************/
  382. VOID free_class1_data_buffer( CLASS1_DATA_BUFFER *class1_data_buffer_ptr )
  383. /*++
  384. Routine Description:
  385. Pushes an element onto the stack of free CLASS1_DATA_BUFFER
  386. structures on the heap.
  387. Arguments:
  388. A pointer to a free CLASS1_DATA_BUFFER structure on the heap.
  389. Return Value:
  390. None.
  391. --*/
  392. {
  393. //
  394. // Pop the input pointer to a free CLASS1_DATA_BUFFER
  395. // structure on the heap onto g_class1_data_buffer_stack.
  396. //
  397. InterlockedPushEntrySList( &g_class1_data_buffer_stack,
  398. ( SINGLE_LIST_ENTRY * )class1_data_buffer_ptr );
  399. }
  400. /*********************************************************************/
  401. VOID clear_class1_data_buffer_stack( VOID )
  402. /*++
  403. Routine Description:
  404. Destroys the stack of free CLASS1_DATA_BUFFER structures on the heap,
  405. freeing all system resources allocated for this data structure.
  406. Arguments:
  407. None.
  408. Return Value:
  409. None.
  410. --*/
  411. {
  412. //
  413. // Flush g_class1_data_buffer_stack of all
  414. // of its elements and set 'curr_struct_ptr'
  415. // to point to a linked list containing
  416. // all of these elements.
  417. //
  418. SINGLE_LIST_ENTRY *curr_struct_ptr = InterlockedFlushSList( &g_class1_data_buffer_stack );
  419. SINGLE_LIST_ENTRY *kill_struct_ptr;
  420. //
  421. // Destroy all elements in the linked
  422. // list initially pointed to by
  423. // 'curr_struct_ptr'
  424. //
  425. while( curr_struct_ptr )
  426. {
  427. kill_struct_ptr = curr_struct_ptr;
  428. curr_struct_ptr = curr_struct_ptr->Next;
  429. free( ( CLASS1_DATA_BUFFER * )kill_struct_ptr );
  430. }
  431. }
  432. /*********************************************************************/
  433. VOID initialize_class2_data_buffer_stack( VOID )
  434. /*++
  435. Routine Description:
  436. Initializes the stack of free CLASS2_DATA_BUFFER structures on
  437. the heap.
  438. Arguments:
  439. None.
  440. Return Value:
  441. None.
  442. --*/
  443. {
  444. //
  445. // Initialize the SLIST_HEADER head that will be used to implement
  446. // the stack of free CLASS2_DATA_BUFFER structures on the heap.
  447. //
  448. InitializeSListHead( &g_class2_data_buffer_stack );
  449. }
  450. /*********************************************************************/
  451. CLASS2_DATA_BUFFER *allocate_class2_data_buffer( VOID )
  452. /*++
  453. Routine Description:
  454. Pops an element off of the stack of free CLASS2_DATA_BUFFER
  455. structures on the heap.
  456. Arguments:
  457. None.
  458. Return Value:
  459. Returns a pointer to a free CLASS2_DATA_BUFFER structure on
  460. the heap.
  461. --*/
  462. {
  463. CLASS2_DATA_BUFFER *class2_data_buffer_ptr;
  464. //
  465. // Attempt to pop a free CLASS2_DATA_BUFFER
  466. // structure off of g_class2_data_buffer_stack.
  467. //
  468. if ( !( class2_data_buffer_ptr =
  469. ( CLASS2_DATA_BUFFER * )InterlockedPopEntrySList( &g_class2_data_buffer_stack ) ) )
  470. {
  471. //
  472. // If g_class2_data_buffer_stack was empty
  473. // allocate a new CLASS2_DATA_BUFFER structure
  474. // off of the heap.
  475. //
  476. class2_data_buffer_ptr = ( CLASS2_DATA_BUFFER * )malloc( sizeof( CLASS2_DATA_BUFFER ) );
  477. }
  478. //
  479. // Return a pointer to the CLASS2_DATA_BUFFER
  480. // structure allocated.
  481. //
  482. return( class2_data_buffer_ptr );
  483. }
  484. /*********************************************************************/
  485. VOID free_class2_data_buffer( CLASS2_DATA_BUFFER *class2_data_buffer_ptr )
  486. /*++
  487. Routine Description:
  488. Pushes an element onto the stack of free CLASS2_DATA_BUFFER
  489. structures on the heap.
  490. Arguments:
  491. A pointer to a free CLASS2_DATA_BUFFER structure on the heap.
  492. Return Value:
  493. None.
  494. --*/
  495. {
  496. //
  497. // Push the input pointer to a free CLASS2_DATA_BUFFER
  498. // structure on the heap onto g_class2_data_buffer_stack.
  499. //
  500. InterlockedPushEntrySList( &g_class2_data_buffer_stack,
  501. ( SINGLE_LIST_ENTRY * )class2_data_buffer_ptr );
  502. }
  503. /*********************************************************************/
  504. VOID clear_class2_data_buffer_stack( VOID )
  505. /*++
  506. Routine Description:
  507. Destroys the stack of free CLASS2_DATA_BUFFER structures on the heap,
  508. freeing all system resources allocated for this data structure.
  509. Arguments:
  510. None.
  511. Return Value:
  512. None.
  513. --*/
  514. {
  515. //
  516. // Flush g_class2_data_buffer_stack of all
  517. // of its elements and set 'curr_struct_ptr'
  518. // to point to a linked list containing
  519. // all of these elements.
  520. //
  521. SINGLE_LIST_ENTRY *curr_struct_ptr = InterlockedFlushSList( &g_class2_data_buffer_stack );
  522. SINGLE_LIST_ENTRY *kill_struct_ptr;
  523. //
  524. // Destroy all elements in the linked
  525. // list initially pointed to by
  526. // 'curr_struct_ptr'
  527. //
  528. while( curr_struct_ptr )
  529. {
  530. kill_struct_ptr = curr_struct_ptr;
  531. curr_struct_ptr = curr_struct_ptr->Next;
  532. free( ( CLASS2_DATA_BUFFER * )kill_struct_ptr );
  533. }
  534. }
  535. /*********************************************************************/
  536. BOOL initialize_isapi_response( ISAPI_RESPONSE *isapi_response_ptr,
  537. EXTENSION_CONTROL_BLOCK *pECB,
  538. CHAR *filename,
  539. DWORD filesize,
  540. CHAR *set_cookie_string,
  541. BOOL use_async_vector_send,
  542. DWORD query_string_length )
  543. /*++
  544. Routine Description:
  545. Initialize an ISAPI response structure by populating it with the
  546. appropriate data.
  547. Arguments:
  548. isapi_response_ptr - Pointer to the ISAPI response structure to be
  549. initialized.
  550. pECB - Pointer to the relevant extension control block.
  551. filename - Optional field indicating the absolute name of the file
  552. requested.
  553. filesize - Optional field indicating the size of the file requested.
  554. set_cookie_string - String to use for Set-Cookie HTTP header field.
  555. use_async_vector_send - Flag indicating whether VectorSend is to be
  556. used in asynchronous or synchronous mode.
  557. Return Value:
  558. Returns TRUE on success and FALSE otherwise.
  559. --*/
  560. {
  561. DWORD remote_addr_size = 16; // 16 == sizeof( isapi_response_ptr->remote_addr )
  562. CHAR fragment_cache_key[ MAX_FRAGMENT_CACHE_KEY_LENGTH ];
  563. CHAR content_length_string[ 16 ];
  564. DWORD content_length_string_length = 16; // 16 == sizeof( content_length_string )
  565. DWORD set_cookie_string_length;
  566. DWORD ii;
  567. //
  568. // Set the fragment cache key.
  569. //
  570. strcpy( fragment_cache_key, g_fragment_cache_key_base );
  571. memcpy( fragment_cache_key + g_fragment_cache_key_base_length,
  572. pECB->lpszQueryString,
  573. query_string_length + 1 );
  574. for ( ii = 0;
  575. isapi_response_ptr->unicode_fragment_cache_key[ ii ] = ( WCHAR )fragment_cache_key[ ii ];
  576. ii++ );
  577. //
  578. // Obtain the IP address of the client.
  579. //
  580. if ( !pECB->GetServerVariable( pECB->ConnID,
  581. "REMOTE_ADDR",
  582. isapi_response_ptr->remote_addr,
  583. &remote_addr_size ) )
  584. {
  585. return( FALSE );
  586. }
  587. //
  588. // Obtain the cookie string.
  589. //
  590. strncpy( isapi_response_ptr->set_cookie_string, set_cookie_string, MAX_COOKIE_STRING_LENGTH );
  591. //
  592. // Populate the vector_element_array data structure.
  593. //
  594. isapi_response_ptr->vector_element_array[ 0 ] = g_vector_element_0;
  595. isapi_response_ptr->vector_element_array[ 1 ].ElementType = HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER;
  596. isapi_response_ptr->vector_element_array[ 1 ].pvContext = isapi_response_ptr->remote_addr;
  597. isapi_response_ptr->vector_element_array[ 1 ].cbSize = remote_addr_size - 1;
  598. isapi_response_ptr->vector_element_array[ 2 ] = g_vector_element_2;
  599. isapi_response_ptr->vector_element_array[ 3 ].ElementType = HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER;
  600. isapi_response_ptr->vector_element_array[ 3 ].pvContext = pECB->lpszQueryString;
  601. isapi_response_ptr->vector_element_array[ 3 ].cbSize = query_string_length;
  602. isapi_response_ptr->vector_element_array[ 4 ] = g_vector_element_4;
  603. isapi_response_ptr->vector_element_array[ 5 ].ElementType = HSE_VECTOR_ELEMENT_TYPE_FRAGMENT;
  604. isapi_response_ptr->vector_element_array[ 5 ].pvContext = ( DWORD * )isapi_response_ptr->unicode_fragment_cache_key;
  605. isapi_response_ptr->vector_element_array[ 6 ] = g_vector_element_6;
  606. //
  607. // Populate the HSE_RESPONSE_VECTOR structure.
  608. // To do this, use the following steps...
  609. //
  610. //
  611. // First, compute the string of HTTP headers to be sent with the
  612. // response. To avoid a costly sprintf call, we will use memcpy
  613. // instead.
  614. //
  615. //
  616. // Copy the initial "hardcoded" component of the HTTP header string.
  617. //
  618. strcpy( isapi_response_ptr->pszHeaders,
  619. "Content-type: text/html\r\n"
  620. "Content-Length: " );
  621. //
  622. // Construct a string representing the value of the HTTP Content-Length
  623. // header field. Determine and store the length of this string. Note
  624. // that 16 is the size of the buffer to which the content_length_string
  625. // is written.
  626. //
  627. dword_to_string( ( DWORD )( filesize +
  628. isapi_response_ptr->vector_element_array[ 0 ].cbSize +
  629. isapi_response_ptr->vector_element_array[ 1 ].cbSize +
  630. isapi_response_ptr->vector_element_array[ 2 ].cbSize +
  631. isapi_response_ptr->vector_element_array[ 3 ].cbSize +
  632. isapi_response_ptr->vector_element_array[ 4 ].cbSize +
  633. isapi_response_ptr->vector_element_array[ 6 ].cbSize ),
  634. content_length_string );
  635. //
  636. // Concatenate the content length string to the header
  637. // string. Note that prior to this operation the length
  638. // of the header string is 41.
  639. //
  640. memcpy( isapi_response_ptr->pszHeaders + 41,
  641. content_length_string,
  642. content_length_string_length = strlen( content_length_string ) );
  643. //
  644. // Concatenate the 14 character hardcoded string "\r\nSet-Cookie: "
  645. // to the header string. Note that just prior to this operation
  646. // the length of the header string is given by the variable 'ii'.
  647. //
  648. ii = 41 + content_length_string_length;
  649. memcpy( isapi_response_ptr->pszHeaders + ii,
  650. "\r\nSet-Cookie: ",
  651. 14 );
  652. //
  653. // Concatenate the Set-Cookie string to the header string. Note
  654. // that just prior to this operation the length of the header
  655. // string is given by the variable ii.
  656. //
  657. ii += 14;
  658. memcpy( isapi_response_ptr->pszHeaders + ii,
  659. set_cookie_string,
  660. set_cookie_string_length = strlen( set_cookie_string ) );
  661. //
  662. // Concatenate the 5 character hardcoded string "\r\n\r\n\0"
  663. // to the header string, indicating its termination.
  664. //
  665. ii += set_cookie_string_length;
  666. memcpy( isapi_response_ptr->pszHeaders + ii, "\r\n\r\n\0", 5 );
  667. //
  668. // Set the 'pszHeaders' field of the HSE_RESPONSE_VECTOR structure
  669. // to point to the HTTP header string just computed.
  670. //
  671. isapi_response_ptr->response_vector.pszHeaders = isapi_response_ptr->pszHeaders;
  672. //
  673. // Set the 'lpElementArray' field of the HSE_RESPONSE_VECTOR structure
  674. // to point to the array of HSE_VECTOR_ELEMENT structures populated
  675. // above.
  676. //
  677. isapi_response_ptr->response_vector.lpElementArray = isapi_response_ptr->vector_element_array;
  678. //
  679. // Indicate that the HSE_RESPONSE_VECTOR structure
  680. // has seven entries.
  681. //
  682. isapi_response_ptr->response_vector.nElementCount = 7;
  683. //
  684. // Set the HTTP status to "200 OK".
  685. //
  686. isapi_response_ptr->response_vector.pszStatus = g_pszStatus_200;
  687. //
  688. // Set the 'dwFlags' field of the HSE_RESPONSE_VECTOR structure
  689. // based on whether or not asynchronous VectorSend is to be
  690. // used.
  691. //
  692. if ( use_async_vector_send )
  693. {
  694. isapi_response_ptr->response_vector.dwFlags = //HSE_IO_FINAL_SEND |
  695. HSE_IO_SEND_HEADERS |
  696. HSE_IO_ASYNC;
  697. }
  698. else
  699. {
  700. isapi_response_ptr->response_vector.dwFlags = //HSE_IO_FINAL_SEND |
  701. HSE_IO_SEND_HEADERS |
  702. HSE_IO_SYNC;
  703. }
  704. //
  705. // Set the following additional fields if the ISAPI
  706. // response is to be sent to the client using
  707. // asynchronous VectorSend.
  708. //
  709. if ( use_async_vector_send )
  710. {
  711. //
  712. // By setting an 'hFile' HANDLE field we can check, in the
  713. // VectorSend completion callback routine, whether the
  714. // asynchronous VectorSend operation just completed made
  715. // use of a file handle. If so, we must close the handle
  716. // in this callback.
  717. //
  718. isapi_response_ptr->hFile = INVALID_HANDLE_VALUE;
  719. }
  720. //
  721. // If you have not yet returned indicating failure, return
  722. // indicating success.
  723. //
  724. return( TRUE );
  725. }
  726. /*********************************************************************/
  727. VOID init_lock( LOCK *lock )
  728. /*++
  729. Routine Description:
  730. Initializes a LOCK object.
  731. NOTE: This locking mechanism is directly based on the dual spin
  732. lock implemented by Neel Jain (njain) for use in the original
  733. SPECweb99 ISAPI. Its reliability remains to be determined.
  734. Arguments:
  735. A pointer to the LOCK object to be initialized.
  736. Return Value:
  737. None.
  738. --*/
  739. {
  740. //
  741. // Indicate that shared ownership is not currently held.
  742. //
  743. lock->current_state = FREE;
  744. //
  745. // Indicate that exclusive ownership is not currently held or being
  746. // waited for.
  747. //
  748. lock->num_writers = 0;
  749. }
  750. /*********************************************************************/
  751. VOID acquire_exclusive_lock( LOCK *lock )
  752. /*++
  753. Routine Description:
  754. Attempts to acquire exclusive ownership of a LOCK object.
  755. NOTE: This locking mechanism is directly based on the dual spin
  756. lock implemented by Neel Jain (njain) for use in the original
  757. SPECweb99 ISAPI. Its reliability remains to be determined.
  758. Arguments:
  759. A pointer to the LOCK object to be acquired.
  760. Return Value:
  761. None.
  762. --*/
  763. {
  764. //
  765. // Indicate that exclusive ownership has been requested.
  766. //
  767. InterlockedIncrement( &( lock->num_writers ) );
  768. while( TRUE )
  769. {
  770. //
  771. // If no other shared or exclusive ownership is held, do
  772. // the following...
  773. //
  774. if ( lock->current_state == FREE )
  775. {
  776. //
  777. // If no other shared or exclusive ownership is held,
  778. // attempt to gain exclusive ownership.
  779. //
  780. if ( FREE == InterlockedCompareExchange( &( lock->current_state ), LOCKED, FREE ) )
  781. {
  782. //
  783. // If exclusive ownership was gained, return.
  784. //
  785. return;
  786. }
  787. else
  788. {
  789. //
  790. // If exclusive ownership could not be gained, go to the
  791. // top of the loop.
  792. //
  793. continue;
  794. }
  795. }
  796. //
  797. // Otherwise, if shared or exclusive ownership is held,
  798. // essentially block this thread and switch to another that
  799. // is ready.
  800. //
  801. else
  802. {
  803. SwitchToThread();
  804. }
  805. }
  806. }
  807. /*********************************************************************/
  808. VOID release_exclusive_lock( LOCK *lock )
  809. /*++
  810. Routine Description:
  811. Relinquishes exclusive ownership of a LOCK object.
  812. NOTE: This locking mechanism is directly based on the dual spin
  813. lock implemented by Neel Jain (njain) for use in the original
  814. SPECweb99 ISAPI. Its reliability remains to be determined.
  815. Arguments:
  816. A pointer to the LOCK object to be released.
  817. Return Value:
  818. None.
  819. --*/
  820. {
  821. //
  822. // Indicate that neither shared nor exclusive ownership is now
  823. // held.
  824. //
  825. lock->current_state = FREE;
  826. //
  827. // Indicate that no exclusive ownership is now held or being
  828. // waited for.
  829. //
  830. InterlockedDecrement( &( lock->num_writers ) );
  831. }
  832. /*********************************************************************/
  833. VOID acquire_shared_lock( LOCK *lock )
  834. /*++
  835. Routine Description:
  836. Attempts to acquire shared ownership of a LOCK object.
  837. NOTE: This locking mechanism is directly based on the dual spin
  838. lock implemented by Neel Jain (njain) for use in the original
  839. SPECweb99 ISAPI. Its reliability remains to be determined.
  840. Arguments:
  841. A pointer to the LOCK object to be acquired.
  842. Return Value:
  843. None.
  844. --*/
  845. {
  846. LONG current_state;
  847. LONG writers_waiting;
  848. while( TRUE )
  849. {
  850. current_state = lock->current_state;
  851. writers_waiting = lock->num_writers;
  852. //
  853. // If no exclusive ownership of the lock is currently
  854. // held or being waited for, do the following...
  855. //
  856. if ( ( current_state != LOCKED ) && ( !writers_waiting ) )
  857. {
  858. //
  859. // Attempt to acquire a new instance of shared ownership
  860. // of the lock.
  861. //
  862. if ( current_state == InterlockedCompareExchange( &( lock->current_state ),
  863. current_state + 1,
  864. current_state ) )
  865. {
  866. //
  867. // If shared ownership was gained, return.
  868. //
  869. return;
  870. }
  871. else
  872. {
  873. //
  874. // If shared ownership could not be gained, go to the
  875. // top of the loop.
  876. //
  877. continue;
  878. }
  879. }
  880. //
  881. // Otherwise, if shared or exclusive ownership is held,
  882. // essentially block this thread and switch to another that
  883. // is ready.
  884. //
  885. else
  886. {
  887. SwitchToThread();
  888. }
  889. }
  890. }
  891. /*********************************************************************/
  892. VOID release_shared_lock( LOCK *lock )
  893. /*++
  894. Routine Description:
  895. Relinquishes shared ownership of a LOCK object.
  896. NOTE: This locking mechanism is directly based on the dual spin
  897. lock implemented by Neel Jain (njain) for use in the original
  898. SPECweb99 ISAPI. Its reliability remains to be determined.
  899. Arguments:
  900. A pointer to the LOCK object to be released.
  901. Return Value:
  902. None.
  903. --*/
  904. {
  905. //
  906. // Indicate that one fewer instance of shared ownership is
  907. // now held.
  908. //
  909. InterlockedDecrement( &( lock->current_state ) );
  910. }
  911. /*********************************************************************/
  912. BOOL load_user_personality_file( VOID )
  913. /*++
  914. Routine Description:
  915. Loads the User.Personality file data into an easily accessible
  916. in-memory data structure.
  917. Arguments:
  918. None.
  919. Return Value:
  920. Returns TRUE if the User.Personality file data is successfully
  921. loaded into the in-memory data structure and FALSE otherwise.
  922. --*/
  923. {
  924. CHAR user_personality_filename[ MAX_PATH ];
  925. HANDLE hFile;
  926. DWORD user_personality_filesize;
  927. CHAR *user_personality_file_data_buffer = NULL;
  928. DWORD bytes_read;
  929. DWORD user_id;
  930. DWORD ii;
  931. //
  932. // Read the User.Personality file into memory. To do this, first
  933. // obtain a handle on this file.
  934. //
  935. strcpy( user_personality_filename, g_root_dir );
  936. strcat( user_personality_filename, "/User.Personality" );
  937. if ( ( hFile = CreateFile( user_personality_filename,
  938. GENERIC_READ,
  939. FILE_SHARE_READ,
  940. NULL,
  941. OPEN_EXISTING,
  942. FILE_ATTRIBUTE_NORMAL,
  943. NULL ) ) == INVALID_HANDLE_VALUE )
  944. {
  945. return( FALSE );
  946. }
  947. //
  948. // Determine the size of the User.Personality file.
  949. //
  950. user_personality_filesize = GetFileSize( hFile, NULL );
  951. //
  952. // Allocate a new memory buffer to hold the raw data of the
  953. // latest version of the User.Personality file.
  954. //
  955. if ( !( user_personality_file_data_buffer = ( CHAR * )malloc( user_personality_filesize ) ) )
  956. {
  957. CloseHandle( hFile );
  958. return( FALSE );
  959. }
  960. //
  961. // Load the raw User.Personality file data into the allocated
  962. // buffer and close the handle to this file.
  963. //
  964. if ( !ReadFile( hFile,
  965. user_personality_file_data_buffer,
  966. user_personality_filesize,
  967. &bytes_read,
  968. NULL ) )
  969. {
  970. CloseHandle( hFile );
  971. return( FALSE );
  972. }
  973. CloseHandle( hFile );
  974. //
  975. // Store the User.Personality file data in a DWORD array that is
  976. // indexed by user ID and whose entries consist of user demographics
  977. // data. This structure makes it easier to access this data than
  978. // if it were read from the raw User.Personality file data.
  979. //
  980. //
  981. // If a DWORD array containing the data for a previous version of the
  982. // User.Personality file exists, free it.
  983. //
  984. if ( g_user_personalities_buffer )
  985. {
  986. free( g_user_personalities_buffer );
  987. g_user_personalities_buffer = NULL;
  988. }
  989. //
  990. // Allocate a new DWORD array.
  991. //
  992. g_num_users = user_personality_filesize / USER_PROFILE_SIZE;
  993. if ( !( g_user_personalities_buffer = ( DWORD * )malloc( g_num_users * sizeof( DWORD ) ) ) )
  994. {
  995. return( FALSE );
  996. }
  997. //
  998. // Fill the DWORD array using the raw User.Personality file data.
  999. //
  1000. for ( ii = 0; ii < g_num_users; ii++ )
  1001. {
  1002. sscanf( user_personality_file_data_buffer + ( ii * USER_PROFILE_SIZE ),
  1003. "%5d %8X",
  1004. &user_id,
  1005. &( g_user_personalities_buffer[ ii ] )
  1006. );
  1007. }
  1008. //
  1009. // Free the buffer containing the raw User.Personality file data.
  1010. //
  1011. free( user_personality_file_data_buffer );
  1012. //
  1013. // If we have not yet returned indicating failure, return indicating
  1014. // success.
  1015. //
  1016. return( TRUE );
  1017. }
  1018. /*********************************************************************/
  1019. BOOL load_custom_ads_file( VOID )
  1020. /*++
  1021. Routine Description:
  1022. Loads the Custom.Ads file data into an easily accessible in-memory
  1023. data structure.
  1024. Arguments:
  1025. None.
  1026. Return Value:
  1027. Returns TRUE is the Custom.Ads file data is successfully
  1028. loaded into the in-memory data structure and false otherwise.
  1029. --*/
  1030. {
  1031. CHAR custom_ads_filename[ MAX_PATH ];
  1032. DWORD custom_ad_filesize = NUM_CUSTOM_ADS * CUSTOM_AD_SIZE;
  1033. CHAR custom_ads_file_data_buffer[ NUM_CUSTOM_ADS * CUSTOM_AD_SIZE ];
  1034. HANDLE hFile;
  1035. DWORD bytes_read;
  1036. DWORD weightings;
  1037. DWORD ii;
  1038. //
  1039. // Read the Custom.Ads file into memory. To do this, first
  1040. // obtain a handle on this file.
  1041. //
  1042. strcpy( custom_ads_filename, g_root_dir );
  1043. strcat( custom_ads_filename, "/Custom.Ads" );
  1044. if ( ( hFile = CreateFile( custom_ads_filename,
  1045. GENERIC_READ,
  1046. FILE_SHARE_READ,
  1047. NULL,
  1048. OPEN_EXISTING,
  1049. FILE_ATTRIBUTE_NORMAL,
  1050. NULL ) ) == INVALID_HANDLE_VALUE )
  1051. {
  1052. return( FALSE );
  1053. }
  1054. //
  1055. // Load the raw Custom.Ads file data into an in-memory buffer
  1056. // and close the handle to this file.
  1057. //
  1058. if ( !ReadFile( hFile,
  1059. custom_ads_file_data_buffer,
  1060. custom_ad_filesize,
  1061. &bytes_read,
  1062. NULL ) )
  1063. {
  1064. CloseHandle( hFile );
  1065. return( FALSE );
  1066. }
  1067. CloseHandle( hFile );
  1068. //
  1069. // Store the Custom.Ads file data in an array (indexed by ad ID)
  1070. // of structs whose fields represent the individual data items that
  1071. // comprise a custom ad. This structure makes it easier to access
  1072. // this data than if it were read from the raw Custom.Ads file.
  1073. //
  1074. for ( ii = 0; ii < NUM_CUSTOM_ADS; ii++ )
  1075. {
  1076. sscanf( custom_ads_file_data_buffer + ( ii * CUSTOM_AD_SIZE ),
  1077. "%5d %8X %8X %3d %10d",
  1078. &( g_custom_ads_buffer[ ii ].ad_id ),
  1079. &( g_custom_ads_buffer[ ii ].ad_demographics ),
  1080. &weightings,
  1081. &( g_custom_ads_buffer[ ii ].minimum_match_value ),
  1082. &( g_custom_ads_buffer[ ii ].expiration_time ) );
  1083. g_custom_ads_buffer[ ii ].gender_wt = ( weightings >> 16 ) & WEIGHTING_MASK;
  1084. g_custom_ads_buffer[ ii ].age_group_wt = ( weightings >> 12 ) & WEIGHTING_MASK;
  1085. g_custom_ads_buffer[ ii ].region_wt = ( weightings >> 8 ) & WEIGHTING_MASK;
  1086. g_custom_ads_buffer[ ii ].interest1_wt = ( weightings >> 4 ) & WEIGHTING_MASK;
  1087. g_custom_ads_buffer[ ii ].interest2_wt = weightings & WEIGHTING_MASK;
  1088. }
  1089. //
  1090. // If we have made it this far without returning indicating failure,
  1091. // return indicating success.
  1092. //
  1093. return( TRUE );
  1094. }
  1095. /*********************************************************************/
  1096. DWORD WINAPI update_user_and_ad_buffers( VOID *dummy_parameter )
  1097. /*++
  1098. Routine Description:
  1099. This function defines a persistent thread that waits on a change
  1100. notification event that is signaled whenever a file in the webserver
  1101. document root is changed (i.e. User.Personality or Custom.Ads) and
  1102. refreshes the in-memory data structures holding the User.Personality
  1103. and Custom.Ads file data with data from the latest versions of these
  1104. files on disk.
  1105. Arguments:
  1106. dummy_parameter - An unused parameter passed through the call to the
  1107. Win32 CreateThread function that invokes the routine
  1108. in a new thread. This parameter added for compatibility
  1109. the CreateThread interface.
  1110. Return Values:
  1111. None. This routine implements a persistent thread that cannot fail
  1112. and so, never returns.
  1113. --*/
  1114. {
  1115. //
  1116. // Create a change notification event that is put in its signalled
  1117. // state whenever a file in the webserver document root directory is
  1118. // modified. Note that the only such files that could possible be
  1119. // changes are the User.Personality and Custom.Ads files.
  1120. //
  1121. HANDLE hEvent = FindFirstChangeNotification( g_root_dir,
  1122. FALSE,
  1123. FILE_NOTIFY_CHANGE_LAST_WRITE );
  1124. //
  1125. // Repeat the following steps indefinitely.
  1126. //
  1127. while( TRUE )
  1128. {
  1129. FindNextChangeNotification( hEvent );
  1130. //
  1131. // Wait for a file under the webserver document root to be
  1132. // written to.
  1133. //
  1134. WaitForSingleObject( hEvent, INFINITE );
  1135. //
  1136. // Refresh the User.Preferences file data in memory.
  1137. //
  1138. acquire_exclusive_lock( &g_user_personalities_buffer_lock );
  1139. load_user_personality_file();
  1140. release_exclusive_lock( &g_user_personalities_buffer_lock );
  1141. //
  1142. // Refresh the Custom.Ads file data in memory.
  1143. //
  1144. acquire_exclusive_lock( &g_custom_ads_buffer_lock );
  1145. load_custom_ads_file();
  1146. release_exclusive_lock( &g_custom_ads_buffer_lock );
  1147. }
  1148. }
  1149. /*********************************************************************/
  1150. DWORD send_error_page( EXTENSION_CONTROL_BLOCK *pECB,
  1151. CHAR *error_message,
  1152. CHAR *status,
  1153. DWORD query_string_length )
  1154. /*++
  1155. Routine Description:
  1156. Sends an HTML error page with a message and status specified by the
  1157. caller.
  1158. Arguments:
  1159. pECB - Pointer to the relevant extension control block.
  1160. error_msg - Error message to send.
  1161. status - Status to send (e.g. "200 OK").
  1162. Return Value:
  1163. Returns HSE_STATUS_SUCCESS if the error page was successfully
  1164. written to the client and HSE_STATUS_ERROR otherwise.
  1165. --*/
  1166. {
  1167. ISAPI_RESPONSE local_isapi_response;
  1168. ISAPI_RESPONSE *isapi_response_ptr = &local_isapi_response;
  1169. CHAR content_length_string[ 16 ];
  1170. DWORD content_length_string_length;
  1171. DWORD ii;
  1172. //
  1173. // Initialize the ISAPI response structure to be associated
  1174. // with the error page.
  1175. //
  1176. if ( !initialize_isapi_response( isapi_response_ptr,
  1177. pECB,
  1178. "",
  1179. 0,
  1180. "",
  1181. FALSE,
  1182. query_string_length ) )
  1183. {
  1184. LOG_ERROR("initialize_isapi_response failed", 0 );
  1185. return( HSE_STATUS_ERROR );
  1186. }
  1187. //
  1188. // Change the response_vector and vector_element_array in the
  1189. // ISAPI response structure to specify and error message (to be
  1190. // transmitted using synchronous I/O). To do this use the
  1191. // following steps...
  1192. //
  1193. //
  1194. // Change the fifth element of the vector_element_array in the
  1195. // ISAPI_RESPONSE structure (i.e. the "meat" of the message) to contain
  1196. // the error message.
  1197. //
  1198. isapi_response_ptr->vector_element_array[ 5 ].ElementType = HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER;
  1199. isapi_response_ptr->vector_element_array[ 5 ].pvContext = error_message;
  1200. isapi_response_ptr->vector_element_array[ 5 ].cbSize = strlen( error_message );
  1201. isapi_response_ptr->vector_element_array[ 5 ].cbOffset = 0;
  1202. //
  1203. // Construct the headers of the HTTP response. Instead of using
  1204. // a slow sprintf call, do the following...
  1205. //
  1206. //
  1207. // Construct the first part of the header string.
  1208. //
  1209. strcat( isapi_response_ptr->pszHeaders,
  1210. "Content-Type: text/html\r\n"
  1211. "Content-Length: " );
  1212. //
  1213. // Construct a string containing the value of the 'Content-Length'
  1214. // header field and use memcpy to concatenate it onto the existing
  1215. // header string (which, incidentally is 41 characters long at this
  1216. // point).
  1217. //
  1218. dword_to_string( ( DWORD )( isapi_response_ptr->vector_element_array[ 0 ].cbSize +
  1219. isapi_response_ptr->vector_element_array[ 1 ].cbSize +
  1220. isapi_response_ptr->vector_element_array[ 2 ].cbSize +
  1221. isapi_response_ptr->vector_element_array[ 3 ].cbSize +
  1222. isapi_response_ptr->vector_element_array[ 4 ].cbSize +
  1223. isapi_response_ptr->vector_element_array[ 5 ].cbSize +
  1224. isapi_response_ptr->vector_element_array[ 6 ].cbSize ),
  1225. content_length_string );
  1226. memcpy( isapi_response_ptr->pszHeaders + 41,
  1227. content_length_string,
  1228. content_length_string_length = strlen( content_length_string ) );
  1229. //
  1230. // Now, use memcpy to concatenate the trailing new-line, carriage
  1231. // return and null terminator characters that denote the end of
  1232. // HTTP headers (incidentally, the header string is 41 + content_
  1233. // length_string_length characters long before this concatenation.
  1234. //
  1235. ii = 41 + content_length_string_length;
  1236. memcpy( isapi_response_ptr->pszHeaders + ii,
  1237. "\r\n\r\n\0",
  1238. 5 );
  1239. isapi_response_ptr->response_vector.pszStatus = status;
  1240. //
  1241. // Finally, send out the error page.
  1242. //
  1243. if ( !pECB->ServerSupportFunction( pECB->ConnID,
  1244. HSE_REQ_VECTOR_SEND,
  1245. &( isapi_response_ptr->response_vector ),
  1246. NULL,
  1247. NULL ) )
  1248. {
  1249. LOG_ERROR("VectorSend() for error page failed", GetLastError() );
  1250. return( HSE_STATUS_ERROR );
  1251. }
  1252. //
  1253. // If you have made it this far without returning indicating an
  1254. // error, return indicating success.
  1255. //
  1256. return( HSE_STATUS_SUCCESS );
  1257. }
  1258. /*********************************************************************/
  1259. VOID dword_to_string( DWORD dword, CHAR *string )
  1260. /*++
  1261. Routine Description:
  1262. Generates a character string that captures the decimal representation
  1263. of a DWORD.
  1264. Arguments:
  1265. dword - The DWORD whose decimal representation is to be captured in
  1266. a character string.
  1267. string - A pointer to the buffer in which the character string generated
  1268. is to be stored.
  1269. string_buffer_size - A pointer to a DWORD which contains the size of
  1270. the output buffer provided. On completion, the
  1271. size of the string generated is written to the
  1272. DWORD pointed to by this parameter.
  1273. Return Value:
  1274. None.
  1275. --*/
  1276. {
  1277. DWORD num_digits;
  1278. INT ii;
  1279. //
  1280. // Determine the number of digits in the decimal
  1281. // representation of the input DWORD by taking the
  1282. // integer part of its base 10 representation.
  1283. //
  1284. num_digits = ( DWORD )log10( dword ) + 1;
  1285. //
  1286. // Scroll through and fill the output buffer from the
  1287. // lowest order to the highest order digit. On each
  1288. // iteration the lowest order decimal digit is obtained
  1289. // by using a modulo 10 (i.e. % 10) operation and then
  1290. // dropped by performing an integer division by 10.
  1291. //
  1292. for ( ii = num_digits - 1; ii >= 0; ii-- )
  1293. {
  1294. string[ ii ] = '0' + ( CHAR )( dword % 10 );
  1295. dword /= 10;
  1296. }
  1297. //
  1298. // Set the '\0' terminating character of the
  1299. // output string after the lowest order digit.
  1300. //
  1301. string[ num_digits ] = '\0';
  1302. }
  1303. /*********************************************************************/
  1304. VOID WINAPI vector_send_completion_callback( EXTENSION_CONTROL_BLOCK *pECB,
  1305. VOID *pvContext,
  1306. DWORD cbIO,
  1307. DWORD dwError )
  1308. /*++
  1309. Routine Description:
  1310. Callback invoked after completion of an asynchronous VectorSend.
  1311. Arguments:
  1312. pECB - Pointer to the relevant extension control block.
  1313. pContext - Pointer to the relevant ISAPI response structure.
  1314. cbIO - Number of bytes sent.
  1315. dwError - Error code for the VectorSend.
  1316. Return Value:
  1317. None.
  1318. --*/
  1319. {
  1320. ISAPI_RESPONSE *isapi_response_ptr = ( ISAPI_RESPONSE * )pvContext;
  1321. DWORD status = HSE_STATUS_SUCCESS;
  1322. //
  1323. // If the file was sent using a file handle, close that
  1324. // handle.
  1325. //
  1326. if ( isapi_response_ptr->hFile != INVALID_HANDLE_VALUE )
  1327. {
  1328. CloseHandle( isapi_response_ptr->hFile );
  1329. isapi_response_ptr->hFile = INVALID_HANDLE_VALUE;
  1330. }
  1331. //
  1332. // Free any class 1 or class 2 data buffer structs used
  1333. // by pushing them back onto the stack of free CLASS1_
  1334. // DATA_BUFFER or the stack of free CLASS2_DATA_BUFFER
  1335. // structures on the heap, respectively.
  1336. //
  1337. if ( isapi_response_ptr->class_number == 1 )
  1338. {
  1339. free_class1_data_buffer( isapi_response_ptr->class1_data_buffer_ptr );
  1340. }
  1341. else if ( isapi_response_ptr->class_number == 2 )
  1342. {
  1343. free_class2_data_buffer( isapi_response_ptr->class2_data_buffer_ptr );
  1344. }
  1345. //
  1346. // Free the ISAPI response structure used by pushing
  1347. // it back on the stack of free ISAPI_RESPONSE
  1348. // structures.
  1349. //
  1350. free_isapi_response( ( ISAPI_RESPONSE * )pvContext );
  1351. //
  1352. // Indicate successful completion or failed completion of
  1353. // client request servicing by calling the HSE_REQ_DONE_
  1354. // WITH_SESSION ServerSupportFunction with the appropriate
  1355. // status code.
  1356. //
  1357. if ( dwError != ERROR_SUCCESS )
  1358. {
  1359. LOG_ERROR("Completion returned error", dwError );
  1360. status = HSE_STATUS_ERROR;
  1361. }
  1362. pECB->ServerSupportFunction( pECB->ConnID,
  1363. HSE_REQ_DONE_WITH_SESSION,
  1364. &status,
  1365. NULL,
  1366. NULL );
  1367. }
  1368. /*********************************************************************/
  1369. VOID CALLBACK read_file_completion_callback( DWORD dwErrorCode,
  1370. DWORD dwNumberOfBytesTransferred,
  1371. OVERLAPPED *overlapped )
  1372. /*++
  1373. Routine Description:
  1374. Callback routine invoked after completion of the asynchronous call
  1375. to ReadFile in handle_class1_or_class2_request. Continues handling
  1376. of a SPECweb99 dynamic GET with custom ad rotation operation in
  1377. which a class 1 or class 2 file is requested.
  1378. Arguments:
  1379. dwErrorCode - Error code returned for the asynchronous ReadFile
  1380. operation.
  1381. dwNumberOfBytesTransferred - Number of bytes transferred in the
  1382. asynchronous ReadFile operation.
  1383. overlapped - A pointer to the OVERLAPPED structure used in the
  1384. asynchronous ReadFile operation. Note that this
  1385. OVERLAPPED structure is the second field of the
  1386. relevant ISAPI_RESPONSE structure, coming immediately
  1387. after a SINGLE_LIST_ENTRY field.
  1388. Return Values:
  1389. None.
  1390. --*/
  1391. {
  1392. ISAPI_RESPONSE *isapi_response_ptr =
  1393. ( ISAPI_RESPONSE * )( ( ( BYTE * )overlapped ) - sizeof( SINGLE_LIST_ENTRY ) );
  1394. CHAR *buffer;
  1395. DWORD status = HSE_STATUS_SUCCESS;
  1396. HCONN connection_id;
  1397. //
  1398. // Now that the asynchronous ReadFile has been is past us,
  1399. // we are done with the copy of the file requested on disk and
  1400. // so, can close the handle to it.
  1401. //
  1402. CloseHandle( isapi_response_ptr->hFile );
  1403. isapi_response_ptr->hFile = INVALID_HANDLE_VALUE;
  1404. //
  1405. // Check if the asynchronous ReadFile operation completed
  1406. // successfully. If not, bomb out.
  1407. //
  1408. if ( dwErrorCode != ERROR_SUCCESS )
  1409. {
  1410. //
  1411. // Cache away the connection ID stored "in" the ISAPI_RESPONSE
  1412. // structure used as we will need it to call the HSE_REQ_DONE_
  1413. // WITH_SESSION ServerSupportFunction even after we have
  1414. // deallocated the ISAPI_RESPONSE structure.
  1415. //
  1416. connection_id = isapi_response_ptr->pECB->ConnID;
  1417. //
  1418. // In the error case free any ISAPI_RESPONSE
  1419. // or CLASS?_DATA_BUFFER structures allocated.
  1420. //
  1421. if ( isapi_response_ptr->class_number == 1 )
  1422. {
  1423. free_class1_data_buffer( isapi_response_ptr->class1_data_buffer_ptr );
  1424. }
  1425. else
  1426. {
  1427. free_class2_data_buffer( isapi_response_ptr->class2_data_buffer_ptr );
  1428. }
  1429. free_isapi_response( isapi_response_ptr );
  1430. //
  1431. // Indicate to IIS that you are finished servicing
  1432. // the client request due to an error, by calling
  1433. // the HSE_REQ_DONE_WITH_SESSION ServerSupportFunction
  1434. // with an HSE_STATUS_ERROR status code.
  1435. //
  1436. status = HSE_STATUS_ERROR;
  1437. isapi_response_ptr->pECB->ServerSupportFunction( connection_id,
  1438. HSE_REQ_DONE_WITH_SESSION,
  1439. &status,
  1440. NULL,
  1441. NULL );
  1442. return;
  1443. }
  1444. if ( isapi_response_ptr->class_number == 1 )
  1445. {
  1446. buffer = isapi_response_ptr->class1_data_buffer_ptr->buffer;
  1447. }
  1448. else
  1449. {
  1450. buffer = isapi_response_ptr->class2_data_buffer_ptr->buffer;
  1451. }
  1452. //
  1453. // Process the raw file data read into memory
  1454. // to ensure that the appropriate custom ad
  1455. // information is inserted.
  1456. //
  1457. insert_custom_ad_information( buffer, isapi_response_ptr->ad_id );
  1458. //
  1459. // Now that the processing of the file data in the buffer
  1460. // is complete, we are ready to send it off to the client.
  1461. // To do this, set the sixth item in the response vector
  1462. // (i.e. the meat of the ISAPI response) to be the data
  1463. // buffer containing the processed file data.
  1464. //
  1465. // Note that the size of the file data to be sent was
  1466. // not changed in the processing applied and so, the
  1467. // HTTP headers or other fields dependent on content
  1468. // length do not need to be changed.
  1469. //
  1470. isapi_response_ptr->vector_element_array[ 5 ].ElementType = HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER;
  1471. isapi_response_ptr->vector_element_array[ 5 ].pvContext = buffer;
  1472. isapi_response_ptr->vector_element_array[ 5 ].cbSize = dwNumberOfBytesTransferred;
  1473. isapi_response_ptr->vector_element_array[ 5 ].cbOffset = 0;
  1474. //
  1475. // Perform the synchronous or asynchronous VectorSend
  1476. // operation.
  1477. //
  1478. if ( !isapi_response_ptr->pECB->ServerSupportFunction( isapi_response_ptr->pECB->ConnID,
  1479. HSE_REQ_VECTOR_SEND,
  1480. &( isapi_response_ptr->response_vector ),
  1481. NULL,
  1482. NULL ) )
  1483. {
  1484. //
  1485. // Cache away the connection ID stored "in" the ISAPI_RESPONSE
  1486. // structure used as we will need it to call the HSE_REQ_DONE_
  1487. // WITH_SESSION ServerSupportFunction even after we have
  1488. // deallocated the ISAPI_RESPONSE structure.
  1489. //
  1490. connection_id = isapi_response_ptr->pECB->ConnID;
  1491. //
  1492. // In the error case, free any ISAPI_RESPONSE
  1493. // or CLASS?_DATA_BUFFER structures allocated.
  1494. //
  1495. if ( isapi_response_ptr->class_number == 1 )
  1496. {
  1497. free_class1_data_buffer( isapi_response_ptr->class1_data_buffer_ptr );
  1498. }
  1499. else
  1500. {
  1501. free_class2_data_buffer( isapi_response_ptr->class2_data_buffer_ptr );
  1502. }
  1503. free_isapi_response( isapi_response_ptr );
  1504. //
  1505. // Indicate to IIS that you are finished servicing
  1506. // the client request due to an error, by calling
  1507. // the HSE_REQ_DONE_WITH_SESSION ServerSupportFunction
  1508. // with an HSE_STATUS_ERROR status code.
  1509. //
  1510. status = HSE_STATUS_ERROR;
  1511. isapi_response_ptr->pECB->ServerSupportFunction( connection_id,
  1512. HSE_REQ_DONE_WITH_SESSION,
  1513. &status,
  1514. NULL,
  1515. NULL );
  1516. return;
  1517. }
  1518. //
  1519. // If you requested a synchronous VectorSend, you are
  1520. // done at this point, so call the HSE_REQ_DONE_WITH_SESSION
  1521. // ServerSupportFunction with an HSE_STATUS_SUCCESS status
  1522. // code and decallocate any ISAPI_RESPONSE or CLASS?_DATA_BUFFER
  1523. // structures used.
  1524. //
  1525. // If you requested an asynchronous VectorSend, just exit;
  1526. // the status code is still the HSE_STATUS_PENDING returned
  1527. // in handle_class1_or_class2_request.
  1528. //
  1529. if ( !isapi_response_ptr->use_async_vector_send )
  1530. {
  1531. connection_id = isapi_response_ptr->pECB->ConnID;
  1532. if ( isapi_response_ptr->class_number == 1 )
  1533. {
  1534. free_class1_data_buffer( isapi_response_ptr->class1_data_buffer_ptr );
  1535. }
  1536. else
  1537. {
  1538. free_class2_data_buffer( isapi_response_ptr->class2_data_buffer_ptr );
  1539. }
  1540. free_isapi_response( isapi_response_ptr );
  1541. isapi_response_ptr->pECB->ServerSupportFunction( connection_id,
  1542. HSE_REQ_DONE_WITH_SESSION,
  1543. &status,
  1544. NULL,
  1545. NULL );
  1546. }
  1547. }
  1548. /*********************************************************************/
  1549. DWORD determine_set_cookie_string( INT64 user_index,
  1550. DWORD last_ad,
  1551. CHAR *set_cookie_string )
  1552. /*++
  1553. Routine Description:
  1554. Computes the Set-Cookie string and the ID of the ad to be sent in a
  1555. based on the index (i.e. ID - 10000) of the user who made the request
  1556. being serviced and the ID of the last ad seen by that user.
  1557. Arguments:
  1558. user_index - The user index of the user whose request is being
  1559. serviced. Note that a user index is defined as the
  1560. pertinent user ID minus 10000. These indices are
  1561. used as user ID's start from 10000.
  1562. last_ad - The ID of the last ad seen by the user whose request is
  1563. being serviced. last_ad is -1 if the user has not
  1564. previously seen an ad.
  1565. set_cookie_string - A pointer to a buffer, of size MAX_COOKIE_STRING_
  1566. LENGTH, that will be used to store the Set-Cookie
  1567. string computed.
  1568. Return Values:
  1569. Returns the ID of the ad to be sent or -1 if an out of range user index
  1570. is provided. Computes the Set-Cookie string and stores it in the buffer
  1571. indicated by the parameter 'set_cookie_string'.
  1572. --*/
  1573. {
  1574. DWORD current_time;
  1575. DWORD ad_index;
  1576. DWORD combined_demographics;
  1577. DWORD ad_weight;
  1578. DWORD expired;
  1579. CHAR ad_index_string[ 4 ];
  1580. CHAR ad_weight_string[ 11 ];
  1581. DWORD ad_index_string_size;
  1582. DWORD ad_weight_string_size;
  1583. DWORD ad_index_string_length;
  1584. DWORD ad_weight_string_length;
  1585. DWORD ii;
  1586. DWORD user_demographics;
  1587. //
  1588. // Check if the user_index is out of range. If it is, use the
  1589. // default Set-Cookie string and return the invalid ad ID of -1.
  1590. //
  1591. if ( user_index < 0 || user_index >= g_num_users )
  1592. {
  1593. strcpy( set_cookie_string, "found_cookie=Ad_id=-1&Ad_weight=00&Expired=1" );
  1594. return( -1 );
  1595. }
  1596. //
  1597. // Obtain the current time.
  1598. //
  1599. time( ( time_t * )&( current_time ) );
  1600. //
  1601. // Obtain the demographic data for the specified user.
  1602. //
  1603. acquire_shared_lock( &g_user_personalities_buffer_lock );
  1604. user_demographics = g_user_personalities_buffer[ user_index ];
  1605. release_shared_lock( &g_user_personalities_buffer_lock );
  1606. //
  1607. // Scroll through custom ads in the in-memory data structure holding
  1608. // the Custom.Ads file data and select an appropriate ad. Note that
  1609. // as this in-memory buffer is a shared resourse, shared ownership of
  1610. // the lock protecting it, 'g_custom_ads_buffer_lock', must first
  1611. // be obtained.
  1612. //
  1613. ad_index = last_ad;
  1614. acquire_shared_lock( &g_custom_ads_buffer_lock );
  1615. do
  1616. {
  1617. //
  1618. // Increment ad_index (initially set to the ad ID of
  1619. // the last ad seen by the user). If you go past the
  1620. // maximum ad ID of 359, go back to the ad with ID 0.
  1621. //
  1622. ad_index = ( ( ad_index + 1 ) % 360 );
  1623. //
  1624. // Determine the combined demographics information of the
  1625. // user and the current ad that you are on.
  1626. //
  1627. combined_demographics = g_custom_ads_buffer[ ad_index ].ad_demographics &
  1628. user_demographics;
  1629. //
  1630. // Using the combined demographics information, calculate
  1631. // the weight of the current ad using the following steps.
  1632. //
  1633. ad_weight = 0;
  1634. if ( combined_demographics & GENDER_MASK )
  1635. {
  1636. ad_weight += g_custom_ads_buffer[ ad_index ].gender_wt;
  1637. }
  1638. if ( combined_demographics & AGE_GROUP_MASK )
  1639. {
  1640. ad_weight += g_custom_ads_buffer[ ad_index ].age_group_wt;
  1641. }
  1642. if ( combined_demographics & REGION_MASK )
  1643. {
  1644. ad_weight += g_custom_ads_buffer[ ad_index ].region_wt;
  1645. }
  1646. if ( combined_demographics & INTEREST1_MASK )
  1647. {
  1648. ad_weight += g_custom_ads_buffer[ ad_index ].interest1_wt;
  1649. }
  1650. if ( combined_demographics & INTEREST2_MASK )
  1651. {
  1652. ad_weight += g_custom_ads_buffer[ ad_index ].interest2_wt;
  1653. }
  1654. //
  1655. // If the weight of the current ad meets a certain minimum
  1656. // threshold, we have a match. In this case, determine whether
  1657. // or not the selected ad has expired and break from the loop.
  1658. //
  1659. if ( ad_weight >= g_custom_ads_buffer[ ad_index ].minimum_match_value )
  1660. {
  1661. if ( current_time >= g_custom_ads_buffer[ ad_index ].expiration_time )
  1662. {
  1663. expired = 1;
  1664. }
  1665. else
  1666. {
  1667. expired = 0;
  1668. }
  1669. break;
  1670. }
  1671. //
  1672. // If the current ad was not acceptable, move on to the next.
  1673. // Continue looping in this fashion until an acceptable ad is
  1674. // found (which may turn out to be the last ad seen). Note that
  1675. // SPECweb99 is clearly ensuring that the custom ads buffer
  1676. // will contain at least one matching record.
  1677. //
  1678. } while( ad_index != last_ad );
  1679. //
  1680. // Once we have found a matching ad, we are done with the
  1681. // custom ads buffer. Release the shared lock held on it.
  1682. //
  1683. release_shared_lock( &g_custom_ads_buffer_lock );
  1684. //
  1685. // Construct the Set-Cookie string to write in the buffer
  1686. // 'set_cookie_string'. To avoid making a costly sprintf
  1687. // call or effectively repeating strlen calls, memcpy will
  1688. // be used.
  1689. //
  1690. // Note that the Set-Cookie string returned will have the format:
  1691. // "found_cookie=Ad_id=<ad_id>&Ad_weight=<ad_weight>&Expired=<expired>"
  1692. //
  1693. //
  1694. // Copy the "hardcoded" base of the Set-Cookie string.
  1695. //
  1696. strcpy( set_cookie_string, "found_cookie=Ad_id=" );
  1697. //
  1698. // Construct a string representing the ID of the ad
  1699. // to be returned. Determine and store the length
  1700. // of this string.
  1701. //
  1702. dword_to_string( ad_index, ad_index_string );
  1703. ad_index_string_length = strlen( ad_index_string );
  1704. //
  1705. // Construct a string representing the weight of the
  1706. // ad selected. Determine and store the length of this
  1707. // string.
  1708. //
  1709. // Note that we do not check to failure of dword_to_string
  1710. // as the buffer 'ad_weight_string' is sufficiently large
  1711. // and so this function is guaranteed to succeed.
  1712. //
  1713. dword_to_string( ad_weight, ad_weight_string );
  1714. ad_weight_string_length = strlen( ad_weight_string );
  1715. //
  1716. // Concatenate the ad ID string onto the Set-Cookie string.
  1717. // Note that 19 is the length of the Set-Cookie string before
  1718. // this operation.
  1719. //
  1720. memcpy( set_cookie_string + 19, ad_index_string, ad_index_string_length );
  1721. //
  1722. // Concatenate the hardcoded, 11 character string "&Ad_weight",
  1723. // onto the Set-Cookie string. Note that ii contains the length
  1724. // of the Set-Cookie string just prior to this operation.
  1725. //
  1726. ii = 19 + ad_index_string_length;
  1727. memcpy( set_cookie_string + ii, "&Ad_weight=", 11 );
  1728. //
  1729. // Concatenate the ad weigth string onto the Set-Cookie string.
  1730. // Note that ii contains the length of the Set-Cookie string
  1731. // just prior to this operation.
  1732. //
  1733. ii += 11;
  1734. memcpy( set_cookie_string + ii, ad_weight_string, ad_weight_string_length );
  1735. //
  1736. // Concatenate either of the hardcoded, 11 character strings
  1737. // "&Expired=1\0" or "&Expired=0\0" onto the Set-Cookie string,
  1738. // depending on the value of the variable 'expired'. Note that
  1739. // ii contains the length of the Set-Cookie string just prior
  1740. // to this operation.
  1741. //
  1742. ii += ad_weight_string_length;
  1743. memcpy( set_cookie_string + ii,
  1744. ( expired ) ? "&Expired=1\0" : "&Expired=0\0",
  1745. 11 );
  1746. //
  1747. // Return the ID of the ad selected.
  1748. //
  1749. return( ad_index );
  1750. }
  1751. /*********************************************************************/
  1752. VOID insert_custom_ad_information( CHAR *buffer, DWORD ad_id )
  1753. /*++
  1754. Routine Description:
  1755. Arguments:
  1756. buffer - Pointer to a buffer, containing the raw data of a class
  1757. 1 or class 2 file, into which custom ad information is to
  1758. be inserted.
  1759. ad_id - The ID of the custom ad to be inserted into the raw file
  1760. data.
  1761. Return Value:
  1762. None
  1763. --*/
  1764. {
  1765. CHAR substitute_directory_string[ 5 ];
  1766. CHAR substitute_class_char;
  1767. CHAR substitute_file_char;
  1768. CHAR *tag_start_ptr;
  1769. DWORD ii;
  1770. DWORD jj;
  1771. //
  1772. // We must now go through the file data buffer process it in
  1773. // the following manner.
  1774. //
  1775. // (1) Find each tag of the form "<!WEB99CAD><IMG SRC=/file_set/
  1776. // dirNNNNN/classX_Y><!/WEB99CAD>" using the minimum required
  1777. // search string "<!WEB99CAD><IMG SRC=/file_set/dir".
  1778. //
  1779. // (2) For each tag found in (1), in turn, do the following:
  1780. //
  1781. // (a) Replace NNNNN with ( ad_id / 36 ) padded to five
  1782. // digits.
  1783. //
  1784. // (b) Replace X with ( ( ad_id / 36 ) / 9 ).
  1785. //
  1786. // (c) Replace Y with ( ad_id % 9 ).
  1787. //
  1788. //
  1789. // Compute the directory number characters. That is, compute the
  1790. // charasters that will be used to replace NNNNN in the tags
  1791. // described.
  1792. //
  1793. substitute_directory_string[ 0 ] = '0';
  1794. substitute_directory_string[ 1 ] = '0';
  1795. substitute_directory_string[ 2 ] = '0';
  1796. substitute_directory_string[ 3 ] = '0' + ( CHAR )( ( ad_id / 36 ) / 10 );
  1797. substitute_directory_string[ 4 ] = '0' + ( CHAR )( ( ad_id / 36 ) % 10 );
  1798. //
  1799. // Compute the class number. That is, compute the character
  1800. // that will be used to replace X in the tags described.
  1801. //
  1802. substitute_class_char = '0' + ( CHAR )( ( ad_id % 36 ) / 9 );
  1803. //
  1804. // Compute the file number. That is, compute the character
  1805. // that will be used to replace Y in the tags described.
  1806. //
  1807. substitute_file_char = '0' + ( CHAR )( ad_id % 9 );
  1808. //
  1809. // Now, actually scroll through the file data buffer, find the
  1810. // tags described and make the specified subsitutions for each.
  1811. //
  1812. for ( tag_start_ptr = strstr( buffer, "<!WEB99CAD><IMG SRC=\"/file_set/dir" );
  1813. tag_start_ptr;
  1814. tag_start_ptr = strstr( tag_start_ptr + 1, "<!WEB99CAD><IMG SRC=\"/file_set/dir" ) )
  1815. {
  1816. //
  1817. // Note that characters 34 through 39 in the tags
  1818. // specified (where the first character is numbered 0)
  1819. // correspond to the NNNNN to be replaced with the
  1820. // substitute directory number.
  1821. //
  1822. for ( ii = 0, jj = 34; ii < 5; ii++, jj++ )
  1823. {
  1824. tag_start_ptr[ jj ] = substitute_directory_string[ ii ];
  1825. }
  1826. //
  1827. // Note that character 45 in the tags specified
  1828. // (where the first character is numbered 0) corresponds
  1829. // to the X to replace with the substitute class character.
  1830. //
  1831. tag_start_ptr[ 45 ] = substitute_class_char;
  1832. //
  1833. // Note that character 47 in the tags specified
  1834. // (where the first character is numbered 0) corresponsds
  1835. // to the Y to replace with the substitute file character.
  1836. //
  1837. tag_start_ptr[ 47 ] = substitute_file_char;
  1838. }
  1839. }
  1840. /*********************************************************************/
  1841. DWORD handle_class1_or_class2_request( EXTENSION_CONTROL_BLOCK *pECB,
  1842. ISAPI_RESPONSE *isapi_response_ptr,
  1843. CHAR *filename,
  1844. DWORD filesize,
  1845. BOOL use_async_vector_send,
  1846. DWORD ad_id,
  1847. DWORD query_string_length )
  1848. /*++
  1849. Routine Description:
  1850. This routine, called from HttpExtensionProc completes the handling
  1851. of a SPECweb99 dynamic GET with custom ad rotation operation in
  1852. which a class 1 or class 2 file is requested.
  1853. Arguments:
  1854. pECB - Pointer to the relevant extension control block.
  1855. isapi_response_ptr - Pointer to the relevant ISAPI_RESPONSE structure.
  1856. filename - Pointer to a string specifying the absolute name of
  1857. the file requested.
  1858. filesize - Size of the file requested.
  1859. use_async_vector_send - Flag indicating whether VectorSend is to be
  1860. used in asynchronous or synchronous mode.
  1861. ad_id - The ID of the custom ad selected.
  1862. query_string_length - The length of the query string provided.
  1863. Return Values:
  1864. Returns HSE_STATUS_ERROR if any failures occur in the routine.
  1865. Otherwise, if either asynchronous VectorSend or ReadFile is
  1866. used, HSE_STATUS_PENDING is returned. Alternatively, if neither
  1867. asynchronous VectorSend nor ReadFile is used, HSE_STATUS_SUCCESS
  1868. is returned.
  1869. --*/
  1870. {
  1871. BOOL use_async_read_file;
  1872. ISAPI_RESPONSE *heap_isapi_response_ptr;
  1873. DWORD bytes_read;
  1874. CHAR *buffer;
  1875. CLASS2_DATA_BUFFER stack_class2_data_buffer;
  1876. DWORD size = sizeof( stack_class2_data_buffer.buffer );
  1877. DWORD ii;
  1878. OVERLAPPED *overlapped_ptr;
  1879. DWORD dwFlagsAndAttributes;
  1880. //
  1881. // We need to obtain the raw file data of the class1 or
  1882. // class 2 file requested. Before we do this, however,
  1883. // we need a buffer in which to hold this data. Allocate
  1884. // such a buffer from the heap if we know, at this point,
  1885. // that will be carrying out an asynchronous I/O operation
  1886. // (i.e. is use_async_vector_send true) and from the stack
  1887. // otherwise.
  1888. //
  1889. if ( use_async_vector_send )
  1890. {
  1891. if ( isapi_response_ptr->class_number == 1 )
  1892. {
  1893. if ( !( isapi_response_ptr->class1_data_buffer_ptr = allocate_class1_data_buffer() ) )
  1894. {
  1895. free_isapi_response( isapi_response_ptr );
  1896. LOG_ERROR( "allocation failed", 0 );
  1897. return( HSE_STATUS_ERROR );
  1898. }
  1899. buffer = isapi_response_ptr->class1_data_buffer_ptr->buffer;
  1900. }
  1901. else
  1902. {
  1903. if ( !( isapi_response_ptr->class2_data_buffer_ptr = allocate_class2_data_buffer() ) )
  1904. {
  1905. free_isapi_response( isapi_response_ptr );
  1906. LOG_ERROR("Allocation failed",0 );
  1907. return( HSE_STATUS_ERROR );
  1908. }
  1909. buffer = isapi_response_ptr->class2_data_buffer_ptr->buffer;
  1910. }
  1911. }
  1912. else
  1913. {
  1914. //
  1915. // Note that if we are not using asynchronous VectorSend
  1916. // it is safe, for now at least, to use a buffer on the stack
  1917. // to store our file data. This may change if we find that
  1918. // we will have to use asynchronous ReadFile later on./
  1919. //
  1920. // Also, we are simply using a CLASS2_DATA_BUFFER buffer
  1921. // field here as it is sufficiently large to hold both
  1922. // class 1 and 2 files and thus, to store an additional
  1923. // CLASS1_DATA_BUFFER on the stack would have been wasteful.
  1924. //
  1925. isapi_response_ptr->class2_data_buffer_ptr = &( stack_class2_data_buffer );
  1926. buffer = isapi_response_ptr->class2_data_buffer_ptr->buffer;
  1927. }
  1928. //
  1929. // Now, attempt to read the data of the file requested
  1930. // into the allocated buffer from the HTTP.SYS fragment
  1931. // cache.
  1932. //
  1933. if ( pECB->ServerSupportFunction( pECB->ConnID,
  1934. HSE_REQ_READ_FRAGMENT_FROM_CACHE,
  1935. buffer,
  1936. &size,
  1937. ( DWORD * )isapi_response_ptr->unicode_fragment_cache_key ) )
  1938. {
  1939. //
  1940. // Now, if you had a cache hit, apply the necessary
  1941. // processing to the file data.
  1942. //
  1943. insert_custom_ad_information( buffer, ad_id );
  1944. //
  1945. // Now that the processing of the file data in the buffer
  1946. // is complete, we are ready to send it off to the client.
  1947. // To do this, set the sixth item in the response vector
  1948. // (i.e. the meat of the ISAPI response) to be the data
  1949. // buffer containing the processed file data.
  1950. //
  1951. // Note that the size of the file data to be sent was
  1952. // not changed in the processing applied and so, the
  1953. // HTTP headers or other fields dependent on content
  1954. // length do not need to be changed.
  1955. //
  1956. isapi_response_ptr->vector_element_array[ 5 ].ElementType = HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER;
  1957. isapi_response_ptr->vector_element_array[ 5 ].pvContext = buffer;
  1958. isapi_response_ptr->vector_element_array[ 5 ].cbSize = filesize;
  1959. //
  1960. // Carry out the actual synchronous or
  1961. // asynchronous VectorSend operation.
  1962. //
  1963. if ( pECB->ServerSupportFunction( pECB->ConnID,
  1964. HSE_REQ_VECTOR_SEND,
  1965. &( isapi_response_ptr->response_vector ),
  1966. NULL,
  1967. NULL ) )
  1968. {
  1969. //
  1970. // If the VectorSend operation returned
  1971. // indicating success return HSE_STATUS_PENDING
  1972. // or HSE_STATUS_SUCCESS depending on whether
  1973. // or not asynchronous or synchronous I/O was
  1974. // used, respectively.
  1975. //
  1976. if ( use_async_vector_send )
  1977. {
  1978. return( HSE_STATUS_PENDING );
  1979. }
  1980. else
  1981. {
  1982. return( HSE_STATUS_SUCCESS );
  1983. }
  1984. }
  1985. else
  1986. {
  1987. DWORD dwError = GetLastError();
  1988. LOG_ERROR(" VectorSend() failed", GetLastError() );
  1989. //
  1990. // Otherwise, if the VectorSend operation
  1991. // returned indicating failure return
  1992. // HSE_STATUS_ERROR.
  1993. //
  1994. // Note that if it was the initiation of an
  1995. // asynchronous VectorSend that failed,
  1996. // the ISAPI_RESPONSE and CLASS1_DATA_BUFFER
  1997. // or CLASS2_DATA_BUFFER structures used
  1998. // must be deallocated before returning.
  1999. //
  2000. if ( use_async_vector_send )
  2001. {
  2002. if ( isapi_response_ptr->class_number == 1 )
  2003. {
  2004. free_class1_data_buffer( isapi_response_ptr->class1_data_buffer_ptr );
  2005. }
  2006. else
  2007. {
  2008. free_class2_data_buffer( isapi_response_ptr->class2_data_buffer_ptr );
  2009. }
  2010. free_isapi_response( isapi_response_ptr );
  2011. }
  2012. return( HSE_STATUS_ERROR );
  2013. }
  2014. }
  2015. //
  2016. // Alternatively, if you had a cache miss, you must
  2017. // read the data of the file requested into memory
  2018. // using either a synchronous or asynchronous ReadFile
  2019. // operation.
  2020. //
  2021. //
  2022. // First, determine the I/O mode to use with ReadFile.
  2023. //
  2024. switch( g_read_file_io_mode_config )
  2025. {
  2026. case USE_ASYNC_IO:
  2027. {
  2028. use_async_read_file = TRUE;
  2029. break;
  2030. }
  2031. case USE_SYNC_IO:
  2032. {
  2033. use_async_read_file = FALSE;
  2034. break;
  2035. }
  2036. case USE_ADAPTABLE_IO:
  2037. {
  2038. use_async_read_file = ( filesize >= g_read_file_async_range_start );
  2039. break;
  2040. }
  2041. };
  2042. //
  2043. // Now, if we are using an ISAPI_RESPONSE structure or file data
  2044. // buffer on the stack and find that we must do an asynchronous
  2045. // ReadFile, we must switch to using an ISAPI_RESPONSE struct and
  2046. // file data buffer allocated from the heap.
  2047. //
  2048. // The condition ( !use_async_vector_send && use_async_read_file )
  2049. // can be explained as follows:
  2050. //
  2051. // (1) We only need to worry about switching to a file data
  2052. // buffer and ISAPI_RESPONSE structure on the heap at this
  2053. // point if we are using synchronous VectorSend, as if we are
  2054. // using asynchronous VectorSend we would have known this earlier
  2055. // and already the heap.
  2056. //
  2057. // (2) Also, if we are using synchronous VectorSend we only need
  2058. // to worry about using an ISAPI_RESPONSE structure and file
  2059. // data buffer on the heap if we are going to use asynchronous
  2060. // ReadFile. Otherwise, all of our I/O is synchronous and stack
  2061. // memory will suffice.
  2062. //
  2063. if ( !use_async_vector_send && use_async_read_file )
  2064. {
  2065. //
  2066. // First, switch from using an ISAPI_RESPONSE structure
  2067. // on the stack to using an ISAPI_RESPONSE structure on
  2068. // the heap.
  2069. //
  2070. //
  2071. // Try to allocate a free ISAPI_RESPONSE
  2072. // structure on the heap.
  2073. //
  2074. if ( !( heap_isapi_response_ptr = allocate_isapi_response() ) )
  2075. {
  2076. LOG_ERROR("Allocation failed", 0 );
  2077. return( HSE_STATUS_ERROR );
  2078. }
  2079. //
  2080. // Now copy all relevant data in the ISAPI_RESPONSE
  2081. // structure on the stack to the newly allocated one
  2082. // on the heap.
  2083. //
  2084. // Note that the vector_element_array member of
  2085. // the ISAPI_RESPONSE structure has seven elements.
  2086. //
  2087. memcpy( heap_isapi_response_ptr, isapi_response_ptr, sizeof( ISAPI_RESPONSE ) );
  2088. heap_isapi_response_ptr->response_vector.lpElementArray = heap_isapi_response_ptr->vector_element_array;
  2089. heap_isapi_response_ptr->response_vector.pszHeaders = heap_isapi_response_ptr->pszHeaders;
  2090. //
  2091. // After copying all of the data from the stack
  2092. // to the heap ISAPI_RESPONSE struct, set
  2093. // 'isapi_response_ptr' to point to the latter.
  2094. //
  2095. isapi_response_ptr = heap_isapi_response_ptr;
  2096. //
  2097. // Now, switch to using a file data buffer on
  2098. // the heap instead of one on the stack.
  2099. //
  2100. //
  2101. // If the file class number is 1, do the following...
  2102. //
  2103. if ( isapi_response_ptr->class_number == 1 )
  2104. {
  2105. //
  2106. // Attempt to allocate a CLASS1_DATA_BUFFER structure
  2107. // off of the stack of free CLASS1_DATA_BUFFER
  2108. // structures on the heap.
  2109. //
  2110. if ( !( isapi_response_ptr->class1_data_buffer_ptr = allocate_class1_data_buffer() ) )
  2111. {
  2112. //
  2113. // In the error case, free the ISAPI_RESPONSE
  2114. // structure allocated from the heap.
  2115. //
  2116. free_isapi_response( isapi_response_ptr );
  2117. LOG_ERROR( "Allocation failed", 0 );
  2118. return( HSE_STATUS_ERROR );
  2119. }
  2120. buffer = isapi_response_ptr->class1_data_buffer_ptr->buffer;
  2121. }
  2122. //
  2123. // Otherwise, if the file class number is 2, do the following...
  2124. // Note that this is essentially a mirror of the case for
  2125. // class 1 directly above.
  2126. //
  2127. else
  2128. {
  2129. //
  2130. // Attempt to allocate a CLASS2_DATA_BUFFER
  2131. // structure off of the stack of free CLASS2_
  2132. // DATA_BUFFER structures on the heap.
  2133. //
  2134. if ( !( isapi_response_ptr->class2_data_buffer_ptr = allocate_class2_data_buffer() ) )
  2135. {
  2136. //
  2137. // In the error case, free the ISAPI_RESPONSE
  2138. // structure allocated from the heap.
  2139. //
  2140. free_isapi_response( isapi_response_ptr );
  2141. LOG_ERROR("Allocation failed", 0 );
  2142. return( HSE_STATUS_ERROR );
  2143. }
  2144. buffer = isapi_response_ptr->class2_data_buffer_ptr->buffer;
  2145. }
  2146. }
  2147. //
  2148. // Now, we must read the contents of the requested file into
  2149. // memory before we can perform the necessary processing on
  2150. // its data. To do this we must first open a handle to the
  2151. // file using CreateFile.
  2152. //
  2153. // Note that we specify an OVERLAPPED structure as we may
  2154. // want to use asynchronous ReadFile.
  2155. //
  2156. if ( use_async_read_file )
  2157. {
  2158. dwFlagsAndAttributes = FILE_FLAG_OVERLAPPED;
  2159. isapi_response_ptr->overlapped.Offset = 0;
  2160. isapi_response_ptr->overlapped.OffsetHigh = 0;
  2161. isapi_response_ptr->overlapped.hEvent = 0;
  2162. overlapped_ptr = &( isapi_response_ptr->overlapped );
  2163. }
  2164. else
  2165. {
  2166. dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
  2167. overlapped_ptr = NULL;
  2168. }
  2169. if ( ( isapi_response_ptr->hFile = CreateFile( filename,
  2170. GENERIC_READ,
  2171. FILE_SHARE_READ,
  2172. NULL,
  2173. OPEN_EXISTING,
  2174. dwFlagsAndAttributes,
  2175. NULL ) ) == INVALID_HANDLE_VALUE )
  2176. {
  2177. //
  2178. // In the failure case, free any ISAPI_RESPONSE
  2179. // and CLASS1_DATA_BUFFER or CLASS2_DATA_BUFFER
  2180. // structures allocated and send an HTML error
  2181. // page to the client.
  2182. //
  2183. if ( use_async_vector_send )
  2184. {
  2185. if ( isapi_response_ptr->class_number == 1 )
  2186. {
  2187. free_class1_data_buffer( isapi_response_ptr->class1_data_buffer_ptr );
  2188. }
  2189. else
  2190. {
  2191. free_class2_data_buffer( isapi_response_ptr->class2_data_buffer_ptr );
  2192. }
  2193. free_isapi_response( isapi_response_ptr );
  2194. }
  2195. return( send_error_page( pECB,
  2196. "File inaccessible.",
  2197. g_pszStatus_404,
  2198. query_string_length ) );
  2199. }
  2200. //
  2201. // If asynchonous ReadFile is to be used, the following
  2202. // steps must be carried out...
  2203. //
  2204. if ( use_async_read_file )
  2205. {
  2206. //
  2207. // Specify the completion callback routine to invoke
  2208. // after the asynchronous ReadFile operation has
  2209. // completed.
  2210. //
  2211. BindIoCompletionCallback( isapi_response_ptr->hFile,
  2212. read_file_completion_callback,
  2213. 0 );
  2214. //
  2215. // Copy the following additional data items, that will be
  2216. // needed in the asynchronous ReadFile completion callback
  2217. // routine, to the ISAPI_RESPONSE struct
  2218. //
  2219. isapi_response_ptr->ad_id = ad_id;
  2220. isapi_response_ptr->pECB = pECB;
  2221. //
  2222. // Initiate the asynchronous ReadFile operation
  2223. // and return HSE_STATUS_PENDING.
  2224. //
  2225. if ( !ReadFile( isapi_response_ptr->hFile,
  2226. buffer,
  2227. filesize,
  2228. &bytes_read,
  2229. overlapped_ptr ) )
  2230. {
  2231. LOG_ERROR( "ReadFile failed()", GetLastError() );
  2232. //
  2233. // In the error case, first close the file
  2234. // handle that has been opened.
  2235. //
  2236. CloseHandle( isapi_response_ptr->hFile );
  2237. isapi_response_ptr->hFile = INVALID_HANDLE_VALUE;
  2238. //
  2239. // Also, free any ISAPI_RESPONSE or CLASS1_DATA_
  2240. // BUFFER structures allocated.
  2241. //
  2242. if ( isapi_response_ptr->class_number == 1 )
  2243. {
  2244. free_class1_data_buffer( isapi_response_ptr->class1_data_buffer_ptr );
  2245. }
  2246. else
  2247. {
  2248. free_class2_data_buffer( isapi_response_ptr->class2_data_buffer_ptr );
  2249. }
  2250. free_isapi_response( isapi_response_ptr );
  2251. return( HSE_STATUS_ERROR );
  2252. }
  2253. //
  2254. // Free the current thread by returning
  2255. // HSE_STATUS_PENDING.
  2256. //
  2257. return( HSE_STATUS_PENDING );
  2258. }
  2259. //
  2260. // Perform the appropriate synchronous ReadFile
  2261. // operation depending on the class number of the
  2262. // file requested.
  2263. //
  2264. if ( !ReadFile( isapi_response_ptr->hFile,
  2265. buffer,
  2266. filesize,
  2267. &bytes_read,
  2268. NULL ) )
  2269. {
  2270. LOG_ERROR( "ReadFile failed()", GetLastError() );
  2271. //
  2272. // In the error case, first free the file
  2273. // handle opened.
  2274. //
  2275. CloseHandle( isapi_response_ptr->hFile );
  2276. isapi_response_ptr->hFile = INVALID_HANDLE_VALUE;
  2277. //
  2278. // Also, free any ISAPI_RESPONSE or CLASS1_
  2279. // DATA_BUFFER structures allocated.
  2280. //
  2281. if ( use_async_vector_send )
  2282. {
  2283. if ( isapi_response_ptr->class_number == 1 )
  2284. {
  2285. free_class1_data_buffer( isapi_response_ptr->class1_data_buffer_ptr );
  2286. }
  2287. else
  2288. {
  2289. free_class2_data_buffer( isapi_response_ptr->class2_data_buffer_ptr );
  2290. }
  2291. free_isapi_response( isapi_response_ptr );
  2292. }
  2293. return( HSE_STATUS_ERROR );
  2294. }
  2295. //
  2296. // We are now done with the copy of the requested file on disk
  2297. // and so, the handle to it can be closed.
  2298. //
  2299. CloseHandle( isapi_response_ptr->hFile );
  2300. isapi_response_ptr->hFile = INVALID_HANDLE_VALUE;
  2301. //
  2302. // Process the raw file data read into memory
  2303. // to ensure that the appropriate custom ad
  2304. // information is inserted.
  2305. //
  2306. insert_custom_ad_information( buffer, ad_id );
  2307. //
  2308. // Now that the processing of the file data in the buffer
  2309. // is complete, we are ready to send it off to the client.
  2310. // To do this, set the sixth item in the response vector
  2311. // (i.e. the meat of the ISAPI response) to be the data
  2312. // buffer containing the processed file data.
  2313. //
  2314. // Note that the size of the file data to be sent was
  2315. // not changed in the processing applied and so, the
  2316. // HTTP headers or other fields dependent on content
  2317. // length do not need to be changed.
  2318. //
  2319. isapi_response_ptr->vector_element_array[ 5 ].ElementType = HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER;
  2320. isapi_response_ptr->vector_element_array[ 5 ].pvContext = buffer;
  2321. isapi_response_ptr->vector_element_array[ 5 ].cbSize = filesize;
  2322. isapi_response_ptr->vector_element_array[ 5 ].cbOffset = 0;
  2323. //
  2324. // Carry out the actual synchronous or
  2325. // asynchronous VectorSend operation.
  2326. //
  2327. if ( pECB->ServerSupportFunction( pECB->ConnID,
  2328. HSE_REQ_VECTOR_SEND,
  2329. &( isapi_response_ptr->response_vector ),
  2330. NULL,
  2331. NULL ) )
  2332. {
  2333. //
  2334. // If the VectorSend operation returned
  2335. // indicating success return HSE_STATUS_PENDING
  2336. // or HSE_STATUS_SUCCESS depending on whether
  2337. // or not asynchronous or synchronous I/O was
  2338. // used, respectively.
  2339. //
  2340. if ( use_async_vector_send )
  2341. {
  2342. return( HSE_STATUS_PENDING );
  2343. }
  2344. else
  2345. {
  2346. return( HSE_STATUS_SUCCESS );
  2347. }
  2348. }
  2349. else
  2350. {
  2351. LOG_ERROR("VectorSend() failed",GetLastError());
  2352. //
  2353. // Otherwise, if the VectorSend operation
  2354. // returned indicating failure return
  2355. // HSE_STATUS_ERROR.
  2356. //
  2357. // Note that if it was the initiation of an
  2358. // asynchronous VectorSend that failed,
  2359. // the ISAPI_RESPONSE and CLASS1_DATA_BUFFER
  2360. // or CLASS2_DATA_BUFFER structures used
  2361. // must be deallocated before returning.
  2362. //
  2363. if ( use_async_vector_send )
  2364. {
  2365. if ( isapi_response_ptr->class_number == 1 )
  2366. {
  2367. free_class1_data_buffer( isapi_response_ptr->class1_data_buffer_ptr );
  2368. }
  2369. else
  2370. {
  2371. free_class2_data_buffer( isapi_response_ptr->class2_data_buffer_ptr );
  2372. }
  2373. free_isapi_response( isapi_response_ptr );
  2374. }
  2375. return( HSE_STATUS_ERROR );
  2376. }
  2377. }
  2378. /*********************************************************************/
  2379. BOOL load_registry_data( VOID )
  2380. /*++
  2381. Routine Description:
  2382. Loads registry values used for configuration of specweb99-CAD.dll.
  2383. Arguments:
  2384. None.
  2385. Return Value:
  2386. Returns TRUE if all registry values are successfully loaded and
  2387. FALSE otherwise.
  2388. --*/
  2389. {
  2390. HKEY hKey;
  2391. DWORD value_type;
  2392. DWORD value_size;
  2393. DWORD sizeof_value;
  2394. BYTE value[ 4 ];
  2395. //
  2396. // Open the registry key containing all values used for
  2397. // specweb99-CAD.dll configuration.
  2398. //
  2399. if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  2400. "Software\\Microsoft\\SPECweb99 ISAPI",
  2401. 0,
  2402. KEY_QUERY_VALUE,
  2403. &hKey ) )
  2404. {
  2405. return( FALSE );
  2406. }
  2407. //
  2408. // Load the value VECTOR_SEND_IO_MODE_CONFIG into the variable
  2409. // g_vector_send_io_mode_config.
  2410. //
  2411. value_size = sizeof_value = sizeof( value );
  2412. if ( RegQueryValueEx( hKey,
  2413. "VECTOR_SEND_IO_MODE_CONFIG",
  2414. NULL,
  2415. &value_type,
  2416. value,
  2417. &value_size ) == NO_ERROR )
  2418. {
  2419. g_vector_send_io_mode_config = *( ( DWORD* )value );
  2420. }
  2421. //
  2422. // Load the value VECTOR_SEND_ASYNC_RANGE_START into the
  2423. // variable g_vector_send_async_range_start.
  2424. //
  2425. value_size = sizeof_value;
  2426. if ( RegQueryValueEx( hKey,
  2427. "VECTOR_SEND_ASYNC_RANGE_START",
  2428. NULL,
  2429. &value_type,
  2430. value,
  2431. &value_size ) == NO_ERROR )
  2432. {
  2433. g_vector_send_async_range_start = *( ( DWORD * )value );
  2434. }
  2435. //
  2436. // Load the value READ_FILE_IO_MODE_CONFIG into the variable
  2437. // g_read_file_io_mode_config.
  2438. //
  2439. value_size = sizeof_value;
  2440. if ( RegQueryValueEx( hKey,
  2441. "READ_FILE_IO_MODE_CONFIG",
  2442. NULL,
  2443. &value_type,
  2444. value,
  2445. &value_size ) == NO_ERROR )
  2446. {
  2447. g_read_file_io_mode_config = *( ( DWORD * )value );
  2448. }
  2449. //
  2450. // Load the value READ_FILE_ASYNC_RANGE_START into the variable
  2451. // g_read_file_async_range_start.
  2452. //
  2453. value_size = sizeof_value;
  2454. if ( RegQueryValueEx( hKey,
  2455. "READ_FILE_ASYNC_RANGE_START",
  2456. NULL,
  2457. &value_type,
  2458. value,
  2459. &value_size ) == NO_ERROR )
  2460. {
  2461. g_read_file_async_range_start = *( ( DWORD * )value );
  2462. }
  2463. //
  2464. // Load the value ROOT_DIR into the variable g_root_dir.
  2465. // Store the length of this string in g_root_dir_length.
  2466. //
  2467. value_size = sizeof( g_root_dir );
  2468. if ( RegQueryValueEx( hKey,
  2469. "ROOT_DIR",
  2470. NULL,
  2471. &value_type,
  2472. ( BYTE * )g_root_dir,
  2473. &value_size ) == NO_ERROR )
  2474. {
  2475. g_root_dir_length = value_size - 1;
  2476. }
  2477. else
  2478. {
  2479. return( FALSE );
  2480. }
  2481. //
  2482. // If you have made it this far without returning indicating
  2483. // failure, return indicating success.
  2484. //
  2485. return( TRUE );
  2486. }
  2487. /*********************************************************************/
  2488. BOOL WINAPI GetExtensionVersion( HSE_VERSION_INFO *pVer )
  2489. /*++
  2490. Routine Description:
  2491. Implementation of the GetExtensionVersion ISAPI entry point.
  2492. Carries out general initialization tasks and provides IIS with
  2493. version information.
  2494. Arguments:
  2495. pVer - Pointer to the version information structure to be
  2496. populated.
  2497. Return Value:
  2498. Returns TRUE if all initialization steps are successfully completed
  2499. and FALSE otherwise.
  2500. --*/
  2501. {
  2502. //
  2503. // Load configuration data from the registry.
  2504. //
  2505. if ( !load_registry_data() )
  2506. {
  2507. return( FALSE );
  2508. }
  2509. //
  2510. // Load the User.Personality file data from disk into an
  2511. // easy to access in-memory data structure.
  2512. //
  2513. if ( !load_user_personality_file() )
  2514. {
  2515. return( FALSE );
  2516. }
  2517. //
  2518. // Load the Custom.Ads file data from disk into an
  2519. // easy to access in-memory data structure.
  2520. //
  2521. if ( !load_custom_ads_file() )
  2522. {
  2523. return( FALSE );
  2524. }
  2525. //
  2526. // Initialize the shared/exclusive mode locks used to guary
  2527. // the in memory data structures containing data from the
  2528. // User.Personality and Custom.Ads files.
  2529. //
  2530. init_lock( &g_user_personalities_buffer_lock );
  2531. init_lock( &g_custom_ads_buffer_lock );
  2532. //
  2533. // Create a persistent thread that will ensure that the
  2534. // data in the User.Personality and Custom.Ads in-memory
  2535. // structures always reflects the most recent versions of
  2536. // these files on disk.
  2537. //
  2538. if ( !( g_update_buffers_thread = CreateThread( NULL,
  2539. 0,
  2540. update_user_and_ad_buffers,
  2541. NULL,
  2542. 0,
  2543. NULL ) ) )
  2544. {
  2545. return( FALSE );
  2546. }
  2547. //
  2548. // Initialize all stacks from which particular structures
  2549. // (e.g. ISAPI_RESPONSE, CLASS1_DATA_BUFFER and CLASS2_DATA_BUFFER
  2550. // structs) on the heap are to be allocated from.
  2551. //
  2552. initialize_isapi_response_stack();
  2553. initialize_class1_data_buffer_stack();
  2554. initialize_class2_data_buffer_stack();
  2555. //
  2556. // Populate the ISAPI version information structure to
  2557. // be used by IIS.
  2558. //
  2559. pVer->dwExtensionVersion = MAKELONG( HSE_VERSION_MINOR,
  2560. HSE_VERSION_MAJOR );
  2561. strcpy( pVer->lpszExtensionDesc,
  2562. "SPECweb99-CAD ISAPI Extension");
  2563. //
  2564. // If you have made it this far without returning indicating
  2565. // failure, return indicating success.
  2566. //
  2567. return( TRUE );
  2568. }
  2569. /*********************************************************************/
  2570. DWORD WINAPI HttpExtensionProc( EXTENSION_CONTROL_BLOCK *pECB )
  2571. /*++
  2572. Routine Description:
  2573. Implementation of the HttpExtensionProc ISAPI entry point.
  2574. Handles a SPECweb99 dynamic GET with custom ad rotation request.
  2575. Arguments:
  2576. pECB - Pointer to the relevant extension control block.
  2577. Return Value:
  2578. Returns HSE_STATUS_ERROR if any failures occur in the routine.
  2579. Otherwise, if either asynchronous VectorSend or ReadFile is
  2580. used, HSE_STATUS_PENDING is returned. Alternatively, if neither
  2581. asynchronous VectorSend nor ReadFile is used, HSE_STATUS_SUCCESS
  2582. is returned.
  2583. --*/
  2584. {
  2585. CHAR server_name[ 32 ];
  2586. CHAR server_port[ 32 ];
  2587. DWORD server_name_size = 32;
  2588. DWORD server_port_size = 32;
  2589. DWORD server_name_length;
  2590. DWORD server_port_length;
  2591. DWORD app_pool_name_size = 1024; // 1024 == sizeof( g_app_pool_name )
  2592. WIN32_FILE_ATTRIBUTE_DATA fileinfo;
  2593. ISAPI_RESPONSE local_isapi_response;
  2594. ISAPI_RESPONSE *isapi_response_ptr = &local_isapi_response;
  2595. CHAR filename[ MAX_PATH ];
  2596. CHAR cookie_string[ MAX_COOKIE_STRING_LENGTH ];
  2597. DWORD cookie_string_size = MAX_COOKIE_STRING_LENGTH;
  2598. CHAR user_id_string[ 10 ];
  2599. CHAR last_ad_string[ 10 ];
  2600. DWORD ii;
  2601. DWORD jj;
  2602. INT64 user_index;
  2603. DWORD last_ad;
  2604. DWORD ad_index;
  2605. BOOL return_value = HSE_STATUS_SUCCESS;
  2606. DWORD combined_demographics;
  2607. DWORD bytes_read;
  2608. BOOL use_async_vector_send;
  2609. HANDLE hFile;
  2610. CHAR file_data_buffer[ FILE_DATA_BUFFER_SIZE ];
  2611. DWORD query_string_length;
  2612. //
  2613. // Initialize the common "prefix" of the HTTP.SYS
  2614. // fragment cache strings to be used.
  2615. //
  2616. if ( InterlockedExchange( &g_fragment_cache_key_base_not_initialized, 0 ) )
  2617. {
  2618. //
  2619. // Obtain the server name.
  2620. //
  2621. if ( !pECB->GetServerVariable( pECB->ConnID,
  2622. "SERVER_NAME",
  2623. server_name,
  2624. &server_name_size ) )
  2625. {
  2626. LOG_ERROR( "GetServerVariable(SERVER_NAME) failed", GetLastError() );
  2627. return( HSE_STATUS_ERROR );
  2628. }
  2629. server_name_length = server_name_size - 1;
  2630. //
  2631. // Obtain the server port number used.
  2632. //
  2633. if ( !pECB->GetServerVariable( pECB->ConnID,
  2634. "SERVER_PORT",
  2635. server_port,
  2636. &server_port_size ) )
  2637. {
  2638. LOG_ERROR( "GetServerVariable(SERVER_PORT) failed", GetLastError() );
  2639. return( HSE_STATUS_ERROR );
  2640. }
  2641. server_port_length = server_port_size - 1;
  2642. //
  2643. // Obtain the name of the application pool used.
  2644. //
  2645. if ( !pECB->GetServerVariable( pECB->ConnID,
  2646. "APP_POOL_ID",
  2647. g_app_pool_name,
  2648. &app_pool_name_size ) )
  2649. {
  2650. LOG_ERROR( "GetServerVariable(APP_POOL_ID) failed", GetLastError() );
  2651. return( HSE_STATUS_ERROR );
  2652. }
  2653. g_app_pool_name_length = app_pool_name_size - 1;
  2654. //
  2655. // Construct the base part of the fragment cache key in the
  2656. // buffer g_fragment_cache_key_base; this will have the form
  2657. // "<app_pool_name>/http://<server_name>:<port_number>".
  2658. //
  2659. // Rather than using unnecessary strcat calls, make use of
  2660. // memcpy to do this.
  2661. //
  2662. //
  2663. // Copy the application pool name to the beginning of the
  2664. // key prefix.
  2665. //
  2666. strcpy( g_fragment_cache_key_base, g_app_pool_name );
  2667. //
  2668. // Concatenate the eight character string literal "/http://'
  2669. // onto the key prefix, which has a length of g_app_pool_
  2670. // name_length before the concatenation.
  2671. //
  2672. memcpy( g_fragment_cache_key_base + g_app_pool_name_length, "/http://", 8 );
  2673. //
  2674. // Concatenate the server name onto the key prefix, which has
  2675. // a length of g_app_pool_name_length + 8 before the
  2676. // concatenation.
  2677. //
  2678. ii = g_app_pool_name_length + 8;
  2679. memcpy( g_fragment_cache_key_base + ii, server_name, server_name_length );
  2680. //
  2681. // Concatenate a ':' character, to separate the server name
  2682. // and port number, onto the key prefix. In the memcpy call
  2683. // that does this, the variable 'ii' contains the length of
  2684. // the key prefix before the concatenation.
  2685. //
  2686. ii += server_name_length;
  2687. g_fragment_cache_key_base[ ii ] = ':';
  2688. //
  2689. // Concatenate the server port onto the key prefix. In the
  2690. // memcpy call that does this, the variable 'ii' contains
  2691. // the length of the key prefix before the concatenation.
  2692. //
  2693. ii += 1;
  2694. memcpy( g_fragment_cache_key_base + ii, server_port, server_port_length );
  2695. ii += server_port_length;
  2696. //
  2697. // Terminate the key prefix string.
  2698. //
  2699. g_fragment_cache_key_base[ ii ] = '\0';
  2700. //
  2701. // Determine and cache in g_fragment_cache_key_base_length,
  2702. // the length of the key prefix.
  2703. //
  2704. g_fragment_cache_key_base_length = strlen( g_fragment_cache_key_base );
  2705. }
  2706. //
  2707. // Construct the absolute name of the file requested.
  2708. // Take the following steps to do this.
  2709. //
  2710. //
  2711. // First copy the webserver root directory path (e.g.
  2712. // "D:/inetpub/wwwroot" to the start of the filename
  2713. // buffer.
  2714. //
  2715. strcpy( filename, g_root_dir );
  2716. //
  2717. // Next concatenate the query string (e.g. "/file_set/
  2718. // dir00001/class0_1") onto the filename string. Here
  2719. // we use memcpy as we need to store the length of the
  2720. // query string for later use and want to avoid repeated
  2721. // strlen operations.
  2722. //
  2723. query_string_length = strlen( pECB->lpszQueryString );
  2724. memcpy( filename + g_root_dir_length,
  2725. pECB->lpszQueryString,
  2726. query_string_length + 1 );
  2727. //
  2728. // Determine the size of the file requested.
  2729. //
  2730. if ( !GetFileAttributesEx( filename,
  2731. GetFileExInfoStandard,
  2732. &fileinfo ) )
  2733. {
  2734. return( send_error_page( pECB,
  2735. "File inaccessible.",
  2736. g_pszStatus_404,
  2737. query_string_length ) );
  2738. }
  2739. //
  2740. // Determine the I/O mode to use with VectorSend.
  2741. //
  2742. switch( g_vector_send_io_mode_config )
  2743. {
  2744. case USE_ASYNC_IO:
  2745. {
  2746. use_async_vector_send = TRUE;
  2747. break;
  2748. }
  2749. case USE_SYNC_IO:
  2750. {
  2751. use_async_vector_send = FALSE;
  2752. break;
  2753. }
  2754. case USE_ADAPTABLE_IO:
  2755. {
  2756. use_async_vector_send = ( fileinfo.nFileSizeLow >= g_vector_send_async_range_start );
  2757. break;
  2758. }
  2759. };
  2760. //
  2761. // Set isapi_response_ptr to point to an ISAPI response
  2762. // structure on the heap if using asynchronous VectorSend.
  2763. // Also set the VectorSend completion callback and return
  2764. // value.
  2765. //
  2766. if ( use_async_vector_send )
  2767. {
  2768. //
  2769. // Try to allocate a free ISAPI_RESPONSE
  2770. // structure on the heap.
  2771. //
  2772. if ( !( isapi_response_ptr = allocate_isapi_response() ) )
  2773. {
  2774. LOG_ERROR( "Allocation failed", 0 );
  2775. return( HSE_STATUS_ERROR );
  2776. }
  2777. //
  2778. // Set the completion callback routine to invoke after completion
  2779. // of the asynchronous VectorSend operation.
  2780. //
  2781. if ( !pECB->ServerSupportFunction( pECB->ConnID,
  2782. HSE_REQ_IO_COMPLETION,
  2783. vector_send_completion_callback,
  2784. NULL,
  2785. ( DWORD * )isapi_response_ptr ) )
  2786. {
  2787. //
  2788. // In the error case, free any ISAPI_RESPONSE
  2789. // structure allocated.
  2790. //
  2791. LOG_ERROR( " REQ_IO_COMPLETION failed", GetLastError() );
  2792. free_isapi_response( isapi_response_ptr );
  2793. return( HSE_STATUS_ERROR );
  2794. }
  2795. //
  2796. // Set the return value to use after the asynchronous
  2797. // VectorSend is initiated to HSE_STATUS_PENDING.
  2798. //
  2799. return_value = HSE_STATUS_PENDING;
  2800. }
  2801. //
  2802. // Parse the cookie string provided by the client.
  2803. //
  2804. if ( !pECB->GetServerVariable( pECB->ConnID,
  2805. "HTTP_COOKIE",
  2806. cookie_string,
  2807. &cookie_string_size ) )
  2808. {
  2809. LOG_ERROR( "GetServerVariable(HTTP_COOKIE) failed", GetLastError() );
  2810. //
  2811. // If there was an error in retrieving the cookie string, free
  2812. // the ISAPI_RESPONSE structure allocated in the asynchronous
  2813. // VectorSend case by placing it on the stack of free
  2814. // ISAPI_RESPONSE structures on the heap.
  2815. //
  2816. if ( use_async_vector_send )
  2817. {
  2818. free_isapi_response( isapi_response_ptr );
  2819. }
  2820. return( HSE_STATUS_ERROR );
  2821. }
  2822. //
  2823. // The cookie string provided is of the form "my_cookie=user_id=<user_id>&
  2824. // last_ad=<last_ad>". Here we copy <user_id> and <last_ad> into
  2825. // user_id_string and last_ad_string.
  2826. //
  2827. // Note that the index at which <user_id> starts in the buffer 'cookie_string'
  2828. // is 18 and the index at which <last_id> starts in the buffer 'cookie_string'
  2829. // is 9 greater than index of the '&' character that terminates <user_id>.
  2830. //
  2831. for ( ii = 0, jj = 18; ( user_id_string[ ii ] = cookie_string[ jj ] ) != '&'; ii++, jj++ );
  2832. user_id_string[ ii ] = '\0';
  2833. for ( ii = 0, jj += 9; ( last_ad_string[ ii ] = cookie_string[ jj ] ); ii++, jj++ );
  2834. //
  2835. // Compute the cookie string and the ID of the ad to send back in
  2836. // the ISAPI response. Store the cookie string in 'cookie_string'
  2837. // and the ad ID in 'ad_index'.
  2838. //
  2839. // Note that the user_index = user_id - 10000, as user_id numbers
  2840. // start at 10000.
  2841. //
  2842. ad_index = determine_set_cookie_string( atoi( user_id_string ) - 10000,
  2843. atoi( last_ad_string ),
  2844. cookie_string );
  2845. //
  2846. // Initialize the ISAPI response using the cookie string computed.
  2847. //
  2848. if ( !initialize_isapi_response( isapi_response_ptr,
  2849. pECB,
  2850. filename,
  2851. fileinfo.nFileSizeLow,
  2852. cookie_string,
  2853. use_async_vector_send,
  2854. query_string_length ) )
  2855. {
  2856. LOG_ERROR("initialize_isapi_response failed", 0);
  2857. //
  2858. // In the error case, free any ISAPI_RESPONSE
  2859. // structure allocated.
  2860. //
  2861. if ( use_async_vector_send )
  2862. {
  2863. free_isapi_response( isapi_response_ptr );
  2864. }
  2865. return( HSE_STATUS_ERROR );
  2866. }
  2867. //
  2868. // Handle the special cases in which a class 1 or 2 file is requested.
  2869. //
  2870. //
  2871. // If the class number of the file requested is either 1 or 2,
  2872. // then the request must be handled differently (i.e. specific
  2873. // substitutions have to be made in tags contained in the file
  2874. // data). In this case, simply return the value resulting from
  2875. // the appropriate call to handle_class1_or_class2_request; this
  2876. // routine handles these special cases.
  2877. //
  2878. // To determine the class number of the file, note that as the
  2879. // query string contains the path of the filename relative to the
  2880. // webserver document root directory (e.g. /file_set/dir00001/class0_1)
  2881. // and class numbers are always one digit, the third last character
  2882. // in the query string will always denote the class number (this
  2883. // explains the use of "query_string_length - 3" below).
  2884. //
  2885. isapi_response_ptr->class_number = pECB->lpszQueryString[ query_string_length - 3 ] - '0';
  2886. if ( isapi_response_ptr->class_number == 1 )
  2887. {
  2888. return( handle_class1_or_class2_request( pECB,
  2889. isapi_response_ptr,
  2890. filename,
  2891. fileinfo.nFileSizeLow,
  2892. use_async_vector_send,
  2893. ad_index,
  2894. query_string_length ) );
  2895. }
  2896. else if ( isapi_response_ptr->class_number == 2 )
  2897. {
  2898. return( handle_class1_or_class2_request( pECB,
  2899. isapi_response_ptr,
  2900. filename,
  2901. fileinfo.nFileSizeLow,
  2902. use_async_vector_send,
  2903. ad_index,
  2904. query_string_length ) );
  2905. }
  2906. //
  2907. // Execute the VectorSend operation. If ServerSupportFunction
  2908. // returns TRUE, handle the cache hit case. Otherwise, assume
  2909. // a cache miss and handle it.
  2910. //
  2911. if ( pECB->ServerSupportFunction( pECB->ConnID,
  2912. HSE_REQ_VECTOR_SEND,
  2913. &( isapi_response_ptr->response_vector ),
  2914. NULL,
  2915. NULL ) )
  2916. {
  2917. return( return_value );
  2918. }
  2919. //
  2920. // Now that a cache miss occurred, we will try to add the requested
  2921. // file to the HTTP.SYS fragment cache using a handle to it and then
  2922. // reattempt the VectorSend. To do this, first obtain a handle to
  2923. // the file using CreateFile.
  2924. //
  2925. if ( ( hFile = CreateFile( filename,
  2926. GENERIC_READ,
  2927. FILE_SHARE_READ,
  2928. NULL,
  2929. OPEN_EXISTING,
  2930. FILE_ATTRIBUTE_NORMAL,
  2931. NULL ) ) == INVALID_HANDLE_VALUE )
  2932. {
  2933. //
  2934. // Again, in the error case free the ISAPI_RESPONSE struct
  2935. // allocated, if any.
  2936. //
  2937. if ( use_async_vector_send )
  2938. {
  2939. free_isapi_response( isapi_response_ptr );
  2940. }
  2941. return( send_error_page( pECB,
  2942. "File inaccessible.",
  2943. g_pszStatus_404,
  2944. query_string_length ) );
  2945. }
  2946. //
  2947. // Add the file to the HTTP.SYS fragment cache using the file
  2948. // handle.
  2949. //
  2950. isapi_response_ptr->vector_element.ElementType = HSE_VECTOR_ELEMENT_TYPE_FILE_HANDLE;
  2951. isapi_response_ptr->vector_element.pvContext = hFile;
  2952. isapi_response_ptr->vector_element.cbSize = fileinfo.nFileSizeLow;
  2953. isapi_response_ptr->vector_element.cbOffset = 0;
  2954. if ( !pECB->ServerSupportFunction( pECB->ConnID,
  2955. HSE_REQ_ADD_FRAGMENT_TO_CACHE,
  2956. &isapi_response_ptr->vector_element,
  2957. ( DWORD * )isapi_response_ptr->unicode_fragment_cache_key,
  2958. NULL ) )
  2959. {
  2960. //
  2961. // If the add HSE_REQ_ADD_FRAGMENT_TO_CACHE operation failed,
  2962. // (e.g. more than one thread attempted this at once), simply
  2963. // try the VectorSend using the file handle.
  2964. //
  2965. isapi_response_ptr->vector_element_array[ 5 ] = isapi_response_ptr->vector_element;
  2966. //
  2967. // You need to store the file handle on the
  2968. // heap to be able to close it in the VectorSend
  2969. // completion callback, if necessary.
  2970. //
  2971. if ( use_async_vector_send )
  2972. {
  2973. isapi_response_ptr->hFile = hFile;
  2974. }
  2975. if ( !pECB->ServerSupportFunction( pECB->ConnID,
  2976. HSE_REQ_VECTOR_SEND,
  2977. &( isapi_response_ptr->response_vector ),
  2978. NULL,
  2979. NULL ) )
  2980. {
  2981. //
  2982. // Clearly, you will not be going to the
  2983. // VectorSend completion callback now.
  2984. //
  2985. LOG_ERROR( "VectorSend() failed", GetLastError() );
  2986. CloseHandle( hFile );
  2987. if ( use_async_vector_send )
  2988. {
  2989. isapi_response_ptr->hFile = INVALID_HANDLE_VALUE;
  2990. }
  2991. //
  2992. // Again, in the failure case, free any ISAPI_RESPONSE
  2993. // structure allocated.
  2994. //
  2995. if ( use_async_vector_send )
  2996. {
  2997. free_isapi_response( isapi_response_ptr );
  2998. }
  2999. return( HSE_STATUS_ERROR );
  3000. }
  3001. if ( !use_async_vector_send )
  3002. {
  3003. CloseHandle( hFile );
  3004. }
  3005. return( return_value );
  3006. }
  3007. //
  3008. // Retry the VectorSend after successfully adding the requested
  3009. // file to the HTTP.SYS fragment cache.
  3010. //
  3011. if ( !pECB->ServerSupportFunction( pECB->ConnID,
  3012. HSE_REQ_VECTOR_SEND,
  3013. &( isapi_response_ptr->response_vector ),
  3014. NULL,
  3015. NULL ) )
  3016. {
  3017. //
  3018. // If the VectorSend operation fails now (e.g. it was flushed
  3019. // from the cache after it was added) simply try the VectorSend
  3020. // using the file handle.
  3021. //
  3022. isapi_response_ptr->vector_element_array[ 5 ] = isapi_response_ptr->vector_element;
  3023. //
  3024. // You need to store the file handle on the
  3025. // heap to be able to close it in the VectorSend
  3026. // completion callback, if necessary.
  3027. //
  3028. if ( use_async_vector_send )
  3029. {
  3030. isapi_response_ptr->hFile = hFile;
  3031. }
  3032. if ( !pECB->ServerSupportFunction( pECB->ConnID,
  3033. HSE_REQ_VECTOR_SEND,
  3034. &( isapi_response_ptr->response_vector ),
  3035. NULL,
  3036. NULL ) )
  3037. {
  3038. //
  3039. // Clearly, you will not be going to the
  3040. // VectorSend completion callback now.
  3041. //
  3042. CloseHandle( hFile );
  3043. if ( use_async_vector_send )
  3044. {
  3045. isapi_response_ptr->hFile = INVALID_HANDLE_VALUE;
  3046. }
  3047. //
  3048. // Again, in the failure case, free the ISAPI_RESPONSE
  3049. // structure allocated, if any.
  3050. //
  3051. if ( use_async_vector_send )
  3052. {
  3053. free_isapi_response( isapi_response_ptr );
  3054. }
  3055. return( HSE_STATUS_ERROR );
  3056. }
  3057. }
  3058. if ( !use_async_vector_send )
  3059. {
  3060. CloseHandle( hFile );
  3061. }
  3062. return( return_value );
  3063. }
  3064. /*********************************************************************/
  3065. BOOL WINAPI TerminateExtension( DWORD dwFlags )
  3066. /*++
  3067. Routine Description:
  3068. Implementation of the TerminateExtension ISAPI entry point.
  3069. Carries out all cleanup tasks needed when SPECweb99-CAD.dll
  3070. is unloaded.
  3071. Arguments:
  3072. dwFlags - A DWORD that specifies whether IIS should shut down
  3073. the extension.
  3074. Return Value:
  3075. Returns TRUE if all cleanup tasks are successfully completed
  3076. and FALSE otherwise.
  3077. --*/
  3078. {
  3079. //
  3080. // Destroy all entries in the stack of free
  3081. // ISAPI_RESPONSE structures on the heap.
  3082. //
  3083. clear_isapi_response_stack();
  3084. //
  3085. // Destroy all entries in the stack of free
  3086. // CLASS1_DATA_BUFFER structures on the heap.
  3087. //
  3088. clear_class1_data_buffer_stack();
  3089. //
  3090. // Destroy all elements in the stack of free
  3091. // CLASS2_DATA_BUFFER structures on the heap.
  3092. //
  3093. clear_class2_data_buffer_stack();
  3094. //
  3095. // Terminate the thread responsible for updating the in-memory
  3096. // data structures holding the User.Personality and Custom.Ads
  3097. // file data and close the handle to it.
  3098. //
  3099. if ( !TerminateThread( g_update_buffers_thread, STILL_ACTIVE ) )
  3100. {
  3101. return( FALSE );
  3102. }
  3103. CloseHandle( g_update_buffers_thread );
  3104. //
  3105. // Destroy the in-heap memory data structure holding
  3106. // the data from the User.Personality file.
  3107. //
  3108. free( g_user_personalities_buffer );
  3109. //
  3110. // If you have made it this far without returning indicating
  3111. // failure, return indicating success.
  3112. //
  3113. return( TRUE );
  3114. }