You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
913 lines
28 KiB
913 lines
28 KiB
/*===================================================================
|
|
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"
|
|
|
|
const DWORD RESPONSE_BUFFER_SIZE = 2048;
|
|
const DWORD BUFFERS_INCREMENT = 256;
|
|
const DWORD ALLOCA_LIMIT = 4096;
|
|
const DWORD MAX_RESPONSE = 32768;
|
|
const DWORD MAX_MESSAGE_LENGTH = 512;
|
|
const DWORD RESPONSE_VECTOR_INTRINSIC_SIZE = 128;
|
|
const DWORD RESPONSE_VECTOR_INITIAL_ALLOC = 512;
|
|
const DWORD RESPONSE_VECTOR_REALLOC_FACTOR = 2;
|
|
// the minimum HTML block that is worth referingin the template rather than copying
|
|
// to the response buffer is roughly 6 times the size of a VectorSend element. This is
|
|
// because each such reference introduces two vector elements (the reference, and the one
|
|
// to the response buffer to follow), and during the system call, 2 additional copies are
|
|
// allocated. This evals out 6*24=144 bytes
|
|
// BUGBUG: might want to change to save long term mem on the expense of short term allocations
|
|
const DWORD MAX_HTML_IN_RESPONSE_BUFFER = 6*sizeof(HSE_VECTOR_ELEMENT);
|
|
|
|
typedef struct
|
|
{
|
|
LONG DynamicBlocks;
|
|
LONG ZeroSizeBlocks;
|
|
LONG TotalCopiedHTMLBytes;
|
|
LONG TotalReferencedHTMLBytes;
|
|
LONG HTML16;
|
|
LONG HTML32;
|
|
LONG HTML48;
|
|
LONG HTML64;
|
|
LONG HTML128;
|
|
LONG HTML256;
|
|
LONG HTML512;
|
|
LONG HTML1024;
|
|
LONG HTML2048;
|
|
LONG HTML4096;
|
|
LONG HTML8192;
|
|
LONG HTML16384;
|
|
LONG HTMLbig;
|
|
LONG Vect8;
|
|
LONG Vect16;
|
|
LONG Vect32;
|
|
LONG Vect64;
|
|
LONG Vect96;
|
|
LONG Vect128;
|
|
LONG Vect192;
|
|
LONG Vect256;
|
|
LONG Vect512;
|
|
LONG Vect1024;
|
|
LONG Vect2048;
|
|
LONG Vect4096;
|
|
LONG VectBig;
|
|
} ResponseVectorStatistics;
|
|
|
|
extern ResponseVectorStatistics sRespVecStats;
|
|
|
|
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 V e c t o r
|
|
*
|
|
*/
|
|
|
|
class CResponseVector
|
|
{
|
|
LPWSABUF m_pExtVector; // Pointer to auxilary vector
|
|
DWORD m_cExtVectorSize; // Size of auxilary vector
|
|
DWORD m_iCurrentEntry; // Logical index of current entry
|
|
BOOL m_fEntryIsOpen:1; // Can we add to current entry?
|
|
DWORD m_cchTotalBuffered; // Total of ouput bytes buffered
|
|
WSABUF m_aVector0[ RESPONSE_VECTOR_INTRINSIC_SIZE ]; // Pre-allocated vector
|
|
|
|
HRESULT GrowVector();
|
|
BOOL IsEntryOpen();
|
|
LPWSABUF GetEntry( UINT i);
|
|
DWORD GetEntryCount();
|
|
|
|
public:
|
|
CResponseVector();
|
|
~CResponseVector();
|
|
VOID Clear();
|
|
HRESULT Append( char * pData, DWORD cbSize);
|
|
HRESULT Insert( char * pData, DWORD cbSize);
|
|
VOID Close();
|
|
VOID GetVectors( LPWSABUF_VECTORS pWsabuf);
|
|
DWORD BytesBuffered();
|
|
};
|
|
|
|
inline BOOL CResponseVector::IsEntryOpen()
|
|
{
|
|
return m_fEntryIsOpen;
|
|
}
|
|
|
|
inline LPWSABUF CResponseVector::GetEntry(UINT i)
|
|
{
|
|
return (i < RESPONSE_VECTOR_INTRINSIC_SIZE) ?
|
|
&m_aVector0[i] : m_pExtVector + i - RESPONSE_VECTOR_INTRINSIC_SIZE;
|
|
}
|
|
|
|
inline DWORD CResponseVector::GetEntryCount()
|
|
{
|
|
return IsEntryOpen() ? m_iCurrentEntry + 1 : m_iCurrentEntry;
|
|
}
|
|
|
|
inline VOID CResponseVector::GetVectors( LPWSABUF_VECTORS pWsabuf)
|
|
{
|
|
DWORD iEntries = GetEntryCount();
|
|
if (iEntries > RESPONSE_VECTOR_INTRINSIC_SIZE)
|
|
{
|
|
pWsabuf->pVector1 = m_aVector0;
|
|
pWsabuf->dwVectorLen1 = RESPONSE_VECTOR_INTRINSIC_SIZE;
|
|
pWsabuf->pVector2 = m_pExtVector;
|
|
pWsabuf->dwVectorLen2 = iEntries - RESPONSE_VECTOR_INTRINSIC_SIZE;
|
|
}
|
|
else
|
|
{
|
|
if (iEntries > 0)
|
|
{
|
|
pWsabuf->pVector1 = m_aVector0;
|
|
pWsabuf->dwVectorLen1 = iEntries;
|
|
}
|
|
else
|
|
{
|
|
pWsabuf->pVector1 = NULL;
|
|
pWsabuf->dwVectorLen1 = 0;
|
|
}
|
|
|
|
pWsabuf->pVector2 = NULL;
|
|
pWsabuf->dwVectorLen2 = 0;
|
|
}
|
|
}
|
|
|
|
inline DWORD CResponseVector::BytesBuffered()
|
|
{
|
|
return m_cchTotalBuffered;
|
|
}
|
|
|
|
// marks the current entry as closed, so that subsequent Append() will create a new entry
|
|
inline VOID CResponseVector::Close()
|
|
{
|
|
if (IsEntryOpen())
|
|
{
|
|
m_fEntryIsOpen = FALSE;
|
|
m_iCurrentEntry++;
|
|
}
|
|
}
|
|
|
|
// Create a new entry: close current, append, and close new entry
|
|
inline HRESULT CResponseVector::Insert(char * pData, DWORD cbSize)
|
|
{
|
|
HRESULT hr;
|
|
Close();
|
|
hr = Append(pData, cbSize);
|
|
Close();
|
|
return hr;
|
|
}
|
|
|
|
class CResponseBufferSet;
|
|
|
|
/*
|
|
* C R e s p o n s e B u f f e r
|
|
*
|
|
*/
|
|
|
|
class CResponseBuffer
|
|
{
|
|
CResponseBufferSet* m_pBufferSet; // Pointer to BufferSet for this object
|
|
CResponseVector m_ResponseVector; // Response vector object
|
|
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_dwBufferLimit; // max to buffer
|
|
BOOL m_fInited; // Initialization status for the object
|
|
|
|
HRESULT GrowBuffers(DWORD cchNewRequest); // Increase the size of the buffers
|
|
|
|
public:
|
|
CResponseBuffer();
|
|
~CResponseBuffer();
|
|
HRESULT Init(CResponseBufferSet * pBufferSet, DWORD dwBufferLimit);
|
|
char * GetBuffer(UINT i);
|
|
DWORD GetBufferSize(UINT i);
|
|
DWORD CountOfBuffers();
|
|
DWORD BytesBuffered();
|
|
CResponseVector * GetResponseVector();
|
|
HRESULT Write(char* pszSource, DWORD cch, BOOL fChunkData, BOOL fTemplateData = FALSE);
|
|
HRESULT Clear();
|
|
VOID SetBufferLimit(DWORD dwBufferLimit);
|
|
|
|
// 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_ResponseVector.BytesBuffered();
|
|
}
|
|
|
|
inline CResponseVector * CResponseBuffer::GetResponseVector()
|
|
{
|
|
return &m_ResponseVector;
|
|
}
|
|
|
|
inline VOID CResponseBuffer::SetBufferLimit(DWORD dwBufferLimit)
|
|
{
|
|
m_dwBufferLimit = dwBufferLimit;
|
|
}
|
|
|
|
/*
|
|
* 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(CResponseBufferSet* pBufferSet, DWORD dwBufferLimit);
|
|
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), FALSE);
|
|
}
|
|
|
|
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(CResponseBufferSet* pBufferSet,
|
|
DWORD dwBufferLimit)
|
|
{
|
|
HRESULT hr = CResponseBuffer::Init(pBufferSet, dwBufferLimit);
|
|
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 B u f f e r S e t
|
|
*
|
|
* Structure that holds the response buffer and Debug response buffer
|
|
*/
|
|
|
|
class CResponseBufferSet {
|
|
|
|
private:
|
|
|
|
CResponseBuffer *m_pResponseBuffer; // Pointer to response buffer object
|
|
CDebugResponseBuffer *m_pClientDebugBuffer; // Pointer to response buffer object for client debugging data
|
|
CTemplate *m_pTemplate; // Pointer to the template for this request
|
|
CTemplate *m_aTemplates[16]; // internal array of templates referenced by this request
|
|
CTemplate **m_ppTemplates; // pointer to current array of templates
|
|
DWORD m_dwTemplatesRefd; // count of templates in array
|
|
DWORD m_dwArraySize; // total slots in array
|
|
DWORD m_fCurTemplateInArray : 1; // TRUE if m_pTemplate is in m_aTemplates
|
|
DWORD m_fTemplateArrayAllocd : 1; // TRUE if array was allocated
|
|
|
|
public:
|
|
|
|
CResponseBufferSet();
|
|
~CResponseBufferSet();
|
|
|
|
HRESULT Init(DWORD dwBufferLimit);
|
|
|
|
HRESULT InitDebugBuffer(DWORD dwBufferLimit);
|
|
|
|
HRESULT AddTemplateToArray();
|
|
|
|
static VOID SendResponseCompletion(CIsapiReqInfo *pIReq,
|
|
PVOID pContext,
|
|
DWORD cbIO,
|
|
DWORD dwError);
|
|
|
|
// inline helpers
|
|
|
|
CResponseBuffer *PResponseBuffer() { return m_pResponseBuffer; }
|
|
CDebugResponseBuffer *PClientDebugBuffer() { return m_pClientDebugBuffer; }
|
|
CTemplate *PTemplate() { return m_pTemplate; }
|
|
VOID SetTemplate(CTemplate *pTemplate)
|
|
{
|
|
m_pTemplate = pTemplate;
|
|
m_fCurTemplateInArray = FALSE;
|
|
}
|
|
VOID SetBufferLimit(DWORD dwBufferLimit) {
|
|
m_pResponseBuffer->SetBufferLimit(dwBufferLimit);
|
|
if (m_pClientDebugBuffer)
|
|
m_pClientDebugBuffer->SetBufferLimit(dwBufferLimit);
|
|
}
|
|
|
|
// Cache on per-class basis
|
|
ACACHE_INCLASS_DEFINITIONS()
|
|
|
|
};
|
|
|
|
/*
|
|
* 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 *);
|
|
~CResponseData();
|
|
|
|
HRESULT Init();
|
|
|
|
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
|
|
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
|
|
CResponseBufferSet *m_pBufferSet; // Buffer set for response 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
|
|
DWORD m_fResponseAborted : 1; // Was "Response.End" invoked?
|
|
DWORD m_fWriteClientError : 1;// Write Client Failed
|
|
DWORD m_fIgnoreWrites : 1; // Ignore all writes? (in case of custom error)
|
|
DWORD m_fBufferingOn : 1; // Buffer response output
|
|
DWORD m_fFlushed : 1; // Has flush been called?
|
|
DWORD m_fChunkData : 1; // Doing HTTP 1.1 chunking?
|
|
DWORD m_fChunkDataInited : 1; // has m_fChunkData been init'd?
|
|
DWORD m_fClientDebugMode : 1; // In client debug mode?
|
|
DWORD m_fClientDebugFlushIgnored : 1; // Flush request ignored due to client debug?
|
|
ULONG m_cRefs; // ref count
|
|
DWORD m_dwBufferLimit; // max to buffer
|
|
|
|
void AppendHeaderToList(CHTTPHeader *pHeader);
|
|
|
|
public:
|
|
STDMETHODIMP QueryInterface(const GUID &, void **);
|
|
STDMETHODIMP_(ULONG) AddRef();
|
|
STDMETHODIMP_(ULONG) Release();
|
|
|
|
DWORD BytesBuffered();
|
|
BOOL FChunkData();
|
|
|
|
VOID SetBufferLimit(DWORD dwBufferLimit);
|
|
|
|
// Cache on per-class basis
|
|
ACACHE_INCLASS_DEFINITIONS()
|
|
};
|
|
|
|
inline DWORD CResponseData::BytesBuffered()
|
|
{
|
|
DWORD dw = m_pBufferSet->PResponseBuffer()->GetResponseVector()->BytesBuffered();
|
|
|
|
if (m_pBufferSet->PClientDebugBuffer())
|
|
dw += m_pBufferSet->PClientDebugBuffer()->GetResponseVector()->BytesBuffered();
|
|
|
|
return dw;
|
|
}
|
|
|
|
inline BOOL CResponseData::FChunkData()
|
|
{
|
|
if (m_fChunkDataInited == FALSE) {
|
|
// If using HTTP/1.1 and not buffering add length ofTransfer-Encoding headers
|
|
if ((m_dwVersionMinor >= 1) && (m_dwVersionMajor >= 1) &&
|
|
(m_fBufferingOn == FALSE) &&
|
|
!m_pIReq->IsChild()) { // don't chunk child request output
|
|
|
|
// UNDONE: Temporary setting to turn off chuncked encoding
|
|
if (Glob(fEnableChunkedEncoding))
|
|
m_fChunkData = TRUE;
|
|
}
|
|
m_fChunkDataInited = TRUE;
|
|
}
|
|
|
|
return m_fChunkData;
|
|
}
|
|
|
|
inline VOID CResponseData::SetBufferLimit(DWORD dwBufferLimit)
|
|
{
|
|
m_dwBufferLimit = dwBufferLimit;
|
|
|
|
m_pBufferSet->SetBufferLimit(dwBufferLimit);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
class CStaticWriteFileCB {
|
|
|
|
public:
|
|
|
|
WSABUF m_wsaBuf;
|
|
|
|
CStaticWriteFileCB() {
|
|
|
|
ZeroMemory( &m_wsaBuf, sizeof(WSABUF));
|
|
|
|
}
|
|
|
|
~CStaticWriteFileCB() {
|
|
|
|
if (m_wsaBuf.buf)
|
|
CloseHandle((HANDLE)m_wsaBuf.buf);
|
|
}
|
|
};
|
|
|
|
/*
|
|
* C R e s p o n s e
|
|
*
|
|
* Implements the Response object
|
|
*/
|
|
class CResponse : public IResponseImpl, 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
|
|
|
|
// FTM Support
|
|
IUnknown *m_pUnkFTM;
|
|
|
|
VOID GetClientVerison(VOID);
|
|
|
|
#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);
|
|
|
|
static HRESULT ConstructSimpleHeaders(
|
|
LPHSE_SEND_HEADER_EX_INFO pHeaderInfo,
|
|
DWORD cbTotal,
|
|
char *szMimeType,
|
|
char *szStatus = NULL,
|
|
char *szExtraHeaders = NULL);
|
|
|
|
HRESULT ConstructHeaders(LPHSE_SEND_HEADER_EX_INFO pHeaderInfo);
|
|
HRESULT WriteResponse();
|
|
VOID 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 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 StaticWrite(CIsapiReqInfo *pIReq,
|
|
char *pchBuf,
|
|
DWORD cchBuf = 0,
|
|
CTemplate *pTemplate = NULL);
|
|
|
|
// static method to send contents of several memory blocks as the entire response (sync)
|
|
static HRESULT WriteBlocksResponse(CIsapiReqInfo *pIReq,
|
|
DWORD cBlocks,
|
|
LPWSABUF pWsaBuf,
|
|
DWORD cbTotal,
|
|
char *szMimeType = NULL,
|
|
char *szStatus = NULL,
|
|
char *szExtraHeaders = NULL);
|
|
|
|
// 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 VOID StaticWriteFileCompletion(CIsapiReqInfo *pIReq,
|
|
PVOID pContext,
|
|
DWORD cbIO,
|
|
DWORD dwError);
|
|
|
|
// static method to send contents of a scriptless template as the entire response (sync)
|
|
static HRESULT WriteScriptlessTemplate(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_pIReq->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::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
|