$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r58110 - in sandbox/SOC/2007/cgi/branches/pickmeup: boost/cgi boost/cgi/common boost/cgi/detail boost/cgi/fcgi boost/cgi/http boost/cgi/impl libs/cgi/build/msvc/9.0/Boost.CGI libs/cgi/build/msvc/9.0/Boost.CGI/acgi_hello_world libs/cgi/example/fcgi/echo libs/cgi/example/fcgi/hello_world
From: lists.drrngrvy_at_[hidden]
Date: 2009-12-02 22:43:01
Author: drrngrvy
Date: 2009-12-02 22:43:00 EST (Wed, 02 Dec 2009)
New Revision: 58110
URL: http://svn.boost.org/trac/boost/changeset/58110
Log:
[Tested: MSVC9.0]
* Refactoring basic_client so FastCGI reuses the same functionality for the most part.
* Fixed an issue with FastCGI where the HTTP server would close the connection if the response was sent before the entire request had been read from the server. Modified fcgi_request_service::close() to read all of the data if it hasn't already been read.
* Other code cleanups.
Added:
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/fcgi/response.hpp   (contents, props changed)
Binary files modified: 
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/Boost.CGI.suo
Text files modified: 
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/basic_client.hpp                                                 |   144 ++++++++++++--                          
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/basic_request.hpp                                                |    11                                         
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/error.hpp                                                 |     2                                         
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/response.hpp                                              |     9                                         
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/detail/protocol_traits.hpp                                       |    40 +--                                     
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/fcgi/client.hpp                                                  |   406 ++++++++++++--------------------------- 
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/fcgi/error.hpp                                                   |     5                                         
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/fcgi/request_service.hpp                                         |     4                                         
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/fcgi/specification.hpp                                           |     1                                         
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/http/status_code.hpp                                             |     6                                         
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/impl/fcgi_request_service.ipp                                    |   113 +++-------                              
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/impl/response.ipp                                                |    47 +++-                                    
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/acgi_hello_world/acgi_hello_world.vcproj |     1                                         
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/fcgi/echo/main.cpp                                        |     4                                         
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/fcgi/hello_world/main.cpp                                 |     1                                         
   15 files changed, 367 insertions(+), 427 deletions(-)
Modified: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/basic_client.hpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/basic_client.hpp	(original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/basic_client.hpp	2009-12-02 22:43:00 EST (Wed, 02 Dec 2009)
@@ -15,11 +15,23 @@
 #include "boost/cgi/http/status_code.hpp"
 #include "boost/cgi/common/role_type.hpp"
 #include "boost/cgi/common/request_status.hpp"
+#include "boost/cgi/detail/protocol_traits.hpp"
 #include "boost/cgi/connections/tcp_socket.hpp"
 
 
 BOOST_CGI_NAMESPACE_BEGIN
  namespace common {
+ 
+  enum client_status
+  {
+    none_, // **FIXME** !
+    constructed,
+    params_read,
+    stdin_read,
+    end_request_sent,
+    closed_, // **FIXME** !
+    //aborted
+  };
 
   /// A client
   /**
@@ -44,9 +56,18 @@
   {
   public:
     //typedef BOOST_CGI_NAMESPACE::map                          map_type;
+    typedef ::BOOST_CGI_NAMESPACE::common::io_service   io_service_type;
+    typedef ::BOOST_CGI_NAMESPACE::common::map          map_type;
     typedef Connection                        connection_type;
     typedef Protocol                          protocol_type;
     typedef typename connection_type::pointer connection_ptr;
+    typedef boost::array<unsigned char, 8>    header_buffer_type;
+    typedef boost::asio::mutable_buffers_1    mutable_buffers_type;
+    typedef typename 
+      detail::protocol_traits<
+          Protocol
+      >::role_type                              role_type;
+
 
     basic_client()
     {
@@ -56,33 +77,52 @@
       //: io_service_(ios)
     {
     }
-
-    bool is_open()
-    {
-      return connection_->is_open();
-    }
-
-    void close()
-    {
-      connection_->close();
-    }
-
-    boost::uint16_t const& request_id() const
-    {
-      return 1;
+    
+    /// Construct the client by claiming a request id.
+    /**
+     * Before loading a request, it will usually not have a request id. This
+     * function reads headers (and corresponding bodies if necessary) until
+     * a BEGIN_REQUEST record is found. The calling request then claims and
+     * serves that request.
+     */
+    template<typename RequestImpl>
+    boost::system::error_code
+      construct(RequestImpl& req, boost::system::error_code& ec)
+    {
+      status_ = constructed;
+      return ec;
+    }
+    
+    boost::system::error_code
+      close(boost::uint64_t app_status, boost::system::error_code& ec)
+    {
+      if (!is_open())
+        ec = error::already_closed;
+      else
+      {
+        status_ = closed_;
+        connection_->close();
+      }
+    }
+
+    void close(boost::uint64_t app_status = 0)
+    {
+      boost::system::error_code ec;
+      close(app_status, ec);
+      detail::throw_error(ec);
     }
 
     /// Associate a connection with this client
     /**
      * Note: the connection must have been created using the new operator
-     *
+     */
     bool set_connection(connection_type* conn)
     {
       // make sure there isn't already a connection associated with the client
-      if (!connection_) return false;
+      //if (!connection_) return false;
       connection_.reset(conn);
       return true;
-    }*/
+    }
 
     //io_service& io_service() { return io_service_; }
 
@@ -99,10 +139,6 @@
       return true;
     }
 
