windows-nt/Source/XPSP1/NT/inetsrv/iis/svcs/w3/server/httpext.cxx
2020-09-26 16:20:57 +08:00

446 lines
12 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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()