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.
416 lines
11 KiB
416 lines
11 KiB
#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 <sgstruct.h>
|
|
#include <limits.h> // definition of LONG_MIN
|
|
#include <ex\refcnt.h> // IRefCounted
|
|
#include <ex\astream.h> // Async stream interfaces
|
|
#include <ex\refhandle.h> // 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 X>
|
|
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<X> 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<UINT>(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<char> 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_)
|