-    /// Get a shared_ptr of the connection associated with the client.
-    connection_ptr& connection() { return connection_; }
-    std::size_t& bytes_left()    { return bytes_left_; }
-
     /// Write some data to the client.
     template<typename ConstBufferSequence>
     std::size_t write_some(const ConstBufferSequence& buf
@@ -111,7 +147,20 @@
       return connection_->write_some(buf, ec);
     }
 
-    /// Read some data from the client.
+    /// Read data into the supplied buffer.
+    /**
+     * Reads some data that, correctly checking and stripping FastCGI headers.
+     *
+     * Returns the number of bytes read and sets `ec` such that `ec` evaluates
+     * to `true` iff an error occured during the read operation.
+     *
+     * Notable errors:
+     * - `fcgi::error::data_for_another_request`
+     * - `fcgi::error::connection_locked`
+     *
+     * These must be dealt with by user code if they choose to read through the
+     * client (reading through the request is recommended).
+     */
     template<typename MutableBufferSequence>
     std::size_t read_some(const MutableBufferSequence& buf
                          , boost::system::error_code& ec)
@@ -145,6 +194,41 @@
     {
       connection_->async_read_some(buf, handler);
     }
+    
+    
+    ////// Querying the client.
+
+    /// Get a shared_ptr of the connection associated with the client.
+    connection_ptr& connection() { return connection_; }
+    std::size_t& bytes_left()    { return bytes_left_; }
+    
+    bool is_open()
+    {
+      return connection_->is_open();
+    }
+
+    /// Get the status of the client.
+    const client_status& status() const
+    {
+      return status_;
+    }
+
+    /// Set the status of the client.
+    void status(client_status status)
+    {
+      status_ = status;
+    }
+
+    bool keep_connection() const
+    {
+      return keep_connection_;
+    }
+    
+    boost::uint16_t const& request_id() const
+    {
+      return request_id_;
+    }
+
   private:
     //io_service&                           io_service_;
     connection_ptr                        connection_;
@@ -152,6 +236,22 @@
   public: // **FIXME**
     // we should never read more than content-length bytes.
     std::size_t                           bytes_left_;
+    
+    boost::uint16_t request_id_;
+    client_status status_;
+    
+    boost::uint64_t total_sent_bytes_;
+    boost::uint64_t total_sent_packets_;
+
+    /// Buffer used to check the header of each packet.
+    //header_buffer_type out_header_;
+    fcgi::spec::header header_;
+
+    /// Output buffer.
+    std::vector<boost::asio::const_buffer> outbuf_;
+
+    bool keep_connection_;
+    role_type role_;
   };
 
  } // namespace common
Modified: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/basic_request.hpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/basic_request.hpp	(original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/basic_request.hpp	2009-12-02 22:43:00 EST (Wed, 02 Dec 2009)
@@ -155,18 +155,21 @@
          return impl->count(key);
       }
       
