/*=================================================================== 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("\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