Boost logo

Boost-Commit :

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 &quot;$(TargetPath)&quot; &quot;c:\code\c++\boost.cgi\cgi-bin\$(TargetName)&quot;"
                         />
                 </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);


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk