windows-nt/Source/XPSP1/NT/inetsrv/iis/svcs/cmp/asp51/response.h
2020-09-26 16:20:57 +08:00

647 lines
19 KiB
C++

/*===================================================================
Microsoft Denali
Microsoft Confidential.
Copyright 1996 Microsoft Corporation. All Rights Reserved.
Component: Response object
File: response.h
Owner: CGrant
This file contains the header info for defining the Response object.
Note: This was largely stolen from Kraig Brocjschmidt's Inside OLE2
second edition, chapter 14 Beeper v5.
===================================================================*/
#ifndef _RESPONSE_H
#define _RESPONSE_H
#include "debug.h"
#include "util.h"
#include "template.h"
#include "disptch2.h"
#include "hashing.h"
#include "memcls.h"
#include "ftm.h"
const DWORD RESPONSE_BUFFER_SIZE = 32768;
const DWORD BUFFERS_INCREMENT = 256;
const DWORD ALLOCA_LIMIT = 4096;
const DWORD MAX_RESPONSE = 32768;
const DWORD MAX_MESSAGE_LENGTH = 512;
class CScriptEngine;
#ifdef USE_LOCALE
extern DWORD g_dwTLS;
#endif
// fixed size allocator for response buffers
ACACHE_FSA_EXTERN(ResponseBuffer)
// forward refs
class CResponse;
class CRequest;
//This file is generated from MKTYPLIB on denali.obj
#include "asptlb.h"
//Type for an object-destroyed callback
typedef void (*PFNDESTROYED)(void);
//Type for the "Get Active Script Engine" callback
typedef CScriptEngine *(*PFNGETSCRIPT)(int iScriptEngine, void *pvContext);
/*
* C H T T P H e a d e r L i n k
*
*/
class CHTTPHeader
{
private:
DWORD m_fInited : 1;
DWORD m_fNameAllocated : 1;
DWORD m_fValueAllocated : 1;
char *m_szName;
char *m_szValue;
DWORD m_cchName;
DWORD m_cchValue;
CHTTPHeader *m_pNext;
char m_rgchLtoaBuffer[20]; // enough for atol
public:
CHTTPHeader();
~CHTTPHeader();
HRESULT InitHeader(BSTR wszName, BSTR wszValue, UINT lCodePage = CP_ACP);
HRESULT InitHeader(char *szName, BSTR wszValue, UINT lCodePage = CP_ACP);
HRESULT InitHeader(char *szName, char *szValue, BOOL fCopyValue);
HRESULT InitHeader(char *szName, long lValue);
char *PSzName();
char *PSzValue();
DWORD CchLength();
void Print(char *szBuf);
void SetNext(CHTTPHeader *pHeader);
CHTTPHeader *PNext();
// Cache on per-class basis
ACACHE_INCLASS_DEFINITIONS()
};
// CHTTPHeader inlines
inline char *CHTTPHeader::PSzName()
{
Assert(m_fInited);
return m_szName;
}
inline char *CHTTPHeader::PSzValue()
{
Assert(m_fInited);
return m_szValue;
}
inline DWORD CHTTPHeader::CchLength()
{
Assert(m_fInited);
return (m_cchName + m_cchValue + 4); // account for ": " and "\r\n"
}
inline void CHTTPHeader::SetNext(CHTTPHeader *pHeader)
{
Assert(m_fInited);
Assert(!m_pNext);
m_pNext = pHeader;
}
inline CHTTPHeader *CHTTPHeader::PNext()
{
return m_pNext;
}
/*
* C R e s p o n s e B u f f e r
*
*/
class CResponseBuffer
{
CResponse* m_pResponse; // Pointer to enclosing response
char **m_rgpchBuffers; // Array of pointers to buffers
char *m_pchBuffer0; // In case of 1 element array of pointers
DWORD m_cBufferPointers; // Count of buffer pointers
DWORD m_cBuffers; // Count of buffers we have allocated
DWORD m_iCurrentBuffer; // Array index for the buffer we are currently filling
DWORD m_cchOffsetInCurrentBuffer; // Offset within the current buffer
DWORD m_cchTotalBuffered; // Total of ouput bytes buffered
BOOL m_fInited; // Initialization status for the object
HRESULT GrowBuffers(DWORD cchNewRequest); // Increase the size of the buffers
public:
CResponseBuffer();
~CResponseBuffer();
HRESULT Init(CResponse* pResponse);
char * GetBuffer(UINT i);
DWORD GetBufferSize(UINT i);
DWORD CountOfBuffers();
DWORD BytesBuffered();
HRESULT Write(char* pszSource, DWORD cch);
HRESULT Flush(CIsapiReqInfo *pIReq);
HRESULT Clear();
// Cache on per-class basis
ACACHE_INCLASS_DEFINITIONS()
};
inline char * CResponseBuffer::GetBuffer(UINT i)
{
Assert( i < m_cBuffers );
return m_rgpchBuffers[i];
}
inline DWORD CResponseBuffer::GetBufferSize(UINT i)
{
Assert( i < m_cBuffers );
// if buffer is final one, its content-length is current offset
if ( i == (m_cBuffers - 1 ) )
{
return m_cchOffsetInCurrentBuffer;
}
// if buffer is other than final one, its content-length is default buffer size
return RESPONSE_BUFFER_SIZE;
}
inline DWORD CResponseBuffer::CountOfBuffers()
{
return m_cBuffers;
}
inline DWORD CResponseBuffer::BytesBuffered()
{
return m_cchTotalBuffered;
}
/*
* C D e b u g R e s p o n s e B u f f e r
*
*/
class CDebugResponseBuffer : public CResponseBuffer
{
private:
HRESULT Write(const char* pszSource);
public:
inline CDebugResponseBuffer() {}
inline ~CDebugResponseBuffer() {}
HRESULT Start();
HRESULT End();
HRESULT InitAndStart(CResponse* pResponse);
HRESULT ClearAndStart();
// the only real method
HRESULT AppendRecord
(
const int cchBlockOffset,
const int cchBlockLength,
const int cchSourceOffset,
const char *pszSourceFile = NULL
);
// Cache on per-class basis
ACACHE_INCLASS_DEFINITIONS()
};
inline HRESULT CDebugResponseBuffer::Write(const char* pszSource)
{
return CResponseBuffer::Write((char *)pszSource, strlen(pszSource));
}
inline HRESULT CDebugResponseBuffer::Start()
{
return Write("<!--METADATA TYPE=\"ASP_DEBUG_INFO\"\r\n");
}
inline HRESULT CDebugResponseBuffer::End()
{
return Write("-->\r\n");
}
inline HRESULT CDebugResponseBuffer::InitAndStart(CResponse* pResponse)
{
HRESULT hr = CResponseBuffer::Init(pResponse);
if (SUCCEEDED(hr))
hr = Start();
return hr;
}
inline HRESULT CDebugResponseBuffer::ClearAndStart()
{
HRESULT hr = CResponseBuffer::Clear();
if (SUCCEEDED(hr))
hr = Start();
return hr;
}
/*
* C R e s p o n s e C o o k i e s
*
* Implements the IRequestDictionary interface for writing cookies.
*/
class CResponseCookies : public IRequestDictionaryImpl
{
private:
IUnknown * m_punkOuter; // for addrefs
CSupportErrorInfo m_ISupportErrImp; // implementation of ISupportErr
CRequest * m_pRequest; // pointer to request object
CResponse * m_pResponse; // pointer to parent object
public:
CResponseCookies(CResponse *, IUnknown *);
~CResponseCookies();
HRESULT Init()
{
return S_OK;
}
HRESULT ReInit(CRequest *);
// The Big Three
STDMETHODIMP QueryInterface(const GUID &, void **);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
// OLE Automation Interface
STDMETHODIMP get_Item(VARIANT varKey, VARIANT *pvarReturn);
STDMETHODIMP get__NewEnum(IUnknown **ppEnumReturn);
STDMETHODIMP get_Count(int *pcValues);
STDMETHODIMP get_Key(VARIANT VarKey, VARIANT *pvar);
// C++ interface to write headers
size_t QueryHeaderSize();
char *GetHeaders(char *szBuffer);
};
/*
* C R e s p o n s e D a t a
*
* Structure that holds the intrinsic's properties.
* The instrinsic keeps pointer to it (NULL when lightweight)
*/
class CResponseData : public IUnknown
{
friend CResponse;
friend CResponseCookies;
friend CResponseBuffer;
private:
// constructor to pass params to members and init members
CResponseData(CResponse *pResponse);
~CResponseData();
HRESULT Init(CResponse *pResponse);
CSupportErrorInfo m_ISupportErrImp; // Interface to indicate that we support ErrorInfo reporting
CIsapiReqInfo * m_pIReq; // CIsapiReqInfo block for HTTP info
CHitObj* m_pHitObj; // pointer to hitobj for this request
CTemplate* m_pTemplate; // Pointer to the template for this request
CHTTPHeader* m_pFirstHeader; // List of
CHTTPHeader* m_pLastHeader; // headers
time_t m_tExpires; // date that the HTML output page expires; -1 if no date assigned
const char* m_szCookieVal; // Value of session id
const char* m_pszDefaultContentType;// Default content type (pointer to static string)
const char* m_pszDefaultExpires; // Default expires header value
char* m_pszContentType; // Content type of response (set by user)
char* m_pszCharSet; // CharSet header of response
char* m_pszCacheControl; // cache-control header of response
char* m_pszStatus; // HTTP Status to be returned
BYTE m_dwVersionMajor; // Major version of HTTP supported by client
BYTE m_dwVersionMinor; // Minor version of HTTP supported by client
CResponseBuffer * m_pResponseBuffer; // Pointer to response buffer object
CDebugResponseBuffer * m_pClientDebugBuffer; // Pointer to response buffer object for client debugging data
int m_IsHeadRequest; // HEAD request flag 0=uninit, 1=not head, 2=head
PFNGETSCRIPT m_pfnGetScript; // Pointer to callback function for obtaining CActiveEngine pointers
void* m_pvGetScriptContext; // Pointer to data for for callback function for CActiveEngines
CResponseCookies m_WriteCookies; // write-only cookie collection
BOOL m_fHeadersWritten : 1; // Have the output headers been written?
BOOL m_fResponseAborted : 1; // Was "Response.End" invoked?
BOOL m_fWriteClientError : 1;// Write Client Failed
BOOL m_fIgnoreWrites : 1; // Ignore all writes? (in case of custom error)
BOOL m_fBufferingOn : 1; // Buffer response output
BOOL m_fFlushed : 1; // Has flush been called?
BOOL m_fChunked : 1; // Doing HTTP 1.1 chunking?
BOOL m_fClientDebugMode : 1; // In client debug mode?
BOOL m_fClientDebugFlushIgnored : 1; // Flush request ignored due to client debug?
ULONG m_cRefs; // ref count
void AppendHeaderToList(CHTTPHeader *pHeader);
public:
STDMETHODIMP QueryInterface(const GUID &, void **);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
// Cache on per-class basis
ACACHE_INCLASS_DEFINITIONS()
};
inline void CResponseData::AppendHeaderToList(CHTTPHeader *pHeader)
{
if (!m_pLastHeader)
{
Assert(!m_pFirstHeader);
m_pFirstHeader = pHeader;
}
else
{
Assert(m_pFirstHeader);
m_pLastHeader->SetNext(pHeader);
}
m_pLastHeader = pHeader;
}
/*
* C R e s p o n s e
*
* Implements the Response object
*/
class CResponse : public IResponseImpl, public CFTMImplementation, public IStream
{
friend CResponseCookies;
friend CResponseBuffer;
private:
// Flags
DWORD m_fInited : 1; // Is initialized?
DWORD m_fDiagnostics : 1; // Display ref count in debug output
DWORD m_fOuterUnknown : 1; // Ref count outer unknown?
// Ref count / Outer unknown
union
{
DWORD m_cRefs;
IUnknown *m_punkOuter;
};
// Properties
CResponseData *m_pData; // pointer to structure that holds
// CResponse properties
VOID GetClientVerison(VOID);
HRESULT WriteClient(BYTE *pb, DWORD cb);
HRESULT WriteClientChunked(BYTE *pb, DWORD cb);
#ifdef DBG
inline void TurnDiagsOn() { m_fDiagnostics = TRUE; }
inline void TurnDiagsOff() { m_fDiagnostics = FALSE; }
void AssertValid() const;
#else
inline void TurnDiagsOn() {}
inline void TurnDiagsOff() {}
inline void AssertValid() const {}
#endif
public:
CResponse(IUnknown *punkOuter = NULL);
~CResponse();
HRESULT CleanUp();
HRESULT Init();
HRESULT UnInit();
HRESULT ReInitTemplate(CTemplate* pTemplate, const char *szCookie);
CTemplate *SwapTemplate(CTemplate* pNewTemplate);
HRESULT ReInit(CIsapiReqInfo *pIReq, const char *szCookie, CRequest *pRequest,
PFNGETSCRIPT pfnGetScript, void *pvGetScriptContext, CHitObj *pHitObj);
HRESULT WriteHeaders(BOOL fSendEntireResponse = FALSE);
HRESULT FinalFlush(HRESULT);
HRESULT WriteSz(CHAR *sz, DWORD cch);
HRESULT WriteBSTR(BSTR bstr);
// append headers of different kind
HRESULT AppendHeader(BSTR wszName, BSTR wszValue);
HRESULT AppendHeader(char *szName, BSTR wszValue);
HRESULT AppendHeader(char *szName, char *szValue, BOOL fCopyValue = FALSE);
HRESULT AppendHeader(char *szName, long lValue);
// inlines
inline BOOL FHeadersWritten();
inline BOOL IsHeadRequest(void);
inline BOOL FResponseAborted();
inline BOOL FWriteClientError();
inline BOOL FDontWrite();
inline void SetHeadersWritten();
inline void SetIgnoreWrites();
inline CIsapiReqInfo* GetIReq();
inline const char* PContentType() const;
inline char *PCustomStatus();
inline void *SwapScriptEngineInfo(void *pvEngineInfo);
//Non-delegating object IUnknown
STDMETHODIMP QueryInterface(REFIID, PPVOID);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
// GetIDsOfNames special-case implementation
STDMETHODIMP GetIDsOfNames(REFIID, OLECHAR **, UINT, LCID, DISPID *);
// Tombstone stub
HRESULT CheckForTombstone();
//IResponse functions
STDMETHODIMP Write(VARIANT varInput);
STDMETHODIMP BinaryWrite(VARIANT varInput);
STDMETHODIMP WriteBlock(short iBlockNumber);
STDMETHODIMP Redirect(BSTR bstrURL);
STDMETHODIMP AddHeader(BSTR bstrHeaderName, BSTR bstrHeaderValue);
STDMETHODIMP Pics(BSTR bstrHeaderValue);
STDMETHODIMP Add(BSTR bstrHeaderValue, BSTR bstrHeaderName);
STDMETHODIMP SetCookie(BSTR bstrHeader, BSTR bstrValue, VARIANT varExpires,
VARIANT varDomain, VARIANT varPath, VARIANT varSecure);
STDMETHODIMP Clear(void);
STDMETHODIMP Flush(void);
STDMETHODIMP End(void);
STDMETHODIMP AppendToLog(BSTR bstrLogEntry);
STDMETHODIMP get_ContentType(BSTR *pbstrContentTypeRet);
STDMETHODIMP put_ContentType(BSTR bstrContentType);
STDMETHODIMP get_CharSet(BSTR *pbstrContentTypeRet);
STDMETHODIMP put_CharSet(BSTR bstrContentType);
STDMETHODIMP get_CacheControl(BSTR *pbstrCacheControl);
STDMETHODIMP put_CacheControl(BSTR bstrCacheControl);
STDMETHODIMP get_Status(BSTR *pbstrStatusRet);
STDMETHODIMP put_Status(BSTR bstrStatus);
STDMETHODIMP get_Expires(VARIANT *pvarExpiresMinutesRet);
STDMETHODIMP put_Expires(long lExpiresMinutes);
STDMETHODIMP get_ExpiresAbsolute(VARIANT *pvarTimeRet);
STDMETHODIMP put_ExpiresAbsolute(DATE dtExpires);
STDMETHODIMP get_Buffer(VARIANT_BOOL* fIsBuffering);
STDMETHODIMP put_Buffer(VARIANT_BOOL fIsBuffering);
STDMETHODIMP get_Cookies(IRequestDictionary **ppDictReturn);
STDMETHODIMP IsClientConnected(VARIANT_BOOL* fIsBuffering);
STDMETHODIMP get_CodePage(long *plVar);
STDMETHODIMP put_CodePage(long var);
STDMETHODIMP get_LCID(long *plVar);
STDMETHODIMP put_LCID(long var);
// static method to send the entire block using SyncWriteClient
static HRESULT SyncWrite(CIsapiReqInfo *pIReq,
char *pchBuf,
DWORD cchBuf = 0);
// static method to send contents of several memory blocks as the entire response (sync)
static HRESULT SyncWriteBlocks(CIsapiReqInfo *pIReq,
DWORD cBlocks,
DWORD cbTotal,
void **rgpvBlock,
DWORD *rgcbBlock,
char *szMimeType = NULL,
char *szStatus = NULL,
char *szExtraHeaders = NULL);
// static method to send contents of a memory block as the entire response (sync)
inline static HRESULT SyncWriteBlock(CIsapiReqInfo *pIReq,
void *pvBlock,
DWORD cbBlock,
char *szMimeType = NULL,
char *szStatus = NULL,
char *szExtraHeaders = NULL)
{
return SyncWriteBlocks(pIReq, 1, cbBlock, &pvBlock, &cbBlock,
szMimeType, szStatus, szExtraHeaders);
}
// static method to send contents of a file as the entire response (sync)
static HRESULT SyncWriteFile(CIsapiReqInfo *pIReq,
TCHAR *szFile,
char *szMimeType = NULL,
char *szStatus = NULL,
char *szExtraHeaders = NULL);
// static method to send contents of a scriptless template as the entire response (sync)
static HRESULT SyncWriteScriptlessTemplate(CIsapiReqInfo *pIReq,
CTemplate *pTemplate);
// IStream implementation
STDMETHODIMP Read(void *pv, ULONG cb, ULONG *pcbRead);
STDMETHODIMP Write(const void *pv, ULONG cb, ULONG *pcbWritten);
STDMETHODIMP Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin,
ULARGE_INTEGER *plibNewPosition);
STDMETHODIMP SetSize(ULARGE_INTEGER libNewSize);
STDMETHODIMP CopyTo(IStream *pstm, ULARGE_INTEGER cb,
ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten);
STDMETHODIMP Commit(DWORD grfCommitFlags);
STDMETHODIMP Revert();
STDMETHODIMP LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb,
DWORD dwLockType);
STDMETHODIMP UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb,
DWORD dwLockType);
STDMETHODIMP Stat(STATSTG *pstatstg, DWORD grfStatFlag);
STDMETHODIMP Clone(IStream **ppstm);
// Cache on per-class basis
ACACHE_INCLASS_DEFINITIONS()
};
inline BOOL CResponse::FHeadersWritten()
{
Assert(m_fInited);
Assert(m_pData);
return m_pData->m_fHeadersWritten;
}
inline BOOL CResponse::FResponseAborted()
{
Assert(m_fInited);
Assert(m_pData);
return m_pData->m_fResponseAborted;
}
inline BOOL CResponse::FWriteClientError()
{
Assert(m_fInited);
Assert(m_pData);
return m_pData->m_fWriteClientError;
}
inline BOOL CResponse::FDontWrite()
{
Assert(m_fInited);
Assert(m_pData);
return (m_pData->m_fWriteClientError || m_pData->m_fIgnoreWrites);
}
inline void CResponse::SetHeadersWritten()
{
Assert(m_fInited);
Assert(m_pData);
m_pData->m_fHeadersWritten = TRUE;
}
inline void CResponse::SetIgnoreWrites()
{
Assert(m_fInited);
Assert(m_pData);
m_pData->m_fIgnoreWrites = TRUE;
}
inline CIsapiReqInfo* CResponse::GetIReq()
{
Assert(m_fInited);
Assert(m_pData);
return m_pData->m_pIReq;
}
inline const char* CResponse::PContentType() const
{
Assert(m_fInited);
Assert(m_pData);
if (m_pData->m_pszContentType)
return m_pData->m_pszContentType;
else
return m_pData->m_pszDefaultContentType;
}
inline char* CResponse::PCustomStatus()
{
Assert(m_fInited);
Assert(m_pData);
return m_pData->m_pszStatus;
}
inline void *CResponse::SwapScriptEngineInfo(void *pvEngineInfo)
{
Assert(m_fInited);
Assert(m_pData);
void *pvOldEngineInfo = m_pData->m_pvGetScriptContext;
m_pData->m_pvGetScriptContext = pvEngineInfo;
return pvOldEngineInfo;
}
#endif //_RESPONSE_H