/*++ Copyright (c) 1999-2001 Microsoft Corporation Module Name : server_support.cxx Abstract: IIS Plus ServerSupportFunction command implementations Author: Wade Hilmo (wadeh) 05-Apr-2000 Project: w3isapi.dll --*/ #include "precomp.hxx" #include "isapi_context.hxx" #include "server_support.hxx" // // BUGBUG - stristr is declared in iisrearc\core\inc\irtlmisc.h, // but doesn't appear to be implemented anywhere. Because of the // way it's declared in that file, we have to use a different // function name here... // const char* stristr2( const char* pszString, const char* pszSubString ); HRESULT SSFSendResponseHeader( ISAPI_CONTEXT * pIsapiContext, LPSTR szStatus, LPSTR szHeaders ) /*++ Routine Description: Sends HTTP status and headers to the client. Arguments: pIsapiContext - The ISAPI_CONTEXT associated with this command. szStatus - The status to send to the client (ie. "200 OK") szHeaders - Headers to send to the client (ie. foo1: value1\r\n\r\n") Return Value: HRESULT --*/ { IIsapiCore * pIsapiCore; HRESULT hr; DBG_ASSERT( pIsapiContext ); DBG_ASSERT( pIsapiContext->CheckSignature() ); IF_DEBUG( ISAPI_SSF_DETAILS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_SEND_RESPONSE_HEADER[%p]: Function Entry\r\n" " Status: '%s'\r\n" " Headers: '%s'\r\n" " \r\n\r\n", pIsapiContext, szStatus, szHeaders )); } pIsapiCore = pIsapiContext->QueryIsapiCoreInterface(); if ( pIsapiCore == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_SEND_RESPONSE_HEADER[%p]: Failed to get interface to server core\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // We need validate the fKeepConn status for the request now, // since http.sys will generate the connection response // header based on it. // // If we're going to support keep-alive, then the // ISAPI must return either a content-length header, // or use chunked transfer encoding. We'll check for // that here. // if ( pIsapiContext->QueryClientKeepConn() ) { if ( szHeaders != NULL && ( stristr2( szHeaders, "content-length: " ) != NULL || stristr2( szHeaders, "transfer-encoding: chunked" ) != NULL ) ) { pIsapiContext->SetKeepConn( TRUE ); } } // // Since we automatically decided to keep the connection alive // or not, we should not honor HSE_STATUS_SUCCESS_AND_KEEP_CONN. // This maintains compatibility with previous IIS versions. // pIsapiContext->SetHonorAndKeepConn( FALSE ); // // Note that NULL is valid for both szStatus and szHeaders, // so there's no need to validate them. // hr = pIsapiCore->SendResponseHeaders( !pIsapiContext->QueryKeepConn(), szStatus, szHeaders, HSE_IO_SYNC ); if ( FAILED( hr ) ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_SEND_RESPONSE_HEADER[%p]: Failed\r\n" " Error: 0x%08x\r\n" " \r\n\r\n", pIsapiContext, hr )); } return hr; } else { pIsapiContext->SetHeadersSent( TRUE ); } IF_DEBUG( ISAPI_SSF_DETAILS ) { IF_DEBUG( ISAPI_SUCCESS_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_SEND_RESPONSE_HEADER[%p]: Succeeded\r\n" " \r\n\r\n", pIsapiContext )); } } return hr; } HRESULT SSFSendResponseHeaderEx( ISAPI_CONTEXT * pIsapiContext, HSE_SEND_HEADER_EX_INFO * pHeaderInfo ) /*++ Routine Description: Sends HTTP status and headers to the client, and offers explicit control over keep-alive for this request. Arguments: pIsapiContext - The ISAPI_CONTEXT associated with this command. pHeaderInfo - The response info to be passed to the client Return Value: HRESULT --*/ { IIsapiCore * pIsapiCore; HRESULT hr; DBG_ASSERT( pIsapiContext ); DBG_ASSERT( pIsapiContext->CheckSignature() ); IF_DEBUG( ISAPI_SSF_DETAILS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_SEND_RESPONSE_HEADER_EX[%p]: Function Entry\r\n" " Status: '%s'\r\n" " Headers: '%s'\r\n" " KeepConn: %d\r\n", pIsapiContext, pHeaderInfo->pszStatus, pHeaderInfo->pszHeader, pHeaderInfo->fKeepConn )); } pIsapiCore = pIsapiContext->QueryIsapiCoreInterface(); if ( pIsapiCore == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_SEND_RESPONSE_HEADER_EX[%p]: Failed to get interface to server core\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // Validate parameters // if ( pHeaderInfo == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_SEND_RESPONSE_HEADER_EX[%p]: Parameter validation failure\r\n" " pHeaderInfo: NULL\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // Set the keep connection flag. It can only be TRUE if the // ISAPI and the client both want keep alive. // // Note that we are trusting the ISAPI to provide some kind // of content length in the case where it's setting fKeepConn // to TRUE. This is the same behavior as IIS 5 which, for // performance reasons, doesn't try to parse the headers from // the ISAPI. // if ( pHeaderInfo->fKeepConn && pIsapiContext->QueryClientKeepConn() ) { pIsapiContext->SetKeepConn( TRUE ); } hr = pIsapiCore->SendResponseHeaders( !pIsapiContext->QueryKeepConn(), const_cast( pHeaderInfo->pszStatus ), const_cast( pHeaderInfo->pszHeader ), HSE_IO_SYNC ); if ( FAILED( hr ) ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_SEND_RESPONSE_HEADER_EX[%p]: Failed.\r\n" " Error: 0x%08x\r\n" " \r\n\r\n", pIsapiContext, hr )); } return hr; } else { pIsapiContext->SetHeadersSent( TRUE ); } IF_DEBUG( ISAPI_SSF_DETAILS ) { IF_DEBUG( ISAPI_SUCCESS_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_SEND_RESPONSE_HEADER_EX[%p]: Succeeded\r\n" " \r\n", pIsapiContext )); } } return hr; } HRESULT SSFMapUrlToPath( ISAPI_CONTEXT * pIsapiContext, LPSTR szBuffer, LPDWORD pcbBuffer ) /*++ Routine Description: Maps a URL into a physical path Arguments: pIsapiContext - The ISAPI_CONTEXT associated with this command. szBuffer - On entry, contains the URL to map. On return, contains the mapped physical path. pcbBuffer - On entry, the size of szBuffer. On successful return, the number of bytes copied to szUrl. On failed return, the number of bytes needed for the physical path. Return Value: HRESULT --*/ { IIsapiCore * pIsapiCore; HRESULT hr; DBG_ASSERT( pIsapiContext ); DBG_ASSERT( pIsapiContext->CheckSignature() ); IF_DEBUG( ISAPI_SSF_DETAILS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_MAP_URL_TO_PATH[%p]: Function Entry\r\n" " URL: %s\r\n" " \r\n\r\n", pIsapiContext, szBuffer )); } pIsapiCore = pIsapiContext->QueryIsapiCoreInterface(); if ( pIsapiCore == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_MAP_URL_TO_PATH[%p]: Failed to get interface to server core\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // Validate parameters // if ( szBuffer == NULL || pcbBuffer == NULL || *pcbBuffer == 0 ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_MAP_URL_TO_PATH[%p]: Parameter validation failure\r\n" " Buffer: '%s'\r\n" " Buffer Size Ptr: %p\r\n" " Buffer Size: %d\r\n", pIsapiContext, pcbBuffer, pcbBuffer ? *pcbBuffer : 0 )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } hr = pIsapiCore->MapPath( reinterpret_cast( szBuffer ), *pcbBuffer, pcbBuffer, FALSE ); if ( FAILED( hr ) ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_MAP_URL_TO_PATH[%p]: Failed\r\n" " Error: 0x%08x\r\n" " \r\n\r\n", pIsapiContext, hr )); } return hr; } IF_DEBUG( ISAPI_SSF_DETAILS ) { IF_DEBUG( ISAPI_SUCCESS_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_MAP_URL_TO_PATH[%p]: Succeeded\r\n" " Mapped URL: %s\r\n" " \r\n\r\n", pIsapiContext, szBuffer )); } } return hr; } HRESULT SSFMapUrlToPathEx( ISAPI_CONTEXT * pIsapiContext, LPSTR szUrl, HSE_URL_MAPEX_INFO * pHseMapInfo, LPDWORD pcbMappedPath ) /*++ Routine Description: Maps a URL to a physical path and returns some metadata metrics for the URL to the caller. Arguments: pIsapiContext - The ISAPI_CONTEXT associated with this command. szUrl - The URL to map pHseMapInfo - Upon return, contains the mapped URL info pcbMappedPath - If non-NULL, contains the buffer size needed to store the mapped physical path. Return Value: HRESULT --*/ { IIsapiCore * pIsapiCore; DWORD cbMapped; HRESULT hr; DBG_ASSERT( pIsapiContext ); DBG_ASSERT( pIsapiContext->CheckSignature() ); IF_DEBUG( ISAPI_SSF_DETAILS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_MAP_URL_TO_PATH_EX[%p]: Function Entry\r\n" " URL='%s'\r\n" " \r\n\r\n", pIsapiContext, szUrl )); } pIsapiCore = pIsapiContext->QueryIsapiCoreInterface(); if ( pIsapiCore == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_MA_URL_TO_PATH_EX[%p]: Failed to get interface to server core\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // Additional parameter validation // if ( szUrl == NULL || pHseMapInfo == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_MAP_URL_TO_PATH_EX[%p]: Parameter validation failure\r\n" " URL: '%s'\r\n" " HSE_URL_MAPEX_INFO: %p\r\n" " \r\n\r\n", pIsapiContext, szUrl, pHseMapInfo )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // The inline buffer within the HSE_URL_MAPEX_INFO structure // is defined as being MAX_PATH size. // cbMapped = MAX_PATH; pHseMapInfo->dwReserved1 = 0; pHseMapInfo->dwReserved2 = 0; hr = pIsapiCore->MapPathEx( reinterpret_cast( szUrl ), (DWORD)strlen(szUrl) + 1, reinterpret_cast( pHseMapInfo->lpszPath ), cbMapped, pcbMappedPath ? pcbMappedPath : &cbMapped, &pHseMapInfo->cchMatchingPath, &pHseMapInfo->cchMatchingURL, &pHseMapInfo->dwFlags, FALSE ); if ( FAILED( hr ) ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_MAP_URL_TO_PATH_EX[%p]: Failed\r\n" " Error: 0x%08x\r\n" " \r\n\r\n", pIsapiContext, hr )); } return hr; } return hr; } HRESULT SSFMapUnicodeUrlToPath( ISAPI_CONTEXT * pIsapiContext, LPWSTR szBuffer, LPDWORD pcbBuffer ) /*++ Routine Description: Maps a URL into a physical path Arguments: pIsapiContext - The ISAPI_CONTEXT associated with this command. szBuffer - On entry, contains the URL to map. On return, contains the mapped physical path. pcbBuffer - On entry, the size of szBuffer. On successful return, the number of bytes copied to szUrl. On failed return, the number of bytes needed for the physical path. Return Value: HRESULT --*/ { IIsapiCore * pIsapiCore; HRESULT hr; DBG_ASSERT( pIsapiContext ); DBG_ASSERT( pIsapiContext->CheckSignature() ); IF_DEBUG( ISAPI_SSF_DETAILS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_MAP_UNICODE_URL_TO_PATH[%p]: Function Entry\r\n" " URL='%S'\r\n" " \r\n\r\n", pIsapiContext, szBuffer )); } pIsapiCore = pIsapiContext->QueryIsapiCoreInterface(); if ( pIsapiCore == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_MA_UNICODE_URL_TO_PATH[%p]: Failed to get interface to server core\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // Validate parameters // if ( szBuffer == NULL || pcbBuffer == NULL || *pcbBuffer == 0 ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_MAP_UNICODE_URL_TO_PATH[%p]: Parameter validation failure\r\n" " Buffer: '%S'\r\n" " Buffer Size Ptr: %p\r\n" " Buffer Size: %d\r\n" " \r\n\r\n", pIsapiContext, szBuffer, pcbBuffer, pcbBuffer ? *pcbBuffer : 0 )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } hr = pIsapiCore->MapPath( reinterpret_cast( szBuffer ), *pcbBuffer, pcbBuffer, TRUE ); if ( FAILED( hr ) ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_MAP_UNICODE_URL_TO_PATH[%p]: Failed\r\n" " Error: 0x%08x\r\n" " \r\n\r\n", pIsapiContext, hr )); } return hr; } return hr; } HRESULT SSFMapUnicodeUrlToPathEx( ISAPI_CONTEXT * pIsapiContext, LPWSTR szUrl, HSE_UNICODE_URL_MAPEX_INFO *pHseMapInfo, LPDWORD pcbMappedPath ) /*++ Routine Description: Maps a URL to a physical path and returns some metadata metrics for the URL to the caller. Arguments: pIsapiContext - The ISAPI_CONTEXT associated with this command. szUrl - The URL to map pHseMapInfo - Upon return, contains the mapped URL info pcbMappedPath - If non-NULL, contains the buffer size needed to store the mapped physical path. Return Value: HRESULT --*/ { IIsapiCore * pIsapiCore; DWORD cbMapped; HRESULT hr; DBG_ASSERT( pIsapiContext ); DBG_ASSERT( pIsapiContext->CheckSignature() ); IF_DEBUG( ISAPI_SSF_DETAILS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_MAP_UNICODE_URL_TO_PATH_EX[%p]: Function Entry\r\n" " URL='%S'\r\n" " \r\n\r\n", pIsapiContext, szUrl )); } pIsapiCore = pIsapiContext->QueryIsapiCoreInterface(); if ( pIsapiCore == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_MA_UNICODE_URL_TO_PATH_EX[%p]: Failed to get interface to server core\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // Additional parameter validation // if ( szUrl == NULL || pHseMapInfo == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_MAP_UNICODE_URL_TO_PATH_EX[%p]: Parameter validation failure\r\n" " URL: '%s'\r\n" " pHseMapInfo: %p\r\n" " \r\n\r\n", pIsapiContext, szUrl, pHseMapInfo )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // The inline buffer within the HSE_URL_MAPEX_INFO structure // is defined as being MAX_PATH size. // cbMapped = MAX_PATH * sizeof(WCHAR); hr = pIsapiCore->MapPathEx( reinterpret_cast( szUrl ), (DWORD)(wcslen(szUrl) + 1)*sizeof(WCHAR), reinterpret_cast( pHseMapInfo->lpszPath ), cbMapped, pcbMappedPath ? pcbMappedPath : &cbMapped, &pHseMapInfo->cchMatchingPath, &pHseMapInfo->cchMatchingURL, &pHseMapInfo->dwFlags, TRUE ); if ( FAILED( hr ) ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_MAP_UNICODE_URL_TO_PATH_EX[%p]: Failed\r\n" " Error: 0x%08x\r\n" " \r\n\r\n", pIsapiContext, hr )); } return hr; } return hr; } HRESULT SSFGetImpersonationToken( ISAPI_CONTEXT * pIsapiContext, HANDLE * phToken ) /*++ Routine Description: Returns a (non-duplicated) copy of the token that the server is using to impersonate the client for this request. Arguments: pIsapiContext - The ISAPI_CONTEXT associated with this command. phToken - Upon return, contains a copy of the token. Return Value: HRESULT --*/ { DBG_ASSERT( pIsapiContext ); DBG_ASSERT( pIsapiContext->CheckSignature() ); IF_DEBUG( ISAPI_SSF_DETAILS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_IMPERSONATION_TOKEN[%p]: Function Entry\r\n" " \r\n\r\n", pIsapiContext )); } // // Validate parameters // if ( phToken == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_IMPERSONATION_TOKEN[%p]: Parameter validation failure\r\n" " Token Ptr: NULL\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } *phToken = pIsapiContext->QueryToken(); return NO_ERROR; } HRESULT SSFIsKeepConn( ISAPI_CONTEXT * pIsapiContext, BOOL * pfIsKeepAlive ) /*++ Routine Description: Returns information about whether the client wants us to keep the connection open or not at completion of this request. Arguments: pIsapiContext - The ISAPI_CONTEXT associated with this command. pfIsKeepAlive - Upon return, TRUE if IIS will be keeping the connection alive, else FALSE. Return Value: HRESULT --*/ { DBG_ASSERT( pIsapiContext ); DBG_ASSERT( pIsapiContext->CheckSignature() ); IF_DEBUG( ISAPI_SSF_DETAILS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_IS_KEEP_CONN[%p]: Function Entry\r\n" " \r\n\r\n", pIsapiContext )); } // // Validate parameters // if ( pfIsKeepAlive == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_IS_KEEP_CONN[%p]: Parameter validation failure\r\n" " KeepAlive Ptr: NULL\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } *pfIsKeepAlive = pIsapiContext->QueryClientKeepConn(); return NO_ERROR; } HRESULT SSFDoneWithSession( ISAPI_CONTEXT * pIsapiContext, DWORD * pHseResult ) /*++ Routine Description: Notifies the server that the calling ISAPI is done with the ECB (and ISAPI_CONTEXT) for this request and that the server can clean up. Arguments: pIsapiContext - The ISAPI_CONTEXT associated with this command. pHseResult - A pointer to the HSE_STATUS code that the extension wants to use. Return Value: HRESULT --*/ { IIsapiCore * pIsapiCore; DBG_ASSERT( pIsapiContext ); DBG_ASSERT( pIsapiContext->CheckSignature() ); DBG_ASSERT( pIsapiContext->QueryIoState() == NoAsyncIoPending ); DBG_REQUIRE( ( pIsapiCore = pIsapiContext->QueryIsapiCoreInterface() ) != NULL ); IF_DEBUG( ISAPI_SSF_DETAILS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_DONE_WITH_SESSION[%p]: Function Entry\r\n" " \r\n\r\n", pIsapiContext )); } // // If the caller wants to do STATUS_SUCCESS_AND_KEEP_CONN, // then we need to do that now. // // Note that this overrides our own determination of whether // the client can support keep-alive or not. We are trusting // the caller to have returned the right headers to make this // work with the client. // if ( pHseResult && *pHseResult == HSE_STATUS_SUCCESS_AND_KEEP_CONN ) { if ( pIsapiContext->QueryClientKeepConn() ) { pIsapiContext->SetKeepConn( TRUE ); pIsapiCore->SetConnectionClose( !pIsapiContext->QueryKeepConn() ); } } // // We'll just release the reference on IsapiContext. // Its destructor will do the rest. // pIsapiContext->DereferenceIsapiContext(); pIsapiContext = NULL; return NO_ERROR; } HRESULT SSFGetCertInfoEx( ISAPI_CONTEXT * pIsapiContext, CERT_CONTEXT_EX * pCertContext ) /*++ Routine Description: Returns certificate information about the client associated with this request. Arguments: pIsapiContext - The ISAPI_CONTEXT associated with this command. pCertContext - Upon return, contains info about the client cert. Return Value: HRESULT --*/ { IIsapiCore * pIsapiCore; HRESULT hr; DBG_ASSERT( pIsapiContext ); DBG_ASSERT( pIsapiContext->CheckSignature() ); IF_DEBUG( ISAPI_SSF_DETAILS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_CERT_INFO_EX[%p]: Function Entry\r\n" " \r\n\r\n", pIsapiContext )); } pIsapiCore = pIsapiContext->QueryIsapiCoreInterface(); if ( pIsapiCore == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_CERT_INFO_EX[%p]: Failed to get interface to server core\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // Validate parameters // if ( pCertContext == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_CERT_INFO_EX[%p]: Parameter validation failure\r\n" " CertContext Ptr: NULL\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } hr = pIsapiCore->GetCertificateInfoEx( pCertContext->cbAllocated, &( pCertContext->CertContext.dwCertEncodingType ), pCertContext->CertContext.pbCertEncoded, &( pCertContext->CertContext.cbCertEncoded ), &( pCertContext->dwCertificateFlags ) ); if ( FAILED( hr ) ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_CERT_INFO_EX[%p]: Failed\r\n" " Error: 0x%08x\r\n" " \r\n\r\n", pIsapiContext, hr )); } return hr; } return hr; } HRESULT SSFIoCompletion( ISAPI_CONTEXT * pIsapiContext, PFN_HSE_IO_COMPLETION pCompletionRoutine, LPVOID pHseIoContext ) /*++ Routine Description: Establishes the I/O completion routine and user-defined context to be used for asynchronous operations associated with this request. Arguments: pIsapiContext - The ISAPI_CONTEXT associated with this command. pCompletionRoutine - The function to call upon I/O completion pHseIoContext - The user-defined context to be passed to the completion routine. Return Value: HRESULT --*/ { DBG_ASSERT( pIsapiContext ); DBG_ASSERT( pIsapiContext->CheckSignature() ); IF_DEBUG( ISAPI_SSF_DETAILS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_IO_COMPLETION[%p]: Function Entry\r\n" " Completion Routine: %p\r\n" " Context: %p\r\n" " \r\n\r\n", pIsapiContext, pCompletionRoutine, pHseIoContext )); } // // Validate parameters // if ( pCompletionRoutine == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_IO_COMPLETION[%p]: Parameter validation failure\r\n" " Completion Routine: NULL\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } pIsapiContext->SetPfnIoCompletion( pCompletionRoutine ); pIsapiContext->SetExtensionContext( pHseIoContext ); return NO_ERROR; } HRESULT SSFAsyncReadClient( ISAPI_CONTEXT * pIsapiContext, LPVOID pBuffer, LPDWORD pcbBuffer ) /*++ Routine Description: Queues an asynchronous read of data from the client. Arguments: pIsapiContext - The ISAPI_CONTEXT associated with this command. pBuffer - Buffer to be filled with read data. pcbBuffer - The size of pBuffer Return Value: HRESULT --*/ { IIsapiCore * pIsapiCore; DWORD cbBuffer; HRESULT hr = NOERROR; DBG_ASSERT( pIsapiContext ); DBG_ASSERT( pIsapiContext->CheckSignature() ); IF_DEBUG( ISAPI_SSF_DETAILS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_ASYNC_READ_CLIENT[%p]: Function Entry\r\n" " Bytes to Read: %d\r\n" " \r\n\r\n", pIsapiContext, pcbBuffer ? *pcbBuffer : 0 )); } pIsapiCore = pIsapiContext->QueryIsapiCoreInterface(); if ( pIsapiCore == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_ASYNC_READ_CLIENT[%p]: Failed to get interface to server core\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // Validate parameters // if ( pIsapiContext->QueryPfnIoCompletion() == NULL || pBuffer == NULL || pcbBuffer == NULL || *pcbBuffer == 0 ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_ASYNC_READ_CLIENT[%p]: Parameter validation failure\r\n" " Completion Routine: %p\r\n" " Buffer Ptr: %p\r\n" " Buffer Size Ptr: %p\r\n" " Buffer Size: %d\r\n" " \r\n\r\n", pIsapiContext, pIsapiContext->QueryPfnIoCompletion(), pBuffer, pcbBuffer, pcbBuffer ? *pcbBuffer : 0 )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // Do the async ReadClient call // if ( pIsapiContext->TryInitAsyncIo( AsyncReadPending ) == FALSE ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_ASYNC_READ_CLIENT[%p]: Failed\r\n" " Another async operation is already pending\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // Since we're never actually reading any data in the async // case, we want to prevent pIsapiCore->ReadClient() from // modifying the buffer size we report back to the caller, // so we'll use a local for cbBuffer. // cbBuffer = *pcbBuffer; // // If this call will be going OOP, save a pointer to the // read buffer so that the core can fill it when the // operation completes. // if ( pIsapiContext->QueryIsOop() ) { DBG_ASSERT( pIsapiContext->QueryAsyncIoBuffer() == NULL ); DBG_ASSERT( pIsapiContext->QueryLastAsyncIo() == 0 ); pIsapiContext->SetAsyncIoBuffer( pBuffer ); pIsapiContext->SetLastAsyncIo( cbBuffer ); } hr = pIsapiCore->ReadClient( reinterpret_cast( pIsapiContext ), pIsapiContext->QueryIsOop() ? NULL : reinterpret_cast( pBuffer ), pIsapiContext->QueryIsOop() ? 0 : cbBuffer, cbBuffer, &cbBuffer, HSE_IO_ASYNC ); if ( FAILED( hr ) ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_ASYNC_READ_CLIENT[%p]: Failed\r\n" " Error: 0x%08x\r\n" " \r\n\r\n", pIsapiContext, hr )); } pIsapiContext->SetAsyncIoBuffer( NULL ); pIsapiContext->SetLastAsyncIo( 0 ); pIsapiContext->UninitAsyncIo(); } return hr; } HRESULT SSFTransmitFile( ISAPI_CONTEXT * pIsapiContext, HSE_TF_INFO * pTfInfo ) /*++ Routine Description: Transmits a file, a portion of a file, or some other data (in the event on a NULL file handle) to the client. Arguments: pIsapiContext - The ISAPI_CONTEXT associated with this command. pTfInfo - Describes the desired transmit file action. Return Value: HRESULT --*/ { IIsapiCore * pIsapiCore; LARGE_INTEGER cbFileSize; HRESULT hr; DBG_ASSERT( pIsapiContext ); DBG_ASSERT( pIsapiContext->CheckSignature() ); IF_DEBUG( ISAPI_SSF_DETAILS ) { STACK_STRA( strFilename,MAX_PATH ); DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_TRANSMIT_FILE[%p]: Function Entry\r\n" " Completion Routine: %p\r\n" " Context: %p\r\n" " File Handle: %p\r\n" " Status Code: '%s'\r\n" " Bytes To Write: %d\r\n" " Offset: %d\r\n" " \r\n\r\n", pIsapiContext, pTfInfo ? pTfInfo->pfnHseIO : 0, pTfInfo ? pTfInfo->pContext : 0, pTfInfo ? pTfInfo->hFile : 0, pTfInfo ? pTfInfo->pszStatusCode : 0, pTfInfo ? pTfInfo->BytesToWrite : 0, pTfInfo ? pTfInfo->Offset : 0 )); IF_DEBUG( ISAPI_DUMP_BUFFERS ) { if ( pTfInfo ) { STACK_STRA( strHead,MAX_PATH ); STACK_STRA( strTail,MAX_PATH ); DWORD dwBytesToDump; dwBytesToDump = pTfInfo->HeadLength; if ( dwBytesToDump > MAX_DEBUG_DUMP ) { dwBytesToDump = MAX_DEBUG_DUMP; } if ( FAILED( strHead.CopyBinary( pTfInfo->pHead, dwBytesToDump ) ) ) { strHead.Copy( "" ); } dwBytesToDump = pTfInfo->TailLength; if ( dwBytesToDump > MAX_DEBUG_DUMP ) { dwBytesToDump = MAX_DEBUG_DUMP; } if ( FAILED( strTail.CopyBinary( pTfInfo->pTail, dwBytesToDump ) ) ) { strTail.Copy( "" ); } DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_TRANSMIT_FILE[%p]: Dump of up to %d bytes of head and tail data\r\n" " Head Data:\r\n" "%s" " Tail Data:\r\n" "%s" " \r\n", pIsapiContext, MAX_DEBUG_DUMP, strHead.QueryStr(), strTail.QueryStr() )); } } } pIsapiCore = pIsapiContext->QueryIsapiCoreInterface(); if ( pIsapiCore == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_TRANSMIT_FILE[%p]: Failed to get interface to server core\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // Validate parameters - For TRANSMIT_FILE, this means: // // - We must have an ISAPI core interface to call through // - We must have an HSE_TF_INFO structure // - The HSE_IO_ASYNC flag must be set // - If HeadLength is set, pHead cannot be NULL // - If TailLength is set, pTail cannot be NULL // - We must have either a completion routine already set // in the ISAPI_CONTEXT, or the HSE_TF_INFO must provide // one // - There can be no other async operations in progress // if ( pTfInfo == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_TRANSMIT_FILE[%p]: Parameter validation failure\r\n" " Transmit File Info Ptr: NULL\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } if ( ( pTfInfo->dwFlags & HSE_IO_ASYNC ) == 0 || pTfInfo->hFile == INVALID_HANDLE_VALUE || ( pTfInfo->HeadLength != 0 && pTfInfo->pHead == NULL ) || ( pTfInfo->TailLength != 0 && pTfInfo->pTail == NULL ) || ( pIsapiContext->QueryPfnIoCompletion() == NULL && pTfInfo->pfnHseIO == NULL ) ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_TRANSMIT_FILE[%p]: Parameter validation failure\r\n" " %s\r\n", " File Handle: %p\r\n" " Head: %p\r\n" " Head Length: %d\r\n" " Tail: %p\r\n" " Tail Length: %d\r\n" " Completion Routine: %p\r\n" " \r\n\r\n", pIsapiContext, pTfInfo->dwFlags & HSE_IO_ASYNC ? "Async flag set" : "Async flag not set", pTfInfo->hFile, pTfInfo->pHead, pTfInfo->HeadLength, pTfInfo->pTail, pTfInfo->TailLength, pTfInfo->pfnHseIO ? pTfInfo->pfnHseIO : pIsapiContext->QueryPfnIoCompletion() )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } if ( pIsapiContext->TryInitAsyncIo( AsyncWritePending ) == FALSE ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_TRANSMIT_FILE[%p]: Failed\r\n" " Another async operation is already pending.\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // We'll do some extra validation in the case where we've been // provided a file handle. // // Specifically, we'll check to make sure that the offset and // bytes-to-write are valid for the file. // // CODEWORK - Do we really need to do this, or can http.sys handle // it? Also, does http.sys treat zero bytes to write // the same as TransmitFile (ie. send the whole file?) // if ( pTfInfo->hFile != NULL ) { if (!GetFileSizeEx(pTfInfo->hFile, &cbFileSize)) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto Done; } if ( pTfInfo->Offset > cbFileSize.QuadPart || (pTfInfo->Offset > 0 && pTfInfo->Offset == cbFileSize.QuadPart ) || pTfInfo->Offset + pTfInfo->BytesToWrite > cbFileSize.QuadPart ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_TRANSMIT_FILE[%p]: Parameter validation failure\r\n" " File Size: %d\r\n" " Offset: %d\r\n" " Bytes to Write: %d\r\n" " \r\n\r\n", pIsapiContext, cbFileSize.QuadPart, pTfInfo->Offset, pTfInfo->BytesToWrite )); } hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); goto Done; } } else { // // No file handle, so initialize the size to zero // cbFileSize.QuadPart = 0; } // // If the HSE_TF_INFO includes I/O completion or context // information, override the existing settings. // if ( pTfInfo->pfnHseIO ) { pIsapiContext->SetPfnIoCompletion( pTfInfo->pfnHseIO ); } if ( pTfInfo->pContext ) { pIsapiContext->SetExtensionContext( pTfInfo->pContext ); } // // If the extension is setting HSE_IO_SEND_HEADERS, then we need // to determine if it's sending some kind of content length. If // it's not, then we need to set _fKeepConn to FALSE. // // CODEWORK // Note that we're making a bold assumption here that if // HSE_IO_SEND_HEADERS is set, then pHead points to a NULL // terminated string. // if ( pIsapiContext->QueryClientKeepConn() && pTfInfo->pHead && ( pTfInfo->dwFlags & HSE_IO_SEND_HEADERS ) && !( pTfInfo->dwFlags & HSE_IO_DISCONNECT_AFTER_SEND ) ) { if ( stristr2( (LPSTR)pTfInfo->pHead, "content-length: " ) != NULL || stristr2( (LPSTR)pTfInfo->pHead, "transfer-encoding: chunked" ) != NULL ) { pIsapiContext->SetKeepConn( TRUE ); } } if ( pIsapiContext->QueryKeepConn() == FALSE ) { pTfInfo->dwFlags |= HSE_IO_DISCONNECT_AFTER_SEND; } else { // // We need to clear the HSE_IO_DISCONNECT_AFTER_SEND flag // in the case where QueryKeepConn is TRUE. // pTfInfo->dwFlags &= ~HSE_IO_DISCONNECT_AFTER_SEND; } // // Save the BytesToWrite part as _cbLastAsyncIo, since the size of // pHead and pTail confuses ISAPI's that examine the cbWritten // value on completion. // ULARGE_INTEGER cbToWrite; if ( pTfInfo->BytesToWrite ) { cbToWrite.QuadPart = pTfInfo->BytesToWrite; } else { cbToWrite.QuadPart = cbFileSize.QuadPart - pTfInfo->Offset; } // // Note that ISAPI doesn't support large integer values, so the // best we can do here is to store the low bits. // pIsapiContext->SetLastAsyncIo( cbToWrite.LowPart ); hr = pIsapiCore->TransmitFile( reinterpret_cast( pIsapiContext ), reinterpret_cast( pTfInfo->hFile ), pTfInfo->Offset, cbToWrite.QuadPart, (pTfInfo->dwFlags & HSE_IO_SEND_HEADERS) ? const_cast( pTfInfo->pszStatusCode ) : NULL, reinterpret_cast( pTfInfo->pHead ), pTfInfo->HeadLength, reinterpret_cast( pTfInfo->pTail ), pTfInfo->TailLength, pTfInfo->dwFlags ); Done: if ( FAILED( hr ) ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_TRANSMIT_FILE[%p]: Failed\r\n" " Error: 0x%08x\r\n" " \r\n\r\n", pIsapiContext, hr )); } pIsapiContext->SetLastAsyncIo( 0 ); pIsapiContext->UninitAsyncIo(); } return hr; } HRESULT SSFSendRedirect( ISAPI_CONTEXT * pIsapiContext, LPSTR szUrl ) /*++ Routine Description: Sends a 302 redirect to the client associated with this request. Arguments: pIsapiContext - The ISAPI_CONTEXT associated with this command. szUrl - The target URL for the redirection. Return Value: HRESULT --*/ { IIsapiCore * pIsapiCore; HRESULT hr; DBG_ASSERT( pIsapiContext ); DBG_ASSERT( pIsapiContext->CheckSignature() ); IF_DEBUG( ISAPI_SSF_DETAILS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_SEND_REDIRECT[%p]: Function Entry\r\n" " URL: '%s'\r\n" " \r\n\r\n", pIsapiContext, szUrl )); } pIsapiCore = pIsapiContext->QueryIsapiCoreInterface(); if ( pIsapiCore == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_SEND_REDIRECT[%p]: Failed to get interface to server core\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // Validate parameters // if ( pIsapiContext == NULL || szUrl == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_SEND_REDIRECT[%p]: Parameter validation failure\r\n" " szUrl: '%s'\r\n" " \r\n\r\n", pIsapiContext, szUrl )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } if ( pIsapiContext->QueryClientKeepConn() ) { pIsapiContext->SetKeepConn( TRUE ); } hr = pIsapiCore->SendRedirect( szUrl, !pIsapiContext->QueryKeepConn() ); if ( FAILED( hr ) ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_SEND_REDIRECT[%p]: Failed\r\n" " Error: 0x%08x\r\n" " \r\n\r\n", pIsapiContext, hr )); } return hr; } return hr; } HRESULT SSFIsConnected( ISAPI_CONTEXT * pIsapiContext, BOOL * pfIsConnected ) /*++ Routine Description: Returns the connection state (connected or not connected) of the client associated with this request. Arguments: pIsapiContext - The ISAPI_CONTEXT associated with this command. pfIsConnected - TRUE upon return if the client is connected, else FALSE. Return Value: HRESULT --*/ { IIsapiCore * pIsapiCore; HRESULT hr; DBG_ASSERT( pIsapiContext ); DBG_ASSERT( pIsapiContext->CheckSignature() ); IF_DEBUG( ISAPI_SSF_DETAILS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_IS_CONNECTED[%p]: Function Entry\r\n" " \r\n\r\n", pIsapiContext )); } pIsapiCore = pIsapiContext->QueryIsapiCoreInterface(); if ( pIsapiCore == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_IS_CONNECTED[%p]: Failed to get interface to server core\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // Validate parameters // if ( pfIsConnected == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_IS_CONNECTED[%p]: Parameter validation failure\r\n" " IsConnected Ptr: NULL\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } hr = pIsapiCore->TestConnection( pfIsConnected ); if ( FAILED( hr ) ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_IS_CONNECTED[%p]: Failed\r\n" " Error: 0x%08x\r\n" " \r\n\r\n", pIsapiContext, hr )); } return hr; } return hr; } HRESULT SSFAppendLog( ISAPI_CONTEXT * pIsapiContext, LPSTR szExtraParam ) /*++ Routine Description: Appends the string passed to the QueryString that will be logged Arguments: pIsapiContext - The ISAPI_CONTEXT associated with this command. szExtraParam - The extra parameter to be logged Return Value: HRESULT --*/ { IIsapiCore * pIsapiCore; HRESULT hr; DBG_ASSERT( pIsapiContext ); DBG_ASSERT( pIsapiContext->CheckSignature() ); IF_DEBUG( ISAPI_SSF_DETAILS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_APPEND_LOG_PARAMETER[%p]: Function Entry\r\n" " Extra Param: '%s'\r\n" " \r\n\r\n", pIsapiContext, szExtraParam )); } pIsapiCore = pIsapiContext->QueryIsapiCoreInterface(); if ( pIsapiCore == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_APPEND_LOG_PARAMETER[%p]: Failed to get interface to server core\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // Validate parameters // if ( szExtraParam == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_APPEND_LOG_PARAMETER[%p]: Parameter validation failure\r\n" " Extra Param: NULL\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } hr = pIsapiCore->AppendLog( szExtraParam, 0 ); if ( FAILED( hr ) ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_APPEND_LOG_PARAMETER[%p]: Failed\r\n" " Error: 0x%08x\r\n" " \r\n\r\n", pIsapiContext, hr )); } return hr; } return hr; } HRESULT SSFExecuteUrl( ISAPI_CONTEXT * pIsapiContext, VOID * pOrigExecUrlInfo, BOOL fIsUnicode ) /*++ Routine Description: Execute a child request Arguments: pIsapiContext - The ISAPI_CONTEXT associated with this command. pOrigExecUrlInfo - Description of child request to execute fIsUnicode - Are we passing unicode data? Return Value: HRESULT --*/ { EXEC_URL_USER_INFO UserName; EXEC_URL_ENTITY_INFO Entity; EXEC_URL_INFO UrlInfo; IIsapiCore * pIsapiCore; HRESULT hr; DBG_ASSERT( pIsapiContext ); DBG_ASSERT( pIsapiContext->CheckSignature() ); IF_DEBUG( ISAPI_SSF_DETAILS ) { HSE_EXEC_URL_ENTITY_INFO *pEntityInfo = NULL; if ( fIsUnicode ) { HSE_EXEC_UNICODE_URL_INFO *pInfo = (HSE_EXEC_UNICODE_URL_INFO *)pOrigExecUrlInfo; HSE_EXEC_UNICODE_URL_USER_INFO *pUserInfo = NULL; if ( pInfo ) { pUserInfo = pInfo->pUserInfo; pEntityInfo = pInfo->pEntity; } DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_EXEC_UNICODE_URL[%p]: Function Entry\r\n" " URL: '%S'\r\n" " Method: '%s'\r\n" " Child Headers: '%s'\r\n" " Flags: 0x%08x (%d)\r\n" " Impersonation Token: %p\r\n" " Custom User Name: '%S'\r\n" " Custom Auth Type: '%s'\r\n" " \r\n\r\n", pIsapiContext, pInfo ? pInfo->pszUrl : NULL, pInfo ? pInfo->pszMethod : NULL, pInfo ? pInfo->pszChildHeaders : NULL, pInfo ? pInfo->dwExecUrlFlags : 0, pInfo ? pInfo->dwExecUrlFlags : 0, pUserInfo ? pUserInfo->hImpersonationToken : NULL, pUserInfo ? pUserInfo->pszCustomUserName : NULL, pUserInfo ? pUserInfo->pszCustomAuthType : NULL )); } else { HSE_EXEC_URL_INFO *pInfo = (HSE_EXEC_URL_INFO *)pOrigExecUrlInfo; HSE_EXEC_URL_USER_INFO *pUserInfo = NULL; if ( pInfo ) { pUserInfo = pInfo->pUserInfo; pEntityInfo = pInfo->pEntity; } DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_EXEC_UNICODE_URL[%p]: Function Entry\r\n" " URL: '%s'\r\n" " Method: '%s'\r\n" " Child Headers: '%s'\r\n" " Flags: 0x%08x (%d)\r\n" " Impersonation Token: %p\r\n" " Custom User Name: '%s'\r\n" " Custom Auth Type: '%s'\r\n" " \r\n\r\n", pIsapiContext, pInfo ? pInfo->pszUrl : NULL, pInfo ? pInfo->pszMethod : NULL, pInfo ? pInfo->pszChildHeaders : NULL, pInfo ? pInfo->dwExecUrlFlags : 0, pInfo ? pInfo->dwExecUrlFlags : 0, pUserInfo ? pUserInfo->hImpersonationToken : NULL, pUserInfo ? pUserInfo->pszCustomUserName : NULL, pUserInfo ? pUserInfo->pszCustomAuthType : NULL )); } IF_DEBUG( ISAPI_DUMP_BUFFERS ) { if ( pEntityInfo ) { STACK_STRA( strBufferDump,512 ); DWORD dwBytesToDump = pEntityInfo->cbAvailable; if ( dwBytesToDump > MAX_DEBUG_DUMP ) { dwBytesToDump = MAX_DEBUG_DUMP; } if ( FAILED( strBufferDump.CopyBinary( pEntityInfo->lpbData, dwBytesToDump ) ) ) { strBufferDump.Copy( "" ); } DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_EXEC_URL[%p]: Dump of up to %d bytes of entity\r\n" "%s" " \r\n\r\n", pIsapiContext, MAX_DEBUG_DUMP, strBufferDump.QueryStr() )); } } } pIsapiCore = pIsapiContext->QueryIsapiCoreInterface(); if ( pIsapiCore == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_EXEC_URL[%p]: Failed to get interface to server core\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } if ( pOrigExecUrlInfo == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_EXEC_URL[%p]: Parameter validation failure\r\n" " ExecUrl Info: NULL\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // This is an async call, make sure a completion routine is set // if ( pIsapiContext->QueryPfnIoCompletion() == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_EXEC_URL[%p]: Failed\r\n" " No I/O completion has been set: NULL\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } if ( pIsapiContext->TryInitAsyncIo( AsyncExecPending ) == FALSE ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_EXEC_URL[%p]: Failed\r\n" " An async operation is already pending: NULL\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // If any of the optional parameters are not NULL, then ensure they are // not empty. Also, copy parameters to the marshallable structure // // Note that any failures from here on down need to goto Done so // that we properly uninitialize async IO. // if (fIsUnicode) { HSE_EXEC_UNICODE_URL_INFO *pExecUnicodeUrlInfo = (HSE_EXEC_UNICODE_URL_INFO *)pOrigExecUrlInfo; if ( pExecUnicodeUrlInfo->pszUrl != NULL ) { if ( pExecUnicodeUrlInfo->pszUrl[ 0 ] == L'\0' ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_EXEC_UNICODE_URL[%p]: Parameter validation failure\r\n" " URL is an empty string.\r\n" " \r\n\r\n", pIsapiContext )); } hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); goto Done; } UrlInfo.fIsUrlUnicode = TRUE; UrlInfo.pszUrl = (BYTE *)pExecUnicodeUrlInfo->pszUrl; UrlInfo.cbUrl = (DWORD)(wcslen(pExecUnicodeUrlInfo->pszUrl) + 1)*sizeof(WCHAR); } else { UrlInfo.pszUrl = NULL; UrlInfo.cbUrl = 0; } if ( pExecUnicodeUrlInfo->pszMethod != NULL ) { if ( pExecUnicodeUrlInfo->pszMethod[ 0 ] == '\0' ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_EXEC_UNICODE_URL[%p]: Parameter validation failure\r\n" " Method is an empty string\r\n" " \r\n\r\n", pIsapiContext )); } hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); goto Done; } } UrlInfo.pszMethod = pExecUnicodeUrlInfo->pszMethod; if ( pExecUnicodeUrlInfo->pszChildHeaders != NULL ) { if ( pExecUnicodeUrlInfo->pszChildHeaders[ 0 ] == '\0' ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_EXEC_UNICODE_URL[%p]: Parameter validation failure\r\n" " ChildHeaders is an empty string\r\n" " \r\n\r\n", pIsapiContext )); } hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); goto Done; } } UrlInfo.pszChildHeaders = pExecUnicodeUrlInfo->pszChildHeaders; if ( pExecUnicodeUrlInfo->pUserInfo != NULL ) { if ( pExecUnicodeUrlInfo->pUserInfo->pszCustomUserName == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_EXEC_UNICODE_URL[%p]: Parameter validation failure\r\n" " Custom User Name: NULL\r\n" " \r\n\r\n", pIsapiContext )); } hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); goto Done; } if ( pExecUnicodeUrlInfo->pUserInfo->pszCustomAuthType == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_EXEC_UNICODE_URL[%p]: Parameter validation failure\r\n" " Custom Auth Type: NULL\r\n" " \r\n\r\n", pIsapiContext )); } hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); goto Done; } UserName.fIsUserNameUnicode = TRUE; UserName.pszUserName = (BYTE *)pExecUnicodeUrlInfo->pUserInfo->pszCustomUserName; UserName.cbUserName = (DWORD)(wcslen(pExecUnicodeUrlInfo->pUserInfo->pszCustomUserName) + 1)*sizeof(WCHAR); UserName.pszAuthType = pExecUnicodeUrlInfo->pUserInfo->pszCustomAuthType; UserName.hImpersonationToken = (DWORD_PTR)pExecUnicodeUrlInfo->pUserInfo->hImpersonationToken; UrlInfo.pUserInfo = &UserName; } else { UrlInfo.pUserInfo = NULL; } // // If we are being told that there is available entity, ensure // that the buffer is not NULL // if ( pExecUnicodeUrlInfo->pEntity != NULL ) { if ( pExecUnicodeUrlInfo->pEntity->cbAvailable != 0 && pExecUnicodeUrlInfo->pEntity->lpbData == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_EXEC_UNICODE_URL[%p]: Parameter validation failure\r\n" " Available Entity bytes: %d\r\n" " Available Entity Ptr: %p\r\n" " \r\n\r\n", pIsapiContext, pExecUnicodeUrlInfo->pEntity->cbAvailable, pExecUnicodeUrlInfo->pEntity->lpbData )); } hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); goto Done; } Entity.cbAvailable = pExecUnicodeUrlInfo->pEntity->cbAvailable; Entity.lpbData = (BYTE *)pExecUnicodeUrlInfo->pEntity->lpbData; } else { // // If no entity body was set for this child execute, then // we should duplicate the original entity body. This means // we will need to bring over the preloaded entity for the // ISAPI which calls this routine. // Entity.cbAvailable = pIsapiContext->QueryECB()->cbAvailable; Entity.lpbData = pIsapiContext->QueryECB()->lpbData; } UrlInfo.pEntity = &Entity; UrlInfo.dwExecUrlFlags = pExecUnicodeUrlInfo->dwExecUrlFlags; } else { HSE_EXEC_URL_INFO *pExecAnsiUrlInfo = (HSE_EXEC_URL_INFO *)pOrigExecUrlInfo; if ( pExecAnsiUrlInfo->pszUrl != NULL ) { if ( pExecAnsiUrlInfo->pszUrl[ 0 ] == '\0' ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_EXEC_URL[%p]: Parameter validation failure\r\n" " URL is an empty string\r\n" " \r\n\r\n", pIsapiContext )); } hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); goto Done; } UrlInfo.fIsUrlUnicode = FALSE; UrlInfo.pszUrl = (BYTE *)pExecAnsiUrlInfo->pszUrl; UrlInfo.cbUrl = (DWORD)strlen(pExecAnsiUrlInfo->pszUrl) + 1; } else { UrlInfo.pszUrl = NULL; UrlInfo.cbUrl = 0; } if ( pExecAnsiUrlInfo->pszMethod != NULL ) { if ( pExecAnsiUrlInfo->pszMethod[ 0 ] == '\0' ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_EXEC_URL[%p]: Parameter validation failure\r\n" " Method is an empty string\r\n" " \r\n\r\n", pIsapiContext )); } hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); goto Done; } } UrlInfo.pszMethod = pExecAnsiUrlInfo->pszMethod; if ( pExecAnsiUrlInfo->pszChildHeaders != NULL ) { if ( pExecAnsiUrlInfo->pszChildHeaders[ 0 ] == '\0' ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_EXEC_URL[%p]: Parameter validation failure\r\n" " ChildHeaders is an empty string\r\n" " \r\n\r\n", pIsapiContext )); } hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); goto Done; } } UrlInfo.pszChildHeaders = pExecAnsiUrlInfo->pszChildHeaders; if ( pExecAnsiUrlInfo->pUserInfo != NULL ) { if ( pExecAnsiUrlInfo->pUserInfo->pszCustomUserName == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_EXEC_URL[%p]: Parameter validation failure\r\n" " Custom User Name: NULL\r\n" " \r\n\r\n", pIsapiContext )); } hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); goto Done; } if ( pExecAnsiUrlInfo->pUserInfo->pszCustomAuthType == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_EXEC_URL[%p]: Parameter validation failure\r\n" " Custom Auth Type: NULL\r\n" " \r\n\r\n", pIsapiContext )); } hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); goto Done; } UserName.fIsUserNameUnicode = FALSE; UserName.pszUserName = (BYTE *)pExecAnsiUrlInfo->pUserInfo->pszCustomUserName; UserName.cbUserName = (DWORD)strlen(pExecAnsiUrlInfo->pUserInfo->pszCustomUserName) + 1; UserName.pszAuthType = pExecAnsiUrlInfo->pUserInfo->pszCustomAuthType; UserName.hImpersonationToken = (DWORD_PTR)pExecAnsiUrlInfo->pUserInfo->hImpersonationToken; UrlInfo.pUserInfo = &UserName; } else { UrlInfo.pUserInfo = NULL; } // // If we are being told that there is available entity, ensure // that the buffer is not NULL // if ( pExecAnsiUrlInfo->pEntity != NULL ) { if ( pExecAnsiUrlInfo->pEntity->cbAvailable != 0 && pExecAnsiUrlInfo->pEntity->lpbData == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_EXEC_URL[%p]: Parameter validation failure\r\n" " Available Entity Bytes: %d\r\n" " Available Entity Ptr: %p\r\n" " \r\n\r\n", pIsapiContext, pExecAnsiUrlInfo->pEntity->cbAvailable, pExecAnsiUrlInfo->pEntity->lpbData )); } hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); goto Done; } Entity.cbAvailable = pExecAnsiUrlInfo->pEntity->cbAvailable; Entity.lpbData = (BYTE *)pExecAnsiUrlInfo->pEntity->lpbData; } else { // // If no entity body was set for this child execute, then // we should duplicate the original entity body. This means // we will need to bring over the preloaded entity for the // ISAPI which calls this routine. // Entity.cbAvailable = pIsapiContext->QueryECB()->cbAvailable; Entity.lpbData = pIsapiContext->QueryECB()->lpbData; } UrlInfo.pEntity = &Entity; UrlInfo.dwExecUrlFlags = pExecAnsiUrlInfo->dwExecUrlFlags; } // // All the heavy lifting is in W3CORE.DLL // hr = pIsapiCore->ExecuteUrl( reinterpret_cast( pIsapiContext ), &UrlInfo ); Done: if ( FAILED( hr ) ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_EXEC_URL[%p]: Failed\r\n" " Error: 0x%08x\r\n" " \r\n\r\n", pIsapiContext, hr )); } pIsapiContext->UninitAsyncIo(); } return hr; } HRESULT SSFGetExecuteUrlStatus( ISAPI_CONTEXT * pIsapiContext, HSE_EXEC_URL_STATUS* pExecUrlStatus ) /*++ Routine Description: Get status of last child execute Arguments: pIsapiContext - The ISAPI_CONTEXT associated with this command. pExecUrlStatus - Filled with status Return Value: HRESULT --*/ { IIsapiCore * pIsapiCore; HRESULT hr; DBG_ASSERT( pIsapiContext ); DBG_ASSERT( pIsapiContext->CheckSignature() ); IF_DEBUG( ISAPI_SSF_DETAILS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_EXEC_URL_STATUS[%p]: Function Entry\r\n" " \r\n\r\n", pIsapiContext )); } pIsapiCore = pIsapiContext->QueryIsapiCoreInterface(); if ( pIsapiCore == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_EXEC_URL_STATUS[%p]: Failed to get interface to server core\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } if ( pExecUrlStatus == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_EXEC_URL_STATUS[%p]: Parameter validation failure\r\n" " EXEC_URL Status Ptr: NULL\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } hr = pIsapiCore->GetExecuteUrlStatus( &(pExecUrlStatus->uHttpStatusCode), &(pExecUrlStatus->uHttpSubStatus), &(pExecUrlStatus->dwWin32Error) ); if ( FAILED( hr ) ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_EXEC_URL_STATUS[%p]: Failed\r\n" " Error: 0x%08x\r\n" " \r\n\r\n", pIsapiContext, hr )); } return hr; } return hr; } HRESULT SSFSendCustomError( ISAPI_CONTEXT * pIsapiContext, HSE_CUSTOM_ERROR_INFO * pCustomErrorInfo ) /*++ Routine Description: Send custom error to client Arguments: pIsapiContext - The ISAPI_CONTEXT associated with this command. pCustomErrorInfo - Describes the custom error to send Return Value: HRESULT --*/ { IIsapiCore * pIsapiCore; HRESULT hr = NOERROR; DBG_ASSERT( pIsapiContext ); DBG_ASSERT( pIsapiContext->CheckSignature() ); IF_DEBUG( ISAPI_SSF_DETAILS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_SEND_CUSTOM_ERROR[%p]: Function Entry\r\n" " Status: '%s'\r\n" " SubError Code: %d\r\n" " \r\n\r\n", pIsapiContext, pCustomErrorInfo ? pCustomErrorInfo->pszStatus : NULL, pCustomErrorInfo ? pCustomErrorInfo->uHttpSubError : 0 )); } pIsapiCore = pIsapiContext->QueryIsapiCoreInterface(); if ( pIsapiCore == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_SEND_CUSTOM_ERROR[%p]: Failed to get interface to server core\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } if ( pCustomErrorInfo == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_SEND_CUSTOM_ERROR[%p]: Parameter validation failure\r\n" " Custom Error Info Ptr: NULL\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // Ensure status is not empty // if ( pCustomErrorInfo->pszStatus != NULL ) { if ( pCustomErrorInfo->pszStatus[ 0 ] == '\0' ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_SEND_CUSTOM_ERROR[%p]: Parameter validation failure\r\n" " Status is an empty string\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } } // // If this is an async call, then make sure a completion routine is set // if ( pCustomErrorInfo->fAsync ) { if ( pIsapiContext->TryInitAsyncIo( AsyncExecPending ) == FALSE ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_SEND_CUSTOM_ERROR[%p]: Failed\r\n" " Another async operation is already pending\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } } hr = pIsapiCore->SendCustomError( pCustomErrorInfo->fAsync ? reinterpret_cast( pIsapiContext ) : NULL, pCustomErrorInfo->pszStatus, pCustomErrorInfo->uHttpSubError ); if ( FAILED( hr ) ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_SEND_CUSTOM_ERROR[%p]: Failed\r\n" " Error: 0x%08x\r\n" " \r\n\r\n", pIsapiContext, hr )); } if ( pCustomErrorInfo->fAsync ) { pIsapiContext->UninitAsyncIo(); } return hr; } return hr; } HRESULT SSFVectorSendDeprecated( ISAPI_CONTEXT * pIsapiContext, HSE_RESPONSE_VECTOR_DEPRECATED * pResponseVector ) /*++ Routine Description: The old deprecated vector-send Arguments: pIsapiContext - The ISAPI_CONTEXT associated with this command. pResponseVector - The vector to be sent Return Value: HRESULT --*/ { HSE_RESPONSE_VECTOR RealResponseVector; STACK_BUFFER( buffResp, 512); HRESULT hr; IF_DEBUG( ISAPI_SSF_DETAILS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_VECTOR_SEND_DEPRECATED[%p]: Function Entry\r\n" " \r\n\r\n", pIsapiContext )); } if ( pResponseVector == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_VECTOR_SEND_DEPRECATED[%p]: Parameter validation failure\r\n" " Response Vector Ptr: NULL\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } RealResponseVector.dwFlags = pResponseVector->dwFlags; RealResponseVector.pszStatus = pResponseVector->pszStatus; RealResponseVector.pszHeaders = pResponseVector->pszHeaders; RealResponseVector.nElementCount = pResponseVector->nElementCount; if (!buffResp.Resize(pResponseVector->nElementCount * sizeof(HSE_VECTOR_ELEMENT))) { return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY ); } RealResponseVector.lpElementArray = (HSE_VECTOR_ELEMENT *)buffResp.QueryPtr(); for (DWORD i=0; inElementCount; i++) { if (pResponseVector->lpElementArray[i].pBuffer != NULL) { RealResponseVector.lpElementArray[i].ElementType = HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER; RealResponseVector.lpElementArray[i].pvContext = pResponseVector->lpElementArray[i].pBuffer; RealResponseVector.lpElementArray[i].cbSize = pResponseVector->lpElementArray[i].cbSize; } else { RealResponseVector.lpElementArray[i].ElementType = HSE_VECTOR_ELEMENT_TYPE_FILE_HANDLE; RealResponseVector.lpElementArray[i].pvContext = pResponseVector->lpElementArray[i].hFile; RealResponseVector.lpElementArray[i].cbOffset = pResponseVector->lpElementArray[i].cbOffset; RealResponseVector.lpElementArray[i].cbSize = pResponseVector->lpElementArray[i].cbSize; } } hr = SSFVectorSend(pIsapiContext, &RealResponseVector); if ( FAILED( hr ) ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_VECTOR_SEND_DEPRECATED[%p]: Failed\r\n" " Error: 0x%08x\r\n" " \r\n\r\n", pIsapiContext, hr )); } return hr; } return hr; } HRESULT SSFVectorSend( ISAPI_CONTEXT * pIsapiContext, HSE_RESPONSE_VECTOR * pResponseVector ) /*++ Routine Description: Send an array of memory/file-handle/fragment-cache chunks Arguments: pIsapiContext - The ISAPI_CONTEXT associated with this command. pResponseVector - The vector to be sent Return Value: HRESULT --*/ { IIsapiCore * pIsapiCore; ULONGLONG cbTotalSend = 0; STACK_BUFFER( buffResp, 512); HRESULT hr = NOERROR; DBG_ASSERT( pIsapiContext ); DBG_ASSERT( pIsapiContext->CheckSignature() ); IF_DEBUG( ISAPI_SSF_DETAILS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_VECTOR_SEND[%p]: Function Entry (%s)\r\n" " Status: '%s'\r\n" " Headers: '%s'\r\n" " Element Count: %d\r\n" " Flags: 0x%08x (%d)\r\n" " \r\n\r\n", pIsapiContext, pResponseVector ? pResponseVector->dwFlags & HSE_IO_ASYNC ? "Asynchronous" : "Synchronous" : "", pResponseVector ? pResponseVector->pszStatus : NULL, pResponseVector ? pResponseVector->pszHeaders : NULL, pResponseVector ? pResponseVector->nElementCount : 0, pResponseVector ? pResponseVector->dwFlags : 0, pResponseVector ? pResponseVector->dwFlags : 0 )); IF_DEBUG( ISAPI_DUMP_BUFFERS ) { if ( pResponseVector && pResponseVector->nElementCount ) { STACK_STRA( strBufferDump,512 ); DWORD dwBytesToDump; DWORD i; for ( i = 0; i < pResponseVector->nElementCount; i++ ) { if ( pResponseVector->lpElementArray[i].ElementType == HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER ) { dwBytesToDump = pResponseVector->lpElementArray[i].cbSize; if ( dwBytesToDump > MAX_DEBUG_DUMP ) { dwBytesToDump = MAX_DEBUG_DUMP; } if ( FAILED( strBufferDump.CopyBinary( pResponseVector->lpElementArray[i].pvContext, dwBytesToDump ) ) ) { strBufferDump.Copy( "" ); } DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_VECTOR_SEND[%p]: Dump of up to %d bytes of element %d\r\n" "%s" " \r\n\r\n", pIsapiContext, MAX_DEBUG_DUMP, i, strBufferDump.QueryStr() )); } else if ( pResponseVector->lpElementArray[i].ElementType == HSE_VECTOR_ELEMENT_TYPE_FILE_HANDLE ) { DBGPRINTF(( DBG_CONTEXT, "\r\n", " HSE_REQ_VECTOR_SEND[%p]: Element %d\r\n" " File Handle: %p\r\n" " Offset: %d\r\n" " Bytes To Send: %d\r\n" " \r\n\r\n", pIsapiContext, pResponseVector->lpElementArray[i].pvContext, pResponseVector->lpElementArray[i].cbOffset, pResponseVector->lpElementArray[i].cbSize )); } } } } } pIsapiCore = pIsapiContext->QueryIsapiCoreInterface(); if ( pIsapiCore == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_VECTOR_SEND[%p]: Failed to get interface to server core\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // verify the data passed in // if ( pResponseVector == NULL || ( ( pResponseVector->dwFlags & HSE_IO_ASYNC ) != 0 && pIsapiContext->TryInitAsyncIo( AsyncVectorPending ) == FALSE ) ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_VECTOR_SEND[%p]: Failed\r\n" " Another async operation is already pending\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } if ((pResponseVector->dwFlags & HSE_IO_SYNC) && (pResponseVector->dwFlags & HSE_IO_ASYNC)) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_VECTOR_SEND[%p]: Parameter validation failure\r\n" " Both HSE_IO_SYNC and HSE_IO_ASYNC were specified\r\n" " \r\n\r\n", pIsapiContext )); } hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); goto Failed; } if (pResponseVector->dwFlags & HSE_IO_SEND_HEADERS) { if ((pResponseVector->pszStatus == NULL) || (pResponseVector->pszHeaders == NULL)) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_VECTOR_SEND[%p]: Parameter validation failure\r\n" " HSE_IO_SEND_HEADERS was specified, but some required info is missing\r\n" " Status: '%s'\r\n" " Headers: '%s'\r\n" " \r\n\r\n", pIsapiContext, pResponseVector->pszStatus, pResponseVector->pszHeaders )); } hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); goto Failed; } } else { if ((pResponseVector->pszStatus != NULL) || (pResponseVector->pszHeaders != NULL)) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_VECTOR_SEND[%p]: Parameter validation failure\r\n" " HSE_IO_SEND_HEADERS was not specified, yet status or header info was provided\r\n" " Status: '%s'\r\n" " Headers: '%s'\r\n" " \r\n\r\n", pIsapiContext, pResponseVector->pszStatus, pResponseVector->pszHeaders )); } hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); goto Failed; } } if (!buffResp.Resize(pResponseVector->nElementCount * sizeof(VECTOR_ELEMENT))) { hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY ); goto Failed; } ZeroMemory(buffResp.QueryPtr(), pResponseVector->nElementCount * sizeof(VECTOR_ELEMENT)); VECTOR_ELEMENT *pVectorElement = (VECTOR_ELEMENT *)buffResp.QueryPtr(); HSE_VECTOR_ELEMENT *pHseVectorElement; for (DWORD i=0; inElementCount; i++) { pHseVectorElement = &pResponseVector->lpElementArray[i]; if (pHseVectorElement->pvContext == NULL) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_VECTOR_SEND[%p]: Parameter validation failure\r\n" " Context: NULL on element %d in the array\r\n" " \r\n\r\n", pIsapiContext, i )); } hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); goto Failed; } switch (pHseVectorElement->ElementType) { case HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER: if (pHseVectorElement->cbSize > MAXULONG) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_VECTOR_SEND[%p]: Parameter validation failure\r\n" " Invalid memory buffer size on element %d in the array\r\n" " Size: %d\r\n" " \r\n\r\n", pIsapiContext, i, pHseVectorElement->cbSize )); } hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); goto Failed; } pVectorElement[i].pBuffer = (BYTE *)pHseVectorElement->pvContext; cbTotalSend += ( pVectorElement[i].cbBufSize = (DWORD)pHseVectorElement->cbSize ); break; case HSE_VECTOR_ELEMENT_TYPE_FILE_HANDLE: if (pHseVectorElement->pvContext == INVALID_HANDLE_VALUE) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_VECTOR_SEND[%p]: Parameter validation failure\r\n" " Handle on file handle element %d in the array is invalid\r\n" " File Handle: %p\r\n" " \r\n\r\n", pIsapiContext, i, pHseVectorElement->pvContext )); } hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); goto Failed; } // // Treat 0 as "send the rest of the file" - same as TransmitFile // if (pHseVectorElement->cbSize == 0) { pHseVectorElement->cbSize = HTTP_BYTE_RANGE_TO_EOF; } pVectorElement[i].hFile = (DWORD_PTR)pHseVectorElement->pvContext; pVectorElement[i].cbOffset = pHseVectorElement->cbOffset; cbTotalSend += ( pVectorElement[i].cbFileSize = pHseVectorElement->cbSize ); break; case HSE_VECTOR_ELEMENT_TYPE_FRAGMENT: pVectorElement[i].pszFragmentName = (WCHAR *)pHseVectorElement->pvContext; break; default: IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_VECTOR_SEND[%p]: Parameter validation failure\r\n" " Unknown type on element %d in the array\r\n" " Element Type: %d\r\n" " \r\n\r\n", pIsapiContext, i, pHseVectorElement->ElementType )); } hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); goto Failed; } } // // Set up the total number of bytes we are trying to send so that ISAPIs // are not confused // pIsapiContext->SetLastAsyncIo( (cbTotalSend > MAXULONG) ? MAXULONG : (DWORD)cbTotalSend ); // // In general, VECTOR_SEND shouldn't touch the connection flags // in the ISAPI_CONTEXT, since ISAPI tries to do the right thing // automatically. // // There are couple of scenarios, though, where we might have a // bit of connection management housekeeping to do. // // If the caller specified the HSE_IO_DISCONNECT_AFTER_SEND flag, // then we need to force the connection closed. // // Otherwise, there are two scenarios where we may need to force // the connection to stay open. // // First, if all of the below are true, we should set the // connection to be open: // // - The client requested keep-alive // - This call is sending headers (HSE_IO_SEND_HEADERS is set) // - The disconnect flag has not been set // // Second, if all of the below are true, we should set the // connection to be open. // // - The client requested keep-alive // - The ISAPI has not already sent headers // - The disconnect flag has not been set // - This is the final send // // One final note: This logic does not account for the case where // this call is sending headers, and the call fails for some reason. // In the asynchronous case, this would be somewhat complicated to // handle, since the completion routine would need to know both if // the caller was sending headers, and also that the I/O failed. // Presumably, if such a failure occurs, the most likely reason is // that the client already disconnected, or it would otherwise be // unlikely for the caller to do something to try and recover and // redo this send in a way that would succeed, which makes all of this // moot. // if ( pResponseVector->dwFlags & HSE_IO_DISCONNECT_AFTER_SEND ) { pIsapiContext->SetKeepConn( FALSE ); } else { if ( pIsapiContext->QueryClientKeepConn() ) { if ( (pResponseVector->dwFlags & HSE_IO_SEND_HEADERS) || ( pIsapiContext->QueryHeadersSent() == FALSE && (pResponseVector->dwFlags & HSE_IO_FINAL_SEND) ) ) { pIsapiContext->SetKeepConn( TRUE ); } } } hr = pIsapiCore->VectorSend( pResponseVector->dwFlags & HSE_IO_ASYNC ? reinterpret_cast( pIsapiContext ) : NULL, !pIsapiContext->QueryKeepConn(), pResponseVector->pszStatus, pResponseVector->pszHeaders, pVectorElement, pResponseVector->nElementCount, !!(pResponseVector->dwFlags & HSE_IO_FINAL_SEND), !!(pResponseVector->dwFlags & HSE_IO_CACHE_RESPONSE) ); if ( FAILED( hr ) ) { goto Failed; } return hr; Failed: DBG_ASSERT( FAILED( hr ) ); IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_VECTOR_SEND[%p]: Failed\r\n" " Error: 0x%08x\r\n" " \r\n\r\n", pIsapiContext, hr )); } if ( pResponseVector->dwFlags & HSE_IO_ASYNC ) { pIsapiContext->SetLastAsyncIo( 0 ); pIsapiContext->UninitAsyncIo(); } return hr; } HRESULT SSFGetCustomErrorPage( ISAPI_CONTEXT * pIsapiContext, HSE_CUSTOM_ERROR_PAGE_INFO * pInfo ) { IIsapiCore * pIsapiCore; HRESULT hr; DBG_ASSERT( pIsapiContext ); DBG_ASSERT( pIsapiContext->CheckSignature() ); IF_DEBUG( ISAPI_SSF_DETAILS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_CUSTOM_ERROR_PAGE[%p]: Function Entry\r\n" " Error: %d\r\n" " SubError: %d\r\n" " \r\n\r\n", pIsapiContext, pInfo ? pInfo->dwError : 0, pInfo ? pInfo->dwSubError : 0 )); } pIsapiCore = pIsapiContext->QueryIsapiCoreInterface(); if ( pIsapiCore == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_CUSTOM_ERROR_PAGE[%p]: Failed to get interface to server core\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // Validate arguments // if ( pInfo == NULL || ( pInfo->dwBufferSize != 0 && pInfo->pBuffer == NULL ) || pInfo->pdwBufferRequired == NULL || pInfo->pfIsFileError == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_CUSTOM_ERROR_PAGE[%p]: Parameter validation failure\r\n" " Info Ptr: %p\r\n" " Buffer Size: %d\r\n" " Buffer Ptr: %p\r\n" " Buffer Required Ptr: %p\r\n" " IsFileError Ptr: %p\r\n" " \r\n\r\n", pIsapiContext, pInfo, pInfo ? pInfo->dwBufferSize : 0, pInfo ? pInfo->pBuffer : NULL, pInfo ? pInfo->pdwBufferRequired : NULL, pInfo ? pInfo->pfIsFileError : NULL )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } hr = pIsapiCore->GetCustomError( pInfo->dwError, pInfo->dwSubError, pInfo->dwBufferSize, reinterpret_cast( pInfo->pBuffer ), pInfo->pdwBufferRequired, pInfo->pfIsFileError, pInfo->pfSendErrorBody ); if ( FAILED( hr ) ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_CUSTOM_ERROR_PAGE[%p]: Failed\r\n" " Error: 0x%08x\r\n" " \r\n\r\n", pIsapiContext, hr )); } return hr; } return hr; } HRESULT SSFIsInProcess( ISAPI_CONTEXT * pIsapiContext, DWORD * pdwAppFlag ) { LPWSTR szClsid; DBG_ASSERT( pIsapiContext ); DBG_ASSERT( pIsapiContext->CheckSignature() ); IF_DEBUG( ISAPI_SSF_DETAILS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_IS_IN_PROCESS[%p]: Function Entry\r\n" " \r\n\r\n", pIsapiContext )); } if ( pdwAppFlag == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_IS_IN_PROCESS[%p]: Parameter validation failure\r\n" " AppFlag Ptr: NULL\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } szClsid = pIsapiContext->QueryClsid(); DBG_ASSERT( szClsid != NULL ); if ( wcslen( szClsid ) == 0 ) { *pdwAppFlag = HSE_APP_FLAG_IN_PROCESS; } else if ( _wcsicmp( szClsid, W3_OOP_POOL_WAM_CLSID ) == NULL ) { *pdwAppFlag = HSE_APP_FLAG_POOLED_OOP; } else { *pdwAppFlag = HSE_APP_FLAG_ISOLATED_OOP; } return NO_ERROR; } HRESULT SSFGetSspiInfo( ISAPI_CONTEXT * pIsapiContext, CtxtHandle * pCtxtHandle, CredHandle * pCredHandle ) { IIsapiCore * pIsapiCore; HRESULT hr; DBG_ASSERT( pIsapiContext ); DBG_ASSERT( pIsapiContext->CheckSignature() ); DBG_REQUIRE( ( pIsapiCore = pIsapiContext->QueryIsapiCoreInterface() ) != NULL ); IF_DEBUG( ISAPI_SSF_DETAILS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_SSPI_INFO[%p]: Function Entry\r\n" " \r\n\r\n", pIsapiContext )); } // // The CtxtHandle and CredHandle are only valid in their // local process. There is no way to duplicate them into // a dllhost. As a result, this function is inproc only. // if ( pIsapiContext->QueryIsOop() ) { return HRESULT_FROM_WIN32( ERROR_INVALID_FUNCTION ); } // // Validate parameters // if ( pCtxtHandle == NULL || pCredHandle == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_SSPI_INFO[%p]: Parameter validation Failure\r\n" " Context Handle Ptr: %p\r\n" " Credential Handle Ptr: %p\r\n" " \r\n\r\n", pIsapiContext, pCtxtHandle, pCredHandle )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } hr = pIsapiCore->GetSspiInfo( reinterpret_cast( pCredHandle ), sizeof( CredHandle ), reinterpret_cast( pCtxtHandle ), sizeof( CtxtHandle ) ); if ( FAILED( hr ) ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_SSPI_INFO[%p]: Failed\r\n" " Error: 0x%08x\r\n" " \r\n\r\n", pIsapiContext, hr )); } return hr; } return hr; } HRESULT SSFGetVirtualPathToken( ISAPI_CONTEXT * pIsapiContext, LPSTR szUrl, HANDLE * pToken, BOOL fUnicode ) { IIsapiCore * pIsapiCore; HRESULT hr = S_OK; DWORD64 dwToken; DBG_ASSERT( pIsapiContext ); DBG_ASSERT( pIsapiContext->CheckSignature() ); DBG_REQUIRE( ( pIsapiCore = pIsapiContext->QueryIsapiCoreInterface() ) != NULL ); IF_DEBUG( ISAPI_SSF_DETAILS ) { if ( fUnicode ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_UNICODE_VIRTUAL_PATH_TOKEN[%p]: Function Entry\r\n" " URL: '%S'\r\n" " \r\n\r\n", pIsapiContext, szUrl )); } else { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_VIRTUAL_PATH_TOKEN[%p]: Function Entry\r\n" " URL: '%s'\r\n" " \r\n\r\n", pIsapiContext, szUrl )); } } // // Validate parameters // if ( szUrl == NULL || pToken == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { if ( fUnicode ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_UNICODE_VIRTUAL_PATH_TOKEN[%p]: Parameter validation failure\r\n" " URL: '%S'\r\n" " Token Ptr: %p\r\n" " \r\n\r\n", pIsapiContext, szUrl, pToken )); } else { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_VIRTUAL_PATH_TOKEN[%p]: Parameter validation failure\r\n" " URL: '%s'\r\n" " Token Ptr: %p\r\n" " \r\n\r\n", pIsapiContext, szUrl, pToken )); } } } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } hr = pIsapiCore->QueryToken( reinterpret_cast( szUrl ), (DWORD)( fUnicode ? (wcslen( (LPWSTR)szUrl ) + 1 ) * sizeof(WCHAR) : strlen( szUrl ) + 1 ), TOKEN_VR_TOKEN, &dwToken, fUnicode ); if (FAILED(hr)) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_%sVIRTUAL_PATH_TOKEN[%p]: Failed\r\n" " Error: 0x%08x\r\n" " \r\n\r\n", fUnicode ? "UNICODE_" : "", pIsapiContext, hr )); } return hr; } *pToken = (HANDLE)dwToken; return hr; } HRESULT SSFGetAnonymousToken( ISAPI_CONTEXT * pIsapiContext, LPSTR szUrl, HANDLE * pToken, BOOL fUnicode ) { IIsapiCore * pIsapiCore; DWORD64 dwToken; HRESULT hr; DBG_ASSERT( pIsapiContext ); DBG_ASSERT( pIsapiContext->CheckSignature() ); DBG_REQUIRE( ( pIsapiCore = pIsapiContext->QueryIsapiCoreInterface() ) != NULL ); IF_DEBUG( ISAPI_SSF_DETAILS ) { if ( fUnicode ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_UNICODE_ANONYMOUS_TOKEN[%p]: Function Entry\r\n" " URL: '%S'\r\n" " \r\n\r\n", pIsapiContext, szUrl )); } else { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_ANONYMOUS_TOKEN[%p]: Function Entry\r\n" " URL: '%s\r\n" " \r\n\r\n", pIsapiContext, szUrl )); } } // // Validate parameters // if ( szUrl == NULL || pToken == NULL ) { if ( fUnicode ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_UNICODE_ANONYMOUS_TOKEN[%p]: Parameter validation failure\r\n" " URL: '%S'\r\n" " Token Ptr: %p\r\n" " \r\n\r\n", pIsapiContext, szUrl, pToken )); } } else { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_ANONYMOUS_TOKEN[%p]: Parameter validation failure\r\n" " URL: '%s'\r\n" " Token Ptr: %p\r\n" " \r\n\r\n", pIsapiContext, szUrl, pToken )); } } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } hr = pIsapiCore->QueryToken( reinterpret_cast( szUrl ), (DWORD)( fUnicode ? (wcslen( (LPWSTR)szUrl ) + 1 ) * sizeof(WCHAR) : strlen( szUrl ) + 1 ), TOKEN_ANONYMOUS_TOKEN, &dwToken, fUnicode ); if ( FAILED( hr ) ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_%sANONYMOUS_TOKEN[%p]: Failed\r\n" " Error: 0x%08x\r\n" " \r\n\r\n", fUnicode ? "UNICODE_" : "", pIsapiContext, hr )); } return hr; } *pToken = (HANDLE)dwToken; return hr; } HRESULT SSFReportUnhealthy( ISAPI_CONTEXT * pIsapiContext, LPSTR szReason ) { IIsapiCore * pIsapiCore; LPWSTR szImage; STACK_STRU( strReason, 512 ); DWORD cbImage; DWORD cbReason; HRESULT hr; DBG_ASSERT( pIsapiContext ); DBG_ASSERT( pIsapiContext->CheckSignature() ); DBG_REQUIRE( ( pIsapiCore = pIsapiContext->QueryIsapiCoreInterface() ) != NULL ); DBG_REQUIRE( ( szImage = pIsapiContext->QueryGatewayImage() ) != NULL ); IF_DEBUG( ISAPI_SSF_DETAILS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_REPORT_UNHEALTHY[%p]: Function Entry\r\n" " Reason: '%s'\r\n" " \r\n\r\n", pIsapiContext, szReason )); } cbImage = (DWORD)( wcslen( szImage ) + 1 ) * sizeof( WCHAR ); // // If the ISAPI has given a reason, we need to send it // as UNICODE. // if ( szReason == NULL ) { cbReason = 0; } else { hr = strReason.CopyA( szReason ); if ( FAILED( hr ) ) { return hr; } cbReason = ( strReason.QueryCCH() + 1 ) * sizeof( WCHAR ); } hr = pIsapiCore->ReportAsUnhealthy( reinterpret_cast( szImage ), cbImage, cbReason ? reinterpret_cast( strReason.QueryStr() ) : NULL, cbReason ); if ( FAILED( hr ) ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_REPORT_UNHEALTHY[%p]: Failed\r\n" " Error: 0x%08x\r\n" " \r\n\r\n", pIsapiContext, hr )); } return hr; } return hr; } HRESULT SSFNormalizeUrl( LPSTR pszURL ) /*++ Routine Description: Normalize URL Arguments: pszURL - On entry, contains not normalized URL. On return, contains normalized URL. Return Value: HRESULT --*/ { HRESULT hr; IF_DEBUG( ISAPI_SSF_DETAILS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_NORMALIZE_URL[]: Function Entry\r\n" " URL: '%s'\r\n" " \r\n\r\n", pszURL )); } // // Validate parameters // if ( pszURL == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_NORMALIZE_URL[]: Parameter validation failure\r\n" " URL: NULL\r\n" " \r\n\r\n" )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } hr = NormalizeUrl( pszURL ); if ( FAILED( hr ) ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_NORMALIZE_URL[]: Failed\r\n" " Error: 0x%08x\r\n" " \r\n\r\n", hr )); } return hr; } return hr; } HRESULT SSFAddFragmentToCache( ISAPI_CONTEXT * pIsapiContext, HSE_VECTOR_ELEMENT * pHseVectorElement, WCHAR * pszFragmentName ) /*++ Routine Description: Add the given fragment to the fragment-cache Arguments: pIsapiContext - The ISAPI_CONTEXT associated with this command. pVectorElement - The fragment to be added pszFragmentName - The name of the fragment Return Value: HRESULT --*/ { IIsapiCore *pIsapiCore = pIsapiContext->QueryIsapiCoreInterface(); HRESULT hr; IF_DEBUG( ISAPI_SSF_DETAILS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_ADD_FRAGMENT_TO_CACHE[%p]: Function Entry\r\n" " Fragment Name: '%S'\r\n" " \r\n\r\n", pIsapiContext, pszFragmentName )); } if ( pIsapiCore == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_ADD_FRAGMENT_TO_CACHE[%p]: Failed to get interface to server core\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // verify the data passed in // if ( pHseVectorElement == NULL || pszFragmentName == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_ADD_FRAGMENT_TO_CACHE[%p]: Parameter validation failure\r\n" " Vector Element Ptr: %p\r\n" " Fragment Name: '%s'\r\n" " \r\n\r\n", pIsapiContext, pHseVectorElement, pszFragmentName )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } VECTOR_ELEMENT VectorElement; ZeroMemory(&VectorElement, sizeof VectorElement); if (pHseVectorElement->pvContext == NULL) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_ADD_FRAGMENT_TO_CACHE[%p]: Parameter validation failure\r\n" " Vector Element Context: NULL\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } switch (pHseVectorElement->ElementType) { case HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER: if (pHseVectorElement->cbSize > MAXULONG) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_ADD_FRAGMENT_TO_CACHE[%p]: Parameter validation failure\r\n" " Memory buffer size element invalid\r\n" " Size: %d\r\n" " \r\n\r\n", pIsapiContext, pHseVectorElement->cbSize )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } VectorElement.pBuffer = (BYTE *)pHseVectorElement->pvContext; VectorElement.cbBufSize = (DWORD)pHseVectorElement->cbSize; break; case HSE_VECTOR_ELEMENT_TYPE_FILE_HANDLE: if (pHseVectorElement->pvContext == INVALID_HANDLE_VALUE) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_ADD_FRAGMENT_TO_CACHE[%p]: Parameter validation failure\r\n" " Element file handle invalid\r\n" " File Handle: %p\r\n" " \r\n\r\n", pIsapiContext, pHseVectorElement->pvContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // Treat 0 as "send the rest of the file" - same as TransmitFile/VectorSend // if (pHseVectorElement->cbSize == 0) { pHseVectorElement->cbSize = HTTP_BYTE_RANGE_TO_EOF; } VectorElement.hFile = (DWORD_PTR)pHseVectorElement->pvContext; VectorElement.cbOffset = pHseVectorElement->cbOffset; VectorElement.cbFileSize = pHseVectorElement->cbSize; break; case HSE_VECTOR_ELEMENT_TYPE_FRAGMENT: default: IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_ADD_FRAGMENT_TO_CACHE[%p]: Parameter validation failure\r\n" " Unknown element type: %d\r\n" " Fragment Name: '%s'\r\n" " \r\n\r\n", pIsapiContext, pHseVectorElement->ElementType )); } return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); } hr = pIsapiCore->AddFragmentToCache(&VectorElement, pszFragmentName); if ( FAILED( hr ) ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_ADD_FRAGMENT_TO_CACHE[%p]: Failed\r\n" " Error: 0x%08x\r\n" " \r\n\r\n", pIsapiContext, hr )); } return hr; } return hr; } HRESULT SSFReadFragmentFromCache( ISAPI_CONTEXT * pIsapiContext, WCHAR * pszFragmentName, BYTE * pvBuffer, DWORD * pcbSize ) /*++ Routine Description: Read the given fragment from the fragment-cache Arguments: pIsapiContext - The ISAPI_CONTEXT associated with this command. pszFragmentName - The name of the fragment pvBuffer - The buffer to read the fragment in pcbSize - On entry, the size of the buffer and on exit, the number of bytes copied Return Value: HRESULT --*/ { IIsapiCore *pIsapiCore = pIsapiContext->QueryIsapiCoreInterface(); HRESULT hr; IF_DEBUG( ISAPI_SSF_DETAILS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_READ_FRAGMENT_FROM_CACHE[%p]: Function Entry\r\n" " Fragment Name: '%S'\r\n" " \r\n\r\n", pIsapiContext, pszFragmentName )); } if ( pIsapiCore == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_READ_FRAGMENT_FROM_CACHE[%p]: Failed to get interface to server core\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // verify the data passed in // if ( pszFragmentName == NULL || pcbSize == NULL || (pvBuffer == NULL && *pcbSize != 0 ) ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_READ_FRAGMENT_FROM_CACHE[%p]: Parameter validation failure\r\n" " Fragment Name: '%s'\r\n" " Size Ptr: %p\r\n" " Size: %d\r\n" " Buffer Ptr: %p\r\n" " \r\n\r\n", pIsapiContext, pszFragmentName, pcbSize, pcbSize ? *pcbSize : 0, pvBuffer )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } hr = pIsapiCore->ReadFragmentFromCache(pszFragmentName, pvBuffer, *pcbSize, pcbSize); if ( FAILED( hr ) ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_READ_FRAGMENT_FROM_CACHE[%p]: Failed\r\n" " Error: 0x%08x\r\n" " \r\n\r\n", pIsapiContext, hr )); } return hr; } return hr; } HRESULT SSFRemoveFragmentFromCache( ISAPI_CONTEXT * pIsapiContext, WCHAR * pszFragmentName ) /*++ Routine Description: Remove the given fragment from the fragment-cache Arguments: pIsapiContext - The ISAPI_CONTEXT associated with this command. pszFragmentName - The name of the fragment Return Value: HRESULT --*/ { IIsapiCore *pIsapiCore = pIsapiContext->QueryIsapiCoreInterface(); HRESULT hr; IF_DEBUG( ISAPI_SSF_DETAILS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_REMOVE_FRAGMENT_FROM_CACHE[%p]: Function Entry\r\n" " Fragment Name: '%S'\r\n" " \r\n\r\n", pIsapiContext, pszFragmentName )); } if ( pIsapiCore == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_REMOVE_FRAGMENT_FROM_CACHE[%p]: Failed to get interface to server core\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // verify the data passed in // if ( pszFragmentName == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_REMOVE_FRAGMENT_FROM_CACHE[%p]: Parameter validation failure\r\n" " Fragment Name: '%s'\r\n" " \r\n\r\n", pIsapiContext, pszFragmentName )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } hr = pIsapiCore->RemoveFragmentFromCache(pszFragmentName); if ( FAILED( hr ) ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_REMOVE_FRAGMENT_FROM_CACHE[%p]: Failed\r\n" " Error: 0x%08x\r\n" " \r\n\r\n", pIsapiContext, hr )); } return hr; } return hr; } HRESULT SSFGetMetadataProperty( ISAPI_CONTEXT * pIsapiContext, DWORD_PTR dwPropertyId, BYTE * pbBuffer, DWORD * pcbBuffer ) /*++ Routine Description: Retrieve a property from the UT_FILE metadata associated with the URL of this request Arguments: pIsapiContext - ISAPI_CONTEXT dwPropertyId - MD_* metabase property ID pbBuffer - Points to buffer pcbBuffer - On input size of buffer, on output size needed/used Return Value: HRESULT --*/ { IIsapiCore * pIsapiCore; HRESULT hr; METADATA_RECORD * pRecord; DBG_ASSERT( pIsapiContext != NULL ); IF_DEBUG( ISAPI_SSF_DETAILS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_METADATA_PROPERTY[%p]: Function Entry\r\n" " PropertyID: 0x%08x (%d)\r\n" " \r\n\r\n", pIsapiContext, dwPropertyId, dwPropertyId )); } pIsapiCore = pIsapiContext->QueryIsapiCoreInterface(); DBG_ASSERT( pIsapiCore != NULL ); if ( pcbBuffer == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_METADATA_PROPERTY[%p]: Parameter validation failure\r\n" " Buffer Ptr: NULL\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } hr = pIsapiCore->GetMetadataProperty( (DWORD) dwPropertyId, pbBuffer, *pcbBuffer, pcbBuffer ); if ( FAILED( hr ) ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_METADATA_PROPERTY[%p]: Failed\r\n" " Error: 0x%08x\r\n" " \r\n\r\n", pIsapiContext, hr )); } return hr; } else { // // OK. Before we return the METADATA_RECORD back to caller, set the // pbMDData buffer pointer (since for OOP the pointer can only be // calculated on this side // DBG_ASSERT( *pcbBuffer >= sizeof( METADATA_RECORD ) ); pRecord = (METADATA_RECORD*) pbBuffer; pRecord->pbMDData = (BYTE*) (pRecord + 1); } return hr; } HRESULT SSFGetCacheInvalidationCallback( ISAPI_CONTEXT * pIsapiContext, PFN_HSE_CACHE_INVALIDATION_CALLBACK * pfnCallback ) /*++ Routine description: Get the callback function to use to flush a response from the http.sys cache Arguments: pIsapiContext - The ISAPI_CONTEXT corresponding to the request pfnCallback - On successful return, the address of the callback function Return: HRESULT --*/ { IIsapiCore * pIsapiCore; HRESULT hr; DBG_ASSERT( pIsapiContext != NULL ); IF_DEBUG( ISAPI_SSF_DETAILS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_CACHE_INVALIDATION_CALLBACK[%p]: Function Entry\r\n" " \r\n\r\n", pIsapiContext )); } pIsapiCore = pIsapiContext->QueryIsapiCoreInterface(); DBG_ASSERT( pIsapiCore != NULL ); if ( pfnCallback == NULL ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_CACHE_INVALIDATION_CALLBACK[%p]: Parameter validation failure\r\n" " Callback Ptr: NULL\r\n" " \r\n\r\n", pIsapiContext )); } return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } hr = pIsapiCore->GetCacheInvalidationCallback((DWORD64 *)pfnCallback); if ( FAILED( hr ) ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_GET_CACHE_INVALIDATION_CALLBACK[%p]: Failed\r\n" " Error: 0x%08x\r\n" " \r\n\r\n", pIsapiContext, hr )); } return hr; } return hr; } HRESULT SSFCloseConnection( ISAPI_CONTEXT * pIsapiContext ) { IIsapiCore * pIsapiCore; HRESULT hr; DBG_ASSERT( pIsapiContext ); DBG_ASSERT( pIsapiContext->CheckSignature() ); DBG_REQUIRE( ( pIsapiCore = pIsapiContext->QueryIsapiCoreInterface() ) != NULL ); IF_DEBUG( ISAPI_SSF_DETAILS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_CLOSE_CONNECTION[%p]: Function Entry\r\n" " \r\n\r\n", pIsapiContext )); } hr = pIsapiCore->CloseConnection(); if ( FAILED( hr ) ) { IF_DEBUG( ISAPI_ERROR_RETURNS ) { DBGPRINTF(( DBG_CONTEXT, "\r\n" " HSE_REQ_CLOSE_CONNECTION[%p]: Failed\r\n" " Error: 0x%08x\r\n" " \r\n\r\n", pIsapiContext, hr )); } return hr; } return hr; } // stristr (stolen from fts.c, wickn) // // case-insensitive version of strstr. // stristr returns a pointer to the first occurrence of // pszSubString in pszString. The search does not include // terminating nul characters. // // BUGBUG: is this DBCS-safe? const char* stristr2( const char* pszString, const char* pszSubString ) { const char *cp1 = (const char*) pszString, *cp2, *cp1a; char first; // get the first char in string to find first = pszSubString[0]; // first char often won't be alpha if (isalpha(first)) { first = (char) tolower(first); for ( ; *cp1 != '\0'; cp1++) { if (tolower(*cp1) == first) { for (cp1a = &cp1[1], cp2 = (const char*) &pszSubString[1]; ; cp1a++, cp2++) { if (*cp2 == '\0') return cp1; if (tolower(*cp1a) != tolower(*cp2)) break; } } } } else { for ( ; *cp1 != '\0' ; cp1++) { if (*cp1 == first) { for (cp1a = &cp1[1], cp2 = (const char*) &pszSubString[1]; ; cp1a++, cp2++) { if (*cp2 == '\0') return cp1; if (tolower(*cp1a) != tolower(*cp2)) break; } } } } return NULL; }