|
|
#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;
//
// Do we need to check if Anonymous auth type is supported when
// we call ANONYMOUS_AUTH_PROVIDER::DoAuthenticate
//
BOOL _fCheckAnonAuthTypeSupported;
//
// 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; //
// Inline filter context used for almost all cases (except
// when we need to persist filter context beyond
// main context lifetime)
//
W3_FILTER_CONTEXT _FilterContext;
//
// 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;
//
// 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;
//
// Keep track of the entity that we've read so far so that
// we can enforce MaxRequestEntityAllowed.
//
DWORD _cbEntityReadSoFar;
//
// 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;
//
// List of *-ScriptMaps which do not want to be notified at all anymore
// about this particular chain of request
//
MULTISZ _mszIgnoredInterceptors;
//
// Call information about last posted completion
//
CHAR * _pszLastPostFileName; DWORD _dwLastPostLineNumber;
//
// Handle for TIMER callback when a W3_MAIN_CONTEXT has existed for too long
//
HANDLE _hTimer;
//
// Per request trace log
//
W3_TRACE_LOG * _pTraceLog;
//
// Can we ignore the apppool check (done when WAS routes us to an
// AppPool we aren't configured by URL-wise
//
BOOL _fIgnoreAppPoolCheck;
//
// static TraceLogFactory
//
static W3_TRACE_LOG_FACTORY * sm_pLogFactory; //
// static File to trace to
//
static HANDLE sm_hTraceFile; static HRESULT SetupTraceLogging( VOID ); static VOID CleanupTraceLogging( VOID ); //
// 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 );
W3_MAIN_CONTEXT(const W3_MAIN_CONTEXT &); void operator=(const W3_MAIN_CONTEXT &);
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;
W3_MAIN_CONTEXT( HTTP_REQUEST * pUlHttpRequest, ULATQ_CONTEXT pUlAtqContext ); ~W3_MAIN_CONTEXT();
VOID * operator new( size_t uiSize, VOID * pPlacement ); VOID operator delete( VOID * pMainContext ); VOID * AllocateFromInlineMemory( DWORD cbSize );
//
// 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(); } 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 QueryCheckAnonAuthTypeSupported( VOID ) { return _fCheckAnonAuthTypeSupported; }
VOID SetCheckAnonAuthTypeSupported( BOOL fCheckAnonAuthTypeSupported ) { _fCheckAnonAuthTypeSupported = fCheckAnonAuthTypeSupported; } BOOL QueryShouldGenerateContentLength( VOID ) const { return _fGenerateContentLength; }
VOID SetShouldGenerateContentLength( BOOL fShouldGenerate ) { _fGenerateContentLength = fShouldGenerate; }
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 UpdateSkipped( HTTP_DATA_CHUNK * pChunks, DWORD cChunks );
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 ); 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 ) { ULATQ_CONTEXT ulatqContext; if ( !InterlockedDecrement( &_cRefs ) ) { //
// Remember the ULATQ context. Once we've deleted the object
// we will free the context
//
ulatqContext = _ulatqContext; delete this; UlAtqFreeContext( ulatqContext ); } } BOOL QueryIgnoreAppPoolCheck( VOID ) const { return _fIgnoreAppPoolCheck; } VOID SetIgnoreAppPoolCheck( VOID ) { _fIgnoreAppPoolCheck = TRUE; } RAW_CONNECTION * QueryRawConnection( VOID ) const { return _pRawConnection; } VOID SetRawConnection( RAW_CONNECTION * pRawConnection );
VOID SetRawConnectionClientContext( DWORD dwCurrentFilter, VOID * pvContext );
BOOL QueryRawConnectionNotificationChanged( VOID );
BOOL IsRawConnectionDisableNotificationNeeded( DWORD dwFilter, DWORD dwNotification ); 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; }
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 );
HRESULT AppendIgnoreInterceptor(STRU &strName) { if (!_mszIgnoredInterceptors.Append(strName)) { return HRESULT_FROM_WIN32(GetLastError()); }
return S_OK; }
BOOL IsIgnoredInterceptor(STRU &strName) { return _mszIgnoredInterceptors.FindString(strName); }
VOID SetDoneWithCompression() { _fDoneWithCompression = TRUE; }
BOOL QueryDoneWithCompression() { return _fDoneWithCompression; }
VOID SetCompressionContext(IN COMPRESSION_CONTEXT *pCompressionContext) { DBG_ASSERT(_pCompressionContext == NULL); _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; _cbEntityReadSoFar += dwRecvd; }
VOID IncrementBytesSent(DWORD dwSent) { _LogContext.m_dwBytesSent += dwSent; }
VOID SetInitialEntityReadSize(DWORD dwBytes) { _cbEntityReadSoFar = dwBytes; }
DWORD QueryEntityReadSoFar() { return _cbEntityReadSoFar; }
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 );
DWORD QueryCurrentStarScriptMapIndex( VOID ) { return 0; }
static HRESULT SetupStateMachine( VOID );
static VOID CleanupStateMachine( VOID );
static HRESULT Initialize( VOID );
static VOID Terminate( 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 ); static VOID PostMainCompletion( CHAR * pszFileName, DWORD dwLineNumber, W3_MAIN_CONTEXT * pMainContext );
W3_TRACE_LOG* QueryTraceLog( VOID ) { return _pTraceLog; } };
#define POST_MAIN_COMPLETION(x) \
W3_MAIN_CONTEXT::PostMainCompletion( __FILE__, __LINE__, (x) )
#endif
|