-      mapped_type& get(key_type const& key, mapped_type const& default_)
+      mapped_type const&
+        get(key_type const& key, mapped_type const& default_) const
       {
         BOOST_ASSERT(impl);
         const_iterator iter = impl->find(key);
-        return iter == impl->end() > default_ : *iter;
+        return iter == impl->end() ? default_ : iter->second;
       }
       
       template<typename T>
       T as(key_type const& key) {
         BOOST_ASSERT(impl);
-        mapped_type& val((*impl)[key]);
-        return val.empty() ? T() : boost::lexical_cast<T>(val);
+        const_iterator iter = impl->find(key);
+        return iter == impl->end()
+                     ? T()
+                     : boost::lexical_cast<T>(val);
       }
       
       mapped_type& operator[](key_type const& varname) {
Modified: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/error.hpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/error.hpp	(original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/error.hpp	2009-12-02 22:43:00 EST (Wed, 02 Dec 2009)
@@ -67,6 +67,8 @@
   // Expected a boundary marker for a multipart form, but did not find it.
   no_boundary_marker,
   
+  already_closed,
+  
   // The content length of the file upload is larger than maximum allowed
   // by the BOOST_CGI_POST_MAX macro.
   max_post_exceeded
Modified: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/response.hpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/response.hpp	(original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/response.hpp	2009-12-02 22:43:00 EST (Wed, 02 Dec 2009)
@@ -141,9 +141,9 @@
     /// Get the contents of the response as a string.
     /**
      * This copies the contents of the response into a string.
-     * Headers aren't included in the dump.
+     * Headers aren't included in the dump unless `include_header` is true.
      */
-    string_type str() const;
+    string_type str(bool include_header = false) const;
 
     /// Format and add a header given name and value, appending CRLF.
     basic_response<char_type>&
@@ -155,7 +155,10 @@
 
     void reset_headers();
     
-    string_type& charset() { return charset_; }
+    /// Get the charset.
+    string_type& charset() const { return charset_; }
+    /// Set the charset.
+    void charset(string_type const& cs) { charset_ = cs; }
 
     bool headers_terminated() const;
 
Modified: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/detail/protocol_traits.hpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/detail/protocol_traits.hpp	(original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/detail/protocol_traits.hpp	2009-12-02 22:43:00 EST (Wed, 02 Dec 2009)
@@ -16,10 +16,13 @@
 #ifndef CGI_REQUEST_TRAITS_HPP_INCLUDED__
 #define CGI_REQUEST_TRAITS_HPP_INCLUDED__
 
+#include <boost/none.hpp>
 #include <boost/shared_ptr.hpp>
 ///////////////////////////////////////////////////////////
 #include "boost/cgi/fwd/basic_protocol_service_fwd.hpp"
 #include "boost/cgi/common/tags.hpp"
+#include "boost/cgi/common/role_type.hpp"
+#include "boost/cgi/fcgi/specification.hpp"
 #include "boost/cgi/fwd/basic_request_fwd.hpp"
 #include "boost/cgi/fwd/basic_connection_fwd.hpp"
 
@@ -42,8 +45,6 @@
   {
   class fcgi_request_impl;
   class fcgi_service_impl;
-  class fcgi_gateway_impl;
-  class fcgi_gateway_service;
   class fcgi_request_service;
   class fcgi_acceptor_service;
   }
@@ -51,8 +52,6 @@
   {
   class scgi_request_impl;
   class scgi_service_impl;
-  class scgi_gateway_impl;
-  class scgi_gateway_service;
   class scgi_request_service;
   class scgi_acceptor_service;
   }
@@ -64,23 +63,11 @@
   class async_cgi_request_impl;
   class fcgi_request_impl;
 
-  //template<typename>
   class cgi_service_impl;
   class acgi_service_impl;
   class async_cgi_service_impl;
   class fcgi_service_impl;
 
-  class cgi_gateway_impl;
-  class acgi_gateway_impl;
-  class async_cgi_gateway_impl;
-  class fcgi_gateway_impl;
-
-  class cgi_gateway_service;
-  class acgi_gateway_service;
-  class async_cgi_gateway_service;
-  class fcgi_gateway_service;
-  template<typename> class gateway_service;
-
   class acgi_acceptor_service;
   class fcgi_acceptor_service;
 
@@ -112,8 +99,8 @@
               >                                      request_type; 
       typedef cgi_service_impl                       service_impl_type;
       typedef common::basic_connection<tags::stdio>  connection_type;
-//    typedef cgi_gateway_impl                       gateway_impl_type;
-//    typedef cgi_gateway_service                    gateway_service_impl_type;
+      typedef boost::none_t                          header_type;
+      typedef common::role_type                      role_type;
     };
 
     template<>
@@ -133,13 +120,12 @@
       typedef common::basic_connection<
                   tags::async_stdio
               >                                      connection_type;
-      typedef async_cgi_gateway_impl                 gateway_impl_type;
-      typedef async_cgi_gateway_service              gateway_service_type;
+      typedef boost::none_t                          header_type;
+      typedef common::role_type                      role_type;
     };
 
     template<>
     struct protocol_traits<tags::acgi>
-    //  : protocol_traits<tags::async_cgi>
     {
       typedef protocol_traits<tags::acgi>            type;
       typedef acgi::request_impl                     impl_type;
@@ -154,8 +140,8 @@
       typedef common::basic_connection<
                   tags::async_stdio
               >                                      connection_type;
-      typedef acgi_gateway_impl                      gateway_impl_type;
-      typedef acgi_gateway_service                   gateway_service_type;
+      typedef boost::none_t                          header_type;
+      typedef common::role_type                      role_type;
     };
 
     template<>
@@ -172,15 +158,13 @@
                 , protocol_service_type
               >                                      request_type; 
       typedef boost::shared_ptr<request_type>        request_ptr;
-      //typedef fcgi_request_service
-      //        ::implementation_type                  request_impl_type;
       typedef fcgi::fcgi_service_impl                service_impl_type;
       typedef fcgi::fcgi_acceptor_service            acceptor_service_impl;
       typedef common::basic_connection<
                   tags::shareable_tcp_socket
               >                                      connection_type;
-      //typedef fcgi_gateway_impl                      gateway_impl_type;
-      //typedef fcgi_gateway_service                   gateway_service_type;
+      typedef fcgi::spec::header                     header_type;
+      typedef fcgi::spec_detail::role_types          role_type;
     };
 
     template<>
@@ -196,8 +180,6 @@
       typedef scgi::scgi_service_impl                service_impl_type;
       typedef scgi::scgi_acceptor_service            acceptor_service_impl;
       typedef common::basic_connection<tags::tcp_socket>     connection_type;
-      //typedef scgi_gateway_impl                      gateway_impl_type;
-      //typedef scgi_gateway_service                   gateway_service_type;
     };
 
     // **FIXME** (remove)
