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