Rewrite of the C++ lib
robs [Tue, 20 Nov 2001 02:29:38 +0000 (02:29 +0000)]
include/fcgio.h
libfcgi/fcgio.cpp

index f46639b..cca5b61 100644 (file)
@@ -1,82 +1,22 @@
 //
-// $Id: fcgio.h,v 1.5 2001/06/22 13:15:10 robs Exp $
-//
-// Allows you communicate with FastCGI streams using C++ iostream
-// objects
-//
-// defines classes fcgi_streambuf, fcgi_ostream, fcgi_istream
-// you can redefine cin, cout, cerr or use your own custom
-// FCGI stream names.
-//
-// ORIGINAL AUTHOR: George Feinberg
-//
-//
-// REWRITTEN BY: Michael Richards  06/20/1999
-//          -added cin support
-//          -added ability to replace cin/cout so existing code only
-//           needs to include the header file and use the normal
-//           cin/cout. This has been altered as of 2/2000, see below.
-//          -added buffered read support which is required for ungets.
-//
-//
-// REWRITTEN AGAIN BY: Michael Shell 02/23/2000
-//
-//            Previous versions of this code had problems.
-//            Two hellish bugs have been fixed and there is now full
-//            buffering for both input and output streams.
-//
-//          - fixed signed char bug in underflow() that would
-//            cause a false EOF to be flagged when reading binary
-//            data. Uploading short binary files via <input type=file
-//            which uses multipart/form-data encoding would reveal
-//            this bug. Also could be triggered by hackers
-//            sending binary data instead of legitimate form data,
-//            in which case the hung network connection, depending on
-//            how the FCGI application server handles things, could
-//            form the basis for a stupid denial of service attack.
-//          - fixed code to properly use the get and put buffers via
-//            underflow() and overflow() NOT xsgetn() and xsputn() as
-//            was done before. Because of this, the previous
-//            version would often drop data, especially if the
-//            user did an initial getline() followed by a read().
-//          - added the attach() method and a parameterless
-//            constructor so that you can declare fcgi_iostream
-//            objects and attach() to them later - after accept().
-//          - enhanced docs to include examples that actually work.
-//          - removed any predefined redefinitions of cin,cout,cerr.
-//            The example shows how you can use these names if you
-//            want (via properly placed #undefs) or use ones of your
-//            choosing (such as fin,fout,ferr). This may be very
-//            helpful when testing code. Also, as a result, you
-//            no longer have to place fcgio2.h in any special
-//            order in your #includes.
-//          - added an experimental method drain() to istream which
-//            allows the user to drain the get buffer. This is
-//            designed to provide users with a way to drain the get
-//            buffer prior to using a read function from the FCGI
-//            library in applications which mix I/O methods. i.e.
-//            it is the input equivalent to flush(). It does not
-//            read from the FCGI stream, but gets only characters
-//            already in the istream buffer. Mixing I/O methods is
-//            not recommended since this iostream implementation
-//            is complete and should provide you with everything
-//            you need.
-//
-//
-// NOTES: encapsulates the FastCGI protocol in an iostream via a
-// nice custom streambuf. Very nice, very robust, and very powerful.
+// Provides support for FastCGI via C++ iostreams.\r
+//\r
+// $Id: fcgio.h,v 1.6 2001/11/20 02:29:38 robs Exp $
 //
 // This work is based on routines written by George Feinberg. They
 // have been mostly re-written and extensively changed by
 // Michael Richards.
 //
 // Rewritten again with bug fixes and numerous enhancements by
-// Michael Shell.
+// Michael Shell.\r
+// \r
+// And rewritten again by Rob Saccoccio. 
 //
 // Special Thanks to Dietmar Kuehl for his help and the numerous custom
 // streambuf examples on his web site.
 //
-// Copyright (c) 2000 Tux the Linux Penguin
+// Copyright (c) 2000 Tux the Linux Penguin\r
+// Copyright (c) 2001 Rob Saccoccio and Chelsea Networks
 //
 // You are free to use this software without charge or royalty
 // as long as this notice is not removed or altered, and recognition
 //
 // This code is offered as-is without any warranty either expressed or
 // implied; without even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE.
