windows-nt/Source/XPSP1/NT/inetsrv/iis/iisrearc/iisplus/ulw3/maincontext.hxx
2020-09-26 16:20:57 +08:00

917 lines
16 KiB
C++

#ifndef _MAINCONTEXT_HXX_
#define _MAINCONTEXT_HXX_
class W3_CONNECTION;
class RAW_CONNECTION;
class W3_MAIN_CONTEXT;
//
// Different states
//
enum CONTEXT_STATE
{
CONTEXT_STATE_START,
CONTEXT_STATE_URLINFO,
CONTEXT_STATE_AUTHENTICATION,
CONTEXT_STATE_AUTHORIZATION,
CONTEXT_STATE_HANDLE_REQUEST,
CONTEXT_STATE_RESPONSE,
CONTEXT_STATE_LOG,
CONTEXT_STATE_DONE,
//
// This should be the last value
//
STATE_COUNT
};
//
// W3_CONNECTION_STATE - Abstract class representing state associated with
// connection (W3_CONNECTION)
//
class W3_CONNECTION_STATE
{
public:
virtual BOOL
Cleanup(
VOID
) = 0;
};
//
// W3_CONTEXT_STATE - Abstract class representing context information for a
// given state, stored for a given W3_MAIN_CONTEXT
// At the end of the state machine, objects implementing
// this class will be cleaned up (using Cleanup()).
//
class W3_MAIN_CONTEXT_STATE
{
public:
virtual
~W3_MAIN_CONTEXT_STATE()
{
}
virtual BOOL
Cleanup(
W3_MAIN_CONTEXT * pContext
) = 0;
VOID *
operator new(
size_t uiSize,
VOID * pPlacement
);
VOID
operator delete(
VOID * pContext
);
};
//
// W3_MAIN_CONTEXT
//
// This class represents the mainline (non-child) context representing the
// the execution of a single HTTP request. This class contains and manages
// the HTTP state machine
//
class W3_MAIN_CONTEXT : public W3_CONTEXT
{
private:
//
// Reference count used to manage fact that this context can be attached
// to a RAW_CONNECTION
//
LONG _cRefs;
//
// Request information
//
W3_REQUEST _request;
//
// Response object (not necessarily used in sending a response)
//
W3_RESPONSE _response;
//
// The associated connection for this given request
//
W3_CONNECTION * _pConnection;
BOOL _fAssociationChecked;
//
// The associated Site for this request
//
W3_SITE * _pSite;
//
// Metadata for request
//
URL_CONTEXT * _pUrlContext;
//
// User for the context. For now, the user cannot be reset for a child
// context and is therefore stored only in the main context. That could
// change later if we allow child requests to take on different
// user identity
//
W3_USER_CONTEXT * _pUserContext;
//
// Did an authentication provider already handle sending
// access denied headers?
//
BOOL _fProviderHandled;
//
// Certificate context representing client certificate if negotiated
//
CERTIFICATE_CONTEXT * _pCertificateContext;
//
// ULATQ context used to communicate with UL
//
ULATQ_CONTEXT _ulatqContext;
//
// Filter state
//
W3_FILTER_CONTEXT * _pFilterContext;
//
// State machine
//
DWORD _currentState;
DWORD _nextState;
//
// State context objects
//
W3_MAIN_CONTEXT_STATE * _rgStateContexts[ STATE_COUNT ];
//
// Should we disconnect at the end of this request?
//
BOOL _fDisconnect;
//
// Are we done with compression for this request?
//
BOOL _fDoneWithCompression;
//
// The COMPRESSION_CONTEXT for the current request
//
COMPRESSION_CONTEXT *_pCompressionContext;
//
// Logging data to be passed on to UL
//
LOG_CONTEXT _LogContext;
//
// Buffer for allocating stuff with lifetime of the request
//
CHUNK_BUFFER _HeaderBuffer;
//
// Do we need to send a final done?
//
BOOL _fNeedFinalDone;
//
// The current context to receive IO completions
//
W3_CONTEXT * _pCurrentContext;
//
// Is this response cacheble in UL?
//
BOOL _fIsUlCacheable;
//
// Access check (put here only since a child request cannot/should not
// change the remote address)
//
ADDRESS_CHECK _IpAddressCheck;
//
// Keep track of available entity body to be read thru UL.
//
DWORD _cbRemainingEntityFromUL;
//
// For HEAD requests, UL will not send a content-length so we'll have
// to do for HEAD requests. The reason we keep this state
// is because filters/child-requests can reset the verb -> a resetting
// which still doesn't change the fact that UL will not be setting
// Content-Length
//
BOOL _fGenerateContentLength;
//
// Raw connection. Needed since we need to tell the raw connection when
// it should no longer reference us
//
RAW_CONNECTION * _pRawConnection;
//
// Handle for TIMER callback when a W3_MAIN_CONTEXT has existed for too long
//
HANDLE _hTimer;
//
// timeout in milliseconds before DebugBreak() is called
// read from registry at static Initialization
//
static DWORD sm_dwTimeout;
//
// Callback function that does the DebugBreak for overtime W3_MAIN_CONTEXT
//
static VOID TimerCallback(PVOID pvParam, BOOLEAN fReason);
//
// Inline buffer to allocate context structures from
//
DWORD _cbInlineOffset;
BYTE _rgBuffer[ 0 ];
public:
//
// Lookaside for main contexts
//
static ALLOC_CACHE_HANDLER * sm_pachMainContexts;
//
// The states
//
static W3_STATE * sm_pStates[ STATE_COUNT ];
static SHORT sm_rgInline[ STATE_COUNT ];
static USHORT sm_cbInlineBytes;
//
// Outstanding thread count. How many threads are still doing
// W3CORE.DLL stuff
//
static LONG sm_cOutstandingThreads;
W3_MAIN_CONTEXT(
HTTP_REQUEST * pUlHttpRequest,
ULATQ_CONTEXT pUlAtqContext
);
~W3_MAIN_CONTEXT();
VOID *
operator new(
size_t size
)
{
DBG_ASSERT( size == sizeof( W3_MAIN_CONTEXT ) );
DBG_ASSERT( sm_pachMainContexts != NULL );
return sm_pachMainContexts->Alloc();
}
VOID
operator delete(
VOID * pMainContext
)
{
DBG_ASSERT( pMainContext != NULL );
DBG_ASSERT( sm_pachMainContexts != NULL );
DBG_REQUIRE( sm_pachMainContexts->Free( pMainContext ) );
}
//
// Overridden W3_CONTEXT methods
//
ULATQ_CONTEXT
QueryUlatqContext(
VOID
)
{
return _ulatqContext;
}
W3_REQUEST *
QueryRequest(
VOID
)
{
return &_request;
}
W3_RESPONSE *
QueryResponse(
VOID
)
{
return &_response;
}
BOOL
QueryResponseSent(
VOID
)
{
return _response.QueryResponseSent();
}
CHUNK_BUFFER *
QueryHeaderBuffer(
VOID
)
{
return &_HeaderBuffer;
}
BOOL
QueryIsUlCacheable(
VOID
)
{
return _fIsUlCacheable;
}
VOID
DisableUlCache(
VOID
)
{
_fIsUlCacheable = FALSE;
}
BOOL
QueryProviderHandled(
VOID
)
{
return _fProviderHandled;
}
BOOL
QueryNeedFinalDone(
VOID
)
{
return _fNeedFinalDone;
}
VOID
SetNeedFinalDone(
VOID
)
{
_fNeedFinalDone = TRUE;
}
BOOL
QueryShouldGenerateContentLength(
VOID
) const
{
return _fGenerateContentLength;
}
W3_USER_CONTEXT *
QueryUserContext(
VOID
)
{
return _pUserContext;
}
W3_USER_CONTEXT *
QueryConnectionUserContext(
VOID
);
VOID
SetConnectionUserContext(
W3_USER_CONTEXT * pUserContext
);
VOID
SetUserContext(
W3_USER_CONTEXT * pUserContext
)
{
// perf ctr
if (pUserContext->QueryAuthType() == MD_AUTH_ANONYMOUS)
{
_pSite->IncAnonUsers();
}
else
{
_pSite->IncNonAnonUsers();
}
_pUserContext = pUserContext;
}
CERTIFICATE_CONTEXT *
QueryCertificateContext(
VOID
) const
{
return _pCertificateContext;
}
VOID
DetermineRemainingEntity(
VOID
);
VOID
SetCertificateContext(
CERTIFICATE_CONTEXT * pCertificateContext
)
{
_pCertificateContext = pCertificateContext;
}
W3_FILTER_CONTEXT *
QueryFilterContext(
BOOL fCreateIfNotFound = TRUE
);
URL_CONTEXT *
QueryUrlContext(
VOID
)
{
return _pUrlContext;
}
W3_SITE *
QuerySite(
VOID
)
{
return _pSite;
}
W3_CONTEXT *
QueryCurrentContext(
VOID
)
{
return _pCurrentContext;
}
VOID
PopCurrentContext(
VOID
)
{
_pCurrentContext = _pCurrentContext->QueryParentContext();
if ( _pCurrentContext == NULL )
{
_pCurrentContext = this;
}
}
VOID
PushCurrentContext(
W3_CONTEXT * pW3Context
)
{
_pCurrentContext = pW3Context;
}
W3_CONTEXT *
QueryParentContext(
VOID
)
{
return NULL;
}
W3_MAIN_CONTEXT *
QueryMainContext(
VOID
)
{
return this;
}
BOOL
QueryDisconnect(
VOID
)
{
return _fDisconnect;
}
VOID
SetDisconnect(
BOOL fDisconnect
)
{
_fDisconnect = fDisconnect;
}
VOID
SetDeniedFlags(
DWORD dwDeniedFlags
)
{
if( _pFilterContext )
{
_pFilterContext->SetDeniedFlags( dwDeniedFlags );
}
}
BOOL
NotifyFilters(
DWORD dwNotification,
VOID * pvFilterInfo,
BOOL * pfFinished
);
BOOL
IsNotificationNeeded(
DWORD dwNotification
);
//
// W3_MAIN_CONTEXT specific methods. These methods are not callable
// when we are in the state of invoking a handler
//
VOID
ReferenceMainContext(
VOID
)
{
InterlockedIncrement( &_cRefs );
}
VOID
DereferenceMainContext(
VOID
)
{
if ( !InterlockedDecrement( &_cRefs ) )
{
delete this;
}
}
VOID
SetRawConnection(
RAW_CONNECTION * pRawConnection
);
BOOL
QueryExpiry(
LARGE_INTEGER * pExpiry
);
HRESULT
ExecuteExpiredUrl(
STRU & strExpUrl
);
HRESULT
PasswdExpireNotify(
VOID
);
HRESULT
PasswdChangeExecute(
VOID
);
HRESULT
ReceiveEntityBody(
BOOL fAsync,
VOID * pBuffer,
DWORD cbBuffer,
DWORD * pBytesReceived
);
DWORD
QueryRemainingEntityFromUl(
VOID
) const
{
return _cbRemainingEntityFromUL;
}
VOID
SetRemainingEntityFromUl(
DWORD cbRemaining
)
{
_cbRemainingEntityFromUL = cbRemaining;
}
HRESULT
GetRemoteDNSName(
STRA * pstrDNSName
);
ADDRESS_CHECK *
QueryAddressCheck(
VOID
)
{
return &_IpAddressCheck;
}
VOID
SetProviderHandled(
BOOL fProviderHandled
)
{
_fProviderHandled = fProviderHandled;
}
HRESULT
OnAccessDenied(
VOID
)
{
return NO_ERROR;
}
VOID
SetUrlContext(
URL_CONTEXT * pUrlContext
)
{
_pUrlContext = pUrlContext;
}
VOID
AssociateSite(
W3_SITE * site
)
{
_pSite = site;
}
VOID *
ContextAlloc(
UINT cbSize
);
BYTE *
QueryInlineBuffer(
VOID
)
{
return _rgBuffer;
}
W3_CONNECTION *
QueryConnection(
BOOL fCreateIfNotFound = TRUE
);
//
// Retrieve context for specified/current state
//
W3_MAIN_CONTEXT_STATE *
QueryContextState(
DWORD contextState = -1
)
{
if ( contextState == -1 )
{
contextState = _currentState;
}
return _rgStateContexts[ contextState ];
}
//
// Set context for current state
//
VOID
SetContextState(
W3_MAIN_CONTEXT_STATE * pStateContext
)
{
_rgStateContexts[ _currentState ] = pStateContext;
}
W3_CONNECTION_STATE *
QueryConnectionState(
VOID
);
VOID
SetConnectionState(
W3_CONNECTION_STATE * pConnectionState
);
VOID SetDoneWithCompression()
{
_fDoneWithCompression = TRUE;
}
BOOL QueryDoneWithCompression()
{
return _fDoneWithCompression;
}
VOID SetCompressionContext(IN COMPRESSION_CONTEXT *pCompressionContext)
{
_pCompressionContext = pCompressionContext;
}
COMPRESSION_CONTEXT *QueryCompressionContext()
{
return _pCompressionContext;
}
HTTP_LOG_FIELDS_DATA *QueryUlLogData()
{
return _LogContext.QueryUlLogData();
}
LOG_CONTEXT *QueryLogContext()
{
return &_LogContext;
}
HRESULT CollectLoggingData(BOOL fCollectForULLogging);
void SetLastIOPending(LAST_IO_PENDING ioPending)
{
_LogContext.m_ioPending = ioPending;
}
LAST_IO_PENDING QueryLastIOPending()
{
return _LogContext.m_ioPending;
}
VOID IncrementBytesRecvd(DWORD dwRecvd)
{
_LogContext.m_dwBytesRecvd += dwRecvd;
}
VOID IncrementBytesSent(DWORD dwSent)
{
_LogContext.m_dwBytesSent += dwSent;
}
VOID
DoWork(
DWORD cbCompletion,
DWORD dwCompletionStatus,
BOOL fIoCompletion
);
BOOL
SetupContext(
HTTP_REQUEST * pUlHttpRequest,
ULATQ_CONTEXT pUlAtqContext
);
VOID
CleanupContext(
VOID
);
VOID
SetFinishedResponse(
VOID
)
{
_nextState = CONTEXT_STATE_RESPONSE;
}
VOID
SetDone(
VOID
)
{
_nextState = CONTEXT_STATE_LOG;
}
VOID
BackupStateMachine(
VOID
);
HRESULT
SetupCertificateContext(
HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo
);
static
HRESULT
SetupStateMachine(
VOID
);
static
VOID
CleanupStateMachine(
VOID
);
static
HRESULT
Initialize(
VOID
);
static
VOID
Terminate(
VOID
);
static
VOID
WaitForThreadDrain(
VOID
);
static
VOID
AddressResolutionCallback(
ADDRCHECKARG pContext,
BOOL fUnused,
LPSTR pszUnused
);
//
// Completion routines called from ULATQ
//
static
VOID
OnIoCompletion(
PVOID pvContext,
DWORD cbWritten,
DWORD dwCompletionStatus,
OVERLAPPED * lpo
);
static
VOID
OnNewRequest(
ULATQ_CONTEXT pContext
);
static
VOID
OnPostedCompletion(
DWORD dwCompletionStatus,
DWORD cbWritten,
LPOVERLAPPED lpo
);
};
#endif