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