-// If it breaks, you get to keep both halves.
-
-
-// BEGIN EXAMPLE CODE: test_fcgio2.cpp
-/*
-// This code uses the fcgiapp interface to show a little bit more
-// complexity and to demonstrate the fact that with fcgio2 and just
-// a few more lines of code (like FCGX_Init etc.) you can easily
-// make FastCGI programs without needing wrapper functions.
-// You can use the fcgi_stdio interface if you you want a
-// simpler accept(). However note that the fcgio2 interface
-// removes the need for the fcgi_stdio wrapper functions.
-// i.e. Why override printf when you aren't going to use it anyway?
-// Also, be aware that because of iostream buffering, you must take
-// care when mixing FCGI iostream I/O with the FCGI library I/O
-// commands (such as printf). Be sure to flush() any open
-// fcgi_ostreams prior to using commands such as printf. This is true
-// even on systems which have the C I/O commands synced with C++
-// iostreams, such as Linux, because the FCGI wrapper printf, etc. are
-// not the same as the "normal" printf etc. It is recommended that you
-// not use any FCGI library input (read) commands if you use
-// fcgi_istream (cin) input as there is no easy way to "flush" (drain)
-// an istream get buffer. However, an experimental istream method
-// drain() has been provided to istream for those of you who need to
-// do mixed input. There should be no need to do mixed I/O as the
-// fcgio2 iostream implementation is complete.
-
-#include <stdlib.h>
-#include "fcgio.h"   // fcgio.h includes fcgiapp.h
-                     // however you must include fcgi_stdio.h if
-                     // you want to use it as fcgio.h does not
-                     // include it for you
-
-#undef cin  // remember you have to undo the stuff predefined
-#undef cout // for cin, cout, cerr if you wish to use these
-#undef cerr // names for your FastCGI streams
-
-int main(void)
-{
-
- int count = 0;
-
- // I can create/declare my objects here, but I don't dare use them
- // until I set them up with attach().
-
- // note that version 1.0 of fcgio used fcgio_istream & fcgio_ostream
- // we made a little change to the names in V2.00 for clarity.
- fcgi_istream cin;  // you do not *HAVE* to use these names, you
- fcgi_ostream cout; // could use other stream names of your choice
- fcgi_ostream cerr; // don't forget that the input is
-                    // fcgi_*I*stream class
-
- FCGX_Request request; // here is our request structure
-
- // get everything ready for the customers
- FCGX_Init();
-
- FCGX_InitRequest(&request,0,0);
-
-
- // let the games begin
- while(FCGX_Accept_r(&request) >= 0)
-    {
-    count++;
-
-    cout.attach(request.out); // now I know my pointer values for
-    cerr.attach(request.err); // this request. attach to them
-    cin.attach(request.in);
-    // attach will initialize everything
-    // alternatively, you could declare the streams here and the
-    // constructor with the (FCGX_Stream *str) parameter would
-    // do the same job as attach
-
-    // If you are using fcgi_stdio.h, the equivalent command would
-    // be cout.attach(FCGI_stdout->fcgx_stream);
-    // and so forth for cin,cerr using FCGI_stdin and FCGI_stderr
-    // respectively.
-
-
-    // now I can fire at will:
-    cout << "Content-type: text/html\r\n\r\n"
-         << "<title> FastCGI cin, cout, cerr tester </title>\r\n"
-         << "<h1><center> FastCGI C++ IOstream test: "
-         << "It works! </center></h1>\r\n";
-    cout << "<h4><center><i> Total served by this task: "
-         << count << "</i></center></h4>\r\n";
-
-// didn't use cin or cerr in this example.
-
-// it is good practice to flush the buffers.
-// use cout.flush() if you don't want the line feed.
-
-   cout << endl;
-
-// there is no cxxx.close() and you do not need it with the fcgio
-// interface. You would need to call cxxx.close() if cxxx was an
-// fstream based object and attached to a file descripter you got
-// from a command like fd=open(blah). (GNU (Linux) based fstreams
-// support this) Then you need to call cxxx.close() before you
-// close the physical file with close(fd). If doing this with
-// fstream objects, you should call cxxx.clear() after
-// attach(fd) as the file descriptor attach is not as complete in
-// initialization as our fcgi_iostream attach()
-// If you don't understand any of this, don't worry about it and
-// forget I even mentioned it.
-
-   // all done with this request
-   FCGX_Finish_r(&request);
-
-   // do the next request
-   }
- return (1);
-}
-
-*/
-
-// END EXAMPLE CODE
-
-/*------------------------------------------------------------------*/
-
+// FITNESS FOR A PARTICULAR PURPOSE.  If it breaks, you get to keep \r
+// both halves.
 
 #ifndef FCGIO_H
 #define FCGIO_H
