|
|
#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
|