|
|
#ifndef W3RESPONSE_HXX_INCLUDED
#define W3RESPONSE_HXX_INCLUDED
//
// HTTP status codes
//
#define REASON(x) (x),sizeof(x)-sizeof(CHAR)
struct HTTP_STATUS { USHORT statusCode; PCHAR pszReason; USHORT cbReason; };
extern HTTP_STATUS HttpStatusOk; extern HTTP_STATUS HttpStatusPartialContent; extern HTTP_STATUS HttpStatusMultiStatus; extern HTTP_STATUS HttpStatusMovedPermanently; extern HTTP_STATUS HttpStatusRedirect; extern HTTP_STATUS HttpStatusMovedTemporarily; extern HTTP_STATUS HttpStatusNotModified; extern HTTP_STATUS HttpStatusBadRequest; extern HTTP_STATUS HttpStatusUnauthorized; extern HTTP_STATUS HttpStatusForbidden; extern HTTP_STATUS HttpStatusNotFound; extern HTTP_STATUS HttpStatusMethodNotAllowed; extern HTTP_STATUS HttpStatusNotAcceptable; extern HTTP_STATUS HttpStatusProxyAuthRequired; extern HTTP_STATUS HttpStatusPreconditionFailed; extern HTTP_STATUS HttpStatusEntityTooLarge; extern HTTP_STATUS HttpStatusUrlTooLong; extern HTTP_STATUS HttpStatusRangeNotSatisfiable; extern HTTP_STATUS HttpStatusExpectationFailed; extern HTTP_STATUS HttpStatusLockedError; extern HTTP_STATUS HttpStatusServerError; extern HTTP_STATUS HttpStatusNotImplemented; extern HTTP_STATUS HttpStatusBadGateway; extern HTTP_STATUS HttpStatusServiceUnavailable; extern HTTP_STATUS HttpStatusGatewayTimeout;
//
// HTTP Sub Errors
//
struct HTTP_SUB_ERROR { USHORT mdSubError; DWORD dwStringId; };
extern HTTP_SUB_ERROR HttpNoSubError; extern HTTP_SUB_ERROR Http401BadLogon; extern HTTP_SUB_ERROR Http401Config; extern HTTP_SUB_ERROR Http401Resource; extern HTTP_SUB_ERROR Http401Filter; extern HTTP_SUB_ERROR Http401Application; extern HTTP_SUB_ERROR Http403ExecAccessDenied; extern HTTP_SUB_ERROR Http403ReadAccessDenied; extern HTTP_SUB_ERROR Http403WriteAccessDenied; extern HTTP_SUB_ERROR Http403SSLRequired; extern HTTP_SUB_ERROR Http403SSL128Required; extern HTTP_SUB_ERROR Http403IPAddressReject; extern HTTP_SUB_ERROR Http403CertRequired; extern HTTP_SUB_ERROR Http403SiteAccessDenied; extern HTTP_SUB_ERROR Http403TooManyUsers; extern HTTP_SUB_ERROR Http403InvalidateConfig; extern HTTP_SUB_ERROR Http403PasswordChange; extern HTTP_SUB_ERROR Http403MapperDenyAccess; extern HTTP_SUB_ERROR Http403CertRevoked; extern HTTP_SUB_ERROR Http403DirBrowsingDenied; extern HTTP_SUB_ERROR Http403CertInvalid; extern HTTP_SUB_ERROR Http403CertTimeInvalid; extern HTTP_SUB_ERROR Http403AppPoolDenied; extern HTTP_SUB_ERROR Http403InsufficientPrivilegeForCgi; extern HTTP_SUB_ERROR Http403PassportLoginFailure; extern HTTP_SUB_ERROR Http404SiteNotFound; extern HTTP_SUB_ERROR Http404DeniedByPolicy; extern HTTP_SUB_ERROR Http404DeniedByMimeMap; extern HTTP_SUB_ERROR Http500UNCAccess; extern HTTP_SUB_ERROR Http500BadMetadata; extern HTTP_SUB_ERROR Http502Timeout; extern HTTP_SUB_ERROR Http502PrematureExit;
#define W3_RESPONSE_INLINE_HEADERS 10
#define W3_RESPONSE_INLINE_CHUNKS 5
#define W3_RESPONSE_SIGNATURE ((DWORD) 'PR3W')
#define W3_RESPONSE_SIGNATURE_FREE ((DWORD) 'pr3w')
#define W3_RESPONSE_ASYNC 0x01
#define W3_RESPONSE_MORE_DATA 0x02
#define W3_RESPONSE_DISCONNECT 0x04
#define W3_RESPONSE_SUPPRESS_ENTITY 0x10
#define W3_RESPONSE_SUPPRESS_HEADERS 0x20
enum W3_RESPONSE_MODE { RESPONSE_MODE_PARSED, RESPONSE_MODE_RAW };
class W3_RESPONSE { private:
DWORD _dwSignature; HTTP_RESPONSE _ulHttpResponse; HTTP_SUB_ERROR _subError; //
// Buffer to store any strings for header values/names which are
// referenced in the _ulHttpResponse
//
CHUNK_BUFFER _HeaderBuffer; HTTP_UNKNOWN_HEADER _rgUnknownHeaders[ W3_RESPONSE_INLINE_HEADERS ]; BUFFER _bufUnknownHeaders;
//
// Buffer to store chunk data structures referenced in calls
// to UlSendHttpResponse or UlSendEntityBody
//
HTTP_DATA_CHUNK _rgChunks[ W3_RESPONSE_INLINE_CHUNKS ]; BUFFER _bufChunks; USHORT _cChunks; ULONGLONG _cbContentLength;
//
// Has this response been touched at all?
//
BOOL _fResponseTouched;
//
// Has a response been sent
//
BOOL _fResponseSent;
//
// Some buffers used when in raw mode
//
STRA _strRawCoreHeaders; CHAR _achRawCoreHeaders[ 200 ];
//
// Are we in raw mode or parsed mode?
//
W3_RESPONSE_MODE _responseMode;
//
// Does an ISAPI expect to complete headers with WriteClient()
//
BOOL _fIncompleteHeaders; //
// Which chunk is the first of actual entity
//
USHORT _cFirstEntityChunk;
//
// Manage where we are as it relates to chunks to be filtered
//
USHORT _cCurrentChunk; ULONGLONG _cbCurrentOffset; BUFFER _bufRawChunk; DWORD _dwSendFlags; BOOL _fHandleCompletion; DWORD _cbTotalCompletion;
static DWORD sm_dwSendRawDataBufferSize;
HRESULT BuildRawCoreHeaders( VOID ); HRESULT SwitchToRawMode( CHAR * pszAdditionalHeaders, DWORD cchAdditionalHeaders ); HRESULT ParseHeadersFromStream( CHAR * pszStream );
HRESULT InsertDataChunk( HTTP_DATA_CHUNK * pNewChunk, LONG cPosition ); HTTP_DATA_CHUNK * QueryChunks( VOID ) { return (HTTP_DATA_CHUNK*) _bufChunks.QueryPtr(); }
VOID Reset( VOID ); public: W3_RESPONSE() : _bufUnknownHeaders( (BYTE*) _rgUnknownHeaders, sizeof( _rgUnknownHeaders ) ), _bufChunks( (BYTE*) _rgChunks, sizeof( _rgChunks ) ), _strRawCoreHeaders( _achRawCoreHeaders, sizeof( _achRawCoreHeaders ) ) { Reset(); _dwSignature = W3_RESPONSE_SIGNATURE; }
~W3_RESPONSE() { _dwSignature = W3_RESPONSE_SIGNATURE_FREE; }
static HRESULT Initialize( VOID );
static VOID Terminate( VOID );
BOOL CheckSignature( VOID ) const { return _dwSignature == W3_RESPONSE_SIGNATURE; }
//
// Core header adding/deleting functions
//
HRESULT SwitchToParsedMode( VOID ); HRESULT DeleteHeader( CHAR * pszHeaderName );
HRESULT SetHeader( DWORD headerIndex, CHAR * pszHeaderValue, USHORT cchHeaderValue, BOOL fAppend = FALSE );
HRESULT SetHeaderByReference( DWORD headerIndex, CHAR * pszHeaderValue, USHORT cchHeaderValue, BOOL fForceParsedMode = FALSE );
HRESULT SetHeader( CHAR * pszHeaderName, USHORT cchHeaderName, CHAR * pszHeaderValue, USHORT cchHeaderValue, BOOL fAppend = FALSE, BOOL fForceParsedMode = FALSE, BOOL fAlwaysAddUnknown = FALSE, BOOL fAppendAsDupHeader = FALSE );
//
// Some friendly SetHeader helpers
//
const CHAR * GetHeader( DWORD headerIndex ) { HRESULT hr; if ( _responseMode == RESPONSE_MODE_RAW ) { hr = SwitchToParsedMode(); if ( FAILED( hr ) ) { return NULL; } } DBG_ASSERT( _responseMode == RESPONSE_MODE_PARSED ); DBG_ASSERT(headerIndex < HttpHeaderResponseMaximum); return _ulHttpResponse.Headers.KnownHeaders[headerIndex].pRawValue; }
HRESULT GetHeader( CHAR * pszHeaderName, STRA * pstrHeaderValue );
VOID ClearHeaders( VOID );
//
// Chunk management
//
HRESULT AddFileHandleChunk( HANDLE hFile, ULONGLONG cbOffset, ULONGLONG cbLength );
HRESULT AddMemoryChunkByReference( PVOID pvBuffer, DWORD cbBuffer );
HRESULT AddFragmentChunk( WCHAR * pszFragmentName, USHORT dwNameLength );
HRESULT Clear( BOOL fClearEntityOnly = FALSE );
HRESULT GenerateAutomaticHeaders( W3_CONTEXT * pW3Context, DWORD * pdwFlags );
//
// ULATQ send APIs
//
HRESULT SendResponse( W3_CONTEXT * pW3Context, DWORD dwResponseFlags, HTTP_CACHE_POLICY *pCachePolicy, DWORD * pcbSent );
HRESULT SendEntity( W3_CONTEXT * pW3Context, DWORD dwResponseFlags, DWORD * pcbSent );
HRESULT ResumeResponseTransfer( W3_CONTEXT * pW3Context, BOOL fCompletion, DWORD cbCompletion, DWORD dwCompletionStatus, BOOL fAsync, DWORD * pcbSent ); HRESULT OnIoCompletion( W3_CONTEXT * pW3Context, DWORD cbCompletion, DWORD dwCompletionStatus ) { DWORD cbSent; if ( _fHandleCompletion == FALSE ) { return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); } else { ResumeResponseTransfer( pW3Context, TRUE, cbCompletion, dwCompletionStatus, TRUE, &cbSent ); return NO_ERROR; } }
//
// Setup and send an ISAPI response
//
HRESULT FilterWriteClient( W3_CONTEXT * pW3Context, PVOID pvData, DWORD cbData );
HRESULT BuildResponseFromIsapi( W3_CONTEXT * pW3Context, LPSTR pszStatusLine, LPSTR pszHeaderStream, DWORD cchHeaderStream );
HRESULT BuildStatusFromIsapi( LPSTR pszStatusLine );
HRESULT AppendResponseHeaders( STRA & strHeaders );
//
// Get the raw response stream for use by raw data filter
//
HRESULT GetRawResponseStream( STRA * pstrResponseStream );
//
// Status code and reason
//
VOID SetStatus( HTTP_STATUS & httpStatus, HTTP_SUB_ERROR & httpSubError = HttpNoSubError ) { _ulHttpResponse.StatusCode = httpStatus.statusCode; _ulHttpResponse.pReason = httpStatus.pszReason; _ulHttpResponse.ReasonLength = httpStatus.cbReason; _subError = httpSubError; _fResponseTouched = TRUE; }
VOID SetStatusCode( USHORT StatusCode ) { _ulHttpResponse.StatusCode = StatusCode; }
VOID GetStatus( HTTP_STATUS *phttpStatus ) { phttpStatus->statusCode = _ulHttpResponse.StatusCode; phttpStatus->pszReason = (PSTR) _ulHttpResponse.pReason; phttpStatus->cbReason = _ulHttpResponse.ReasonLength; }
HRESULT SetStatus( USHORT StatusCode, STRA & strReason, HTTP_SUB_ERROR & subError = HttpNoSubError );
HRESULT GetStatusLine( STRA * pstrStatusLine );
USHORT QueryStatusCode( VOID ) const { return _ulHttpResponse.StatusCode; }
HRESULT QuerySubError( HTTP_SUB_ERROR * pSubError ) { if ( pSubError == NULL ) { DBG_ASSERT( FALSE ); return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } pSubError->mdSubError = _subError.mdSubError; pSubError->dwStringId = _subError.dwStringId; return NO_ERROR; }
VOID SetSubError( HTTP_SUB_ERROR * pSubError ) { if ( pSubError == NULL ) { DBG_ASSERT( FALSE ); return; } _subError.mdSubError = pSubError->mdSubError; _subError.dwStringId = pSubError->dwStringId; } VOID FindStringId( VOID );
//
// Touched state. Used to determine whether the system needs to send
// an error (500) response due to not state handler creating a response
//
BOOL QueryResponseTouched( VOID ) const { return _fResponseTouched; }
BOOL QueryResponseSent( VOID ) const { return _fResponseSent; }
ULONGLONG QueryContentLength( VOID ) const { return _cbContentLength; }
//
// Is there any entity in this response (used by custom error logic)
//
BOOL QueryEntityExists( VOID ) { return _cChunks > 0 && _cChunks > _cFirstEntityChunk; } };
#endif
|