@@ -213,132 +34,92 @@ int main(void)
 
 #include "fcgiapp.h"
 
-// we aren't pulling from the heap, so it is best not to make it too big
-#define FCGIO_BUFSIZE 200
-
-// FastCGI streambuf replacement. Implements low level I/O to the
-// FastCGI C functions so our higher level iostreams will talk
-// in the FastCGI protocol
+/*
+ *  fcgi_streambuf
+ */
 class fcgi_streambuf : public streambuf
 {
-  public:
-    // constructor
-    fcgi_streambuf(void);
-    ~fcgi_streambuf();
+public:
 
-    // handles allocation of buffers by doing nothing since buffer
-    // allocation isn't needed
-    virtual int doallocate();
+    DLLAPI fcgi_streambuf(FCGX_Stream * strm = NULL);
 
-    // gets data (upto the given maximum) from the get buffer and
-    // copies it to the given char array. Returns the number of chars
-    // written or -1 on error. A returned value less than the given
-    // maximum, assuming the user requested at least one char,
-    // indicates that the get buffer is empty. The underflow() method
-    // is never called to refill the get buffer, so this method can be
-    // used to drain the get buffer. It is used to form an istream
-    // drain() method which is the input equivalent to flush().
-    virtual int drain_strm(char *,int);
+    DLLAPI ~fcgi_streambuf(void);
 
-    // let's us know if this strembuf has been initialized
-    virtual int isstrmdefined(void);
+    DLLAPI int attach(FCGX_Stream * strm);
 
-    // (for writers) empties the put buffer and possibly an
-    // overflow char into the FCGI interface
-    virtual int overflow(int);
+    // Consume the put area (if buffered) and c (if c is not EOF).
+    DLLAPI virtual int overflow(int);
 
-    // bogus routine in case somebody thinks they know
-    // better and calls it. We currently are happy with
-    // our static buffer.
-    virtual streambuf * setbuf(char *, int);
+    // Flush the put area (if buffered) and the FCGX buffer to the client.\r
+    // Note: sync() is protected in some implementations.
+    DLLAPI virtual int sync();
 
-    // initializes the buffering and FCGI interface
-    virtual void stream_initialize(FCGX_Stream *,int);
+    // Fill the get area (if buffered) and return the next character.
+    DLLAPI virtual int underflow();
 
-    // (for writers) flushes the put buffer into the FCGI
-    // interface and then flushes the FCGI interface
-    virtual int sync();
+    // Use a buffer.  The only reasons that a buffer would be useful is\r
+    // to support the use of the unget()/putback() or seek() methods.  Using\r
+    // a buffer will result in less efficient I/O.  Note: the underlying\r
+    // FastCGI library (FCGX) maintains its own input and output buffers.  \r
+    // Note: setbuf() is protected in some implementations.
+    DLLAPI virtual streambuf * setbuf(char * buf, int len);
 
-    // (for readers) fills the get buffer with data from the
-    // FCGI interface
-    virtual int underflow();
+    DLLAPI virtual int xsgetn(char * s, int n);\r
+    DLLAPI virtual int xsputn(const char * s, int n);\r
 
-  private:
-    // pointer to our underlying FCGI interface
-    FCGX_Stream * fcgx_strm;
+private:
 
-    // our buffer
-    static int buffersize;
-    char buffer[FCGIO_BUFSIZE];
+    FCGX_Stream * fcgx;
 
-    // little flag so that we can tell if the
-    // fcgi_str pointer was ever set
-    int defined;
+    // buf is just handy to have around\r
+    char * buf;\r
+\r
+    // this isn't kept by the base class\r
+    int bufsize;
+    \r
+    void reset(void);\r
 };
 
