#ifndef _BODY_H_ #define _BODY_H_ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // BODY.H // // Common implementation classes from which request body and // response body are derived. // // Copyright 1986-1997 Microsoft Corporation, All Rights Reserved // #include #include // definition of LONG_MIN #include // IRefCounted #include // Async stream interfaces #include // auto_ref_handle, etc. // ======================================================================== // // CLASS IAsyncPersistObserver // // Async I/O completion callback object interface used by // IBody::AsyncPersist(). Callers of AsyncPersist() must pass an object // conforming to this interface. That object will be notified when // the async persist operation completes via a call to its // PersistComplete() member function. // class IAsyncPersistObserver : public IRefCounted { // NOT IMPLEMENTED // IAsyncPersistObserver& operator=( const IAsyncPersistObserver& ); public: // CREATORS // virtual ~IAsyncPersistObserver() = 0; // MANIPULATORS // virtual VOID PersistComplete( HRESULT hr ) = 0; }; // ======================================================================== // // CLASS IAcceptObserver // // Passed to the IBody::Accept() and IBodyPartAccept() methods when // accepting a body part visitor. The accept observer is called whenever // the accept operation completes (which may happen asynchronously). // Note that the body part visitor is often the accept observer itself, // but it doesn't have to be. The accept code which notifies the observer // is not aware that it is notifying a visitor. // class IAcceptObserver { // NOT IMPLEMENTED // IAcceptObserver& operator=( const IAcceptObserver& ); public: // CREATORS // virtual ~IAcceptObserver() = 0; // MANIPULATORS // virtual VOID AcceptComplete( UINT64 cbAccepted64 ) = 0; }; // ======================================================================== // // CLASS CAsyncDriver // // Implements a mechanism to allow an object to be driven asynchronously // from any one thread at a time. // template class CAsyncDriver { // // Number of calls to Run() that will be made before // the object requires another call to Start() to // get it going again. Each call to Start() increments // this count by one. The count is decremented by // one as each Run() completes. // LONG m_lcRunCount; // NOT IMPLEMENTED // CAsyncDriver( const CAsyncDriver& ); CAsyncDriver& operator=( const CAsyncDriver& ); public: // CREATORS // CAsyncDriver() : m_lcRunCount(0) {} #ifdef DBG ~CAsyncDriver() { m_lcRunCount = LONG_MIN; } #endif // MANIPULATORS // VOID Start(X& x) { // // The object's Run() implementation often allows the final ref // on the object to be released. And this CAsyncDriver is often // a member of that object. Therefore, we need to AddRef() the // object to keep ourselves alive until we return from this // function. It's kinda strange, but the alternative is to // require callers to AddRef() the object themselves, but that // approach would be more prone to error. // auto_ref_ptr px(&x); AssertSz( m_lcRunCount >= 0, "CAsyncDriver::Start() called on destroyed/bad CAsyncDriver!" ); // // Start/Restart/Continue the driver // if ( InterlockedIncrement( &m_lcRunCount ) == 1 ) { do { x.Run(); } while ( InterlockedDecrement( &m_lcRunCount ) > 0 ); } } }; // ======================================================================== // // CLASS IBodyPart // // Defines the interface to a body part. An IBodyPart object is assumed // to consist of the body part data and an internal iterator over that // data. // // An IBodyPart must implement the following methods: // // CbSize() // Returns the size (in bytes) of the body part. Necessary for // computation of a part's contribution to the content length. // // Rewind() // Prepares the body part to be traversed again by new visitor. // // Accept() // Accepts a body part visitor object to iterate over the body part. // The accept operation may be asynchronous either because the // body part chooses to implement it that way, or because the accepted // visitor requires it. For this reason, an accept observer is // also used. This observer should be called whenever the // accept operation completes. // class IBodyPart { // NOT IMPLEMENTED // IBodyPart& operator=( const IBodyPart& ); public: // CREATORS // virtual ~IBodyPart() = 0; // ACCESSORS // virtual UINT64 CbSize64() const = 0; // MANIPULATORS // virtual VOID Accept( IBodyPartVisitor& v, UINT64 ibPos64, IAcceptObserver& obsAccept ) = 0; virtual VOID Rewind() = 0; }; // ======================================================================== // // CLASS IBodyPartVisitor // // Defines an interface for an object used to access body part data. // A body part visitor handles three types of data: in-memory bytes (text), // files, and streams (via IAsyncStream). What the visitor does with that // data and how it does it is not specified; the behavior is provided by // the visitor itself. The IBodyPartVisitor interface just standardizes // things to provide for asynchronous iteration over the entire body // without the need for custom asynchronous iteration code everywhere. // // A body part visitor may implement any of its VisitXXX() methods // as asynchronous operations. Regardless, the visitor must call // VisitComplete() on the visitor observer passed to it whenever // the visit operation completes. // // When visiting body part data in one of the VisitXXX() methods, // a visitor does not have to visit (i.e. buffer) ALL of the data // before calling IAcceptObserver::AcceptComplete(). It can just // call AcceptComplete() with the number of bytes that can actually // be accepted. // class IAsyncStream; class IBodyPartVisitor { // NOT IMPLEMENTED // IBodyPartVisitor& operator=( const IBodyPartVisitor& ); public: // CREATORS // virtual ~IBodyPartVisitor() = 0; // MANIPULATORS // virtual VOID VisitBytes( const BYTE * pbData, UINT cbToVisit, IAcceptObserver& obsAccept ) = 0; virtual VOID VisitFile( const auto_ref_handle& hf, UINT64 ibOffset64, UINT64 cbToVisit64, IAcceptObserver& obsAccept ) = 0; virtual VOID VisitStream( IAsyncStream& stm, UINT cbToVisit, IAcceptObserver& obsAccept ) = 0; virtual VOID VisitComplete() = 0; }; // ======================================================================== // // CLASS IBody // // Common request/response body interface // class IAsyncStream; class IBody { // NOT IMPLEMENTED // IBody& operator=( const IBody& ); public: // ======================================================================== // // CLASS iterator // class iterator { // NOT IMPLEMENTED // iterator& operator=( const iterator& ); public: // CREATORS // virtual ~iterator() = 0; // MANIPULATORS // virtual VOID Accept( IBodyPartVisitor& v, IAcceptObserver& obs ) = 0; virtual VOID Prune() = 0; }; // CREATORS // virtual ~IBody() = 0; // ACCESSORS // virtual BOOL FIsEmpty() const = 0; virtual UINT64 CbSize64() const = 0; // MANIPULATORS // virtual VOID Clear() = 0; virtual VOID AddText( LPCSTR lpszText, UINT cbText ) = 0; VOID AddText( LPCSTR lpszText ) { AddText(lpszText, static_cast(strlen(lpszText))); } virtual VOID AddFile( const auto_ref_handle& hf, UINT64 ibFile64, UINT64 cbFile64 ) = 0; virtual VOID AddStream( IStream& stm ) = 0; virtual VOID AddStream( IStream& stm, UINT ibOffset, UINT cbSize ) = 0; virtual VOID AddBodyPart( IBodyPart * pBodyPart ) = 0; virtual VOID AsyncPersist( IAsyncStream& stm, IAsyncPersistObserver& obs ) = 0; virtual IStream * GetIStream( IAsyncIStreamObserver& obs ) = 0; virtual iterator * GetIter() = 0; }; IBody * NewBody(); // ======================================================================== // // CLASS CFileBodyPart // // Represents a file body part. A file body part is a part whose content // can be accessed with the standard Win32 APIs ReadFile() and TransmitFile(). // // Note: File body parts using this implementation must be no longer // than ULONG_MAX bytes! // class CFileBodyPart : public IBodyPart { // The file handle // auto_ref_handle m_hf; // Starting offset into the file // UINT64 m_ibFile64; // Size of the content // UINT64 m_cbFile64; // NOT IMPLEMENTED // CFileBodyPart( const CFileBodyPart& ); CFileBodyPart& operator=( const CFileBodyPart& ); public: // CREATORS // CFileBodyPart( const auto_ref_handle& hf, UINT64 ibFile64, UINT64 cbFile64 ); // ACCESSORS // UINT64 CbSize64() const { return m_cbFile64; } // MANIPULATORS // VOID Rewind(); VOID Accept( IBodyPartVisitor& v, UINT64 ibPos64, IAcceptObserver& obsAccept ); }; // ======================================================================== // // CLASS CTextBodyPart // class CTextBodyPart : public IBodyPart { // String buffer to hold the text // StringBuffer m_bufText; // NOT IMPLEMENTED // CTextBodyPart( const CTextBodyPart& ); CTextBodyPart& operator=( const CTextBodyPart& ); public: // AddTextBytes() // // NOTE: this method was added for XML emitting. // In that scenaro, an XML response is composed of // many -- potentially thousands -- of calls to add // response bytes. If we strictly went and used the // CMethUtil methods to ::AddResponseText(), we would // end up with many -- potentially thousands -- of body // parts. So, the upshot here is that performance of // such a mechanism would suck. // // By adding the method -- and moving the declaration of // this class to a publicly available header, we can now // create a text body part as a component of the emitting // process, and pour our data into body part directly. // Once the content is complete, we can then simply add // the body part. // VOID AddTextBytes ( UINT cbText, LPCSTR lpszText ); // CREATORS // CTextBodyPart( UINT cbText, LPCSTR lpszText ); // ACCESSORS // UINT64 CbSize64() const { return m_bufText.CbSize(); } // MANIPULATORS // VOID Rewind(); VOID Accept( IBodyPartVisitor& v, UINT64 ibPos64, IAcceptObserver& obsAccept ); }; #endif // !defined(_BODY_H_)