917 lines
16 KiB
C++
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
|