Modified: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/fcgi/client.hpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/fcgi/client.hpp	(original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/fcgi/client.hpp	2009-12-02 22:43:00 EST (Wed, 02 Dec 2009)
@@ -35,313 +35,167 @@
 BOOST_CGI_NAMESPACE_BEGIN
  namespace common {
 
-  enum client_status
-  {
-    none_, // **FIXME** !
-    constructed,
-    params_read,
-    stdin_read,
-    end_request_sent,
-    closed_, // **FIXME** !
-    //aborted
-  };
-
   /// A client that uses a TCP socket that owned by it.
-  template<typename Protocol>
-  class basic_client<connections::shareable_tcp, Protocol>
+  /// Construct
+  template<>
+  basic_client<
+      connections::shareable_tcp
+    , ::BOOST_CGI_NAMESPACE::common::tags::fcgi
+  >::basic_client()
+    : request_id_(-1)
+    , status_(none_)
+    , keep_connection_(false)
+    , total_sent_bytes_(0)
+    , total_sent_packets_(0)
+    , header_()
+    , outbuf_()
   {
-  public:
-    typedef ::BOOST_CGI_NAMESPACE::common::io_service   io_service_type;
-    typedef ::BOOST_CGI_NAMESPACE::common::map          map_type;
-    typedef Protocol                                    protocol_type;
-    typedef connections::shareable_tcp                  connection_type;
-    typedef typename connection_type::pointer           connection_ptr;
-    typedef boost::array<
-        unsigned char
-      , fcgi::spec::header_length::value
-    >                                         header_buffer_type;
-    typedef boost::asio::mutable_buffers_1    mutable_buffers_type;
-    typedef fcgi::spec_detail::role_types     role_type;
-
-    /// Construct
-    basic_client()
-      : request_id_(-1)
-      , status_(none_)
-      , keep_connection_(false)
-      , total_sent_bytes_(0)
-      , total_sent_packets_(0)
-      , header_()
-      , outbuf_()
-    {
-    }
+  }
 
-    /// Construct
-    basic_client(io_service_type& ios)
-      : request_id_(-1)
-      , status_(none_)
-      , keep_connection_(false)
-      , total_sent_bytes_(0)
-      , total_sent_packets_(0)
-      , header_()
-      , outbuf_()
-    {
-    }
-
-    /// Destroy
-    /** Closing the connection as early as possible is good for efficiency */
-    ~basic_client()
-    {
-      close();
-    }
-
-    /// Construct the client by claiming a request id.
-    /**
-     * Before loading a request, it will usually not have a request id. This
-     * function reads headers (and corresponding bodies if necessary) until
-     * a BEGIN_REQUEST record is found. The calling request then claims and
-     * serves that request.
-     */
-    template<typename RequestImpl>
-    boost::system::error_code
-      construct(RequestImpl& req, boost::system::error_code& ec)
-    {
-      status_ = constructed;
-      return ec;
-    }
-
-    bool is_open() const
-    {
-      return connection_->is_open();
-    }
-
-    void close(boost::uint64_t app_status = 0)
-    {
-      boost::system::error_code ec;
-      close(app_status, ec);
-      detail::throw_error(ec);
-    }
+  /// Construct
+  template<>
+  basic_client<
+      connections::shareable_tcp
+    , ::BOOST_CGI_NAMESPACE::common::tags::fcgi
+  >::basic_client(io_service_type& ios)
+    : request_id_(-1)
+    , status_(none_)
+    , keep_connection_(false)
+    , total_sent_bytes_(0)
+    , total_sent_packets_(0)
+    , header_()
+    , outbuf_()
+  {
+  }
 
-    boost::system::error_code
-      close(boost::uint64_t app_status, boost::system::error_code& ec)
+  /// Override basic_client::close().
+  /**
+   * Closing a FastCGI means sending an END_REQUEST header
+   * to the HTTP server and potentially closing the connection.
+   *
+   * Note that in general the HTTP server is responsible for the
+   * lifetime of the connection, but can hand that control over
+   * to the library (eg. if the server is set up to recycle
+   * connections after N requests).
+   */
+  template<>
+  boost::system::error_code
+  basic_client<
+      connections::shareable_tcp
+    , ::BOOST_CGI_NAMESPACE::common::tags::fcgi
+  >::close(boost::uint64_t app_status, boost::system::error_code& ec)
+  {
+    // Note that the request may already be closed if the client aborts
+    // the connection.
+    if (!is_open())
+      ec = error::already_closed;
+    else
     {
-      // We can safely ignore this next bit when the connection
-      // is already closed. This might happen when the client aborts
-      // the connection.
-      if (!ec && status_ != closed_ && connection_->is_open())
-      {
-        outbuf_.clear();
-        header_.reset(fcgi::spec_detail::END_REQUEST, request_id_, 8);
+      status_ = closed_;
+      outbuf_.clear();
+      header_.reset(fcgi::spec_detail::END_REQUEST, request_id_, 8);
 
-        // Write an EndRequest packet to the server.
-        fcgi::spec::end_request_body body(
-          app_status, fcgi::spec_detail::REQUEST_COMPLETE);
+      // Write an EndRequest packet to the server.
+      fcgi::spec::end_request_body body(
+        app_status, fcgi::spec_detail::REQUEST_COMPLETE);
 
-        outbuf_.push_back(header_.data());
-        outbuf_.push_back(body.data());
+      outbuf_.push_back(header_.data());
+      outbuf_.push_back(body.data());
 
-        write(*connection_, outbuf_, boost::asio::transfer_all(), ec);
+      write(*connection_, outbuf_, boost::asio::transfer_all(), ec);
 
-        if (!ec && !keep_connection_)
-        {
-          connection_->close();
-        }
-      }
-      
-      if (ec && !keep_connection_)
+      if (!ec && !keep_connection_)
       {
-        // If there was an error writing to the client, we can ignore it
-        // unless the `keep_connection_` flag is set.
-        // The client has likely aborted the request if we reach here.
-        ec = boost::system::error_code();
+        connection_->close();
       }
-      return ec;
     }
+    return ec;
+  }
 
-    /// Associate a connection with this client
-    /**
-     * Note: the connection must have been created using the new operator
-     */
-    bool set_connection(connection_type* conn)
-    {
-      // make sure there isn't already a connection associated with the client
-      //if (!connection_) return false;
-      connection_.reset(conn);
-      return true;
-    }
+  /// Write some data to the client.
+  template<>
+  template<typename ConstBufferSequence>
+  std::size_t 
+  basic_client<
+      connections::shareable_tcp
+    , ::BOOST_CGI_NAMESPACE::common::tags::fcgi
+  >::write_some(
+      const ConstBufferSequence& buf
+    , boost::system::error_code& ec
+  )
+  {
+    typename ConstBufferSequence::const_iterator iter = buf.begin();
+    typename ConstBufferSequence::const_iterator end  = buf.end(); 
 
-    /// Associate a connection with this client
-    bool set_connection(const connection_type::pointer& conn)
-    {
-      // make sure there isn't already a connection associated with the client
-      //if (!connection_) return false;
-      connection_ = conn;
-      return true;
-    }
+    outbuf_.clear();
+    outbuf_.push_back(boost::asio::buffer(header_.data()));
 
-    /// Get a shared_ptr of the connection associated with the client.
-    connection_type::pointer&
-    connection() { return connection_; }
-
-    /// Write some data to the client.
-    template<typename ConstBufferSequence>
-    std::size_t 
-    write_some(const ConstBufferSequence& buf, boost::system::error_code& ec)
+    int total_buffer_size(0);
+    for(; iter != end; ++iter)
     {
-      typename ConstBufferSequence::const_iterator iter = buf.begin();
-      typename ConstBufferSequence::const_iterator end  = buf.end(); 
-
-      outbuf_.clear();
-      outbuf_.push_back(boost::asio::buffer(header_.data()));
-
-      int total_buffer_size(0);
-      for(; iter != end; ++iter)
+      boost::asio::const_buffer buffer(*iter);
+      std::size_t new_buf_size( boost::asio::buffer_size(*iter) );
+      if (total_buffer_size + new_buf_size 
+           > static_cast<std::size_t>(fcgi::spec::max_packet_size::value))
       {
-        boost::asio::const_buffer buffer(*iter);
-        std::size_t new_buf_size( boost::asio::buffer_size(*iter) );
-        if (total_buffer_size + new_buf_size 
-             > static_cast<std::size_t>(fcgi::spec::max_packet_size::value))
+        // If the send buffer is empty, extract a chunk of the
+        // new buffer to send. If there is already some data
+        // ready to send, don't add any more data to the pack.
+        if (total_buffer_size == 0)
         {
-          // If the send buffer is empty, extract a chunk of the
-          // new buffer to send. If there is already some data
-          // ready to send, don't add any more data to the pack.
-          if (total_buffer_size == 0)
-          {
-            total_buffer_size
-              = std::min<std::size_t>(new_buf_size,65500);
-            /*
-            std::cerr<< "Oversized buffer: " << total_buffer_size
-                     << " / " << new_buf_size << " bytes sent\n";
-            */
-            outbuf_.push_back(
-              boost::asio::buffer(*iter, total_buffer_size));
-            break;
-          }
-          else
-            break;
+          total_buffer_size
+            = std::min<std::size_t>(new_buf_size,65500);
+          /*
+          std::cerr<< "Oversized buffer: " << total_buffer_size
+                   << " / " << new_buf_size << " bytes sent\n";
+          */
+          outbuf_.push_back(
+            boost::asio::buffer(*iter, total_buffer_size));
+          break;
         }
         else
-        {
-          total_buffer_size += new_buf_size;
-          outbuf_.push_back(*iter);
-        }
+          break;
+      }
+      else
+      {
+        total_buffer_size += new_buf_size;
+        outbuf_.push_back(*iter);
       }
-      header_.reset(fcgi::spec_detail::STDOUT, request_id_, total_buffer_size);
-      
-      std::size_t bytes_transferred
-        = boost::asio::write(*connection_, outbuf_
-                            , boost::asio::transfer_all(), ec);
-
-      
-      std::cerr<< "Transferred " << bytes_transferred
-               << " / " << total_buffer_size << " bytes (running total: "
-               << total_sent_bytes_ << " bytes; "
-               << total_sent_packets_ << " packets).\n";
-      if (ec)
-        std::cerr<< "Error " << ec << ": " << ec.message() << '\n';
-      
-      total_sent_bytes_ += bytes_transferred;
-      total_sent_packets_ += 1;
-      // Now remove the protocol overhead from the caller, who
-      // doesn't care about them.
-      bytes_transferred -= fcgi::spec::header_length::value;
-      // Check everything was written ok.
-      if (!ec && bytes_transferred != total_buffer_size)
-        ec = ::BOOST_CGI_NAMESPACE::fcgi::error::couldnt_write_complete_packet;
-
-      return bytes_transferred;
-    }
-
-    /// Read data into the supplied buffer.
-    /**
-     * Reads some data that, correctly checking and stripping FastCGI headers.
-     *
-     * Returns the number of bytes read and sets `ec` such that `ec` evaluates
-     * to `true` iff an error occured during the read operation.
-     *
-     * Notable errors:
-     * - `fcgi::error::data_for_another_request`
-     * - `fcgi::error::connection_locked`
-     *
-     * These must be dealt with by user code if they choose to read through the
-     * client (reading through the request is recommended).
-     */
-    template<typename MutableBufferSequence>
-    std::size_t
-    read_some(const MutableBufferSequence& buf, boost::system::error_code& ec)
-    {
-      return connection_->read_some(buf, ec);
-    }
-
-    /// Asynchronously write some data to the client.
-    template<typename ConstBufferSequence, typename Handler>
-    void async_write_some(const ConstBufferSequence& buf, Handler handler)
-    {
-      connection_->async_write_some(buf, handler);
-    }
-
-    /// Asynchronously read some data from the client.
-    template<typename MutableBufferSequence, typename Handler>
-    void async_read_some(const MutableBufferSequence& buf, Handler handler)
-    {
-      connection_->async_read_some(buf, handler);
-    }
-
-
-    /// Get the status of the client.
-    const client_status& status() const
-    {
-      return status_;
-    }
-
-    /// Set the status of the client.
-    void status(client_status status)
-    {
-      status_ = status;
-    }
-
-    bool keep_connection() const
-    {
-      return keep_connection_;
-    }
-
-    std::size_t& bytes_left()
-    {
-      return bytes_left_;
-    }
-
-    boost::uint16_t const& request_id() const
-    {
-      return request_id_;
     }
-
-  public:
-    friend class fcgi_request_service;
-    boost::uint16_t request_id_;
-    client_status status_;
-    std::size_t bytes_left_;    
-    connection_ptr   connection_;
+    header_.reset(fcgi::spec_detail::STDOUT, request_id_, total_buffer_size);
     
-    boost::uint64_t total_sent_bytes_;
-    boost::uint64_t total_sent_packets_;
-
-    /// Buffer used to check the header of each packet.
-    //header_buffer_type out_header_;
-    fcgi::spec::header header_;
+    std::size_t bytes_transferred
+      = boost::asio::write(*connection_, outbuf_
+                          , boost::asio::transfer_all(), ec);
 
-    /// Output buffer.
-    std::vector<boost::asio::const_buffer> outbuf_;
-
-    bool keep_connection_;
-    role_type role_;
+    total_sent_bytes_ += bytes_transferred;
+    total_sent_packets_ += 1;
+    
+    if (ec)
+      std::cerr<< "Error " << ec << ": " << ec.message() << '\n';
+    else    
+      std::cerr
+        << "Transferred " << bytes_transferred
+        << " / " << total_buffer_size << " bytes (running total: "
+        << total_sent_bytes_ << " bytes; "
+        << total_sent_packets_ << " packets).\n";
+
+    // Now remove the protocol overhead for the caller, who
+    // doesn't care about them.
+    bytes_transferred -= fcgi::spec::header_length::value;
+    // Check everything was written ok.
+    if (!ec && bytes_transferred != total_buffer_size)
+      ec = ::BOOST_CGI_NAMESPACE::fcgi::error::couldnt_write_complete_packet;
 
-  };
+    return bytes_transferred;
+  }
 
  } // namespace common
 
 namespace fcgi {
     typedef
       common::basic_client<
-        connections::shareable_tcp, ::BOOST_CGI_NAMESPACE::common::fcgi_
+        connections::shareable_tcp, ::BOOST_CGI_NAMESPACE::common::tags::fcgi
       >
     client;
 } // namespace fcgi