-int fcgi_streambuf::buffersize = FCGIO_BUFSIZE;
-
-// Here's the istream class definition.
+/*
+ *  fcgi_istream - deprecated
+ */
 class fcgi_istream : public istream
 {
-  public:
-    fcgi_istream();
-    fcgi_istream(FCGX_Stream *str);
-    ~fcgi_istream();
+public:
 
-    // connects the fcgi_streambuf of  an existing fcgi_istream
-    // object to a given FCGI interface
-    virtual void attach(FCGX_Stream *str);
+    // deprecated
+    DLLAPI fcgi_istream(FCGX_Stream * strm = NULL);
+    
+    // deprecated
+    DLLAPI ~fcgi_istream(void) {}
 
-    // allows you to drain down the streambuf buffer. It will not
-    // read any chars from the FCGI interface. You can repeatedly
-    // call drain() to empty the get buffer prior to using a
-    // FCGI library function to ensure syncronization of the
-    // reads. i.e. it flushes the input stream
-    // This method should be considered both nonstandard and
-    // experimental. It's use is entirely optional to the user,
-    // but could be very helpful for applications which use
-    // both istream and FCGI library based reads on a single
-    // FCGI interface and need a way to sync the reads.
-    // It copies upto the given number of chars into the given
-    // char array. It returns the number of chars written or
-    // -1 on error. If the number of chars written is less than
-    // the number the user requested, the get buffer is empty.
-    // This method does not alter or check any of the input
-    // status flags such as EOF or FAIL since it does not interact
-    // with the underlying FCGI interface at all - it only reads from
-    // the get buffer.
-    virtual int drain(char *,int);
+    // deprecated
+    DLLAPI virtual void attach(FCGX_Stream * strm);
 
-    // lets us know if this object has been initialized
-    virtual int isdefined(void);
+private:
 
-  private:
-    // FastCGI streambuf
     fcgi_streambuf fcgi_strmbuf;
-
 };
 
-
-
-// Here's the ostream class definition.
+/*
+ *  fcgi_ostream - deprecated
+ */
 class fcgi_ostream : public ostream
 {
-  public:
-    fcgi_ostream(void);
-    fcgi_ostream(FCGX_Stream *str);
-    ~fcgi_ostream();
+public:
+    
+    // deprecated
+    DLLAPI fcgi_ostream(FCGX_Stream * strm = NULL);
+    
+    // deprecated
+    DLLAPI ~fcgi_ostream(void) {}
 
-  // connects the fcgi_streambuf of an existing fcgi_ostream
-  // object to a given FCGI interface
-  virtual void attach(FCGX_Stream *str);
+    // deprecated
+    DLLAPI virtual void attach(FCGX_Stream *str);
 
-  // lets us know if this object has been initialized
-  virtual int isdefined(void);
+private:
 
-  private:
-    // FastCGI streambuf
     fcgi_streambuf fcgi_strmbuf;
 };
 
-#endif FCGIO_H
+#endif /* FCGIO_H */
index c1b4367..4deb4e5 100644 (file)
@@ -1,17 +1,12 @@
 //
-// $Id: fcgio.cpp,v 1.5 2001/06/22 14:27:06 robs Exp $
+// $Id: fcgio.cpp,v 1.6 2001/11/20 02:29:39 robs Exp $
 //
-// Allows you communicate with FastCGI streams using C++ iostream
-// objects
+// Allows you communicate with FastCGI streams using C++ iostreams
 //
 // ORIGINAL AUTHOR:     George Feinberg
 // REWRITTEN BY:        Michael Richards  06/20/1999
 // REWRITTEN AGAIN BY:  Michael Shell     02/23/2000
-//
-// Special Thanks to Dietmar Kuehl for his help and the numerous custom
-// streambuf examples on his web site.
-//
-// see the header file fcgio2.h for lotsa docs and a code example.
+// REWRITTEN AGAIN BY:  Rob Saccoccio     11 Nov 2001
 //
 // Copyright (c) 2000 Tux the Linux Penguin
 //
 // implied; without even the implied warranty of MERCHANTABILITY or
 // FITNESS FOR A PARTICULAR PURPOSE.
 
-/*------------------------------------------------------------------*/
-
-#ifdef _WIN32
-#define DLLAPI  __declspec(dllexport)
-#endif
-
+#define DLLAPI  __declspec(dllexport)\r
 #include "fcgio.h"
 
+fcgi_streambuf::fcgi_streambuf(FCGX_Stream * strm) 
+{ 
+    this->fcgx = strm;\r
+    this->buf = NULL;
+    this->bufsize = 0;\r
+    setbuf(NULL, 0);
+}
 
