446 lines
12 KiB
C++
446 lines
12 KiB
C++
/*++
|
||
|
||
Copyright (c) 1994 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
httpext.cxx
|
||
|
||
Abstract:
|
||
|
||
This module contains the Microsoft HTTP server extension module
|
||
|
||
Author:
|
||
|
||
John Ludeman (johnl) 09-Oct-1994
|
||
|
||
Revision History:
|
||
Murali R. Krishnan (MuraliK) 20-July-1996
|
||
Rewrote to enable multiple Extension class forwarding
|
||
--*/
|
||
|
||
|
||
/************************************************************
|
||
* Include Headers
|
||
************************************************************/
|
||
|
||
#pragma warning( disable:4509 ) // nonstandard extension: SEH with destructors
|
||
|
||
#include <w3p.hxx>
|
||
#include "wamexec.hxx"
|
||
#include "wamreq.hxx"
|
||
#include "WamW3.hxx"
|
||
#include "ExecDesc.hxx"
|
||
|
||
/************************************************************
|
||
* Prototypes
|
||
************************************************************/
|
||
|
||
BOOL IsImageRunnableInProcOnly( const STR & strImagePath);
|
||
|
||
|
||
|
||
|
||
|
||
/************************************************************
|
||
* Functions
|
||
************************************************************/
|
||
|
||
/*****************************************************************/
|
||
|
||
BOOL
|
||
HTTP_REQUEST::ProcessBGI(
|
||
EXEC_DESCRIPTOR * pExec,
|
||
BOOL * pfHandled,
|
||
BOOL * pfFinished,
|
||
BOOL fTrusted,
|
||
BOOL fStarScript
|
||
)
|
||
/*++
|
||
Description:
|
||
This method handles the gateway request to server application.
|
||
|
||
Arguments:
|
||
pExec - Execution Descriptor block
|
||
pfHandled - Indicates we handled this request
|
||
pfFinished - Indicates no further processing is required
|
||
fTrusted - Can this app be trusted to process things on a read only
|
||
vroot
|
||
|
||
Return Value:
|
||
TRUE if successful, FALSE on error
|
||
--*/
|
||
{
|
||
const STR * pstrBgiPath;
|
||
DBG_ASSERT( *(pExec->_pGatewayType) == GATEWAY_BGI);
|
||
|
||
// UNDONE: Need to decide what to do with this.
|
||
if ( !pExec->IsRunningDAV() &&
|
||
!VrootAccessCheck( pExec->_pMetaData, FILE_GENERIC_EXECUTE ) )
|
||
{
|
||
SetDeniedFlags( SF_DENIED_RESOURCE );
|
||
return FALSE;
|
||
}
|
||
|
||
if ( pExec->_pstrGatewayImage->IsEmpty()) {
|
||
|
||
DBG_ASSERT(pExec->_pAppPathURIBlob == NULL);
|
||
// obtain the physical path now
|
||
//
|
||
// Retrieve AppPathURIBlob for other ISAPI DLLs.
|
||
// See below for more detail comment about AppPathURIBlob.
|
||
//
|
||
if ( !LookupVirtualRoot( pExec->_pstrPhysicalPath,
|
||
pExec->_pstrURL->QueryStr(),
|
||
pExec->_pstrURL->QueryCCH(),
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
FALSE,
|
||
NULL,
|
||
&(pExec->_pAppPathURIBlob) ))
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
pstrBgiPath = pExec->_pstrPhysicalPath;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Retrieve AppPathURIBlob for each Exec descriptor, such that
|
||
// a .STM file and a .ASP file in the same application will have
|
||
// two different AppPathURIBlob. The AppPathURIBlob will solve the
|
||
// problem that .STM file is loaded under default application(inproc)
|
||
// even the request's URL points to an out-proc application.
|
||
//
|
||
if ( pExec->_pAppPathURIBlob == NULL )
|
||
{
|
||
if ( !CacheUri( QueryW3Instance(),
|
||
&(pExec->_pAppPathURIBlob),
|
||
pExec->_pMetaData,
|
||
pExec->_pstrURL->QueryStr(),
|
||
pExec->_pstrURL->QueryCCH(),
|
||
pExec->_pstrPhysicalPath,
|
||
pExec->_pstrUnmappedPhysicalPath ) )
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// If the AppPathURIBlob contains a valid MetaData, we need to AddRef it.
|
||
// Because this MetaData object is only referenced once if HTTP_REQUEST.pURIInfo
|
||
// contains that. AppPathURIBlob is another URIInfo that points to the MetaData
|
||
// object, therefore, We need to AddRef the Metadata object here.
|
||
// Exec.Reset always CheckIn the _pAppPathURIBlob(), and FreeMetaData reference in
|
||
// the Reset.
|
||
//
|
||
if (pExec->_pAppPathURIBlob->pMetaData)
|
||
{
|
||
TsReferenceMetaData(pExec->_pAppPathURIBlob->pMetaData->QueryCacheInfo());
|
||
}
|
||
}
|
||
|
||
pstrBgiPath = pExec->_pstrGatewayImage;
|
||
}
|
||
|
||
if ( !fStarScript &&
|
||
!pExec->IsRunningDAV() &&
|
||
!(fTrusted && IS_ACCESS_ALLOWED2(pExec, SCRIPT)) &&
|
||
!IS_ACCESS_ALLOWED2(pExec, EXECUTE) )
|
||
{
|
||
*pfHandled = TRUE;
|
||
if ( pExec->IsChild() )
|
||
{
|
||
SetLastError( ERROR_INVALID_FLAGS );
|
||
return FALSE;
|
||
}
|
||
else
|
||
{
|
||
Disconnect( HT_FORBIDDEN, IDS_EXECUTE_ACCESS_DENIED, FALSE, pfFinished );
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
return ( DoWamRequest( pExec, *pstrBgiPath, pfHandled, pfFinished));
|
||
} // HTTP_REQUEST::ProcessBGI()
|
||
|
||
|
||
BOOL
|
||
HTTP_REQUEST::DoWamRequest(
|
||
EXEC_DESCRIPTOR * pExec,
|
||
const STR & strPath,
|
||
BOOL * pfHandled,
|
||
BOOL * pfFinished
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This method handles a gateway request to a server extension DLL
|
||
|
||
Arguments:
|
||
|
||
pExec - Execution descriptor block
|
||
strPath - Fully qualified path to DLL
|
||
pfHandled - Indicates we handled this request
|
||
pfFinished - Indicates no further processing is required
|
||
|
||
Return Value:
|
||
|
||
TRUE if successful, FALSE on error
|
||
|
||
--*/
|
||
{
|
||
BOOL fReturn = TRUE;
|
||
|
||
DBG_ASSERT( *(pExec->_pGatewayType) == GATEWAY_BGI);
|
||
|
||
//
|
||
// 1. Have we already checked if this current request for a legacy
|
||
// ISAPI that has to be routed to inproc only AppRoot instance?
|
||
//
|
||
// _pAppPathURIBlob is associated with each Exec descriptor. Therefore,
|
||
// We can use this URIBlob to distiguish a .STM file's application path(always runs
|
||
// in proc) or a .ASP file's application path (could be out-proc application)
|
||
// This also solves the problem that "#EXEC ISA=/OUTAPP/hello.asp" case in a .STM
|
||
// file.(Child Execution).
|
||
// The Child execution will get a new EXEC object.
|
||
//
|
||
if ( !pExec->_pAppPathURIBlob->bUseAppPathChecked) {
|
||
|
||
//
|
||
// This is the first time we are checking the ISAPI application root
|
||
// path with respect to current image path
|
||
//
|
||
|
||
BOOL fInProcOnly = IsImageRunnableInProcOnly( strPath);
|
||
|
||
//
|
||
// set the state of the inproc-only vs. anything in the URIInfo record
|
||
// so that other callers can use this as well
|
||
// UNDONE: For K2/beta3, combine this with the script map lookup
|
||
//
|
||
|
||
InterlockedExchange((LPLONG)&(pExec->_pAppPathURIBlob->bInProcOnly), (LONG)fInProcOnly);
|
||
InterlockedExchange((LPLONG)&(pExec->_pAppPathURIBlob->bUseAppPathChecked),(LONG)TRUE);
|
||
|
||
DBG_ASSERT(pExec->_pAppPathURIBlob->bUseAppPathChecked);
|
||
}
|
||
|
||
g_pWamDictator->Reference();
|
||
|
||
fReturn = BoolFromHresult( g_pWamDictator->ProcessWamRequest( this, pExec, &strPath, pfHandled, pfFinished ) );
|
||
|
||
g_pWamDictator->Dereference();
|
||
|
||
return fReturn;
|
||
} // HTTP_REQUEST::DoWamRequest()
|
||
|
||
|
||
|
||
BOOL
|
||
HTTP_REQUEST::ProcessAsyncGatewayIO(VOID)
|
||
/*++
|
||
Description:
|
||
Calls the ISA (gateway) async i/o completion function
|
||
(via this request's wamreq)
|
||
|
||
Arguments:
|
||
None
|
||
|
||
Returns:
|
||
TRUE on success
|
||
FALSE on failure
|
||
|
||
--*/
|
||
{
|
||
|
||
g_pWamDictator->Reference();
|
||
DBG_ASSERT( QueryState() == HTR_GATEWAY_ASYNC_IO );
|
||
DBG_ASSERT( _pWamRequest );
|
||
|
||
BOOL fRet = TRUE;
|
||
HRESULT hr = NOERROR;
|
||
|
||
|
||
//
|
||
// Set state to doverb, since we have completed async i/o. Preserve the error codes.
|
||
//
|
||
|
||
SetState( HTR_DOVERB, QueryLogHttpResponse(), QueryLogWinError());
|
||
|
||
|
||
//
|
||
// Ref the wamreq - other threads may access it while we
|
||
// wait for ISA async i/o completion function to return
|
||
//
|
||
|
||
//
|
||
// Guard against ISAs which call HSE_REQ_DONE_WITH_SESSION or return
|
||
// in the mainline (with something other than HSE_STATUS_PENDING) before
|
||
// async completion. When this happens the _pWamRequest may be NULLed
|
||
// from underneath us.
|
||
//
|
||
|
||
__try
|
||
{
|
||
_pWamRequest->AddRef();
|
||
}
|
||
__except( EXCEPTION_EXECUTE_HANDLER )
|
||
{
|
||
hr = E_FAIL;
|
||
}
|
||
|
||
if ( FAILED(hr) )
|
||
{
|
||
g_pWamDictator->Dereference();
|
||
return FALSE;
|
||
}
|
||
|
||
hr = _pWamRequest->ProcessAsyncGatewayIO( QueryIOStatus(), QueryBytesWritten() );
|
||
|
||
if( FAILED(hr) ) {
|
||
|
||
//
|
||
// If i/o completion callback failed, log it
|
||
//
|
||
|
||
const CHAR * apsz[1];
|
||
|
||
// UNDONE is this valid? used to be ...
|
||
//apsz[0] = _SeInfo.ecb.lpszQueryString;
|
||
apsz[0] = _Exec._pstrURLParams->QueryStr();
|
||
|
||
DBGPRINTF(( DBG_CONTEXT,
|
||
"\n\n[ProcessAsyncGatewayIO] Exception occurred "
|
||
" in calling the callback for %s\n",
|
||
apsz[0]));
|
||
|
||
g_pInetSvc->LogEvent( W3_EVENT_EXTENSION_EXCEPTION,
|
||
1,
|
||
apsz,
|
||
0 );
|
||
|
||
fRet = FALSE;
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// Deref the wamreq
|
||
//
|
||
|
||
_pWamRequest->Release();
|
||
|
||
g_pWamDictator->Dereference();
|
||
return fRet;
|
||
|
||
} // ProcessAsyncGatewayIO()
|
||
|
||
|
||
|
||
VOID HTTP_REQUEST::CancelAsyncGatewayIO(VOID)
|
||
/*++
|
||
Description:
|
||
Cancels pending ISA (gateway) async i/o operation
|
||
|
||
Arguments:
|
||
None
|
||
|
||
Returns:
|
||
Nothing
|
||
|
||
--*/
|
||
{
|
||
|
||
DBG_ASSERT( QueryState() == HTR_GATEWAY_ASYNC_IO );
|
||
DBG_ASSERT( _pWamRequest );
|
||
|
||
SetState( HTR_DONE );
|
||
|
||
if( _pWamRequest ) {
|
||
|
||
_pWamRequest->Release();
|
||
}
|
||
|
||
} // CancelAsyncGatewayIO()
|
||
|
||
|
||
|
||
BOOL
|
||
IsImageRunnableInProcOnly( const STR & strImagePath)
|
||
/*++
|
||
Description:
|
||
This function takes the image path supplied and checks to see if this
|
||
matches any present in the InProc-only ISAPI's list. If it does, then
|
||
this function returns TRUE else FALSE.
|
||
This is used to check for and support legacy ISAPI applications that
|
||
can only run inproc
|
||
|
||
Arguments:
|
||
strImagePath - STR object containing the fully qualified image path
|
||
(physical path is present)
|
||
|
||
Returns:
|
||
TRUE if this ISAPI Application can only be run inproc
|
||
(i.e., image path is present in the InProc-only list)
|
||
FALSE, otherwise
|
||
|
||
--*/
|
||
{
|
||
|
||
LPCSTR pszImagePathStart = strImagePath.QueryStr();
|
||
LPCSTR pszDllNameOnly; // points to just the DLL name after last '\\'
|
||
|
||
IF_DEBUG( BGI )
|
||
{
|
||
DBGPRINTF(( DBG_CONTEXT,
|
||
" IsRunnableInProcOnly([%d] %s\n",
|
||
strImagePath.QueryCCH(),
|
||
strImagePath.QueryStr()
|
||
));
|
||
}
|
||
|
||
W3_IIS_SERVICE * pSvc = (W3_IIS_SERVICE *) g_pInetSvc;
|
||
|
||
// Check the full path
|
||
if (pSvc->IsInProcISAPI(pszImagePathStart))
|
||
return TRUE;
|
||
|
||
//
|
||
// Get the DLL name alone for relative path checks.
|
||
// DLL name appears after the last path-separator '\\'
|
||
// NYI: How to optimize this relative path check?
|
||
//
|
||
|
||
pszDllNameOnly = strrchr( pszImagePathStart, '\\');
|
||
if ( pszDllNameOnly == NULL) {
|
||
//
|
||
// There were no path-separator '\\' found in the image name
|
||
//
|
||
|
||
//
|
||
// Since we get absolute path for image from earlier stages
|
||
// This should not happen!
|
||
//
|
||
DBG_ASSERT( FALSE);
|
||
|
||
// reset to the start of the name and continue
|
||
pszDllNameOnly = pszImagePathStart;
|
||
} else {
|
||
|
||
DBG_ASSERT( *pszDllNameOnly == '\\'); // just paranoid
|
||
|
||
//
|
||
// Skip past the path separator for comparisons to work correctly
|
||
//
|
||
pszDllNameOnly++;
|
||
}
|
||
|
||
return pSvc->IsInProcISAPI(pszDllNameOnly);
|
||
} // IsImageRunnableInProcOnly()
|
||
|
||
|