Modified: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/fcgi/error.hpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/fcgi/error.hpp	(original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/fcgi/error.hpp	2009-12-02 22:43:00 EST (Wed, 02 Dec 2009)
@@ -73,6 +73,9 @@
   // (I have no access to a server that supports it)
   multiplexing_not_supported,
   
+  // The client has already been closed.
+  already_closed,
+  
   // An empty FastCGI packet was read (eg. STDIN or GET_PARAM data has been read).
   //empty_packet_read,
   
@@ -98,6 +101,8 @@
              "multiplexed). This isn't handled for now. **FIXME**";
     case accepting_on_an_open_request:
       return "You called async_accept before closing a request.";
+    case already_closed:
+      return "The client has already been closed.";
     case multiplexing_not_supported:
       return "Multiplexing connections are not yet supported.";
     //case empty_packet_read:
Modified: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/fcgi/request_service.hpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/fcgi/request_service.hpp	(original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/fcgi/request_service.hpp	2009-12-02 22:43:00 EST (Wed, 02 Dec 2009)
@@ -154,9 +154,11 @@
       impl.service_ = &ps;
     }
 
+    /// Check if the request is still open.
     bool is_open(implementation_type& impl)
     {
-      return !impl.all_done_ && impl.client_.is_open();
+      return impl.request_status_ != common::null
+          && !impl.all_done_ && impl.client_.is_open();
     }
 
     /// Close the request.
Added: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/fcgi/response.hpp
==============================================================================
--- (empty file)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/fcgi/response.hpp	2009-12-02 22:43:00 EST (Wed, 02 Dec 2009)
@@ -0,0 +1,21 @@
+//                 -- fcgi/response.hpp --
+//
+//            Copyright (c) Darren Garvey 2009.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+//
+////////////////////////////////////////////////////////////////
+#ifndef CGI_FCGI_RESPONSE_HPP_INCLUDED__
+#define CGI_FCGI_RESPONSE_HPP_INCLUDED__
+
+#include "boost/cgi/common/response.hpp"
+
+namespace boost { namespace fcgi {
+
+  typedef ::BOOST_CGI_NAMESPACE::common::response response;
+
+} }
+
+#endif // CGI_FCGI_RESPONSE_HPP_INCLUDED__
+
Modified: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/fcgi/specification.hpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/fcgi/specification.hpp	(original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/fcgi/specification.hpp	2009-12-02 22:43:00 EST (Wed, 02 Dec 2009)
@@ -10,6 +10,7 @@
 #define CGI_FCGI_SPECIFICATION_HPP_INCLUDED__
 
 #include <boost/cstdint.hpp>
+#include <boost/asio/buffer.hpp>
 
 // NOTE: CamelCase style mimicks the FastCGI specification
 // SEE: http://www.fastcgi.com/devkit/doc/fcgi-spec.html#S8
Modified: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/http/status_code.hpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/http/status_code.hpp	(original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/http/status_code.hpp	2009-12-02 22:43:00 EST (Wed, 02 Dec 2009)
@@ -84,9 +84,11 @@
   } // namespace http
  } // namespace common
 
-  using namespace common::http; // **FIXME**
-
 BOOST_CGI_NAMESPACE_END
 
+namespace boost { namespace http {
+  using namespace ::BOOST_CGI_NAMESPACE::common::http;
+} } // namespace boost::http
+
 #endif // CGI_HTTP_STATUS_CODE_HPP_INCLUDED__
 
Modified: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/impl/fcgi_request_service.ipp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/impl/fcgi_request_service.ipp	(original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/impl/fcgi_request_service.ipp	2009-12-02 22:43:00 EST (Wed, 02 Dec 2009)
@@ -72,20 +72,35 @@
     /// Close the request.
     BOOST_CGI_INLINE int
     fcgi_request_service::close(
-        implementation_type& impl, ::BOOST_CGI_NAMESPACE::common::http::status_code& hsc
+        implementation_type& impl
+      , ::BOOST_CGI_NAMESPACE::common::http::status_code& hsc
       , int program_status)
     {
-      impl.all_done_ = true;
-      impl.client_.close(program_status);
-      impl.request_status_ = common::closed;
+      boost::system::error_code ec;
+      close(impl, hsc, program_status, ec);
+      detail::throw_error(ec);
       return program_status;
     }
 
     BOOST_CGI_INLINE int
     fcgi_request_service::close(
-        implementation_type& impl, ::BOOST_CGI_NAMESPACE::common::http::status_code& hsc
-      , int program_status, boost::system::error_code& ec)
+        implementation_type& impl
+      , ::BOOST_CGI_NAMESPACE::common::http::status_code& hsc
+      , int program_status
+      , boost::system::error_code& ec)
     {
+      /**
+       * Apache on Windows with mod_fcgid requires that all of the
+       * pending data for the connection is read before the response
+       * is sent.
+       */
+      while(!ec 
+        && impl.client_.status() < common::stdin_read
+        && impl.request_status_ != common::loaded)
+      {
+        parse_packet(impl, ec);
+      }
+
       impl.all_done_ = true;
       impl.client_.close(program_status, ec);
       impl.request_status_ = common::closed;
@@ -115,7 +130,6 @@
       impl.request_status_ = common::null;
       impl.request_role_ = spec_detail::ANY;
       impl.all_done_ = false;
-
       impl.client_.status_ = common::none_;
       impl.client_.request_id_ = -1;
     }
@@ -140,7 +154,7 @@
 
       impl.client_.construct(impl, ec);
       // Bomb out if the client isn't open here.
-      if (!impl.client_.connection_->is_open())
+      if (!impl.client_.connection()->is_open())
           return error::client_not_open;
 
       while(!ec)
@@ -198,22 +212,23 @@
           && opts & common::parse_post_only)
       {
         std::cerr<< "Parsing post vars now.\n";
+
+        if (opts & common::parse_post_only)
+        {
+          while(!ec 
+            && impl.client_.status() < common::stdin_read
+            && impl.request_status_ != common::loaded)
+          {
+            parse_packet(impl, ec);
+          }
+        }
+        
         if (parse_post_vars(impl, ec))
               return ec;
       }
       if (opts & common::parse_cookies_only)
         parse_cookie_vars(impl, ec);
         