-// **** fcgio_streambuf
-
-// default constructor
-fcgi_streambuf::fcgi_streambuf(void)
-   {
-   // we setup the buffer
-   setb(buffer,buffer + (buffersize * sizeof(char)),0);
-   // but we do not know yet if we are a reader or
-   // a writer
-   setp(0,0);
-   setg(0,0,0);
-
-   // good idea to declare buffer status
-   if (buffersize < 1) unbuffered(1);
-   else unbuffered(0);
-
-   // disarm till initialized
-   fcgx_strm = NULL;
-   defined = 0;
-   }
-
-
-// destructor
-fcgi_streambuf::~fcgi_streambuf(void) {}
-
-
-// do nothing
-int fcgi_streambuf::doallocate()
-   {
-   return (0);
-   }
-
-
-// drain the get area
-// this method provides an advanced feature and is
-// considered experimental, see the header file for docs
-// it is provided as it may save somebody someday
-int fcgi_streambuf::drain_strm(char *s, int n)
-   {
-   int numinget;     // number of chars in get buffer
-   int numtoextract; // number of chars to pull out of the
-                     // get area
-
-   int i;            // counter
-
-   // no meaning if not initialized
-   if (!defined) return (EOF);
-   // is already drained if no buffer
-   if (unbuffered()) return (0);
-
-   numinget = egptr() - gptr(); // calculate how much stuff is in
-                                // the get buffer
-
-   // bogus requests deserve bogus answers
-   if (n<1) return (0);
-
-   // an empty get area is an already drained get area
-   if (numinget<1) return(0);
+fcgi_streambuf::~fcgi_streambuf(void)
+{
+    overflow(EOF);
+    // FCGX_Finish()/FCGX_Accept() will flush and close
+} 
 
-   // the number we extract is the lesser of the number of chars
-   // in the get area and the number of chars the user's array
-   // can hold. Maybe should use a ? operator here.
-   if (numinget<n) numtoextract = numinget;
-   else numtoextract = n;
-
-   // copy over the data
-   // adjust the get pointer
-   // probably could use memcpy() to speed things up,
-   // however this may not be portable and if you are
-   // using drain(), performance is gonna take a back seat
-   for (i=0;i<numtoextract;i++)
-       {
-       s[i] = *gptr();
-       gbump(1);
-       }
-   // all done
-   return (numtoextract);
-   }
-
-
-// little routine so that you can tell if the streambuf
-// was ever initialized
-int fcgi_streambuf::isstrmdefined(void)
-   {
-   return defined;
-   }
-
-
-// overflow is called for flush and every time the put buffer
-// is full. Returns EOF on error
-// This is the only method that actually writes data to
-// the FCGI interface.
 int fcgi_streambuf::overflow(int c)
-  {
-  int numinbuf; // number of chars in put buffer
-
-  // we will not allow a bogus fcgx_strm (because the user
-  // forgot to attach()) to do even more harm.
-  if (!defined) return (EOF);
-
-  // get the number of chars in the put buffer
-  numinbuf = pptr() - pbase();
-
-  // send out the entire put buffer
-  if (numinbuf > 0 && !unbuffered())
-     if (FCGX_PutStr(pbase(), numinbuf, fcgx_strm) < 0) return (EOF);
-
-  // reset the put buffer to empty
-  setp(pbase(),epptr());
-
-  // if we are given an overflow char, send it out too.
-  if (c >= 0)
-     if (FCGX_PutChar(c, fcgx_strm) < 0) return (EOF);
-
-  // all done
-  return (0);
-  }
-
-
-// we have our own methods to setup buffering
-// in case somebody calls this, ignore it
-streambuf * fcgi_streambuf::setbuf(char *s, int n)
-   {
-   // Touch the args to avoid compiler warnings
-   s = NULL; n = 0;
-   return this;
-   }
-
-
-// just sets up the pointer and declares things defined.
-// used by fcgi_iostream attach()
-void fcgi_streambuf::stream_initialize(FCGX_Stream *str, int dir)
-   {
-   // setup the main buffer
-   setb(buffer,buffer + (buffersize * sizeof(char)),0);
-   setp(0,0);
-   setg(0,0,0);
-
-   if (buffersize < 1) unbuffered(1);
-   else // setup the get or put buffers
-      {
-      unbuffered(0);
-      if (dir) // if writer
-         {
-         setg(0,0,0); // no get buffer
-         setp(base(),ebuf()); // buffer is all put
-         }
-      else // reader
-         {
-         setg(base(),ebuf(),ebuf()); // buffer is all get
-         setp(0,0); // no put buffer
-         }
-      }
-
-   // set the FCGI interface
-   fcgx_strm = str;
-   // we are ready for action
-   defined = 1;
-   }
-
-
-// flush all the output
+{
+    if (this->bufsize)
+    {
+        int plen = pptr() - pbase();
+
+        if (plen) 
+        {
+            if (FCGX_PutStr(pbase(), plen, this->fcgx) != plen) return EOF;
+            pbump(-plen);
+        }
+    }
+
+    if (c != EOF) 
+    {
+        if (FCGX_PutChar(c, this->fcgx) != c) return EOF;
+    }
+
+    return 0;
+}
+
+// default base class behaviour seems to be inconsistent\r
 int fcgi_streambuf::sync()
