963 lines
23 KiB
C++
963 lines
23 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (c) 1999 Microsoft Corporation
|
||
|
|
||
|
Module Name :
|
||
|
urlinfo.cxx
|
||
|
|
||
|
Abstract:
|
||
|
Gets metadata for URL
|
||
|
|
||
|
Author:
|
||
|
Bilal Alam (balam) 8-Jan-2000
|
||
|
|
||
|
Environment:
|
||
|
Win32 - User Mode
|
||
|
|
||
|
Project:
|
||
|
ULW3.DLL
|
||
|
--*/
|
||
|
|
||
|
#include "precomp.hxx"
|
||
|
#include <stringau.hxx>
|
||
|
|
||
|
ALLOC_CACHE_HANDLER * URL_CONTEXT::sm_pachUrlContexts;
|
||
|
|
||
|
//
|
||
|
// Utility to guard against ~ inconsistency
|
||
|
//
|
||
|
|
||
|
DWORD
|
||
|
CheckIfShortFileName(
|
||
|
IN WCHAR * pszPath,
|
||
|
IN HANDLE hImpersonation,
|
||
|
OUT BOOL * pfShort
|
||
|
);
|
||
|
|
||
|
W3_STATE_URLINFO::W3_STATE_URLINFO()
|
||
|
{
|
||
|
_hr = URL_CONTEXT::Initialize();
|
||
|
}
|
||
|
|
||
|
W3_STATE_URLINFO::~W3_STATE_URLINFO()
|
||
|
{
|
||
|
URL_CONTEXT::Terminate();
|
||
|
}
|
||
|
|
||
|
CONTEXT_STATUS
|
||
|
W3_STATE_URLINFO::OnCompletion(
|
||
|
W3_MAIN_CONTEXT * pMainContext,
|
||
|
DWORD cbCompletion,
|
||
|
DWORD dwCompletionStatus
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Handle URLINFO completions. CheckAccess() is called in DoWork() and this
|
||
|
call is asynchronous.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pMainContext - W3_MAIN_CONTEXT representing execution of state machine
|
||
|
cbCompletion - Number of bytes in an async completion
|
||
|
dwCompletionStatus - Error status of a completion
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
CONTEXT_STATUS_CONTINUE - if we should continue in state machine
|
||
|
else stop executing the machine and free up the current thread
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
CONTEXT_STATUS contextStatus;
|
||
|
BOOL fAccessAllowed;
|
||
|
|
||
|
contextStatus = pMainContext->CheckAccess( TRUE, // this is a completion
|
||
|
dwCompletionStatus,
|
||
|
&fAccessAllowed );
|
||
|
|
||
|
if ( contextStatus == CONTEXT_STATUS_PENDING )
|
||
|
{
|
||
|
return CONTEXT_STATUS_PENDING;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If access is not allowed, then just finish state machine (
|
||
|
// response has already been sent)
|
||
|
//
|
||
|
|
||
|
if ( !fAccessAllowed )
|
||
|
{
|
||
|
pMainContext->SetFinishedResponse();
|
||
|
}
|
||
|
|
||
|
return CONTEXT_STATUS_CONTINUE;
|
||
|
}
|
||
|
|
||
|
CONTEXT_STATUS
|
||
|
W3_STATE_URLINFO::DoWork(
|
||
|
W3_MAIN_CONTEXT * pMainContext,
|
||
|
DWORD cbCompletion,
|
||
|
DWORD dwCompletionStatus
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Handle retrieving the metadata for this request
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pMainContext - W3_MAIN_CONTEXT representing execution of state machine
|
||
|
cbCompletion - Number of bytes in an async completion
|
||
|
dwCompletionStatus - Error status of a completion
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
CONTEXT_STATUS_CONTINUE - if we should continue in state machine
|
||
|
else stop executing the machine and free up the current thread
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
URL_CONTEXT * pUrlContext = NULL;
|
||
|
BOOL fFinished = FALSE;
|
||
|
HRESULT hr = NO_ERROR;
|
||
|
W3_METADATA * pMetaData = NULL;
|
||
|
CONTEXT_STATUS contextStatus = CONTEXT_STATUS_CONTINUE;
|
||
|
W3_REQUEST * pHttpRequest = pMainContext->QueryRequest();
|
||
|
W3_RESPONSE * pResponse = pMainContext->QueryResponse();
|
||
|
BOOL fAccessAllowed = FALSE;
|
||
|
|
||
|
DBG_ASSERT( pHttpRequest != NULL );
|
||
|
DBG_ASSERT( pResponse != NULL );
|
||
|
|
||
|
//
|
||
|
// Set the context state
|
||
|
//
|
||
|
|
||
|
hr = URL_CONTEXT::RetrieveUrlContext( pMainContext,
|
||
|
pMainContext->QueryRequest(),
|
||
|
&pUrlContext,
|
||
|
&fFinished );
|
||
|
if ( FAILED( hr ) )
|
||
|
{
|
||
|
goto Failure;
|
||
|
}
|
||
|
|
||
|
DBG_ASSERT( fFinished || ( pUrlContext != NULL ) );
|
||
|
pMainContext->SetUrlContext( pUrlContext );
|
||
|
|
||
|
//
|
||
|
// From now on, errors in this function should not cleanup the URL
|
||
|
// context since it is owned by the main context
|
||
|
//
|
||
|
|
||
|
pUrlContext = NULL;
|
||
|
|
||
|
//
|
||
|
// If filter wants out, leave
|
||
|
//
|
||
|
|
||
|
if ( fFinished )
|
||
|
{
|
||
|
pMainContext->SetDone();
|
||
|
return CONTEXT_STATUS_CONTINUE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Check access now. That means checking for IP/SSL/Certs. We will
|
||
|
// avoid the authentication type check since the others (IP/SSL/Certs)
|
||
|
// take priority.
|
||
|
//
|
||
|
|
||
|
contextStatus = pMainContext->CheckAccess( FALSE, // not a completion
|
||
|
NO_ERROR,
|
||
|
&fAccessAllowed );
|
||
|
if ( contextStatus == CONTEXT_STATUS_PENDING )
|
||
|
{
|
||
|
return CONTEXT_STATUS_PENDING;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If we don't have access, then the appropriate error response was
|
||
|
// already sent. Just finish the state machine
|
||
|
//
|
||
|
|
||
|
if ( !fAccessAllowed )
|
||
|
{
|
||
|
pMainContext->SetFinishedResponse();
|
||
|
}
|
||
|
|
||
|
return CONTEXT_STATUS_CONTINUE;
|
||
|
|
||
|
Failure:
|
||
|
|
||
|
if ( pUrlContext != NULL )
|
||
|
{
|
||
|
delete pUrlContext;
|
||
|
}
|
||
|
|
||
|
if ( !pMainContext->QueryResponseSent() )
|
||
|
{
|
||
|
if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
|
||
|
{
|
||
|
// For the non-8dot3 case
|
||
|
pMainContext->QueryResponse()->SetStatus( HttpStatusNotFound );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pMainContext->QueryResponse()->SetStatus( HttpStatusServerError );
|
||
|
}
|
||
|
|
||
|
pMainContext->SetFinishedResponse();
|
||
|
pMainContext->SetErrorStatus( hr );
|
||
|
}
|
||
|
|
||
|
return CONTEXT_STATUS_CONTINUE;
|
||
|
}
|
||
|
|
||
|
//static
|
||
|
HRESULT
|
||
|
URL_CONTEXT::RetrieveUrlContext(
|
||
|
W3_CONTEXT * pW3Context,
|
||
|
W3_REQUEST * pRequest,
|
||
|
OUT URL_CONTEXT ** ppUrlContext,
|
||
|
BOOL * pfFinished
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
For a given request, get a URL_CONTEXT which represents the
|
||
|
metadata and URI-specific info for that request
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pW3Context - W3_CONTEXT for the request
|
||
|
pRequest - New request to lookup
|
||
|
ppUrlContext - Set to point to new URL_CONTEXT
|
||
|
pfFinished - Set to true if isapi filter said we're finished
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
HRESULT
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
STACK_STRU( strUrl, MAX_PATH );
|
||
|
W3_URL_INFO * pUrlInfo = NULL;
|
||
|
W3_METADATA * pMetaData = NULL;
|
||
|
URL_CONTEXT * pUrlContext = NULL;
|
||
|
HRESULT hr = NO_ERROR;
|
||
|
HANDLE hToken = NULL;
|
||
|
|
||
|
if ( pW3Context == NULL ||
|
||
|
pRequest == NULL ||
|
||
|
ppUrlContext == NULL ||
|
||
|
pfFinished == NULL )
|
||
|
{
|
||
|
DBG_ASSERT( FALSE );
|
||
|
return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
|
||
|
}
|
||
|
*ppUrlContext = NULL;
|
||
|
|
||
|
hr = pRequest->GetUrl( &strUrl );
|
||
|
if ( FAILED( hr ) )
|
||
|
{
|
||
|
goto Failure;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Lookup the URI info for this request
|
||
|
//
|
||
|
|
||
|
DBG_ASSERT( g_pW3Server->QueryUrlInfoCache() != NULL );
|
||
|
|
||
|
hr = g_pW3Server->QueryUrlInfoCache()->GetUrlInfo(
|
||
|
pW3Context,
|
||
|
strUrl,
|
||
|
&pUrlInfo );
|
||
|
if ( FAILED( hr ) )
|
||
|
{
|
||
|
goto Failure;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now, create a URL_CONTEXT object which contains the W3_URL_INFO and
|
||
|
// W3_METADATA pointers as well as state information for use on cleanup
|
||
|
//
|
||
|
|
||
|
DBG_ASSERT( pUrlInfo != NULL );
|
||
|
|
||
|
pMetaData = (W3_METADATA*) pUrlInfo->QueryMetaData();
|
||
|
DBG_ASSERT( pMetaData != NULL );
|
||
|
|
||
|
pUrlContext = new URL_CONTEXT( pMetaData, pUrlInfo );
|
||
|
if ( pUrlContext == NULL )
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
|
||
|
goto Failure;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now notify URL_MAP filters
|
||
|
//
|
||
|
|
||
|
if ( pW3Context->IsNotificationNeeded( SF_NOTIFY_URL_MAP ) )
|
||
|
{
|
||
|
STACK_STRA( straPhys, MAX_PATH + 1 );
|
||
|
STACK_STRA( straUrl, MAX_PATH + 1 );
|
||
|
BOOL fRet;
|
||
|
HTTP_FILTER_URL_MAP filterMap;
|
||
|
STACK_STRU( strPhysicalPath, MAX_PATH );
|
||
|
|
||
|
hr = straPhys.CopyW( pUrlInfo->QueryPhysicalPath()->QueryStr() );
|
||
|
if ( FAILED( hr ) )
|
||
|
{
|
||
|
goto Failure;
|
||
|
}
|
||
|
|
||
|
hr = straUrl.CopyW( strUrl.QueryStr() );
|
||
|
if ( FAILED( hr ) )
|
||
|
{
|
||
|
goto Failure;
|
||
|
}
|
||
|
|
||
|
filterMap.pszURL = straUrl.QueryStr();
|
||
|
filterMap.pszPhysicalPath = straPhys.QueryStr();
|
||
|
filterMap.cbPathBuff = MAX_PATH + 1;
|
||
|
|
||
|
fRet = pW3Context->NotifyFilters( SF_NOTIFY_URL_MAP,
|
||
|
&filterMap,
|
||
|
pfFinished );
|
||
|
|
||
|
//
|
||
|
// If the filter is done, then we're done
|
||
|
//
|
||
|
|
||
|
if ( *pfFinished )
|
||
|
{
|
||
|
hr = NO_ERROR;
|
||
|
goto Failure;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If the physical path was changed, remember it here
|
||
|
//
|
||
|
|
||
|
hr = strPhysicalPath.CopyA( (CHAR*) filterMap.pszPhysicalPath );
|
||
|
if ( FAILED( hr ) )
|
||
|
{
|
||
|
goto Failure;
|
||
|
}
|
||
|
|
||
|
if ( pUrlInfo->QueryPhysicalPath()->QueryCCH() != strPhysicalPath.QueryCCH() ||
|
||
|
wcscmp( pUrlInfo->QueryPhysicalPath()->QueryStr(),
|
||
|
strPhysicalPath.QueryStr() ) != 0 )
|
||
|
{
|
||
|
hr = pUrlContext->SetPhysicalPath( strPhysicalPath );
|
||
|
if ( FAILED( hr ) )
|
||
|
{
|
||
|
goto Failure;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// We don't accept short filename since they can break metabase
|
||
|
// equivalency
|
||
|
//
|
||
|
|
||
|
if ( wcschr( pUrlContext->QueryPhysicalPath()->QueryStr(),
|
||
|
L'~' ) )
|
||
|
{
|
||
|
BOOL fShort = FALSE;
|
||
|
|
||
|
if ( pMetaData->QueryVrAccessToken() != NULL )
|
||
|
{
|
||
|
hToken = pMetaData->QueryVrAccessToken()->QueryImpersonationToken();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hToken = NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD dwError = CheckIfShortFileName(
|
||
|
pUrlContext->QueryPhysicalPath()->QueryStr(),
|
||
|
hToken,
|
||
|
&fShort );
|
||
|
if ( dwError != ERROR_SUCCESS )
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32( dwError );
|
||
|
goto Failure;
|
||
|
}
|
||
|
|
||
|
if ( fShort )
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
|
||
|
goto Failure;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*ppUrlContext = pUrlContext;
|
||
|
return S_OK;
|
||
|
|
||
|
Failure:
|
||
|
if ( pUrlContext != NULL )
|
||
|
{
|
||
|
delete pUrlContext;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( pUrlInfo != NULL )
|
||
|
{
|
||
|
pUrlInfo->DereferenceCacheEntry();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//static
|
||
|
HRESULT
|
||
|
W3_STATE_URLINFO::MapPath(
|
||
|
W3_CONTEXT * pW3Context,
|
||
|
STRU & strUrl,
|
||
|
STRU * pstrPhysicalPath,
|
||
|
DWORD * pcchDirRoot,
|
||
|
DWORD * pcchVRoot,
|
||
|
DWORD * pdwMask
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Send a URL/Physical-Path pair to a filter for processing
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pW3Context - W3_CONTEXT for the request
|
||
|
strUrl - The URL to be mapped
|
||
|
pstrPhysicalPath - Filled with the mapped path upon return. Set with
|
||
|
metadata physical path on entry
|
||
|
pcchDirRoot - Set to point to number of characters in found physical path
|
||
|
pcchVRoot - Set to point to number of characters in found virtual path
|
||
|
pdwMask - Set to point to the access perms mask of virtual path
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
SUCCEEDED()/FAILED()
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
W3_URL_INFO * pUrlInfo = NULL;
|
||
|
W3_METADATA * pMetaData = NULL;
|
||
|
|
||
|
DBG_ASSERT( pstrPhysicalPath );
|
||
|
|
||
|
//
|
||
|
// Get and keep the metadata and urlinfo for this path
|
||
|
//
|
||
|
|
||
|
DBG_ASSERT( g_pW3Server->QueryUrlInfoCache() != NULL );
|
||
|
|
||
|
hr = g_pW3Server->QueryUrlInfoCache()->GetUrlInfo(
|
||
|
pW3Context,
|
||
|
strUrl,
|
||
|
&pUrlInfo );
|
||
|
if ( FAILED( hr ) )
|
||
|
{
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
DBG_ASSERT( pUrlInfo != NULL );
|
||
|
|
||
|
//
|
||
|
// Call the filters
|
||
|
//
|
||
|
|
||
|
hr = FilterMapPath( pW3Context,
|
||
|
pUrlInfo,
|
||
|
pstrPhysicalPath );
|
||
|
if ( FAILED( hr ) )
|
||
|
{
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
pMetaData = pUrlInfo->QueryMetaData();
|
||
|
DBG_ASSERT( pMetaData != NULL );
|
||
|
|
||
|
//
|
||
|
// Return the other goodies
|
||
|
//
|
||
|
|
||
|
if ( pcchDirRoot != NULL )
|
||
|
{
|
||
|
*pcchDirRoot = pMetaData->QueryVrPath()->QueryCCH();
|
||
|
}
|
||
|
|
||
|
if ( pcchVRoot != NULL )
|
||
|
{
|
||
|
if (strUrl.QueryCCH())
|
||
|
{
|
||
|
*pcchVRoot = pMetaData->QueryVrLen();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*pcchVRoot = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( pdwMask != NULL )
|
||
|
{
|
||
|
*pdwMask = pMetaData->QueryAccessPerms();
|
||
|
}
|
||
|
|
||
|
Exit:
|
||
|
|
||
|
if ( pUrlInfo != NULL )
|
||
|
{
|
||
|
pUrlInfo->DereferenceCacheEntry();
|
||
|
pUrlInfo = NULL;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// static
|
||
|
HRESULT
|
||
|
W3_STATE_URLINFO::FilterMapPath(
|
||
|
W3_CONTEXT * pW3Context,
|
||
|
W3_URL_INFO * pUrlInfo,
|
||
|
STRU * pstrPhysicalPath
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Have URL_MAP filters do their thing
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pW3Context - Context
|
||
|
pUrlInfo - Contains virtual/physical path
|
||
|
pstrPhysicalPath - Filled with physical path
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
SUCCEEDED()/FAILED()
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
BOOL fFinished = FALSE;
|
||
|
W3_METADATA * pMetaData = NULL;
|
||
|
STACK_STRU( strFilterPath, MAX_PATH );
|
||
|
STRU * pstrFinalPhysical = NULL;
|
||
|
|
||
|
if ( pW3Context == NULL ||
|
||
|
pUrlInfo == NULL ||
|
||
|
pstrPhysicalPath == NULL )
|
||
|
{
|
||
|
DBG_ASSERT( FALSE );
|
||
|
return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
|
||
|
}
|
||
|
|
||
|
pMetaData = pUrlInfo->QueryMetaData();
|
||
|
DBG_ASSERT( pMetaData != NULL );
|
||
|
|
||
|
//
|
||
|
// We now have the metadata physical path. Let filters change it here
|
||
|
//
|
||
|
|
||
|
if ( pW3Context->IsNotificationNeeded( SF_NOTIFY_URL_MAP ) )
|
||
|
{
|
||
|
STACK_STRA( straPhys, MAX_PATH + 1 );
|
||
|
STACK_STRA( straUrl, MAX_PATH + 1 );
|
||
|
BOOL fRet;
|
||
|
HTTP_FILTER_URL_MAP filterMap;
|
||
|
|
||
|
hr = straPhys.CopyW( pUrlInfo->QueryUrlTranslated()->QueryStr() );
|
||
|
if ( FAILED( hr ) )
|
||
|
{
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
hr = straUrl.CopyW( pUrlInfo->QueryUrl() );
|
||
|
if ( FAILED( hr ) )
|
||
|
{
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
filterMap.pszURL = straUrl.QueryStr();
|
||
|
filterMap.pszPhysicalPath = straPhys.QueryStr();
|
||
|
filterMap.cbPathBuff = MAX_PATH + 1;
|
||
|
|
||
|
fRet = pW3Context->NotifyFilters( SF_NOTIFY_URL_MAP,
|
||
|
&filterMap,
|
||
|
&fFinished );
|
||
|
|
||
|
//
|
||
|
// Ignore finished flag in this case since we really can't do much
|
||
|
// to advance to finish (since an ISAPI is calling this)
|
||
|
//
|
||
|
|
||
|
if ( !fRet )
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32( GetLastError() );
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Remember the mapped path
|
||
|
//
|
||
|
|
||
|
hr = strFilterPath.CopyA( (CHAR*) filterMap.pszPhysicalPath );
|
||
|
if ( FAILED( hr ) )
|
||
|
{
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
pstrFinalPhysical = &strFilterPath;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// No filter is mapping, therefore just take the URL_INFO's physical
|
||
|
// path
|
||
|
//
|
||
|
|
||
|
pstrFinalPhysical = pUrlInfo->QueryUrlTranslated();
|
||
|
|
||
|
DBG_ASSERT( pstrFinalPhysical != NULL );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// We don't accept short filename since they can break metabase
|
||
|
// equivalency
|
||
|
//
|
||
|
|
||
|
if ( wcschr( pstrFinalPhysical->QueryStr(),
|
||
|
L'~' ) )
|
||
|
{
|
||
|
BOOL fShort = FALSE;
|
||
|
DWORD dwError = CheckIfShortFileName(
|
||
|
pstrFinalPhysical->QueryStr(),
|
||
|
pW3Context->QueryImpersonationToken(),
|
||
|
&fShort );
|
||
|
if ( dwError != ERROR_SUCCESS )
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32( dwError );
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
if ( fShort )
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
|
||
|
goto Exit;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Copy the physical path is requested
|
||
|
//
|
||
|
|
||
|
hr = pstrPhysicalPath->Copy( *pstrFinalPhysical );
|
||
|
if ( FAILED( hr ) )
|
||
|
{
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
Exit:
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
CheckIfShortFileName(
|
||
|
IN WCHAR * pszPath,
|
||
|
IN HANDLE hImpersonation,
|
||
|
OUT BOOL * pfShort
|
||
|
)
|
||
|
/*++
|
||
|
Description:
|
||
|
|
||
|
This function takes a suspected NT/Win95 short filename and checks if there's
|
||
|
an equivalent long filename. For example, c:\foobar\ABCDEF~1.ABC is the same
|
||
|
as c:\foobar\abcdefghijklmnop.abc.
|
||
|
|
||
|
NOTE: This function should be called unimpersonated - the FindFirstFile() must
|
||
|
be called in the system context since most systems have traverse checking turned
|
||
|
off - except for the UNC case where we must be impersonated to get network access.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pszPath - Path to check
|
||
|
hImpersonation - Impersonation handle if this is a UNC path - can be NULL if not UNC
|
||
|
pfShort - Set to TRUE if an equivalent long filename is found
|
||
|
|
||
|
Returns:
|
||
|
|
||
|
Win32 error on failure
|
||
|
--*/
|
||
|
{
|
||
|
DWORD err = NO_ERROR;
|
||
|
WIN32_FIND_DATA FindData;
|
||
|
WCHAR * psz;
|
||
|
BOOL fUNC;
|
||
|
|
||
|
psz = wcschr( pszPath, L'~' );
|
||
|
*pfShort = FALSE;
|
||
|
fUNC = (*pszPath == L'\\');
|
||
|
|
||
|
//
|
||
|
// Loop for multiple tildas - watch for a # after the tilda
|
||
|
//
|
||
|
|
||
|
while ( psz++ )
|
||
|
{
|
||
|
if ( *psz >= L'0' && *psz <= L'9' )
|
||
|
{
|
||
|
WCHAR achTmp[MAX_PATH];
|
||
|
WCHAR * pchEndSeg;
|
||
|
WCHAR * pchBeginSeg;
|
||
|
HANDLE hFind;
|
||
|
|
||
|
//
|
||
|
// Isolate the path up to the segment with the
|
||
|
// '~' and do the FindFirst with that path
|
||
|
//
|
||
|
|
||
|
pchEndSeg = wcschr( psz, L'\\' );
|
||
|
if ( !pchEndSeg )
|
||
|
{
|
||
|
pchEndSeg = psz + wcslen( psz );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If the string is beyond MAX_PATH then we allow it through
|
||
|
//
|
||
|
|
||
|
if ( ((INT) (pchEndSeg - pszPath)) >= MAX_PATH )
|
||
|
{
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
memcpy( achTmp,
|
||
|
pszPath,
|
||
|
(INT) (pchEndSeg - pszPath) * sizeof( WCHAR ) );
|
||
|
achTmp[pchEndSeg - pszPath] = L'\0';
|
||
|
|
||
|
if ( fUNC && hImpersonation )
|
||
|
{
|
||
|
if ( !SetThreadToken( NULL, hImpersonation ))
|
||
|
{
|
||
|
return GetLastError();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
hFind = FindFirstFileW( achTmp, &FindData );
|
||
|
|
||
|
if ( fUNC && hImpersonation )
|
||
|
{
|
||
|
RevertToSelf();
|
||
|
}
|
||
|
|
||
|
if ( hFind == INVALID_HANDLE_VALUE )
|
||
|
{
|
||
|
err = GetLastError();
|
||
|
|
||
|
DBGPRINTF(( DBG_CONTEXT,
|
||
|
"FindFirst failed!! - \"%s\", error %d\n",
|
||
|
achTmp,
|
||
|
GetLastError() ));
|
||
|
|
||
|
//
|
||
|
// If the FindFirstFile() fails to find the file then return
|
||
|
// success - the path doesn't appear to be a valid path which
|
||
|
// is ok.
|
||
|
//
|
||
|
|
||
|
if ( err == ERROR_FILE_NOT_FOUND ||
|
||
|
err == ERROR_PATH_NOT_FOUND )
|
||
|
{
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
DBG_REQUIRE( FindClose( hFind ));
|
||
|
|
||
|
//
|
||
|
// Isolate the last segment of the string which should be
|
||
|
// the potential short name equivalency
|
||
|
//
|
||
|
|
||
|
pchBeginSeg = wcsrchr( achTmp, L'\\' );
|
||
|
DBG_ASSERT( pchBeginSeg );
|
||
|
pchBeginSeg++;
|
||
|
|
||
|
//
|
||
|
// If the last segment doesn't match the long name then this is
|
||
|
// the short name version of the path
|
||
|
//
|
||
|
|
||
|
if ( _wcsicmp( FindData.cFileName, pchBeginSeg ))
|
||
|
{
|
||
|
*pfShort = TRUE;
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
psz = wcschr( psz, L'~' );
|
||
|
}
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
HRESULT
|
||
|
URL_CONTEXT::OpenFile(
|
||
|
FILE_CACHE_USER * pFileUser,
|
||
|
W3_FILE_INFO ** ppOpenFile
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Open the physical path for this request. If a map path filter did some
|
||
|
redirecting, we will use that path. Otherwise we will just use the
|
||
|
path determined by metadata and cached in the W3_URL_INFO
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pFileUser - User to open file as
|
||
|
ppOpenFile - Set to file cache entry on success
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
HRESULT
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
BOOL fDoCache;
|
||
|
|
||
|
DBG_ASSERT( QueryMetaData() != NULL );
|
||
|
|
||
|
fDoCache = !QueryMetaData()->QueryNoCache();
|
||
|
|
||
|
//
|
||
|
// If an ISAPI filter changed the physical path, then we need to go
|
||
|
// directly to the file cache. Otherwise, we can go thru the
|
||
|
// W3_URL_INFO which may already have the cached file associated
|
||
|
//
|
||
|
|
||
|
if ( _strPhysicalPath.IsEmpty() )
|
||
|
{
|
||
|
//
|
||
|
// No filter. Fast path :-)
|
||
|
//
|
||
|
|
||
|
DBG_ASSERT( _pUrlInfo != NULL );
|
||
|
|
||
|
hr = _pUrlInfo->GetFileInfo( pFileUser,
|
||
|
fDoCache,
|
||
|
ppOpenFile );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Filter case. Must lookup in file cache :-(
|
||
|
//
|
||
|
|
||
|
DBG_ASSERT( g_pW3Server->QueryFileCache() != NULL );
|
||
|
|
||
|
hr = g_pW3Server->QueryFileCache()->GetFileInfo(
|
||
|
_strPhysicalPath,
|
||
|
QueryMetaData()->QueryDirmonConfig(),
|
||
|
pFileUser,
|
||
|
fDoCache,
|
||
|
ppOpenFile );
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//static
|
||
|
HRESULT
|
||
|
URL_CONTEXT::Initialize(
|
||
|
VOID
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Initialize URL_CONTEXT lookaside
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
None
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
HRESULT
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
ALLOC_CACHE_CONFIGURATION acConfig;
|
||
|
HRESULT hr = NO_ERROR;
|
||
|
|
||
|
//
|
||
|
// Setup allocation lookaside
|
||
|
//
|
||
|
|
||
|
acConfig.nConcurrency = 1;
|
||
|
acConfig.nThreshold = 100;
|
||
|
acConfig.cbSize = sizeof( URL_CONTEXT );
|
||
|
|
||
|
DBG_ASSERT( sm_pachUrlContexts == NULL );
|
||
|
|
||
|
sm_pachUrlContexts = new ALLOC_CACHE_HANDLER( "URL_CONTEXT",
|
||
|
&acConfig );
|
||
|
|
||
|
if ( sm_pachUrlContexts == NULL )
|
||
|
{
|
||
|
return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
|
||
|
}
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
//static
|
||
|
VOID
|
||
|
URL_CONTEXT::Terminate(
|
||
|
VOID
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Clean up URL_CONTEXT lookaside
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
None
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
HRESULT
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
if ( sm_pachUrlContexts != NULL )
|
||
|
{
|
||
|
delete sm_pachUrlContexts;
|
||
|
sm_pachUrlContexts = NULL;
|
||
|
}
|
||
|
}
|
||
|
|