-      if (opts & common::parse_post_only)
-      {
-        while(!ec 
-          && impl.client_.status() < common::stdin_read
-          && impl.request_status_ != common::loaded)
-        {
-          parse_packet(impl, ec);
-        }
-      }
-        
       if (ec == error::eof) {
         ec = boost::system::error_code();
         return ec;
@@ -365,23 +380,10 @@
       // clear the header first (might be unneccesary).
       impl.header_buf_ = implementation_type::header_buffer_type();
 
-      if (8 != read(*impl.client_.connection_, buffer(impl.header_buf_)
+      if (8 != read(*impl.client_.connection(), buffer(impl.header_buf_)
                    , boost::asio::transfer_all(), ec) || ec)
         return ec;
       
-      //if (ec) return ec;
-
-      /*
-      std::cerr<< std::endl
-          << "[hw] Header details {" << std::endl
-          << "  RequestId := " << fcgi::spec::get_request_id(impl.header_buf_) << std::endl
-          << "  FastCGI version := " << fcgi::spec::get_version(impl.header_buf_) << std::endl
-          << "  Type := " << fcgi::spec::get_type(impl.header_buf_)
-          << " (" << fcgi::spec::request_type::to_string(impl.header_buf_) << ")" << std::endl
-          << "  Content-length := " << fcgi::spec::get_content_length(impl.header_buf_) << std::endl
-          << "}" << std::endl;
-      */
-
       return ec;
     }
 
@@ -422,17 +424,6 @@
       }catch(...){
         ec = error::abort_request_record_recieved_for_invalid_request;
       }
-/*
-      connection_type::request_map_type::iterator i
-        = connection_->find(id);
-
-      if (i == connection_type::request_map_type::iterator())
-      {
-        return bad_request_id;
-      }
-
-      //lookup_request(id).abort();
-*/
       return ec;
     }
 