-   {
-   // flush the put area
-   if (overflow(-1) < 0) return (EOF);
-
-   // now flush FCGX
-   return FCGX_FFlush(fcgx_strm);
-   }
-
+{
+    if (overflow(EOF)) return EOF;\r
+    if (FCGX_FFlush(this->fcgx)) return EOF;
+    return 0;
+}
 
-// Underflow is called to get characters to fill up the get buffer
-// so something that uses the stream can get the data. If there
-// is nothing else to read, this returns EOF. This is the only method
-// which reads from the FCGI interface.
 int fcgi_streambuf::underflow()
-   {
-   int numread;
-
-   // we will not allow a bogus fcgx_strm (because the user
-   // forgot to attach()) to do even more harm.
-   if (!defined) return (EOF);
-
-   // if it is unbuffered, then get & return a char
-   if (unbuffered()) return FCGX_GetChar(fcgx_strm);
-
-   // read as much data as we can, then adjust the get area so it
-   // reflects the data we just read
-   numread=FCGX_GetStr(base(), blen(), fcgx_strm);
-   if (numread<=0) return EOF;
-   setg(base(),base(),base()+numread);
-
-   // We avoid a common bug. You NEED the unsigned char cast or
-   // else this routine will return a false EOF when reading
-   // control chars outside the normal ascii range!
-   // i.e. "negative" chars map to positive ints and we
-   // reserve negative return values for EOF and error
-   // conditions. Now, even binary data will come through
-   // perfectly.
-   // The reason the get buffer uses chars rather
-   // than unsigned chars is a mystery from AT&T history.
-   // It probably has to due with the old 7bit text limits.
-   return ((unsigned char)(*eback()));
-   }
-
-
-
-// here comes the higher level iostream stuff
-
-// **** Istream
-
-// parameterless constructor allows us to create first, then
-// initialize later via attach()
-fcgi_istream::fcgi_istream() {}
-
-
-// or we can create and initialize in one step
-// constructor calls ios::init to assign our streambuf to
-// the istream derived class. Also sets up buffering.
-fcgi_istream::fcgi_istream(FCGX_Stream *str)
-   {
-   // initialize as a reader, use all buffering for the
-   // get area
-   fcgi_strmbuf.stream_initialize(str,0);
-   // init is a protected member of ios
-   init(&fcgi_strmbuf);
-   }
-
-
-// destructor
-fcgi_istream::~fcgi_istream() {}
-
-
-// does everything the constructor with parameter does at the
-// request of the programmer
-void fcgi_istream::attach(FCGX_Stream *str)
-   {
-   // initialize as a reader, use all buffering for the
-   // get area
-   fcgi_strmbuf.stream_initialize(str,0);
-   // init is a protected member of ios
-   init(&fcgi_strmbuf);
-   }
-
-
-// experimental method to drain the get buffer. Allows you
-// to sync reads with FCGI library (non-istream reads).
-// reads upto n chars into the s array from the get buffer, does
-// not call underflow(). Returned is the number of chars extracted
-// or EOF on error. If n>0 (normal use) and returns a nonnegative
-// value less than n, the get buffer is empty and it is safe to
-// use an FCGI library read.
-// see the header file for more info
-int fcgi_istream::drain(char *s, int n)
-   {
-   return (fcgi_strmbuf.drain_strm(s,n));
-   }
-
-
-// little routine so that you can tell if the streambuf
-// was ever defined
-int fcgi_istream::isdefined(void)
-   {
-   return (fcgi_strmbuf.isstrmdefined());
-   }
-
-
-
-// **** Ostream
-
-// parameterless constructor allows us to create first, then
-// initialize later via attach()
-fcgi_ostream::fcgi_ostream() {}
-
-
-// or we can create and initialize in one step
-// constructor calls ios::init to assign our streambuf to
-// the ostream derived class. Also sets up buffering
-fcgi_ostream::fcgi_ostream(FCGX_Stream *str)
-  {
-  // initialize as a writer, use all buffering for the
-  // put area
-  fcgi_strmbuf.stream_initialize(str,1);
-  // init is a protected member of ios
-  init(&fcgi_strmbuf);
-  }
-
-
-// destructor
-fcgi_ostream::~fcgi_ostream()
-   {
-   // don't blowup if the user never defined the
-   // stream
-   if (fcgi_strmbuf.isstrmdefined())
-      {
-      // this may protect a few poor souls who forgot to flush
-      // before deleting. Always flush when you are done.
-      fcgi_strmbuf.sync();
-      }
-   }
-
-
-// does everything the constructor with parameter does at the
-// request of the programmer
-void fcgi_ostream::attach(FCGX_Stream *str)
-   {
-   // initialize as a writer, use all buffering for the
-   // put area
-   fcgi_strmbuf.stream_initialize(str,1);
-   // init is a protected member of ios
-   init(&fcgi_strmbuf);
-   }
-
-
-// helper function to find out if this
-// stream was ever initialized.
-int fcgi_ostream::isdefined(void)
-   {
-   return (fcgi_strmbuf.isstrmdefined());
-   }
-
+{
+    if (this->bufsize)
+    {
+        if (in_avail() == 0)
+        {
+            int glen = FCGX_GetStr(eback(), this->bufsize, this->fcgx);
+            if (glen <= 0) return EOF;
+
+            setg(eback(), eback(), eback() + glen);
+        }
+
+        return (unsigned char) *gptr();       
+    }
+    else
+    {
+        return FCGX_GetChar(this->fcgx);
+    } 
+}
+
+void fcgi_streambuf::reset(void)\r
+{\r
+    // it should be ok to set up both the get and put areas\r
+    char * end = this->buf + this->bufsize;\r
+    this->setg(this->buf, this->buf, end);\r
+    this->setb(this->buf, end);\r
+}\r
+\r
+streambuf * fcgi_streambuf::setbuf(char * buf, int len)
+{
+    // XXX support moving data from an old buffer\r
+    if (this->bufsize) return NULL;\r
+\r
+    this->buf = buf;\r
+    this->bufsize = len;\r
+\r
+    // the base setbuf() *has* to be called\r
+    streambuf::setbuf(buf, len);
+
+    reset();\r
+
+    return this;
+}\r
+\r
+int fcgi_streambuf::attach(FCGX_Stream * strm)\r
+{ \r
+    this->fcgx = strm;\r
+\r
+    if (this->bufsize)\r
+    {\r
+        reset();\r
+    }\r
+\r
+    return 0;\r
+}
+
+int fcgi_streambuf::xsgetn(char * s, int n) 
+{\r
+    return (this->bufsize) \r
+        ? streambuf::xsgetn(s, n) \r
+        : FCGX_GetStr(s, n, this->fcgx);
+}\r
+   \r
+int fcgi_streambuf::xsputn(const char * s, int n) 
+{\r
+    return (this->bufsize) \r
+        ? streambuf::xsputn(s, n) \r
+        : FCGX_PutStr(s, n, this->fcgx);\r
+}\r
+\r
+// deprecated\r
+fcgi_istream::fcgi_istream(FCGX_Stream * strm) :\r
+    istream(&fcgi_strmbuf)
+{
+    fcgi_strmbuf.attach(strm);
+}
+
+// deprecated\r
+void fcgi_istream::attach(FCGX_Stream * strm)
+{
+    fcgi_strmbuf.attach(strm);
+}
+
+// deprecated\r
+fcgi_ostream::fcgi_ostream(FCGX_Stream * strm) :
+    ostream(&fcgi_strmbuf)\r
+{
+    fcgi_strmbuf.attach(strm);
+}
+
+// deprecated\r
+void fcgi_ostream::attach(FCGX_Stream * strm)
+{
+    fcgi_strmbuf.attach(strm);
+}