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.
1244 lines
31 KiB
1244 lines
31 KiB
/*********************************************************************
|
|
* *
|
|
* File: specweb99-GET.cxx *
|
|
* ---- *
|
|
* *
|
|
* *
|
|
* Overview: *
|
|
* -------- *
|
|
* *
|
|
* Implementation of the standard dynamic GET operation in the *
|
|
* SPECweb99 benchmark. *
|
|
* *
|
|
* *
|
|
* Revision History: *
|
|
* ---------------- *
|
|
* *
|
|
* Date Author Reason *
|
|
* ---- ------ ------ *
|
|
* *
|
|
* 07/03/02 Ankur Upadhyaya Initial Creation. *
|
|
* *
|
|
*********************************************************************/
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
|
|
//
|
|
// Includes.
|
|
//
|
|
|
|
|
|
#include <windows.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <malloc.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "httpextp.h"
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
|
|
//
|
|
// Defines.
|
|
//
|
|
|
|
|
|
#define USE_SYNC_IO 1
|
|
|
|
#define USE_ASYNC_IO 2
|
|
|
|
#define USE_ADAPTABLE_IO 3
|
|
|
|
#define MAX_FRAGMENT_CACHE_KEY_LENGTH 1024
|
|
|
|
#define MAX_APP_POOL_NAME_LENGTH 1024
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
|
|
//
|
|
// Type definitions.
|
|
//
|
|
|
|
|
|
typedef struct isapi_response
|
|
{
|
|
|
|
SINGLE_LIST_ENTRY item_entry;
|
|
|
|
HSE_RESPONSE_VECTOR response_vector;
|
|
|
|
HSE_VECTOR_ELEMENT vector_element_array[ 7 ];
|
|
|
|
CHAR remote_addr[ 16 ];
|
|
|
|
CHAR pszHeaders[ 53 ];
|
|
|
|
WCHAR unicode_fragment_cache_key[ MAX_FRAGMENT_CACHE_KEY_LENGTH ];
|
|
|
|
HANDLE hFile;
|
|
HSE_VECTOR_ELEMENT vector_element;
|
|
|
|
} ISAPI_RESPONSE;
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
|
|
//
|
|
// Global Variables.
|
|
//
|
|
|
|
|
|
DWORD g_vector_send_io_mode_config = USE_SYNC_IO;
|
|
|
|
DWORD g_vector_send_async_range_start = 0;
|
|
|
|
CHAR *g_pszStatus_200 = "200 OK";
|
|
|
|
CHAR *g_pszStatus_404 = "404 File Inaccessible";
|
|
|
|
CHAR g_fragment_cache_key_base[ MAX_FRAGMENT_CACHE_KEY_LENGTH ];
|
|
|
|
DWORD g_fragment_cache_key_base_length;
|
|
|
|
volatile LONG g_fragment_cache_key_base_not_initialized = 1;
|
|
|
|
static CHAR s_szElement1[] = "<html>\n"
|
|
"<head><title>SPECweb99 Dynamic GET & POST Test</title></head>\n"
|
|
"<body>\n"
|
|
"<p>SERVER_SOFTWARE = Microsoft-IIS/6.0\n"
|
|
"<p>REMOTE_ADDR = ";
|
|
HSE_VECTOR_ELEMENT g_vector_element_0 = { HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER,
|
|
s_szElement1,
|
|
0,
|
|
sizeof(s_szElement1) - 1 };
|
|
|
|
static CHAR s_szElement2[] = "\n<p>SCRIPT_NAME = /specweb99-GET.dll\n"
|
|
"<p>QUERY_STRING = ";
|
|
HSE_VECTOR_ELEMENT g_vector_element_2 = { HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER,
|
|
s_szElement2,
|
|
0,
|
|
sizeof(s_szElement2) - 1 };
|
|
|
|
static char s_szElement4[] = "\n<pre>\n";
|
|
HSE_VECTOR_ELEMENT g_vector_element_4 = { HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER,
|
|
s_szElement4,
|
|
0,
|
|
sizeof(s_szElement4) - 1 };
|
|
|
|
static char s_szElement6[] = "</pre>\n"
|
|
"</body>\n</html>\n";
|
|
HSE_VECTOR_ELEMENT g_vector_element_6 = { HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER,
|
|
s_szElement6,
|
|
0,
|
|
sizeof(s_szElement6) - 1 };
|
|
|
|
SLIST_HEADER g_isapi_response_stack;
|
|
|
|
CHAR g_root_dir[ MAX_PATH ];
|
|
|
|
CHAR g_app_pool_name[ MAX_APP_POOL_NAME_LENGTH ];
|
|
|
|
DWORD g_root_dir_length;
|
|
|
|
DWORD g_app_pool_name_length;
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
|
|
//
|
|
// Function prototypes.
|
|
//
|
|
|
|
|
|
VOID initialize_isapi_response_stack( VOID );
|
|
|
|
ISAPI_RESPONSE *allocate_isapi_response( VOID );
|
|
|
|
VOID free_isapi_response( ISAPI_RESPONSE *isapi_response_ptr );
|
|
|
|
VOID clear_isapi_response_stack( VOID );
|
|
|
|
BOOL initialize_isapi_response( ISAPI_RESPONSE *isapi_response_ptr,
|
|
EXTENSION_CONTROL_BLOCK *pECB,
|
|
DWORD filesize,
|
|
BOOL use_async_vector_send,
|
|
DWORD query_string_length );
|
|
|
|
DWORD send_error_page( EXTENSION_CONTROL_BLOCK *pECB,
|
|
CHAR *error_message,
|
|
CHAR *pszStatus,
|
|
DWORD query_string_length );
|
|
|
|
VOID WINAPI vector_send_completion_callback( LPEXTENSION_CONTROL_BLOCK pECB,
|
|
VOID *pContext,
|
|
DWORD cbIO,
|
|
DWORD dwError );
|
|
|
|
BOOL load_registry_data( VOID );
|
|
|
|
BOOL WINAPI GetExtensionVersion( HSE_VERSION_INFO *pVer );
|
|
|
|
DWORD WINAPI HttpExtensionProc( EXTENSION_CONTROL_BLOCK *pECB );
|
|
|
|
BOOL WINAPI TerminateExtension( DWORD dwFlags );
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
|
|
VOID initialize_isapi_response_stack( VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize the stack of ISAPI response structs on the heap.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
|
|
//
|
|
// Create the ISAPI response stack as a linked list.
|
|
//
|
|
|
|
InitializeSListHead( &g_isapi_response_stack );
|
|
|
|
}
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
|
|
ISAPI_RESPONSE *allocate_isapi_response( VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocates a free ISAPI response struct on the ISAPI response stack.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Returns a pointer to the ISAPI response struct allocated or NULL
|
|
if no such struct was available.
|
|
|
|
--*/
|
|
{
|
|
|
|
|
|
//
|
|
// If the stack is non-empty, pop an ISAPI response struct from it
|
|
// and return a pointer to it. Otherwise, allocate a new ISAPI
|
|
// response struct and return a pointer to it.
|
|
//
|
|
|
|
ISAPI_RESPONSE *isapi_response_ptr;
|
|
|
|
if ( !( isapi_response_ptr =
|
|
( ISAPI_RESPONSE * )InterlockedPopEntrySList( &g_isapi_response_stack ) ) )
|
|
{
|
|
|
|
isapi_response_ptr = ( ISAPI_RESPONSE * )malloc( sizeof( ISAPI_RESPONSE ) );
|
|
|
|
}
|
|
|
|
return( isapi_response_ptr );
|
|
|
|
}
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
|
|
VOID free_isapi_response( ISAPI_RESPONSE *isapi_response_ptr )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free a previously allocated ISAPI response struct by placing it
|
|
back on the ISAPI response stack.
|
|
|
|
Arguments:
|
|
|
|
isapi_response_ptr - A pointer to the struct to be freed.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
|
|
//
|
|
// Push the given ISAPI response struct onto the stack.
|
|
//
|
|
|
|
InterlockedPushEntrySList( &g_isapi_response_stack,
|
|
( SINGLE_LIST_ENTRY * )isapi_response_ptr );
|
|
|
|
}
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
|
|
VOID clear_isapi_response_stack( VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free all memory on the heap used by the ISAPI response stack.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
|
|
//
|
|
// Free all structs in the ISAPI response stack.
|
|
//
|
|
|
|
SINGLE_LIST_ENTRY *current_struct = InterlockedFlushSList( &g_isapi_response_stack );
|
|
|
|
SINGLE_LIST_ENTRY *struct_to_kill;
|
|
|
|
while( current_struct )
|
|
{
|
|
|
|
struct_to_kill = current_struct;
|
|
|
|
current_struct = current_struct->Next;
|
|
|
|
free( ( ISAPI_RESPONSE * )struct_to_kill );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
|
|
BOOL initialize_isapi_response( ISAPI_RESPONSE *isapi_response_ptr,
|
|
EXTENSION_CONTROL_BLOCK *pECB,
|
|
DWORD filesize,
|
|
BOOL use_async_vector_send,
|
|
DWORD query_string_length )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize an ISAPI response struct by populating it with the
|
|
appropriate data.
|
|
|
|
Arguments:
|
|
|
|
isapi_response_ptr - Pointer to the ISAPI response struct to be
|
|
initialized.
|
|
|
|
pECB - Pointer to the relevant extension control block.
|
|
|
|
filesize - Size of the file requested.
|
|
|
|
use_async_vector_send - Flag indicating whether VectorSend is to be
|
|
used in asynchronous or synchronous mode.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
DWORD remote_addr_size = 16; // 16 == sizeof( isapi_response_ptr->remote_addr )
|
|
|
|
CHAR fragment_cache_key[ MAX_FRAGMENT_CACHE_KEY_LENGTH ];
|
|
|
|
DWORD ii;
|
|
|
|
CHAR content_length_string[ 16 ];
|
|
|
|
DWORD content_length_string_length;
|
|
|
|
|
|
//
|
|
// Set the fragment cache key.
|
|
//
|
|
|
|
memcpy( fragment_cache_key, g_fragment_cache_key_base, g_fragment_cache_key_base_length );
|
|
|
|
memcpy( fragment_cache_key + g_fragment_cache_key_base_length,
|
|
pECB->lpszQueryString,
|
|
query_string_length + 1 );
|
|
|
|
for ( ii = 0;
|
|
isapi_response_ptr->unicode_fragment_cache_key[ ii ] = ( WCHAR )fragment_cache_key[ ii ];
|
|
ii++ );
|
|
|
|
|
|
//
|
|
// Obtain the IP address of the client.
|
|
//
|
|
|
|
if ( !pECB->GetServerVariable( pECB->ConnID,
|
|
"REMOTE_ADDR",
|
|
isapi_response_ptr->remote_addr,
|
|
&remote_addr_size ) )
|
|
{
|
|
|
|
return( FALSE );
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Populate the vector_element_array data structure.
|
|
//
|
|
|
|
isapi_response_ptr->vector_element_array[ 0 ] = g_vector_element_0;
|
|
|
|
|
|
isapi_response_ptr->vector_element_array[ 1 ].ElementType = HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER;
|
|
|
|
isapi_response_ptr->vector_element_array[ 1 ].pvContext = isapi_response_ptr->remote_addr;
|
|
|
|
isapi_response_ptr->vector_element_array[ 1 ].cbSize = remote_addr_size - 1;
|
|
|
|
|
|
isapi_response_ptr->vector_element_array[ 2 ] = g_vector_element_2;
|
|
|
|
|
|
isapi_response_ptr->vector_element_array[ 3 ].ElementType = HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER;
|
|
|
|
isapi_response_ptr->vector_element_array[ 3 ].pvContext = pECB->lpszQueryString;
|
|
|
|
isapi_response_ptr->vector_element_array[ 3 ].cbSize = query_string_length;
|
|
|
|
|
|
isapi_response_ptr->vector_element_array[ 4 ] = g_vector_element_4;
|
|
|
|
|
|
isapi_response_ptr->vector_element_array[ 5 ].ElementType = HSE_VECTOR_ELEMENT_TYPE_FRAGMENT;
|
|
|
|
isapi_response_ptr->vector_element_array[ 5 ].pvContext = ( DWORD * )isapi_response_ptr->unicode_fragment_cache_key;
|
|
|
|
|
|
isapi_response_ptr->vector_element_array[ 6 ] = g_vector_element_6;
|
|
|
|
|
|
//
|
|
// Populate the response_vector struct.
|
|
//
|
|
|
|
memcpy( isapi_response_ptr->pszHeaders, "Content-Type: text/html\r\nContent-Length: ", 41 );
|
|
|
|
// Construct content length string...
|
|
|
|
_ui64toa( filesize +
|
|
isapi_response_ptr->vector_element_array[ 0 ].cbSize +
|
|
isapi_response_ptr->vector_element_array[ 1 ].cbSize +
|
|
isapi_response_ptr->vector_element_array[ 2 ].cbSize +
|
|
isapi_response_ptr->vector_element_array[ 3 ].cbSize +
|
|
isapi_response_ptr->vector_element_array[ 4 ].cbSize +
|
|
isapi_response_ptr->vector_element_array[ 6 ].cbSize,
|
|
|
|
content_length_string,
|
|
|
|
10 );
|
|
|
|
content_length_string_length = strlen( content_length_string );
|
|
|
|
memcpy( isapi_response_ptr->pszHeaders + 41, content_length_string, content_length_string_length );
|
|
|
|
ii = 41 + content_length_string_length;
|
|
|
|
memcpy( isapi_response_ptr->pszHeaders + ii, "\r\n\r\n\0", 5 );
|
|
|
|
isapi_response_ptr->response_vector.pszHeaders = isapi_response_ptr->pszHeaders;
|
|
|
|
isapi_response_ptr->response_vector.lpElementArray = isapi_response_ptr->vector_element_array;
|
|
|
|
isapi_response_ptr->response_vector.nElementCount = 7;
|
|
|
|
isapi_response_ptr->response_vector.pszStatus = g_pszStatus_200;
|
|
|
|
if ( use_async_vector_send )
|
|
{
|
|
|
|
isapi_response_ptr->response_vector.dwFlags = //HSE_IO_FINAL_SEND |
|
|
HSE_IO_SEND_HEADERS |
|
|
HSE_IO_ASYNC;
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
isapi_response_ptr->response_vector.dwFlags = //HSE_IO_FINAL_SEND |
|
|
HSE_IO_SEND_HEADERS |
|
|
HSE_IO_SYNC;
|
|
|
|
}
|
|
|
|
//
|
|
// Set the following additional fields is the ISAPI
|
|
// response if to be sent to the client using
|
|
// asynchronous VectorSend.
|
|
//
|
|
|
|
if ( use_async_vector_send )
|
|
{
|
|
|
|
|
|
//
|
|
// By setting an 'hFile' HANDLE field we can check, in the
|
|
// VectorSend completion callback routine, whether the
|
|
// asynchronous VectorSend operation just completed made
|
|
// use of a file handle. If so, we must close the handle
|
|
// in this callback.
|
|
//
|
|
|
|
isapi_response_ptr->hFile = INVALID_HANDLE_VALUE;
|
|
|
|
}
|
|
|
|
return( TRUE );
|
|
|
|
}
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
|
|
DWORD send_error_page( EXTENSION_CONTROL_BLOCK *pECB,
|
|
CHAR *error_msg,
|
|
CHAR *status,
|
|
DWORD query_string_length )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sends an HTML error page to the client indicating that the file
|
|
requested could not be accessed.
|
|
|
|
Arguments:
|
|
|
|
pECB - Pointer to the relevant extension control block.
|
|
|
|
error_msg - Error message to send.
|
|
|
|
status - Status to send (e.g. "200 OK").
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
ISAPI_RESPONSE local_isapi_response;
|
|
|
|
ISAPI_RESPONSE *isapi_response_ptr = &local_isapi_response;
|
|
|
|
CHAR content_length_string[ 16 ];
|
|
|
|
DWORD content_length_string_length;
|
|
|
|
DWORD ii;
|
|
|
|
|
|
//
|
|
// Initialize the ISAPI response struct to be associated with
|
|
// the error page.
|
|
//
|
|
|
|
initialize_isapi_response( isapi_response_ptr,
|
|
pECB,
|
|
0,
|
|
FALSE,
|
|
query_string_length );
|
|
|
|
|
|
//
|
|
// Change the response_vector and vector_element_array in the
|
|
// ISAPI response struct to specify an error message (to be
|
|
// transmitted using synchronous I/O).
|
|
//
|
|
|
|
isapi_response_ptr->vector_element_array[ 5 ].ElementType = HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER;
|
|
|
|
isapi_response_ptr->vector_element_array[ 5 ].pvContext = error_msg;
|
|
|
|
isapi_response_ptr->vector_element_array[ 5 ].cbSize = strlen( error_msg );
|
|
|
|
isapi_response_ptr->vector_element_array[ 5 ].cbOffset = 0;
|
|
|
|
memcpy( isapi_response_ptr->pszHeaders, "Content-Type: text/html\r\nContent-Length: ", 41 );
|
|
|
|
_ui64toa( isapi_response_ptr->vector_element_array[ 0 ].cbSize +
|
|
isapi_response_ptr->vector_element_array[ 1 ].cbSize +
|
|
isapi_response_ptr->vector_element_array[ 2 ].cbSize +
|
|
isapi_response_ptr->vector_element_array[ 3 ].cbSize +
|
|
isapi_response_ptr->vector_element_array[ 4 ].cbSize +
|
|
isapi_response_ptr->vector_element_array[ 5 ].cbSize +
|
|
isapi_response_ptr->vector_element_array[ 6 ].cbSize,
|
|
|
|
content_length_string,
|
|
|
|
10 );
|
|
|
|
content_length_string_length = strlen( content_length_string );
|
|
|
|
memcpy( isapi_response_ptr->pszHeaders + 41, content_length_string, content_length_string_length );
|
|
|
|
ii = 41 + content_length_string_length;
|
|
|
|
memcpy( isapi_response_ptr->pszHeaders + ii, "\r\n\r\n\0", 5 );
|
|
|
|
isapi_response_ptr->response_vector.pszStatus = status;
|
|
|
|
|
|
//
|
|
// Send out the error page.
|
|
//
|
|
|
|
if ( !pECB->ServerSupportFunction( pECB->ConnID,
|
|
HSE_REQ_VECTOR_SEND,
|
|
&( isapi_response_ptr->response_vector ),
|
|
NULL,
|
|
NULL ) )
|
|
{
|
|
|
|
return( HSE_STATUS_ERROR );
|
|
|
|
}
|
|
|
|
return( HSE_STATUS_SUCCESS );
|
|
|
|
}
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
|
|
VOID WINAPI vector_send_completion_callback( LPEXTENSION_CONTROL_BLOCK pECB,
|
|
VOID *pContext,
|
|
DWORD cbIO,
|
|
DWORD dwError )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback invoked after completion of an asynchronous VectorSend.
|
|
|
|
Arguments:
|
|
|
|
pECB - Pointer to the relevant extension control block.
|
|
|
|
pContext - Pointer to the relevant ISAPI response struct.
|
|
|
|
cbIO - Number of bytes of sent.
|
|
|
|
dwError - Error code for the VectorSend.
|
|
|
|
Return Value:
|
|
|
|
Returns HSE_STATUS_SUCCESS.
|
|
|
|
--*/
|
|
{
|
|
|
|
DWORD status = HSE_STATUS_SUCCESS;
|
|
|
|
ISAPI_RESPONSE *isapi_response_ptr = ( ISAPI_RESPONSE * )pContext;
|
|
|
|
if ( isapi_response_ptr->hFile != INVALID_HANDLE_VALUE )
|
|
{
|
|
|
|
CloseHandle( isapi_response_ptr->hFile );
|
|
|
|
isapi_response_ptr->hFile = INVALID_HANDLE_VALUE;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Free the ISAPI response struct used.
|
|
//
|
|
|
|
free_isapi_response( ( ISAPI_RESPONSE * )pContext );
|
|
|
|
|
|
//
|
|
// Indicate successful completion of client request servicing.
|
|
//
|
|
|
|
pECB->ServerSupportFunction( pECB->ConnID,
|
|
HSE_REQ_DONE_WITH_SESSION,
|
|
&status,
|
|
NULL,
|
|
NULL );
|
|
|
|
}
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
|
|
BOOL load_registry_data( VOID )
|
|
{
|
|
|
|
HKEY hKey;
|
|
|
|
DWORD value_type;
|
|
|
|
DWORD value_size;
|
|
|
|
DWORD sizeof_value;
|
|
|
|
BYTE value[ 4 ];
|
|
|
|
if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
"Software\\Microsoft\\SPECweb99 ISAPI",
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&hKey ) )
|
|
{
|
|
|
|
return( FALSE );
|
|
|
|
}
|
|
|
|
value_size = sizeof_value = sizeof( value );
|
|
|
|
if ( RegQueryValueEx( hKey,
|
|
"VECTOR_SEND_IO_MODE_CONFIG",
|
|
NULL,
|
|
&value_type,
|
|
value,
|
|
&value_size ) == NO_ERROR )
|
|
{
|
|
g_vector_send_io_mode_config = *( ( DWORD* )value );
|
|
}
|
|
|
|
value_size = sizeof_value;
|
|
|
|
if ( RegQueryValueEx( hKey,
|
|
"VECTOR_SEND_ASYNC_RANGE_START",
|
|
NULL,
|
|
&value_type,
|
|
value,
|
|
&value_size ) == NO_ERROR )
|
|
{
|
|
g_vector_send_async_range_start = *( ( DWORD * )value );
|
|
}
|
|
|
|
value_size = sizeof( g_root_dir );
|
|
|
|
if ( RegQueryValueEx( hKey,
|
|
"ROOT_DIR",
|
|
NULL,
|
|
&value_type,
|
|
( BYTE * )g_root_dir,
|
|
&value_size ) == NO_ERROR )
|
|
{
|
|
g_root_dir_length = value_size - 1;
|
|
}
|
|
else
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
|
|
}
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
|
|
BOOL WINAPI GetExtensionVersion( HSE_VERSION_INFO *pVer )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Implementation of the GetExtensionVersion ISAPI entry point.
|
|
Carries out general initialization tasks and provides IS with
|
|
version information.
|
|
|
|
Arguments:
|
|
|
|
pVer - Pointer to the version information struct to be populated.
|
|
|
|
Return Value:
|
|
|
|
Returns TRUE.
|
|
|
|
--*/
|
|
{
|
|
|
|
|
|
//
|
|
// Carry out general initialization steps.
|
|
//
|
|
|
|
load_registry_data();
|
|
|
|
initialize_isapi_response_stack();
|
|
|
|
|
|
//
|
|
// Write version information.
|
|
//
|
|
|
|
pVer->dwExtensionVersion = MAKELONG( HSE_VERSION_MINOR,
|
|
HSE_VERSION_MAJOR );
|
|
|
|
strcpy( pVer->lpszExtensionDesc,
|
|
"SPECweb99-GET ISAPI Extension");
|
|
|
|
return( TRUE );
|
|
|
|
}
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
|
|
DWORD WINAPI HttpExtensionProc( EXTENSION_CONTROL_BLOCK *pECB )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Implementation of the HttpExtensionProc ISAPI entry point.
|
|
Handles a SPECweb99 standard dynamic GET request.
|
|
|
|
Arguments:
|
|
|
|
pECB - Pointer to the relevant extension control block.
|
|
|
|
Return Value:
|
|
|
|
DWORD - If synchronous VectorSend is used or an error page is to be
|
|
sent, HSE_STATUS_SUCCESS is returned. Otherwise, if
|
|
asynchronous VectorSend is used, HSE_STATUS_PENDING is returned.
|
|
|
|
--*/
|
|
{
|
|
|
|
BOOL use_async_vector_send;
|
|
|
|
WIN32_FILE_ATTRIBUTE_DATA fileinfo;
|
|
|
|
ISAPI_RESPONSE local_isapi_response;
|
|
|
|
ISAPI_RESPONSE *isapi_response_ptr = &local_isapi_response;
|
|
|
|
DWORD return_value = HSE_STATUS_SUCCESS;
|
|
|
|
HANDLE hFile;
|
|
|
|
CHAR filename[ MAX_PATH ];
|
|
|
|
DWORD bytes_read;
|
|
|
|
DWORD query_string_length = strlen( pECB->lpszQueryString );
|
|
|
|
CHAR server_name[ 32 ];
|
|
|
|
CHAR server_port[ 32 ];
|
|
|
|
DWORD server_name_size = 32;
|
|
|
|
DWORD server_port_size = 32;
|
|
|
|
DWORD server_name_length;
|
|
|
|
DWORD server_port_length;
|
|
|
|
DWORD app_pool_name_size = 1024; // 1024 == sizeof( g_app_pool_name )
|
|
|
|
DWORD ii;
|
|
|
|
|
|
if ( InterlockedExchange( &g_fragment_cache_key_base_not_initialized, 0 ) )
|
|
{
|
|
|
|
if ( !pECB->GetServerVariable( pECB->ConnID,
|
|
"SERVER_NAME",
|
|
server_name,
|
|
&server_name_size ) )
|
|
{
|
|
|
|
return( HSE_STATUS_ERROR );
|
|
|
|
}
|
|
|
|
server_name_length = server_name_size - 1;
|
|
|
|
if ( !pECB->GetServerVariable( pECB->ConnID,
|
|
"SERVER_PORT",
|
|
server_port,
|
|
&server_port_size ) )
|
|
{
|
|
|
|
return( HSE_STATUS_ERROR );
|
|
|
|
}
|
|
|
|
server_port_length = server_port_size - 1;
|
|
|
|
if ( !pECB->GetServerVariable( pECB->ConnID,
|
|
"APP_POOL_ID",
|
|
g_app_pool_name,
|
|
&app_pool_name_size ) )
|
|
{
|
|
|
|
return( HSE_STATUS_ERROR );
|
|
|
|
}
|
|
|
|
g_app_pool_name_length = app_pool_name_size - 1;
|
|
|
|
strcpy( g_fragment_cache_key_base, g_app_pool_name );
|
|
|
|
memcpy( g_fragment_cache_key_base + g_app_pool_name_length, "/http://", 8 );
|
|
|
|
ii = g_app_pool_name_length + 8;
|
|
|
|
memcpy( g_fragment_cache_key_base + ii, server_name, server_name_length );
|
|
|
|
ii += server_name_length;
|
|
|
|
g_fragment_cache_key_base[ ii ] = ':';
|
|
|
|
ii += 1;
|
|
|
|
memcpy( g_fragment_cache_key_base + ii, server_port, server_port_length );
|
|
|
|
ii += server_port_length;
|
|
|
|
g_fragment_cache_key_base[ ii ] = '/';
|
|
|
|
g_fragment_cache_key_base[ ii + 1 ] = '\0';
|
|
|
|
g_fragment_cache_key_base_length = strlen( g_fragment_cache_key_base );
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Determine the size of the file requested.
|
|
//
|
|
|
|
memcpy( filename, g_root_dir, g_root_dir_length );
|
|
|
|
memcpy( filename + g_root_dir_length, pECB->lpszQueryString, query_string_length + 1 );
|
|
|
|
if ( !GetFileAttributesEx( filename,
|
|
GetFileExInfoStandard,
|
|
&fileinfo ) )
|
|
{
|
|
|
|
return( send_error_page( pECB,
|
|
"File inaccessible.",
|
|
g_pszStatus_404,
|
|
query_string_length ) );
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Determine the I/O mode to use with VectorSend.
|
|
//
|
|
|
|
switch( g_vector_send_io_mode_config )
|
|
{
|
|
|
|
case USE_ASYNC_IO:
|
|
{
|
|
|
|
use_async_vector_send = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case USE_SYNC_IO:
|
|
{
|
|
|
|
use_async_vector_send = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case USE_ADAPTABLE_IO:
|
|
{
|
|
|
|
use_async_vector_send = ( fileinfo.nFileSizeLow >= g_vector_send_async_range_start );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Set isapi_response_ptr to point to an ISAPI response struct on
|
|
// the heap if using asynchronous I/O. Also set the VectorSend
|
|
// completion callback and return value.
|
|
//
|
|
|
|
if ( use_async_vector_send )
|
|
{
|
|
|
|
if ( !( isapi_response_ptr = allocate_isapi_response() ) )
|
|
{
|
|
|
|
return( HSE_STATUS_ERROR );
|
|
|
|
}
|
|
|
|
pECB->ServerSupportFunction( pECB->ConnID,
|
|
HSE_REQ_IO_COMPLETION,
|
|
vector_send_completion_callback,
|
|
NULL,
|
|
( DWORD * )isapi_response_ptr );
|
|
|
|
return_value = HSE_STATUS_PENDING;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Initialize the ISAPI response struct.
|
|
//
|
|
|
|
initialize_isapi_response( isapi_response_ptr,
|
|
pECB,
|
|
fileinfo.nFileSizeLow,
|
|
use_async_vector_send,
|
|
query_string_length );
|
|
|
|
|
|
//
|
|
// Execute the VectorSend operation. If ServerSupportFunction
|
|
// returns TRUE, handle the cache hit case. Otherwise, assume
|
|
// a cache miss and handle it.
|
|
//
|
|
|
|
if ( pECB->ServerSupportFunction( pECB->ConnID,
|
|
HSE_REQ_VECTOR_SEND,
|
|
&( isapi_response_ptr->response_vector ),
|
|
NULL,
|
|
NULL ) )
|
|
{
|
|
|
|
return( return_value );
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Get a handle to the file requested.
|
|
//
|
|
|
|
if ( ( hFile = CreateFile( filename,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL ) ) == INVALID_HANDLE_VALUE )
|
|
{
|
|
|
|
if ( use_async_vector_send )
|
|
{
|
|
|
|
free_isapi_response( isapi_response_ptr );
|
|
|
|
}
|
|
|
|
return( send_error_page( pECB,
|
|
"File inaccessible.",
|
|
g_pszStatus_404,
|
|
query_string_length ) );
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Add the file data to the HTTP.SYS fragment cache.
|
|
//
|
|
|
|
isapi_response_ptr->vector_element.ElementType = HSE_VECTOR_ELEMENT_TYPE_FILE_HANDLE;
|
|
|
|
isapi_response_ptr->vector_element.pvContext = hFile;
|
|
|
|
isapi_response_ptr->vector_element.cbSize = fileinfo.nFileSizeLow;
|
|
|
|
isapi_response_ptr->vector_element.cbOffset = 0;
|
|
|
|
if ( !pECB->ServerSupportFunction( pECB->ConnID,
|
|
HSE_REQ_ADD_FRAGMENT_TO_CACHE,
|
|
&isapi_response_ptr->vector_element,
|
|
( DWORD * )isapi_response_ptr->unicode_fragment_cache_key,
|
|
NULL ) )
|
|
{
|
|
|
|
isapi_response_ptr->vector_element_array[ 5 ] = isapi_response_ptr->vector_element;
|
|
|
|
if ( use_async_vector_send )
|
|
{
|
|
|
|
isapi_response_ptr->hFile = hFile;
|
|
|
|
}
|
|
|
|
if ( !pECB->ServerSupportFunction( pECB->ConnID,
|
|
HSE_REQ_VECTOR_SEND,
|
|
&( isapi_response_ptr->response_vector ),
|
|
NULL,
|
|
NULL ) )
|
|
{
|
|
|
|
if ( use_async_vector_send )
|
|
{
|
|
|
|
isapi_response_ptr->hFile = INVALID_HANDLE_VALUE;
|
|
|
|
free_isapi_response( isapi_response_ptr );
|
|
|
|
}
|
|
|
|
CloseHandle( hFile );
|
|
|
|
return( HSE_STATUS_ERROR );
|
|
|
|
}
|
|
if ( !use_async_vector_send )
|
|
{
|
|
CloseHandle( hFile );
|
|
}
|
|
|
|
return( return_value );
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Retry the VectorSend.
|
|
//
|
|
|
|
if ( !pECB->ServerSupportFunction( pECB->ConnID,
|
|
HSE_REQ_VECTOR_SEND,
|
|
&( isapi_response_ptr->response_vector ),
|
|
NULL,
|
|
NULL ) )
|
|
{
|
|
|
|
isapi_response_ptr->vector_element_array[ 5 ] = isapi_response_ptr->vector_element;
|
|
|
|
if ( use_async_vector_send )
|
|
{
|
|
|
|
isapi_response_ptr->hFile = hFile;
|
|
|
|
}
|
|
|
|
if ( !pECB->ServerSupportFunction( pECB->ConnID,
|
|
HSE_REQ_VECTOR_SEND,
|
|
&( isapi_response_ptr->response_vector ),
|
|
NULL,
|
|
NULL ) )
|
|
{
|
|
|
|
if ( use_async_vector_send )
|
|
{
|
|
|
|
isapi_response_ptr->hFile = INVALID_HANDLE_VALUE;
|
|
|
|
free_isapi_response( isapi_response_ptr );
|
|
|
|
}
|
|
|
|
CloseHandle( hFile );
|
|
|
|
return( HSE_STATUS_ERROR );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( !use_async_vector_send )
|
|
{
|
|
CloseHandle( hFile );
|
|
}
|
|
|
|
return( return_value );
|
|
|
|
}
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
|
|
BOOL WINAPI TerminateExtension( DWORD dwFlags )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Carries out all cleanup tasks.
|
|
|
|
Arguments:
|
|
|
|
dwFlags - A DWORD that specifies whether IIS should shut down the
|
|
extension.
|
|
|
|
Return Value:
|
|
|
|
Returns TRUE.
|
|
|
|
--*/
|
|
{
|
|
|
|
|
|
//
|
|
// Carry out cleanup tasks.
|
|
//
|
|
|
|
clear_isapi_response_stack();
|
|
|
|
return( TRUE );
|
|
|
|
}
|