@@ -586,7 +577,7 @@
       , boost::system::error_code& ec)
     {
       std::size_t bytes_read
-        = read(*impl.client_.connection_, buf
+        = read(*impl.client_.connection(), buf
               , boost::asio::transfer_all(), ec);
 
       BOOST_ASSERT(bytes_read == fcgi::spec::get_length(impl.header_buf_)
@@ -659,24 +650,6 @@
 BOOST_CGI_NAMESPACE_BEGIN
  namespace fcgi {
 
-/*
-    fdetail::request_type&
-      get_or_make_request(implementation_type& impl, boost::uint16_t id)
-    {
-      implementation_type::client_type::connection_type::request_vector_type&
-        requests = impl.client_.connection_->requests_;
-
-      if (!requests.at(id-1))
-      {
-        if (requests.size() < (id-1))
-          requests.resize(id);
-        requests.at(id-1) = fdetail::request_type::create(*impl.service_);
-      }
-
-      return *requests.at(id-1);
-    }
-*/
-
     BOOST_CGI_INLINE boost::system::error_code
     fcgi_request_service::process_begin_request(
         implementation_type& impl, boost::uint16_t id
@@ -693,22 +666,8 @@
         //  << fcgi::spec::begin_request::get_role(impl.header_buf_) << std::endl;
 
         implementation_type::client_type::connection_type&
-          conn = *impl.client_.connection_;
-
-        if (conn.get_slot(id, ec))
-        { // error
-          return ec;
-        }
-
-        // **FIXME** THIS LEAKS MEMORY!!!!!!!
-        //requests.at(id-1)
-        //request_type* new_request = new request_type(impl, ec);
-
-        //conn.add_request(id, new_request, true, ec);
-
-        return ec;//error::multiplexed_request_incoming;
+          conn = *impl.client_.connection();
       }
-
       return ec;
     }
 
Modified: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/impl/response.ipp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/impl/response.ipp	(original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/impl/response.ipp	2009-12-02 22:43:00 EST (Wed, 02 Dec 2009)
@@ -324,10 +324,27 @@
   /// Get the response as a string.
   template<typename T> BOOST_CGI_INLINE  
   typename basic_response<T>::string_type
-    basic_response<T>::str() const
+    basic_response<T>::str(bool include_header) const
   {
-    return string_type(boost::asio::buffer_cast<const char_type *>(buffer_->data()),
-                       boost::asio::buffer_size(buffer_->data()));
+    string_type body;
+    if (include_header)
+    {
+      typedef std::vector<string_type>::const_iterator iter_t;
+      for (
+        iter_t iter(headers_.begin()), end(headers_.end());
+        iter != end;
+        ++iter
+      ) {
+        body += *iter;
+      }
+      if (!headers_terminated_)   body += "\r\n";
+    }
+    
+    body += string_type(
+      boost::asio::buffer_cast<const char_type *>(buffer_->data()),
+      boost::asio::buffer_size(buffer_->data()));
+      
+    return body;
   }
 
 
@@ -415,19 +432,23 @@
   {
     BOOST_CGI_ADD_DEFAULT_HEADER;
     
-    BOOST_ASSERT((headers_[0].length() > 13 && "Content-type header not found"));
-    
-    headers_[0].insert(headers_[0].length()-2, "; charset: " + charset_);
-
     // Terminate the headers.
     if (!headers_terminated_)
       headers_.push_back("\r\n");
 
-    //{ Construct a ConstBufferSequence out of the headers we have.
-    typedef typename std::vector<string_type>::iterator iter;
-    for (iter i(headers_.begin()), e(headers_.end()); i != e; ++i)
-    {
-      headers.push_back(common::buffer(*i));
+    typedef std::vector<string_type>::iterator iter_t;
+    for (
+      iter_t iter(headers_.begin()), end(headers_.end());
+      iter != end;
+      ++iter
+    )
+    {
+      boost::cgi::common::name type(iter->substr(0, 12).c_str());
+      if (type == "Content-type")
+        iter->insert(iter->length()-2, "; charset: " + charset_);    
+
+      //{ Construct a ConstBufferSequence out of the headers we have.
+      headers.push_back(common::buffer(*iter));
     }
     //}
 
@@ -483,7 +504,7 @@
     operator<< (BOOST_CGI_NAMESPACE::common::basic_response<CharT>& resp
                , BOOST_CGI_NAMESPACE::common::charset_header<CharT> const& hdr)
   {
-    resp.charset() = hdr.content;
+    resp.charset(hdr.content);
     return resp;
   }
 
Modified: sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/Boost.CGI.suo
==============================================================================
Binary files. No diff available.
Modified: sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/acgi_hello_world/acgi_hello_world.vcproj
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/acgi_hello_world/acgi_hello_world.vcproj	(original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/acgi_hello_world/acgi_hello_world.vcproj	2009-12-02 22:43:00 EST (Wed, 02 Dec 2009)
@@ -163,6 +163,7 @@
                         />
                         <Tool
                                 Name="VCPostBuildEventTool"
+				CommandLine="copy "$(TargetPath)" "c:\code\c++\boost.cgi\cgi-bin\$(TargetName)""
                         />
                 </Configuration>
         </Configurations>
Modified: sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/fcgi/echo/main.cpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/fcgi/echo/main.cpp	(original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/fcgi/echo/main.cpp	2009-12-02 22:43:00 EST (Wed, 02 Dec 2009)
@@ -203,6 +203,8 @@
     }
   }
   
+  std::cin.get();
+  
   return ret;
 
 }catch(boost::system::system_error const& se){
@@ -217,5 +219,7 @@
   std::cerr<< "[fcgi] Uncaught exception!" << std::endl;
   return -3;
 }
+  std::cerr<< "Press enter to continue." << std::endl;
+  std::cin.get();
 }
 //]
Modified: sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/fcgi/hello_world/main.cpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/fcgi/hello_world/main.cpp	(original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/fcgi/hello_world/main.cpp	2009-12-02 22:43:00 EST (Wed, 02 Dec 2009)
@@ -31,6 +31,7 @@
   // the response text.
   req.load(parse_env);
   resp<< content_type("text/plain")
+      << header("X-Protocol", "FastCGI")
       << "Hello there, universe.";
 
   return commit(req, resp, 0);