Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r56250 - in sandbox/SOC/2007/cgi/branches/pickmeup: boost/cgi boost/cgi/acgi boost/cgi/cgi boost/cgi/common boost/cgi/connections boost/cgi/detail boost/cgi/fcgi boost/cgi/impl boost/cgi/utility libs/cgi/build/msvc/9.0/Boost.CGI libs/cgi/build/msvc/9.0/Boost.CGI/0.fcgi_template libs/cgi/build/msvc/9.0/Boost.CGI/acgi_ctemplate_cookie_game libs/cgi/build/msvc/9.0/Boost.CGI/cgi_ctemplate_debug_server libs/cgi/build/msvc/9.0/Boost.CGI/cgi_file_browser libs/cgi/build/msvc/9.0/Boost.CGI/fcgi_amortization libs/cgi/build/msvc/9.0/Boost.CGI/fcgi_echo_threaded libs/cgi/build/msvc/9.0/Boost.CGI/fcgi_file_browser libs/cgi/doc/src libs/cgi/doc/src/user_guide/tutorial libs/cgi/example/acgi/cookie_game libs/cgi/example/acgi/cookie_game2 libs/cgi/example/cgi/DebugServer2 libs/cgi/example/cgi/echo libs/cgi/example/cgi/file_browser libs/cgi/example/fcgi/amortization libs/cgi/example/fcgi/echo libs/cgi/example/fcgi/file_browser libs/cgi/example/fcgi/hello_world
From: lists.drrngrvy_at_[hidden]
Date: 2009-09-16 19:05:45


Author: drrngrvy
Date: 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
New Revision: 56250
URL: http://svn.boost.org/trac/boost/changeset/56250

Log:
* Updated `form_parser` class that no longer uses Boost.Regex (just uses std::string::find(), etc.). Tested with IE8, FF3.5 and Chrome2 on MSVC8.0.
* Uploaded files in multipart/form-data classes now saved to disk and meta data stored in the request (see, eg. `basic_request<>::is_file()`).
* Added support for binary reading / writing. This seems quite stable with CGI, but needs some more work to make writing binary data with FastCGI work properly (note: reading binary data with FastCGI works).
* Misc bug fixes.
* Misc documentation updates.
Added:
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/0.fcgi_template/
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/0.fcgi_template/fcgi_file_browser.vcproj (contents, props changed)
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/cgi_file_browser/
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/cgi_file_browser/cgi_file_browser.vcproj (contents, props changed)
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/fcgi_echo_threaded/
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/fcgi_echo_threaded/fcgi_echo_threaded.vcproj (contents, props changed)
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/fcgi_file_browser/
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/fcgi_file_browser/fcgi_file_browser.vcproj (contents, props changed)
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/cgi/file_browser/
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/cgi/file_browser/main.cpp
      - copied, changed from r55954, /sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/cgi/echo/main.cpp
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/fcgi/file_browser/
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/fcgi/file_browser/main.cpp (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/acgi/request_impl.hpp | 4
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/basic_request.hpp | 239 ++++++++++++-------
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/cgi/request_impl.hpp | 4
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/error.hpp | 24 +
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/form_parser.hpp | 96 +++++--
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/form_part.hpp | 25 +
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/parse_options.hpp | 22
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/request_base.hpp | 40 ++
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/request_service.hpp | 8
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/request_status.hpp | 1
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/response.hpp | 23 -
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/connections/async_stdio.hpp | 12
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/connections/shareable_tcp_socket.hpp | 11
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/connections/stdio.hpp | 68 +++--
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/connections/tcp_socket.hpp | 14
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/detail/cgi_service_impl_base.hpp | 81 +++---
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/detail/throw_error.hpp | 3
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/fcgi/acceptor_service_impl.hpp | 47 +--
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/fcgi/client.hpp | 96 ++++---
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/fcgi/error.hpp | 13
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/fcgi/request_service.hpp | 28 +-
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/fcgi/specification.hpp | 137 ++++++++--
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/impl/fcgi_request_service.ipp | 249 ++++++++-----------
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/impl/form_parser.ipp | 484 +++++++++------------------------------
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/impl/response.ipp | 5
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/utility/commit.hpp | 19 +
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/Boost.CGI.sln | 24 +
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/acgi_ctemplate_cookie_game/acgi_ctemplate_cookie_game.vcproj | 4
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/cgi_ctemplate_debug_server/cgi_ctemplate_debug_server.vcproj | 2
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/fcgi_amortization/fcgi_amortization.vcproj | 2
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/doc/src/design.qbk | 9
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/doc/src/user_guide/tutorial/quickstart.qbk | 16 -
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/acgi/cookie_game/main.cpp | 65 +++--
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/acgi/cookie_game2/main.cpp | 8
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/cgi/DebugServer2/TracebackServer.cpp | 2
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/cgi/DebugServer2/TracebackServer.hpp | 17
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/cgi/DebugServer2/ctemplate.cpp | 15
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/cgi/echo/main.cpp | 307 ++++++++++++++++++++++--
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/cgi/file_browser/main.cpp | 93 ++++++-
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/fcgi/amortization/main.cpp | 54 ++--
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/fcgi/echo/main.cpp | 54 +--
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/fcgi/hello_world/main.cpp | 8
   42 files changed, 1366 insertions(+), 1067 deletions(-)

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/acgi/request_impl.hpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/acgi/request_impl.hpp (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/acgi/request_impl.hpp 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -20,12 +20,12 @@
  namespace acgi {
 
   class request_impl
- : public detail::cgi_request_impl_base<common::async_stdio_connection>
+ : public detail::cgi_request_impl_base<connections::async_stdio>
   {
   public:
     typedef ::cgi::acgi::service protocol_service_type;
     typedef protocol_service_type::protocol_type protocol_type;
- typedef common::async_stdio_connection connection_type;
+ typedef connections::async_stdio connection_type;
     typedef
       ::cgi::common::basic_client<
         connection_type, common::tags::acgi

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-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -38,6 +38,11 @@
 #include "boost/cgi/detail/throw_error.hpp"
 #include "boost/cgi/detail/protocol_traits.hpp"
 
+#ifndef BOOST_CGI_POST_MAX
+ /// Restrict POST data to less than 7MB per request.
+# define BOOST_CGI_POST_MAX 6663322
+#endif // BOOST_CGI_POST_MAX
+
 namespace cgi {
  namespace common {
 
@@ -110,15 +115,22 @@
       
       void set(map_type& data) { impl = &data; }
       
- iterator begin() { BOOST_ASSERT(impl); return impl->begin(); }
- iterator end() { BOOST_ASSERT(impl); return impl->end(); }
- const_iterator begin() const { BOOST_ASSERT(impl); return impl->begin(); }
- const_iterator end() const { BOOST_ASSERT(impl); return impl->end(); }
-
- reverse_iterator rbegin() { BOOST_ASSERT(impl); return impl->rbegin(); }
- reverse_iterator rend() { BOOST_ASSERT(impl); return impl->rend(); }
- const_reverse_iterator rbegin() const { BOOST_ASSERT(impl); return impl->rbegin(); }
- const_reverse_iterator rend() const { BOOST_ASSERT(impl); return impl->rend(); }
+ iterator begin() {
+ BOOST_ASSERT(impl); return impl->begin(); }
+ iterator end() {
+ BOOST_ASSERT(impl); return impl->end(); }
+ const_iterator begin() const {
+ BOOST_ASSERT(impl); return impl->begin(); }
+ const_iterator end() const {
+ BOOST_ASSERT(impl); return impl->end(); }
+ reverse_iterator rbegin() {
+ BOOST_ASSERT(impl); return impl->rbegin(); }
+ reverse_iterator rend() {
+ BOOST_ASSERT(impl); return impl->rend(); }
+ const_reverse_iterator rbegin() const {
+ BOOST_ASSERT(impl); return impl->rbegin(); }
+ const_reverse_iterator rend() const {
+ BOOST_ASSERT(impl); return impl->rend(); }
 
       bool empty() { BOOST_ASSERT(impl); return impl->empty(); }
       
@@ -126,7 +138,10 @@
       
       size_type size() const { BOOST_ASSERT(impl); return impl->size(); }
       
- size_type count(const key_type& key) { BOOST_ASSERT(impl); return impl->count(key); }
+ size_type count(const key_type& key) {
+ BOOST_ASSERT(impl);
+ return impl->count(key);
+ }
       
       template<typename T>
       T as(key_type const& key) {
@@ -141,6 +156,7 @@
       }
       
       operator map_type&() { BOOST_ASSERT(impl); return *impl; }
+ bool operator!() const { return !impl; }
 
     private:
       map_type* impl;
@@ -167,7 +183,6 @@
       : detail::basic_sync_io_object<service_type>()
     {
       if (opts > parse_none) load(opts, ec);
- construct();
     }
 
     // Throws
@@ -178,7 +193,6 @@
     {
       set_protocol_service(s);
       if (opts > parse_none) load(opts, base_env);
- construct();
     }
 
     // Won't throw
@@ -190,7 +204,6 @@
     {
       set_protocol_service(s);
       if (opts > parse_none) load(opts, ec, base_env);
- construct();
     }
 
     /// Make a new mutiplexed request from an existing connection.
@@ -202,7 +215,6 @@
       boost::system::error_code ec;
       this->service.begin_request_helper(this->implementation
                                         , impl.header_buf_, ec);
- construct();
       detail::throw_error(ec);
     }
 
@@ -226,6 +238,9 @@
     void construct()
     {
       this->env.set(env_vars(this->implementation.vars_));
+ // By default, set the form map to the environment.
+ //if (!this->form)
+ // this->form.set(env_vars(this->implementation.vars_));
       this->post.set(post_vars(this->implementation.vars_));
       this->get.set(get_vars(this->implementation.vars_));
       this->cookies.set(cookie_vars(this->implementation.vars_));
@@ -241,7 +256,21 @@
       this->service.set_service(this->implementation, ps);
     }
 
- /// Return `true` if the request is still open (ie. not aborted or closed)
+ /// The id of this request.
+ /**
+ * This is 1 for CGI/aCGI requests, but may be != 1 for FastCGI
+ * requests.
+ *
+ * Note that for FastCGI requests, the id's are assigned on a
+ * *per-connection* policy, so in one application you may have
+ * several requests with the same id.
+ */
+ int id()
+ {
+ return this->service.request_id(this->implementation);
+ }
+
+ /// Check if the request is still open (ie. not aborted or closed)
     bool is_open()
     {
       return this->service.is_open(this->implementation);
@@ -249,9 +278,9 @@
 
     /// Synchronously read/parse the request meta-data
     /**
- * Note: 'loading' including reading/parsing STDIN if parse_stdin == true
+ * Note: 'loading' including reading/parsing STDIN if
+ * parse_stdin == true
      */
- // Throwing semantics
     void load(parse_options parse_opts = parse_env, char** base_env = NULL)
     {
       boost::system::error_code ec;
@@ -264,17 +293,31 @@
       load(parse_options parse_opts, boost::system::error_code& ec
           , char** base_environment = NULL, bool is_command_line = true)
     {
- this->service.load(this->implementation, parse_opts, ec);
- if (base_environment)
- this->service.load_environment(this->implementation, base_environment
- , is_command_line);
- if (parse_opts > parse_env && parse_opts & parse_form)
+ construct();
+ // Parse just the environment first, then check the user
+ // isn't trying to upload more data than we want to let them.
+ // Define `BOOST_CGI_POST_MAX` to set the maximum content-length
+ // allowed.
+ if (parse_opts & parse_env)
       {
- common::name rm(request_method().c_str());
- form.set(
- (rm == "GET" || rm == "HEAD") ? get :
- rm == "POST" ? post : env
- );
+ //this->service.load(this->implementation, parse_env, ec);
+ //if (content_length() >= BOOST_CGI_POST_MAX)
+ // ec = common::error::max_post_exceeded;
+ this->service.load(this->implementation, parse_opts, ec);
+ // Load the environment passed by the user.
+ if (base_environment)
+ this->service.load_environment(
+ this->implementation, base_environment
+ , is_command_line);
+
+ if (parse_opts > parse_env && parse_opts & parse_form)
+ {
+ common::name rm(request_method().c_str());
+ form.set(
+ (rm == "GET" || rm == "HEAD") ? get :
+ rm == "POST" ? post : env
+ );
+ }
       }
       return ec;
     }
@@ -289,8 +332,8 @@
     /// Get the buffer containing the POST data.
     /**
      * **FIXME**
- * This actually returns the whole buffer on FastCGI at the moment, which
- * contains the params too.
+ * This actually returns the whole buffer on FastCGI at the moment,
+ * which contains the params too.
      */
     buffer_type& post_buffer()
     {
@@ -300,7 +343,8 @@
     // **FIXME**
     /// Asynchronously read/parse the request meta-data
     /**
- * Note: 'loading' including reading/parsing STDIN if parse_stdin == true
+ * Note: 'loading' including reading/parsing STDIN if
+ * parse_stdin == true
      */
     //template<typename Handler>
     //void async_load(Handler handler, bool parse_stdin = false)
@@ -309,28 +353,28 @@
     // , handler);
     //}
 
- /// Notify the server the request has finished being handled
+ /// Notify the server the request has been handled.
     /**
- * In certain situations (such as a Proactor client using the async read
- * functions) it will be necessary to call end, rather than just returning
- * from the sub_main function.
- *
- * @param program_status This value is returned to the server indicating the
- * state of the request after it was finished handling. It is
- * implementation defined how the server deals with this, and it may have
- * no effect on the http status code returned to the client (eg. 200 OK).
+ * In certain situations (such as a Proactor client using the async
+ * read functions) it will be necessary to call end, rather than
+ * just returning from the sub_main function.
+ *
+ * @param program_status This value is returned to the server
+ * indicating the state of the request after it was finished
+ * handling. It is implementation defined how the server deals with
+ * this, and it may have no effect on the http status code returned
+ * to the client (eg. 200 OK).
      *
      * @returns The value of program_status
      */
     int close(common::http::status_code http_status = http::ok
              , int program_status = 0)
     {
- //BOOST_ASSERT( request_status_ != ended );
-
- //this->service.set_status(this->implementation, http_status);
       boost::system::error_code ec;
       this->service.close(this->implementation, http_status,
           program_status, ec);
+ // Clear the request data so the object can be reused.
+ clear();
       detail::throw_error(ec);
       return program_status;
     }
@@ -343,7 +387,7 @@
                                 , program_status, ec);
     }
 
- /// Reject the request with a standard '500 Internal Server Error' error
+ /// Reject the request with a '500 Internal Server Error' error.
     int reject()
     {
       this->service.set_status(this->implementation, aborted);
@@ -351,12 +395,40 @@
                                 , http::internal_server_error);
     }
 
- /// Abort a request
+ /// Abort a request.
     void abort()
     {
       this->service.set_status(this->implementation, aborted);
     }
 
+ /// Check if a POST variable references a file upload.
+ /**
+ * File uploads, which originate from a form POSTed using the
+ * multipart/form-data encoding type are saved to disk.
+ *
+ * Only the filename is stored in the POST map for the request.
+ * If you expect a field to be a file upload, check if it is using
+ * this function.
+ */
+ bool is_file(common::name const& key)
+ {
+ return this->service.is_file(this->implementation, key.c_str());
+ }
+
+ /// Check if a POST variable references a file upload.
+ /**
+ * File uploads, which originate from a form POSTed using the
+ * multipart/form-data encoding type are saved to disk.
+ *
+ * Only the filename is stored in the POST map for the request.
+ * If you expect a field to be a file upload, check if it is using
+ * this function.
+ */
+ bool is_file(string_type const& key)
+ {
+ return this->service.is_file(this->implementation, key);
+ }
+
     /// Clear the data for the request, for reusing this object.
     // I'd imagine clearing and re-loading a request is quicker than
     // destroying/re-creating one. **Unverified claims** **FIXME**
@@ -424,7 +496,7 @@
 
     // [helper-functions for the basic CGI 1.1 meta-variables.
     string_type& auth_type()
- { return env_("AUTH_TYPE"); }
+ { return env["AUTH_TYPE"]; }
 
     /// Get the content length as a long.
     /**
@@ -433,72 +505,72 @@
      */
     long content_length()
     {
- string_type& cl(env_("CONTENT_LENGTH"));
+ string_type& cl(env["CONTENT_LENGTH"]);
       return boost::lexical_cast<long>(cl.empty() ? "0" : cl);
     }
 
     string_type& content_type()
- { return env_("CONTENT_TYPE"); }
+ { return env["CONTENT_TYPE"]; }
 
     string_type& gateway_interface()
- { return env_("GATEWAY_INTERFACE"); }
+ { return env["GATEWAY_INTERFACE"]; }
 
     common::path_info path_info()
- { return env_("PATH_INFO"); }
+ { return env["PATH_INFO"]; }
 
     string_type& path_translated()
- { return env_("PATH_TRANSLATED"); }
+ { return env["PATH_TRANSLATED"]; }
 
     string_type& query_string()
- { return env_("QUERY_STRING"); }
+ { return env["QUERY_STRING"]; }
 
     string_type& remote_addr()
- { return env_("REMOTE_ADDR"); }
+ { return env["REMOTE_ADDR"]; }
 
     string_type& remote_host()
- { return env_("REMOTE_HOST"); }
+ { return env["REMOTE_HOST"]; }
 
     string_type& remote_ident()
- { return env_("REMOTE_IDENT"); }
+ { return env["REMOTE_IDENT"]; }
 
     string_type& remote_user()
- { return env_("REMOTE_USER"); }
+ { return env["REMOTE_USER"]; }
 
     string_type& method()
- { return env_("REQUEST_METHOD"); }
+ { return env["REQUEST_METHOD"]; }
 
     string_type& request_method()
- { return env_("REQUEST_METHOD"); }
+ { return env["REQUEST_METHOD"]; }
 
     string_type& url()
- { return env_("REQUEST_URL"); }
+ { return env["REQUEST_URL"]; }
 
     string_type& request_url()
- { return env_("REQUEST_URL"); }
+ { return env["REQUEST_URL"]; }
 
     string_type& script_name()
- { return env_("SCRIPT_NAME"); }
+ { return env["SCRIPT_NAME"]; }
 
     string_type& script_url()
- { return env_("SCRIPT_URL"); }
+ { return env["SCRIPT_URL"]; }
 
     string_type& script_uri()
- { return env_("SCRIPT_URI"); }
+ { return env["SCRIPT_URI"]; }
 
     string_type& server_name()
- { return env_("SERVER_NAME"); }
+ { return env["SERVER_NAME"]; }
 
     string_type& server_port()
- { return env_("SERVER_PORT"); }
+ { return env["SERVER_PORT"]; }
 
     string_type& server_protocol()
- { return env_("SERVER_PROTOCOL"); }
+ { return env["SERVER_PROTOCOL"]; }
 
     string_type& server_software()
- { return env_("SERVER_SOFTWARE"); }
+ { return env["SERVER_SOFTWARE"]; }
 
     string_type& referer()
- { return env_("HTTP_REFERER"); }
+ { return env["HTTP_REFERER"]; }
     // -- end helper-functions]
 
     /// Get the charset from the CONTENT_TYPE header
@@ -534,9 +606,19 @@
     ////////////////////////////////////////////////////////////
     // Note on operator[]
     // ------------------
+ //
+ // ** DEPRECATED **
+ // These operator overloads are deprecated.
+ // Use member variables instead, eg.
+ // ``
+ // request req;
+ // req.get["whatever"]
+ // req.env["request_method"]
+ // ``
+ // ** DEPRECATED **
+ //
     // It is overloaded on different enum types to allow
- // compile-time (I hope) retrieval of different data
- // maps.
+ // compile-time retrieval of different data maps.
     //
 
     // The first three overloads are for directly looking into the
@@ -611,25 +693,6 @@
         return env_vars(this->implementation.vars_);
     }
     ////////////////////////////////////////////////////////////
-
- /// The id of this request.
- /**
- * This is 1 for CGI/aCGI requests, but may be != 1 for FastCGI requests.
- * Note that for FastCGI requests, the id's are assigned on a
- * *per-connection* policy, so in one application you may have several
- * requests with the same id.
- */
- int id()
- {
- return this->service.request_id(this->implementation);
- }
-
- private:
- // Internal shortcut for named env-var functions (eg. script_name() above).
- string_type& env_(const char* name)
- {
- return env_vars(this->implementation.vars_)[name];
- }
   };
 
  } // namespace common

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/cgi/request_impl.hpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/cgi/request_impl.hpp (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/cgi/request_impl.hpp 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -38,11 +38,11 @@
    * restricted but if someone really wants to copy the data, then they can.
    */
   class cgi_request_impl
- : public detail::cgi_request_impl_base<common::stdio_connection>
+ : public detail::cgi_request_impl_base<connections::stdio>
   {
   public:
     typedef common::basic_client<
- common::stdio_connection, common::tags::cgi
+ connections::stdio, common::tags::cgi
> client_type;
     typedef common::tags::cgi protocol_type;
 

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-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -55,7 +55,17 @@
   eof,
   
   // The first multipart form boundary was not found.
- multipart_form_boundary_not_found
+ multipart_form_boundary_not_found,
+
+ // The first multipart form boundary was not found.
+ multipart_meta_data_not_terminated,
+
+ // Expected a boundary marker for a multipart form, but did not find it.
+ no_boundary_marker,
+
+ // The content length of the file upload is larger than maximum allowed
+ // by the BOOST_CGI_POST_MAX macro.
+ max_post_exceeded
 };
 
   namespace detail {
@@ -70,17 +80,25 @@
     switch(e)
     {
     case client_closed:
- return "Attempting to read from or write to a client that has been closed.";
+ return "Attempting to read from or write to a client that has been"
+ " closed.";
     case accepting_on_an_open_request:
- return "`async_accept` called with an open request (ie. it should be closed first).";
+ return "`async_accept` called with an open request (ie. it should be"
+ " closed first).";
     case multipart_form_boundary_not_found:
       return "The first multipart form boundary was not found.";
+ case no_boundary_marker:
+ return "Expected a boundary marker for a multipart form, but did not"
+ " find it.";
     case invalid_form_type:
       return "The CONTENT_TYPE for form data wasn't recognised.";
     case eof:
       return "End of File.";
     case duplicate_request:
       return "FastCGI: new request received with a duplicate id.";
+ case max_post_exceeded:
+ return "The content length of the file upload is larger than maximum"
+ " allowed by the BOOST_CGI_POST_MAX macro.";
     default:
       return "(CGI) BOOM!!!";
     }

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/form_parser.hpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/form_parser.hpp (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/form_parser.hpp 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -25,6 +25,22 @@
 #include "boost/cgi/common/map.hpp"
 #include "boost/cgi/common/form_part.hpp"
 
+/// Set the directory that uploads are stored in.
+/**
+ * When files are uploaded, using multipart/form-data, uploaded
+ * files are saved to disk, rather than being held in memory.
+ *
+ * This macro determines where uploaded files are stored.
+ *
+ * You must ensure the user that your web server runs as has read and
+ * write permissions to this directory. You should never allow this to
+ * be the same directory the FastCGI script is running in, or any
+ * directory containing executable files.
+ */
+#if !defined(BOOST_CGI_UPLOAD_DIRECTORY)
+# define BOOST_CGI_UPLOAD_DIRECTORY "../upload/"
+#endif // BOOST_CGI_UPLOAD_DIRECTORY
+
 namespace cgi {
  namespace detail {
 
@@ -32,48 +48,78 @@
   class form_parser
   {
   public:
+ /// The callback functor to read more data.
     typedef
       boost::function<
         std::size_t (boost::system::error_code&)
>
     callback_type;
 
- typedef std::string string_type;
- typedef boost::asio::mutable_buffers_1 mutable_buffers_type;
- typedef std::vector<char> buffer_type;
- typedef ::cgi::common::map map_type;
+ typedef common::map map_type;
+ typedef common::form_part::string_type string_type;
+ typedef common::form_part::buffer_type buffer_type;
+ typedef boost::asio::mutable_buffers_1 mutable_buffers_type;
 
+ /// The context used for parsing.
+ struct context
+ {
+ string_type& content_type;
+ buffer_type& buffer;
+ std::vector<common::form_part>& form_parts;
+ std::size_t& bytes_left;
+ common::post_map& data_map;
+ const callback_type callback;
+ bool& stdin_parsed;
+ // A random string, used for marking uploaded files.
+ // Set this to something like the user's REMOTE_ADDR.
+ string_type random_string;
+ std::size_t offset;
+
+ buffer_type::iterator pos;
+ string_type boundary_marker;
+ std::list<string_type> boundary_markers;
+ };
+
+ form_parser() : context_(NULL) {}
 /*
- form_parser();
- form_parser(callback_type const& callback);
-*/
     form_parser(
         buffer_type&, common::post_map&, string_type const&
       , callback_type const&, std::size_t&, bool&);
+*/
 
- std::string buffer_string()
+ string_type buffer_string()
     {
- return std::string(buffer_.begin() + offset_, buffer_.end());
+ return string_type(context_->buffer.begin() + context_->offset
+ , context_->buffer.end());
     }
     
+ /// Run the parser on the given `context`.
     boost::system::error_code
- parse(boost::system::error_code& ec);
+ parse(context ctx, boost::system::error_code& ec);
 
+ /// URL-encoded forms.
+ /**
+ * Parse forms where the content-type is "application/www-url-encoded".
+ */
     boost::system::error_code
       parse_url_encoded_form(boost::system::error_code& ec);
 
+ /// Parse a multipart form.
+ /**
+ * Parse forms where the content-type is "multipart/form-data".
+ */
     boost::system::error_code
       parse_multipart_form(boost::system::error_code& ec);
 
+ /// Parse a single form part.
     boost::system::error_code
       parse_form_part(boost::system::error_code& ec);
 
- boost::system::error_code
- parse_form_part_data(boost::system::error_code& ec);
-
- boost::system::error_code
- parse_form_part_meta_data(boost::system::error_code& ec);
-
+ /// Erase any front-cruft on the form data.
+ /**
+ * In multipart forms, any characters that precede the first form
+ * boundary are ignored. This function erases those characters.
+ */
     boost::system::error_code
       move_to_start_of_first_part(boost::system::error_code& ec);
 
@@ -81,22 +127,8 @@
     boost::system::error_code
       parse_boundary_marker(boost::system::error_code& ec);
 
- //private:
- public:
- string_type const& content_type_;
- buffer_type& buffer_;
- std::size_t& bytes_left_;
- buffer_type::iterator pos_;
- //bool& stdin_data_read_;
- common::post_map& data_map_;
-
- std::string boundary_marker;
- std::list<std::string> boundary_markers;
- std::vector<common::form_part> form_parts_;
-
- const callback_type callback_;
- bool& stdin_parsed_;
- std::size_t offset_;
+private:
+ context* context_;
   };
 
  } // namespace detail

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/form_part.hpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/form_part.hpp (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/form_part.hpp 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -3,6 +3,7 @@
 
 #include <map>
 #include <vector>
+#include <string>
 #include <boost/range.hpp>
 
 namespace cgi {
@@ -10,7 +11,9 @@
 
    struct form_part
    {
- typedef std::vector<char> buffer_type;
+ typedef std::string string_type;
+ //typedef std::vector<char> buffer_type;
+ typedef string_type buffer_type;
      typedef buffer_type::iterator iter_t;
      
      typedef boost::iterator_range<
@@ -20,29 +23,37 @@
      typedef std::pair<iter_t, iter_t> pair_t;
      
      typedef std::map<
- std::string, pair_t
+ string_type, pair_t
> meta_data_map_type;
    
      form_part()
      {
      }
+
+ bool operator==(form_part& other) {
+ return this->name == other.name;
+ }
    
      meta_data_map_type meta_data_;
 
      /// The boundary marker that's needed.
      // If this is empty, it means the corresponding data has been read.
- std::string boundary_marker_;
+ string_type boundary_marker_;
 
      //range_type buffer_;
      pair_t buffer_;
 
- std::string content_type; // must exist
- std::string name; // must exist (?) **FIXME**
-
+ string_type content_type; // must exist
+ string_type content_disposition; // must exist
+ string_type name; // must exist
+ string_type filename;
+ // Where the actual uploaded file is stored.
+ string_type path;
+
      // Using a simple map while everything is changing. This will not copy the
      // values when it is properly implemented (it'll hold a pair of iterators
      // to the data).
- //std::map<std::string, std::string> meta_data_;
+ //std::map<string_type, string_type> meta_data_;
      
      // Boolean to show if the form part has been completely read/parsed
      //bool finished_;

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/parse_options.hpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/parse_options.hpp (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/parse_options.hpp 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -10,16 +10,18 @@
    // anything you will have unspecified behaviour.
    enum parse_options
    {
- parse_none = 0
- , parse_env = 1
- , parse_get_only = 2
- , parse_get = parse_get_only | parse_env
- , parse_post_only = 4
- , parse_post = parse_post_only | parse_env
- , parse_form = parse_env | parse_get | parse_post
- , parse_cookie_only = 8
- , parse_cookie = parse_cookie_only | parse_env
- , parse_all = parse_env | parse_form | parse_cookie
+ parse_none = 0
+ , parse_env = 1
+ , parse_get_only = 2
+ , parse_get = parse_get_only | parse_env
+ , parse_post_only = 4
+ , parse_post = parse_post_only | parse_env
+ , parse_form = parse_env | parse_get | parse_post
+ , parse_cookie_only = 8
+ , parse_cookie = parse_cookie_only | parse_env
+ , parse_cookies_only = 8
+ , parse_cookies = parse_cookies_only | parse_env
+ , parse_all = parse_env | parse_form | parse_cookie
    };
 
  } // namespace common

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/request_base.hpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/request_base.hpp (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/request_base.hpp 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -17,8 +17,10 @@
 ////////////////////////////////////////////////////////////////
 #include <boost/asio/buffer.hpp>
 #include <boost/system/error_code.hpp>
+#include <boost/algorithm/string/find.hpp>
 ////////////////////////////////////////////////////////////////
 #include "boost/cgi/common/map.hpp"
+#include "boost/cgi/common/form_part.hpp"
 #include "boost/cgi/common/parse_options.hpp"
 #include "boost/cgi/detail/extract_params.hpp"
 #include "boost/cgi/detail/save_environment.hpp"
@@ -49,7 +51,8 @@
     {
       typedef char char_type; // **FIXME**
       typedef std::basic_string<char_type> string_type;
- typedef std::vector<char_type> buffer_type;
+ typedef string_type buffer_type;
+ //typedef std::vector<char_type> buffer_type;
       typedef boost::asio::const_buffers_1 const_buffers_type;
       typedef boost::asio::mutable_buffers_1 mutable_buffers_type;
  
@@ -80,6 +83,8 @@
       /// Whether the environment has been parsed yet.
       bool env_parsed_;
 
+ std::vector<common::form_part> form_parts_;
+
       mutable_buffers_type prepare(std::size_t size)
       {
         // Make sure we're not trying to make a zero-sized buffer.
@@ -124,6 +129,23 @@
       return impl.client_.read_some(buf,ec);
     }
 
+ /// Check if a given POST variable represents a file upload.
+ template<typename ImplType>
+ bool is_file(ImplType& impl
+ , typename ImplType::string_type const& key)
+ {
+ typedef std::vector<common::form_part>::const_iterator
+ iter_t;
+
+ for(iter_t iter (impl.form_parts_.begin())
+ , end (impl.form_parts_.end()); iter != end; ++iter)
+ {
+ if (iter->name == key.c_str() && !iter->filename.empty())
+ return true;
+ }
+ return false;
+ }
+
     /// Synchronously read/parse the request meta-data
     template<typename ImplType>
     boost::system::error_code
@@ -137,26 +159,30 @@
       }
 
       std::string const& cl = env_vars(impl.vars_)["CONTENT_LENGTH"];
- // This will throw if the content-length isn't a valid number (which shouldn't ever happen).
- impl.characters_left_ = cl.empty() ? 0 : boost::lexical_cast<std::size_t>(cl);
+ // This will throw if the content-length isn't a valid number
+ // (which shouldn't ever happen).
+ impl.characters_left_
+ = cl.empty() ? 0 : boost::lexical_cast<std::size_t>(cl);
       impl.client_.bytes_left() = impl.characters_left_;
 
- std::string const& request_method = env_vars(impl.vars_)["REQUEST_METHOD"];
+ std::string const& request_method
+ = env_vars(impl.vars_)["REQUEST_METHOD"];
 
       if ((request_method == "GET" || request_method == "HEAD")
- && (parse_opts & common::parse_get))
+ && (parse_opts & common::parse_get_only))
       {
         parse_get_vars(impl, ec);
       }
       else
- if (request_method == "POST" && parse_opts & common::parse_post)
+ if (request_method == "POST"
+ && parse_opts & common::parse_post_only)
       {
         parse_post_vars(impl, ec);
       }
 
       if (ec) return ec;
 
- if (parse_opts & common::parse_cookie)
+ if (parse_opts & common::parse_cookies_only)
       {
         if (!parse_cookie_vars(impl, ec)) // returns an error_code
           return ec;

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/request_service.hpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/request_service.hpp (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/request_service.hpp 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -44,12 +44,6 @@
     typedef Protocol protocol_type;
     typedef common::basic_protocol_service<Protocol> protocol_service_type;
 
- /// The unique service identifier
- //static boost::asio::io_service::id id;
- //explicit request_service()
- //{
- //}
-
     request_service(::cgi::common::io_service& ios)
       : detail::service_base<request_service<Protocol> >(ios)
       , service_impl_(boost::asio::use_service<service_impl_type>(ios))
@@ -123,7 +117,6 @@
     {
       return service_impl_.read_some(impl, buf, ec);
     }
-*/
     std::string
       GET(impl_type& impl, const std::string& name
          , boost::system::error_code& ec)
@@ -145,6 +138,7 @@
       return service_impl_.cookie(impl, name, ec);
     }
 
+*/
     /*
     std::string
       header(impl_type& impl, const std::string& name

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/request_status.hpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/request_status.hpp (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/request_status.hpp 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -17,6 +17,7 @@
      , unloaded
      , activated
      , accepted = activated
+ , env_read
      , loaded
      , ok = loaded
      , aborted

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-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -167,29 +167,6 @@
 
     /// Get the headers
     std::vector<string_type>& headers();
-
- //friend std::basic_ostream<char_type>& operator<<(std::basic_ostream<char_type>&, self_type& resp);
- /*
- friend self_type& operator<<(self_type& self, basic_cookie<char_type> const&);
- friend self_type& operator<<(self_type& self, basic_header<char_type> const&);
- friend self_type& operator<<(self_type& self, basic_response<char_type> const&);
- friend self_type& operator<<(self_type& self, http::status_code);
- */
-
- /*
- template<typename T>
- std::basic_ostream<string_type>& operator<<(T& t)
- {
- ostream_<< t;
- return ostream_;
- }
-
- template<typename T>
- self_type& operator<<(const T& t) {
- ostream_<< t;
- return *this;
- }
- */
 
   protected:
     // Vector of all the headers, each followed by a CRLF

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/connections/async_stdio.hpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/connections/async_stdio.hpp (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/connections/async_stdio.hpp 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -122,16 +122,12 @@
     ::cgi::common::io_service& io_service_;
   };
 
- typedef basic_connection<tags::async_stdio> async_stdio_connection;
-
+ } // namespace common
 
- // template<typename ProtocolService = detail::async_cgi_service>
- //struct async_stdio_connection
- //{
- // typedef basic_connection<tags::async_cgi, ProtocolService> type;
- //};
+ namespace connections {
+ typedef common::basic_connection<common::tags::async_stdio> async_stdio;
+ } // namespace connections
 
- } // namespace common
 } // namespace cgi
 
 #endif // CGI_ASYNC_STDIO_HPP_INCLUDED__

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/connections/shareable_tcp_socket.hpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/connections/shareable_tcp_socket.hpp (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/connections/shareable_tcp_socket.hpp 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -210,14 +210,13 @@
     std::set<int> deletable_request_ids_;
   };
 
- // probably deletable typedef (leaving it here to keep an open mind)
- typedef basic_connection<tags::shareable_tcp_socket> shareable_tcp_connection;
+ } // namespace common
 
- namespace connection {
- typedef basic_connection<tags::shareable_tcp_socket> shareable_tcp;
- } // namespace connection
+ namespace connections {
+ typedef common::basic_connection<
+ common::tags::shareable_tcp_socket> shareable_tcp;
+ } // namespace connections
 
- } // namespace common
 } // namespace cgi
 
 #include "boost/cgi/detail/pop_options.hpp"

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/connections/stdio.hpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/connections/stdio.hpp (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/connections/stdio.hpp 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -11,6 +11,8 @@
 
 #include <cstdio>
 #include <string>
+#include <io.h>
+#include <fcntl.h>
 ///////////////////////////////////////////////////////////
 #include <boost/system/error_code.hpp>
 #include <boost/asio.hpp>
@@ -34,12 +36,26 @@
     basic_connection()
       : is_open_(true)
     {
+#if BOOST_WINDOWS
+ // We have to open stdin in binary mode on windows,
+ // or "\r\n" sequences are truncated to "\n".
+ _setmode(_fileno(stdin),_O_BINARY);
+ _setmode(_fileno(stdout),_O_BINARY);
+ _setmode(_fileno(stderr),_O_BINARY);
+#endif
     }
 
     template<typename T>
     basic_connection(T&)
       : is_open_(true)
     {
+#if BOOST_WINDOWS
+ // We have to open stdin in binary mode on windows,
+ // or "\r\n" sequences are truncated to "\n".
+ _setmode(_fileno(stdin),_O_BINARY);
+ _setmode(_fileno(stdout),_O_BINARY);
+ _setmode(_fileno(stderr),_O_BINARY);
+#endif
     }
 
     bool is_open() const
@@ -60,7 +76,7 @@
     template<typename MutableBufferSequence>
     std::size_t read_some(MutableBufferSequence buf
                          , boost::system::error_code& ec)
- {
+ {
       if (std::fread(boost::asio::buffer_cast<void *>(buf)
                     , boost::asio::buffer_size(buf)
                     , 1, stdin))
@@ -83,22 +99,34 @@
     std::size_t write_some(ConstBufferSequence& buf
                           , boost::system::error_code& ec)
     {
+ ec = boost::system::error_code();
+
       std::size_t bytes_transferred(0);
- for(typename ConstBufferSequence::const_iterator i = buf.begin()
- ; i != buf.end(); ++i)
+ for(typename ConstBufferSequence::const_iterator i = buf.begin(),
+ end (buf.end())
+ ; !ec && i != end; ++i)
       {
         std::size_t buf_len = boost::asio::buffer_size(*i);
         bytes_transferred += buf_len;
- int ret( fputs(boost::asio::buffer_cast<const char*>(*i), stdout) );
- if (ret == EOF)
+ //int ret(fputs(boost::asio::buffer_cast<const char*>(*i), stdout));
+ //if (ret == EOF)
+ //{
+ // return ::cgi::error::broken_pipe;
+ //}
+ //std::cerr<< "[buf] "
+ // << std::string(boost::asio::buffer_cast<const char*>(*i), buf_len)
+ // << std::endl;
+ if (!std::fwrite(boost::asio::buffer_cast<const void *>(*i)
+ , buf_len, 1, stdout))
         {
- return ::cgi::error::broken_pipe;
+ if (std::feof(stdout))
+ ec = ::cgi::error::eof;
+ else
+ if (std::ferror(stdout))
+ ec = ::cgi::error::bad_write;
+ else
+ ec = ::cgi::error::broken_pipe;
         }
- //else
- //if (ret < 0)
- //{
- // return ::cgi::error::
- //std::cout.write(boost::asio::buffer_cast<const char*>(*i), buf_len);
       }
       return bytes_transferred;
     }
@@ -107,22 +135,12 @@
     bool is_open_;
   };
 
- namespace connection {
-
- typedef basic_connection<tags::stdio> stdio;
-
- } // namespace connection
-
- // Deprecated
- typedef basic_connection<tags::stdio> stdio_connection;
+ } // namespace common
 
- // template<typename ProtocolService = detail::cgi_service>
- //struct stdio_connection
- //{
- // typedef basic_connection<tags::stdio, ProtocolService> type;
- //};
+ namespace connections {
+ typedef common::basic_connection<common::tags::stdio> stdio;
+ } // namespace connections
 
- } // namespace common
 } // namespace cgi
 
 #endif // CGI_STDIO_CONNECTION_IMPL_HPP_INCLUDED__

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/connections/tcp_socket.hpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/connections/tcp_socket.hpp (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/connections/tcp_socket.hpp 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -95,17 +95,13 @@
   private:
     next_layer_type sock_;
   };
+
+ } // namespace common
 
- namespace connection {
-
- typedef basic_connection<tags::tcp_socket> tcp;
-
- } // namespace connection
-
- // Deprecated
- typedef basic_connection<tags::tcp_socket> tcp_connection;
+ namespace connections {
+ typedef common::basic_connection<common::tags::tcp_socket> tcp;
+ } // namespace connections
 
- } // namespace common
 } // namespace cgi
 
 #include "boost/cgi/detail/pop_options.hpp"

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/detail/cgi_service_impl_base.hpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/detail/cgi_service_impl_base.hpp (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/detail/cgi_service_impl_base.hpp 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -107,7 +107,8 @@
      */
     bool is_open(implementation_type& impl)
     {
- return impl.status() >= common::accepted && impl.status() <= common::aborted;
+ return impl.status() >= common::accepted
+ && impl.status() <= common::aborted;
     }
 
     /// Return the connection associated with the request
@@ -117,6 +118,8 @@
       return impl.client_;
     }
 
+ void clear(implementation_type& impl) { }
+
     int request_id(implementation_type& impl) { return 1; }
 
     // **FIXME** should return error_code
@@ -128,7 +131,7 @@
       return status;
     }
 
- /// Synchronously read/parse the request meta-data
+ /// Synchronously read/parse the request data
     boost::system::error_code&
     load(implementation_type& impl, common::parse_options parse_opts
         , boost::system::error_code& ec)
@@ -140,10 +143,12 @@
       }
 
       std::string const& cl = env_vars(impl.vars_)["CONTENT_LENGTH"];
- impl.characters_left_ = cl.empty() ? 0 : boost::lexical_cast<std::size_t>(cl);
- impl.client_.bytes_left() = impl.characters_left_;
-
- std::string const& request_method = env_vars(impl.vars_)["REQUEST_METHOD"];
+ impl.characters_left_
+ = cl.empty() ? 0 : boost::lexical_cast<std::size_t>(cl);
+ impl.client_.bytes_left()
+ = impl.characters_left_;
+ std::string const& request_method
+ = env_vars(impl.vars_)["REQUEST_METHOD"];
 
       if ((request_method == "GET" || request_method == "HEAD")
           && parse_opts > common::parse_env
@@ -152,7 +157,8 @@
         parse_get_vars(impl, ec);
       }
       else
- if (request_method == "POST" && (parse_opts & common::parse_post_only))
+ if (request_method == "POST"
+ && (parse_opts & common::parse_post_only))
       {
         parse_post_vars(impl, ec);
       }
@@ -170,20 +176,6 @@
       return ec;
     }
 
- /// Synchronously read/parse the request meta-data
- /**
- * @param parse_stdin if true then STDIN data is also read/parsed
- */
- boost::system::error_code&
- load(implementation_type& impl, bool parse_stdin
- , boost::system::error_code& ec)
- {
- return load(impl, parse_stdin
- ? common::parse_all
- : (common::parse_env | common::parse_cookie)
- , ec);
- }
-
     role_type
     get_role(implementation_type& impl)
     {
@@ -191,13 +183,15 @@
     }
 
     /// Set the http status (this does nothing for aCGI)
- void set_status(implementation_type& impl, common::http::status_code&)
+ void set_status(
+ implementation_type& impl, common::http::status_code&)
     {
       // **FIXME**
     }
 
     /// Set the request status
- void set_status(implementation_type& impl, common::request_status status)
+ void set_status(
+ implementation_type& impl, common::request_status status)
     {
       impl.status() = status;
     }
@@ -214,7 +208,7 @@
     boost::system::error_code
     read_env_vars(RequestImpl& impl, boost::system::error_code& ec)
     {
- // Only do this once.
+ // Only call this once.
       if (!impl.env_parsed_)
         detail::save_environment(env_vars(impl.vars_));
       impl.env_parsed_ = true;
@@ -226,23 +220,34 @@
     boost::system::error_code
     parse_post_vars(RequestImpl& impl, boost::system::error_code& ec)
     {
- // Make sure this function hasn't already been called
- //BOOST_ASSERT (!impl.stdin_parsed());
-
- ;
-
- impl.fp_.reset
- (
- new typename implementation_type::form_parser_type
- ( impl.post_buffer_
+ // **FIXME** use callback_functor<> in form_parser instead.
+ std::size_t& bytes_left (impl.client_.bytes_left_);
+ std::size_t bytes_read (0);
+ do {
+ bytes_read = read_some(impl, ec);
+ bytes_left -= bytes_read;
+ } while (!ec && bytes_left);
+
+ if (!impl.fp_)
+ // Construct a form_parser instance.
+ impl.fp_.reset(new implementation_type::form_parser_type());
+
+ // Create a context for this request.
+ implementation_type::form_parser_type::context
+ context
+ = { env_vars(impl.vars_)["CONTENT_TYPE"]
+ , impl.post_buffer_
+ , impl.form_parts_
+ , impl.client_.bytes_left_
                 , post_vars(impl.vars_)
- , env_vars(impl.vars_)["CONTENT_TYPE"]
                 , callback_functor<self_type>(impl, this)
- , impl.client_.bytes_left_
                 , impl.stdin_parsed_
- )
- );
- impl.fp_->parse(ec);
+ , env_vars(impl.vars_)["REMOTE_ADDR"]
+ };
+
+ // Parse the current request.
+ impl.fp_->parse(context, ec);
+
       return ec;
     }
   };

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/detail/throw_error.hpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/detail/throw_error.hpp (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/detail/throw_error.hpp 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -21,7 +21,8 @@
      if(ec)
      {
        boost::system::system_error err(ec);
- boost::throw_exception(err);
+ //boost::throw_exception(err);
+ throw err;
      }
    }
 

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/fcgi/acceptor_service_impl.hpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/fcgi/acceptor_service_impl.hpp (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/fcgi/acceptor_service_impl.hpp 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -143,26 +143,10 @@
      boost::system::error_code
        default_init(implementation_type& impl, boost::system::error_code& ec)
      {
+ // I've never got the default initialisation working on Windows...
 #if ! defined(BOOST_WINDOWS)
- //assign(impl.acceptor_, , 0, ec);
        return acceptor_service_.assign(impl.acceptor_, boost::asio::ip::tcp::v4()
                                       , 0, ec);
-#else
-//# error "Windows isn't supported at the moment"
- HANDLE hListen = INVALID_HANDLE_VALUE;
- boost::asio::detail::socket_type sock;
- struct sockaddr sa;
- int sa_len = sizeof(sa);
-#if NO_WSAACCEPT
-// sock = accept((boost::asio::detail::socket_type)hListen, &sa, &sa_len);
-// if (sock == INVALID_SOCKET)
-// return cgi::error::invalid_socket;
-#else
-//#error BOOST_WINDOWS
- //sock = WSAAccept((unsigned int)hListen, &sa, &sa_len, NULL, (DWORD)NULL);
- if (sock == INVALID_SOCKET)
- return ::cgi::error::invalid_socket;
-#endif
 #endif
        return ec;
      }
@@ -320,26 +304,30 @@
      is_cgi(implementation_type& impl)
      {
        boost::system::error_code ec;
-//#if ! defined(BOOST_WINDOWS)
- socklen_t len
- = static_cast<socklen_t>(local_endpoint(impl,ec).capacity());
- int ret = getpeername(native(impl), local_endpoint(impl,ec).data(), &len);
- int err = errno;
- return ( ret != 0 && errno == ENOTCONN ) ? false : true;
-//#else
-// return false;
-//#endif
+ socklen_t len (
+ static_cast<socklen_t>(local_endpoint(impl,ec).capacity()) );
+ int check (
+ getpeername(native(impl), local_endpoint(impl,ec).data(), &len) );
+
+ /// The FastCGI check works differently on Windows and UNIX.
+#if defined(BOOST_WINDOWS)
+ return ( check == SOCKET_ERROR &&
+ WSAGetLastError() == WSAENOTCONN ) ? false : true;
+#else
+ return ( check == -1 &&
+ errno == ENOTCONN ) ? false : true;
+#endif
      }
 
    public:
      template<typename CommonGatewayRequest, typename Handler>
- void check_for_waiting_request(implementation_type& impl
+ int check_for_waiting_request(implementation_type& impl
                                    , CommonGatewayRequest& request
                                    , Handler handler)
      {
        // We can't call accept on an open request (close it first).
        if (request.is_open())
- return handler(error::accepting_on_an_open_request);
+ return handler(fcgi::error::accepting_on_an_open_request);
 
        // If the client is open, make sure the request is clean.
        // ie. don't leak data from one request to another!
@@ -353,8 +341,9 @@
          return handler(boost::system::error_code());
 
        // ...otherwise accept a new connection (asynchronously).
- return acceptor_service_.async_accept(impl.acceptor_,
+ acceptor_service_.async_accept(impl.acceptor_,
          request.client().connection()->next_layer(), 0, handler);
+ return 0;
      }
 
    public:

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-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -44,20 +44,20 @@
 
   /// A client that uses a TCP socket that owned by it.
   template<typename Protocol>
- class basic_client<common::shareable_tcp_connection, Protocol>
+ class basic_client<connections::shareable_tcp, Protocol>
   {
   public:
     typedef ::cgi::common::io_service io_service_type;
     typedef ::cgi::common::map map_type;
     typedef Protocol protocol_type;
- typedef common::shareable_tcp_connection connection_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_t role_type;
+ typedef fcgi::spec_detail::role_types role_type;
 
     /// Construct
     basic_client()
@@ -72,8 +72,6 @@
       : request_id_(-1)
       , status_(none_)
       , keep_connection_(false)
- //, io_service_(ios)
- //, connection_(new connection_type::pointer(ios))
     {
     }
 
@@ -96,7 +94,6 @@
       construct(RequestImpl& req, boost::system::error_code& ec)
     {
       status_ = constructed;
-
       return ec;
     }
 
@@ -155,8 +152,6 @@
       return ec;
     }
 
- //io_service_type& io_service() { return io_service_; }
-
     /// Associate a connection with this client
     /**
      * Note: the connection must have been created using the new operator
@@ -197,16 +192,44 @@
       for(; iter != end; ++iter)
       {
         boost::asio::const_buffer buffer(*iter);
- int new_buf_size( boost::asio::buffer_size(buffer) );
+ std::size_t new_buf_size( boost::asio::buffer_size(*iter) );
+ std::cerr<< "-" << new_buf_size << "-";
         // only write a maximum of 65535 bytes
- if (total_buffer_size + new_buf_size
+ if (total_buffer_size + new_buf_size
> fcgi::spec::max_packet_size::value)
- break;
- total_buffer_size += new_buf_size;
- bufs.push_back(*iter);
+ {
+ if (new_buf_size > fcgi::spec::max_packet_size::value)
+ {
+ std::cerr<< "Buffer too big." << std::endl;
+ total_buffer_size = 65000;
+ bufs.push_back(boost::asio::buffer(*iter, 65000));
+ break;
+ /*
+ std::size_t bytes_left(new_buf_size);
+ std::size_t bufsz(0);
+ while (bytes_left > 0)
+ {
+ if (bytes_left > fcgi::spec::max_packet_size::value)
+ bufsz = fcgi::spec::max_packet_size::value;
+ else
+ bufsz = bytes_left;
+ bufs.push_back(boost::asio::const_buffer(buffer, bufsz));
+ bytes_left -= bufsz;
+ }
+ */
+ }
+ else
+ break;
+ }
+ else
+ {
+ total_buffer_size += new_buf_size;
+ bufs.push_back(*iter);
+ }
       }
- std::cerr<< "Size of write buffer := " << total_buffer_size << std::endl;
- //detail::make_header(out_header_, buf
+ //std::cerr<< '\n';
+ spec::stdout_header header(request_id_, total_buffer_size);
+ bufs[0] = header.data();
       out_header_[0] = static_cast<unsigned char>(1);
       out_header_[1] = static_cast<unsigned char>(6);
       out_header_[2] = static_cast<unsigned char>(request_id_ >> 8) & 0xff;
@@ -215,11 +238,24 @@
       out_header_[5] = static_cast<unsigned char>(total_buffer_size) & 0xff;
       out_header_[6] = static_cast<unsigned char>(0);
       out_header_[7] = 0;
+
+ bool empty = bufs.empty();
+ std::size_t size = bufs.size();
+ typedef std::vector<boost::asio::const_buffer>::const_iterator
+ iter_t;
+ for (iter_t iter(bufs.begin()), end(bufs.end()); iter != end; ++iter)
+ {
+ size = boost::asio::buffer_size(*iter);
+ std::string str (
+ boost::asio::buffer_cast<const char*>(*iter)
+ , boost::asio::buffer_size(*iter) );
+ }
 
       std::size_t bytes_transferred
         = boost::asio::write(*connection_, bufs, boost::asio::transfer_all(), ec);
 
- if (0 != (total_buffer_size + fcgi::spec::header_length::value
+ //std::cerr<< "Transferred " << bytes_transferred << " bytes (total: " << total_buffer_size << ")." << std::endl;
+ if (!ec && 0 != (total_buffer_size + fcgi::spec::header_length::value
           - bytes_transferred))
         ec = ::cgi::error::couldnt_write_complete_packet;
 
@@ -244,9 +280,7 @@
     std::size_t
     read_some(const MutableBufferSequence& buf, boost::system::error_code& ec)
     {
- std::size_t bytes_read(0);
-
- return bytes_read;
+ return connection_->read_some(buf, ec);
     }
 
     /// Asynchronously write some data to the client.
@@ -281,8 +315,6 @@
       return keep_connection_;
     }
 
- //int id() { return request_id_; }
-
     std::size_t& bytes_left()
     {
       return bytes_left_;
@@ -297,41 +329,23 @@
     friend class fcgi_request_service;
     boost::uint16_t request_id_;
     client_status status_;
- std::size_t bytes_left_;
- //request_impl_type* current_request_;
-
- /// A marker to say if the final STDIN (and/or DATA) packets have been
- // read. Note: having data on the connection doesn't imply it's for
- // this request; we can save time by knowing when to not even try.
- //bool closed_;
-
+ std::size_t bytes_left_;
     connection_ptr connection_;
 
- //fcgi::spec_detail::Header hdr_;
     /// Buffer used to check the header of each packet.
     header_buffer_type out_header_;
 
     bool keep_connection_;
     role_type role_;
 
- public:
-
- //template<typename Request>
- //Request& lookup_request(boost::uint16_t id)
- //{
-
-
- //*/
   };
 
-//#include "boost/cgi/fcgi/client_fwd.hpp"
-
  } // namespace common
 
 namespace fcgi {
     typedef
       common::basic_client<
- common::shareable_tcp_connection, ::cgi::common::fcgi_
+ connections::shareable_tcp, ::cgi::common::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-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -24,8 +24,8 @@
 {
   bad_header_type = 1,
 
- /// A packet arrived for a request id that doesn't exist and the packet
- // wasn't a BEGIN_REQUEST record.
+ /// A packet arrived for a request id that doesn't exist and the
+ /// packet wasn't a BEGIN_REQUEST record.
   bad_request_id,
 
   /// When trying to write a packet, the client::write_some() call didn't
@@ -62,9 +62,16 @@
   // **FIXME**
   bad_read,
 
+ // **FIXME**
+ bad_write,
+
   // A client wasn't able to open.
   client_not_open,
   
+ // Multiplexing connections are not yet supported.
+ // (I have no access to a server that supports it)
+ multiplexing_not_supported,
+
   // An empty FastCGI packet was read (eg. STDIN or GET_PARAM data has been read).
   //empty_packet_read,
   
@@ -90,6 +97,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 multiplexing_not_supported:
+ return "Multiplexing connections are not yet supported.";
     //case empty_packet_read:
     // return "An empty FastCGI packet was read (eg. STDIN or GET_PARAM data has been read).";
     default:

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-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -52,7 +52,8 @@
>::request_type request_type;
 
       implementation_type()
- : client_()
+ : id_(0)
+ , client_()
         , stdin_parsed_(false)
         , http_status_(::cgi::common::http::no_content)
         , request_status_(common::unloaded)
@@ -63,19 +64,19 @@
 
       protocol_service_type* service_;
 
+ boost::uint16_t id_;
+
       client_type client_;
 
       bool stdin_parsed_;
       ::cgi::common::http::status_code http_status_;
       common::request_status request_status_;
- fcgi::spec_detail::role_t request_role_;
+ fcgi::spec_detail::role_types request_role_;
       std::size_t characters_left_;
 
       bool all_done_;
 
- /************** New stuff *****************/
       header_buffer_type header_buf_;
- boost::uint16_t id_;
       typedef detail::form_parser form_parser_type;
 
       boost::scoped_ptr<form_parser_type> fp_;
@@ -93,8 +94,9 @@
      };
 
     typedef fcgi_request_service self_type;
- typedef ::cgi::fcgi::fcgi_request_service full_type;
+ typedef fcgi_request_service full_type;
     typedef self_type::implementation_type::protocol_type protocol_type;
+ typedef self_type::implementation_type::string_type string_type;
     typedef self_type::implementation_type::request_type request_type;
 
     template<typename Service>
@@ -180,11 +182,7 @@
     boost::system::error_code
     load(implementation_type& impl, common::parse_options opts
           , boost::system::error_code& ec);
-/*
- boost::system::error_code
- load(implementation_type& impl, common::parse_options parse_opts
- , boost::system::error_code& ec);
-*/
+
     // **FIXME**
     template<typename Handler>
     void async_load(implementation_type& impl, bool parse_stdin, Handler handler);
@@ -248,22 +246,22 @@
     // **FIXME**
     boost::system::error_code
       process_begin_request(implementation_type& impl, boost::uint16_t id
- , const unsigned char* buf, boost::uint16_t
+ , const unsigned char* buf, boost::uint32_t
                            , boost::system::error_code& ec);
 
     boost::system::error_code
       process_abort_request(implementation_type& impl, boost::uint16_t id
- , const unsigned char* buf, boost::uint16_t
+ , const unsigned char* buf, boost::uint32_t
                            , boost::system::error_code& ec);
 
     boost::system::error_code
       process_params(implementation_type& impl, boost::uint16_t id
- , const unsigned char* buf, boost::uint16_t len
+ , const unsigned char* buf, boost::uint32_t len
                     , boost::system::error_code& ec);
 
     boost::system::error_code
       process_stdin(implementation_type& impl, boost::uint16_t id
- , const unsigned char* buf, boost::uint16_t len
+ , const unsigned char* buf, boost::uint32_t len
                    , boost::system::error_code& ec);
 
     /// Parse the current header
@@ -278,7 +276,7 @@
     typedef boost::system::error_code
       ( full_type::* proc_func_t)
       (implementation_type& impl, boost::uint16_t, const unsigned char*
- , boost::uint16_t, boost::system::error_code&);
+ , boost::uint32_t, boost::system::error_code&);
 
     static const proc_func_t proc_funcs[];
   

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-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -9,7 +9,6 @@
 #ifndef CGI_FCGI_SPECIFICATION_HPP_INCLUDED__
 #define CGI_FCGI_SPECIFICATION_HPP_INCLUDED__
 
-//#include <inttypes.h>
 #include <boost/cstdint.hpp>
 
 // NOTE: CamelCase style mimicks the FastCGI specification
@@ -37,18 +36,19 @@
       = (unsigned char)BOOST_CGI_FASTCGI_VERSION_1;
 
     // Values for the type component of Header
- enum request_t { BEGIN_REQUEST = 1
- , ABORT_REQUEST = 2
- , END_REQUEST = 3
- , PARAMS = 4
- , STDIN = 5
- , STDOUT = 6
- , STDERR = 7
- , DATA = 8
- , GET_VALUES = 9
- , GET_VALUES_RESULT = 10
- , UNKNOWN_TYPE = 11
- , MAXTYPE = UNKNOWN_TYPE
+ enum request_types
+ { BEGIN_REQUEST = 1
+ , ABORT_REQUEST = 2
+ , END_REQUEST = 3
+ , PARAMS = 4
+ , STDIN = 5
+ , STDOUT = 6
+ , STDERR = 7
+ , DATA = 8
+ , GET_VALUES = 9
+ , GET_VALUES_RESULT = 10
+ , UNKNOWN_TYPE = 11
+ , MAXTYPE = UNKNOWN_TYPE
     };
 
     // a null request id is a management record
@@ -61,14 +61,14 @@
     const boost::uint16_t MAX_MSG_LEN = 65535;
 
     // Values for role component of BeginRequestBody
- enum role_t { RESPONDER = 1
+ enum role_types { RESPONDER = 1
                 , AUTHORIZER = 2
                 , FILTER = 3
                 , ANY
     };
 
     // Values for protocolStatus component of EndRequestBody
- enum status_t { REQUEST_COMPLETE = 0
+ enum status_types { REQUEST_COMPLETE = 0
                   , CANT_MPX_CONN = 1
                   , OVERLOADED = 2
                   , UNKNOWN_ROLE = 3
@@ -93,16 +93,29 @@
         unsigned char paddingLength_;
         unsigned char reserved_;
       } impl;
-
+
     public:
- Header() { memset(static_cast<void*>(&this->impl), 0, sizeof(this->impl)); }
+ typedef boost::asio::const_buffers_1 const_buffers_type;
 
- Header(request_t t, int id, int len)
+ Header()
+ {
+ memset(static_cast<void*>(&this->impl)
+ , 0, sizeof(this->impl));
+ }
+
+ Header(request_types t, int id, int len)
       {
         reset(t, id, len);
       }
+
+ const_buffers_type data() const
+ {
+ return boost::asio::buffer(
+ static_cast<const void*>(&impl)
+ , sizeof(impl));
+ }
 
- void reset(request_t t, int id, int len)
+ void reset(request_types t, int id, int len)
       {
         impl.version_ = (VERSION_NUM);
         impl.type_ = ((unsigned char)t);
@@ -200,13 +213,13 @@
       EndRequestBody() {}
 
       EndRequestBody( boost::uint64_t appStatus
- , status_t procStatus
+ , status_types procStatus
                     )
       {
         reset(appStatus, procStatus);
       }
 
- void reset( boost::uint64_t appStatus, status_t procStatus)
+ void reset( boost::uint64_t appStatus, status_types procStatus)
       {
         impl.appStatusB3_ = ( (appStatus >> 24) & 0xff );
         impl.appStatusB2_ = ( (appStatus >> 16) & 0xff );
@@ -234,7 +247,7 @@
     public:
       EndRequestRecord( boost::uint16_t id
                       , boost::uint64_t appStatus
- , status_t procStatus
+ , status_types procStatus
                       )
       {
         impl.header_.reset( END_REQUEST, id, sizeof(EndRequestBody) );
@@ -301,6 +314,11 @@
   namespace specification {
 
 #include <boost/mpl/int.hpp>
+
+ /// Define the FastCGI spec using types.
+ /**
+ * Types are better than macros.
+ */
 
     struct max_packet_size
       : boost::mpl::int_<65535>
@@ -324,9 +342,9 @@
     int get_version(Array& a) { return static_cast<int>(a[0]); }
     
     template<typename Array>
- spec_detail::request_t get_type(Array& a)
+ spec_detail::request_types get_type(Array& a)
     {
- return static_cast<spec_detail::request_t>(a[1]);
+ return static_cast<spec_detail::request_types>(a[1]);
     }
     
     template<typename Array>
@@ -397,25 +415,84 @@
       {
         typedef boost::mpl::int_<8> size;
       };
+
+ typedef boost::array<
+ unsigned char
+ , header_length::value
+ > buffer_type;
+
+ buffer_type impl;
+
+ begin_request(buffer_type& buf)
+ : impl(buf)
+ {
+ }
+
+ spec_detail::role_types role()
+ {
+ return static_cast<spec_detail::role_types>(
+ (impl[0] << 8) + impl[1] );
+ }
+
+ unsigned char flags()
+ {
+ return impl[2];
+ }
 
       template<typename Array>
- static spec_detail::role_t
- get_role(Array& a)
+ static spec_detail::role_types
+ role(Array& a)
       {
- return static_cast<spec_detail::role_t>( (a[0] << 8) + a[1] );
+ return static_cast<spec_detail::role_types>(
+ (a[0] << 8) + a[1] );
       }
 
       template<typename Array>
       static unsigned char
- get_flags(Array& a)
+ flags(Array& a)
       {
         return a[2];
       }
-
- //typedef spec_detail::BEGIN_REQUEST type;
+ };
+
+ struct stdout_header
+ : spec_detail::Header
+ {
+ explicit stdout_header(int request_id, int content_len)
+ : Header(spec_detail::STDOUT, request_id, content_len)
+ {
+ }
+ };
+
+ class BeginRequestBody
+ {
+ /// The underlying type of a BeginRequestBody sub-header.
+ /**
+ * To guarantee the header is laid out exactly as we want, the
+ * structure must be a POD-type (see http://tinyurl.com/yo9eav).
+ */
+ struct implementation_type
+ {
+ unsigned char roleB1_;
+ unsigned char roleB0_;
+ unsigned char flags_;
+ unsigned char reserved_[5];
+ } impl;
+
+ public:
+
+ int role() const
+ {
+ return (impl.roleB1_ << 8 ) + impl.roleB0_;
+ }
 
+ unsigned char flags() const
+ {
+ return impl.flags_;
+ }
     };
 
+
     struct role_type
     {
       template<typename Array>

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-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -13,6 +13,7 @@
 #include <boost/system/error_code.hpp>
 #include <boost/fusion/include/vector.hpp>
 ////////////////////////////////////////////////////////////////
+#include "boost/cgi/fcgi/error.hpp"
 #include "boost/cgi/fcgi/client.hpp"
 #include "boost/cgi/fcgi/request_service.hpp"
 #include "boost/cgi/common/map.hpp"
@@ -108,6 +109,7 @@
       common::cookie_vars(impl.vars_).clear();
       common::env_vars(impl.vars_).clear();
       impl.stdin_parsed_ = false;
+ impl.get_parsed_ = false;
       impl.http_status_ = common::http::no_content;
       impl.request_status_ = common::null;
       impl.request_role_ = spec_detail::ANY;
@@ -127,109 +129,64 @@
      * packet for this request arrives from the server.
      *
      */
-/*
- /// Synchronously read/parse the request meta-data
- BOOST_CGI_INLINE boost::system::error_code
- fcgi_request_service::load(
- implementation_type& impl, common::parse_options parse_opts
- , boost::system::error_code& ec)
- {
- if (parse_opts & common::parse_env)
- {
- if (!read_env_vars(impl, ec)) // returns an error_code
- return ec;
- }
-
- std::string const& cl = env_vars(impl.vars_)["CONTENT_LENGTH"];
- impl.characters_left_ = cl.empty() ? 0 : boost::lexical_cast<std::size_t>(cl);
- impl.client_.bytes_left() = impl.characters_left_;
-
- std::string const& request_method = env_vars(impl.vars_)["REQUEST_METHOD"];
-
- if (request_method == "GET" && parse_opts & common::parse_get)
- {
- parse_get_vars(impl, ec);
- }
- else
- if (request_method == "POST" && parse_opts & common::parse_post)
- {
- parse_post_vars(impl, ec);
- }
-
- if (ec) return ec;
-
- if (parse_opts & common::parse_cookie)
- {
- if (!parse_cookie_vars(impl, ec)) // returns an error_code
- return ec;
- }
-
- set_status(impl, common::loaded);
-
- return ec;
- }
-/*/
     BOOST_CGI_INLINE boost::system::error_code
     fcgi_request_service::load(
         implementation_type& impl, common::parse_options opts
       , boost::system::error_code& ec)
     {
- //int header_len( get_length_of_header(impl, ec) );
- BOOST_ASSERT(!ec && "Can't load request due to previous errors.");
+ BOOST_ASSERT(!ec &&
+ "Can't load request due to previous errors.");
 
       impl.client_.construct(impl, ec);
       // Bomb out if the client isn't open here.
       if (!impl.client_.connection_->is_open())
           return error::client_not_open;
 
- for(;;)
+ while(!ec)
       {
         if (read_header(impl, ec))
           break;
- int id(fcgi::spec::get_request_id(impl.header_buf_));
- if (id == fcgi::spec::null_request_id::value)
+ int id(spec::get_request_id(impl.header_buf_));
+ if (id == spec::null_request_id::value)
           handle_admin_request(impl);
         else
- if (fcgi::spec::get_type(impl.header_buf_)
- == fcgi::spec::begin_request::value)
+ if (impl.id_ && impl.id_ != id)
+ {
+ // The library doesn't support multiplexed connections yet,
+ // mainly because I've never had access to a server that
+ // supports it.
+ //
+ // If you have one, can I use it?
+ ec = error::multiplexing_not_supported;
+ }
+ else
+ if (spec::get_type(impl.header_buf_)
+ == spec::begin_request::value)
         {
           impl.id_ = id;
           impl.client_.request_id_ = id;
- if (read_header(impl, ec))
+ if (!read_header(impl, ec))
+ {
+ spec::begin_request packet(impl.header_buf_);
+ impl.request_role_ = packet.role();
+ impl.client_.keep_connection_
+ = packet.flags() & spec::keep_connection;
             break;
- impl.request_role_ = fcgi::spec::begin_request::get_role(impl.header_buf_);
- //std::cerr<< "[hw] New request role: " << impl.request_role_
- // << " (" << fcgi::spec::role_type::to_string(impl.header_buf_) << ")"
- // << std::endl;
- impl.client_.keep_connection_
- = fcgi::spec::begin_request::get_flags(impl.header_buf_)
- & fcgi::spec::keep_connection;
- //std::cerr<< "keep connection := " << impl.client_.keep_connection_ << std::endl;
- break;
+ }
         }else
           handle_other_request_header(impl);
       }
-
- read_env_vars(impl, ec);
-
- if (opts & common::parse_post_only)
+
+ if (//impl.request_status_ < common::env_read &&
+ opts & common::parse_env)
       {
- 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;
+ read_env_vars(impl, ec);
+ //impl.request_status_ = common::env_read;
       }
- //else
- //if (ec == error::empty_packet_read)
- // return ec;
-
- const std::string& request_method = env_vars(impl.vars_)["REQUEST_METHOD"];
+
+ string_type const&
+ request_method (env_vars(impl.vars_)["REQUEST_METHOD"]);
+
       if (request_method == "GET")
       {
         if (parse_get_vars(impl, ec))
@@ -243,7 +200,25 @@
         if (parse_post_vars(impl, ec))
               return ec;
       }
- parse_cookie_vars(impl, 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;
+ }
+ else if (ec) return ec;
+
+ bool check = impl.client_.is_open();
 
       return ec;
     }
@@ -278,25 +253,29 @@
         implementation_type& impl
       , boost::system::error_code& ec)
     {
- // Make sure this function hasn't already been called
- //BOOST_ASSERT( impl.post_vars().empty() );
-
- //# error "Not implemented"
- // **FIXME** should use form_parser, when it's ready.
- // Only works with url-encoded forms (ie. not with multipart forms)
-
- impl.fp_.reset
- (
- new implementation_type::form_parser_type
- ( impl.post_buffer_
+ if (!impl.fp_)
+ // Construct a form_parser instance.
+ impl.fp_.reset(new implementation_type::form_parser_type());
+
+ impl.client_.bytes_left_
+ = boost::lexical_cast<std::size_t>(
+ env_vars(impl.vars_)["CONTENT_LENGTH"]);
+
+ // Create a context for this request.
+ implementation_type::form_parser_type::context
+ context
+ = { env_vars(impl.vars_)["CONTENT_TYPE"]
+ , impl.post_buffer_
+ , impl.form_parts_
+ , impl.client_.bytes_left_
                 , post_vars(impl.vars_)
- , env_vars(impl.vars_)["CONTENT_TYPE"]
                 , callback_functor<self_type>(impl, this)
- , impl.client_.bytes_left_
                 , impl.stdin_parsed_
- )
- );
- impl.fp_->parse(ec);
+ , env_vars(impl.vars_)["REMOTE_ADDR"]
+ };
+
+ // Parse the current request.
+ impl.fp_->parse(context, ec);
 
       return ec;
     }
@@ -326,7 +305,7 @@
       }
 
       //if (read_header(ec))
- return -1;
+ return 0;
 
       //boost::tribool state = parse_header(impl);
       //std::size_t bytes_read;//( connection_->read_some(buf, ec) );
@@ -355,7 +334,8 @@
           ec = error::bad_header_type;
         else // => (state == boost::indeterminate)
         {
- std::size_t remaining(fcgi::spec::get_length(impl.header_buf_));
+ std::size_t remaining(
+ fcgi::spec::get_length(impl.header_buf_));
 
           if (remaining)
           {
@@ -425,7 +405,7 @@
     BOOST_CGI_INLINE boost::system::error_code
     fcgi_request_service::process_abort_request(
         implementation_type& impl, boost::uint16_t id
- , const unsigned char* buf, boost::uint16_t
+ , const unsigned char* buf, boost::uint32_t
       , boost::system::error_code& ec)
     {
       if (id == fcgi::spec::get_request_id(impl.header_buf_))
@@ -457,22 +437,20 @@
     BOOST_CGI_INLINE boost::system::error_code
     fcgi_request_service::process_params(
         implementation_type& impl, boost::uint16_t id
- , const unsigned char* buf, boost::uint16_t len
+ , const unsigned char* buf, boost::uint32_t len
       , boost::system::error_code& ec)
     {
       if (0 == len)
       { // This is the final param record.
         
         impl.client_.status(common::params_read);
-
- //std::cerr<< "[hw] Final PARAM record found." << std::endl;
         return ec;
       }
 
       while(len)
       {
         boost::uint32_t name_len, data_len;
- std::string name, data;
+ string_type name, data;
         if (*buf >> 7 == 0)
         {
             name_len = *(buf++);
@@ -507,10 +485,6 @@
         buf += (name_len + data_len);
         len -= (name_len + data_len);
 
- //std::cerr<< "[hw] name := " << name << std::endl;
- //std::cerr<< "[hw] data := " << data << std::endl;
-
- // **FIXME**
         env_vars(impl.vars_)[name.c_str()] = data;
       }
 
@@ -521,20 +495,14 @@
     BOOST_CGI_INLINE boost::system::error_code
     fcgi_request_service::process_stdin(
         implementation_type& impl, boost::uint16_t id
- , const unsigned char* buf, boost::uint16_t len
+ , const unsigned char* buf, boost::uint32_t len
       , boost::system::error_code& ec)
     {
       if (0 == len)
       {
- impl.client_.status_ = common::stdin_read;
-
- // **FIXME**
- //std::cerr<< "[hw] Final STDIN record found." << std::endl;
+ impl.client_.status(common::stdin_read);
         return ec;
       }
-
- // **FIXME**
- //std::cerr<< "[hw] Found some STDIN stuff." << std::endl;
       return ec;
     }
 
@@ -558,13 +526,13 @@
           impl.client_.status(common::stdin_read);
           return true;
         } else
- return boost::indeterminate; //0 == fcgi::spec::get_length(impl.header_buf_) ? true : boost::indeterminate;
+ return boost::indeterminate;
       case PARAMS:
         if (0 == fcgi::spec::get_length(impl.header_buf_)) {
           impl.client_.status(common::params_read);
           return true;
         } else
- return boost::indeterminate; //0 == fcgi::spec::get_length(impl.header_buf_) ? true : boost::indeterminate;
+ return boost::indeterminate;
       case ABORT_REQUEST:
         return false;
       case UNKNOWN_TYPE:
@@ -577,36 +545,34 @@
     fcgi_request_service::parse_packet(
         implementation_type& impl, boost::system::error_code& ec)
     {
- //current_request_ = &req;
-
       if (this->read_header(impl, ec))
         return ec;
 
       boost::tribool state = this->parse_header(impl);
 
       if (state)
- { // the header has been handled and all is ok; continue.
- return ec;
- }else
+ {
+ // the header has been handled and all is ok.
+ // **NOOP**
+ } else
       if (!state)
       { // The header is confusing; something's wrong. Abort.
- return error::bad_header_type;
+ ec = error::bad_header_type;
       }
- // else route (ie. state == boost::indeterminate)
-
- std::size_t remaining(fcgi::spec::get_length(impl.header_buf_));
- if (remaining)
+ else
       {
- implementation_type::mutable_buffers_type buf
- = impl.prepare(remaining);
+ std::size_t remaining(fcgi::spec::get_length(impl.header_buf_));
+ if (remaining)
+ {
+ implementation_type::mutable_buffers_type buf
+ = impl.prepare(remaining);
 
- if (this->read_body(impl, buf, ec))
- return ec;
+ if (this->read_body(impl, buf, ec))
+ return ec;
 
- this->parse_body(impl, buf, ec);
- }
- //else
- // ec = error::empty_packet_read;
+ this->parse_body(impl, buf, ec);
+ }
+ }
       return ec;
     }
 
@@ -618,7 +584,8 @@
       , boost::system::error_code& ec)
     {
       std::size_t bytes_read
- = read(*impl.client_.connection_, buf, boost::asio::transfer_all(), ec);
+ = read(*impl.client_.connection_, buf
+ , boost::asio::transfer_all(), ec);
 
       BOOST_ASSERT(bytes_read == fcgi::spec::get_length(impl.header_buf_)
                    && "Couldn't read all of the record body.");
@@ -654,12 +621,12 @@
        if (read_header(impl, ec))
          return ec;
         
- impl.request_role_
- = fcgi::spec::begin_request::get_role(impl.header_buf_);
- impl.client_.role_ = impl.request_role_;
+ spec::begin_request packet(impl.header_buf_);
+ impl.request_role_ = packet.role();
+ impl.client_.role_ = packet.role();
        impl.client_.keep_connection_
- = fcgi::spec::begin_request::get_flags(impl.header_buf_)
- & fcgi::spec::keep_connection;
+ = packet.flags() & spec::keep_connection;
+
        impl.client_.status_ = common::constructed;
        
        return ec;
@@ -707,7 +674,7 @@
     BOOST_CGI_INLINE boost::system::error_code
     fcgi_request_service::process_begin_request(
         implementation_type& impl, boost::uint16_t id
- , const unsigned char* buf, boost::uint16_t
+ , const unsigned char* buf, boost::uint32_t
       , boost::system::error_code& ec)
     {
       if (impl.client_.request_id_ == 0) // ie. hasn't been set yet.

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/impl/form_parser.ipp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/impl/form_parser.ipp (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/impl/form_parser.ipp 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -16,73 +16,28 @@
 #include "boost/cgi/common/source_enums.hpp"
 
 #include <iostream> // **FIXME**
+#include <fstream>
+#include <boost/algorithm/string/trim.hpp>
+#include <boost/random/mersenne_twister.hpp>
 
 namespace cgi {
  namespace detail {
 
-/*
- BOOST_CGI_INLINE
- form_parser::form_parser (
- )
- : content_type_(env_vars(impl.vars_)["CONTENT_TYPE"])
- , buffer_(impl.buffer_)
- , bytes_left_(impl.client_.bytes_left_)
- //, stdin_data_read_(impl.stdin_data_read_)
- , offset_(0)
- , data_map_(post_vars(impl.vars_))
- , callback_()
- {
- }
-
- BOOST_CGI_INLINE
- form_parser::form_parser (
- , callback_type const& callback
- )
- : content_type_(env_vars(impl.vars_)["CONTENT_TYPE"])
- , buffer_(impl.buffer_)
- , bytes_left_(impl.client_.bytes_left_)
- //, stdin_data_read_(impl.stdin_data_read_)
- , offset_(0)
- , data_map_(post_vars(impl.vars_))
- , callback_(callback)
- {
- }
-*/
-
- BOOST_CGI_INLINE
- form_parser::form_parser (
- buffer_type& buf
- , common::post_map& data_map
- , form_parser::string_type const& ct
- , callback_type const& callback
- , std::size_t& bytes_left
- , bool& stdin_parsed
- )
- : content_type_(ct)//env_vars(impl.vars_)["CONTENT_TYPE"])
- , buffer_(buf)
- , bytes_left_(bytes_left)
- , data_map_(data_map)
- , callback_(callback)
- , stdin_parsed_(stdin_parsed)
- , offset_(0)
- {
- }
-
     BOOST_CGI_INLINE
     boost::system::error_code
- form_parser::parse(boost::system::error_code& ec)
+ form_parser::parse(context ctx, boost::system::error_code& ec)
     {
- BOOST_ASSERT(!content_type_.empty());
+ context_ = &ctx;
+
+ BOOST_ASSERT(!ctx.content_type.empty());
 
- if (content_type_.find("application/x-www-form-urlencoded") != std::string::npos)
- {
+ if (ctx.content_type.find(
+ "application/x-www-form-urlencoded") != string_type::npos)
         parse_url_encoded_form(ec);
- }
        else
- if (content_type_.find("multipart/form-data") != std::string::npos)
- {
+ if (ctx.content_type.find(
+ "multipart/form-data") != string_type::npos)
         parse_multipart_form(ec);
- }
       else
         return ec = error::invalid_form_type;
 
@@ -93,9 +48,7 @@
     boost::system::error_code
       form_parser::parse_url_encoded_form(boost::system::error_code& ec)
     {
- typedef buffer_type buffer_type;
- typedef std::string string_type; // Ahem.
- buffer_type& str(buffer_);
+ buffer_type& str(context_->buffer);
      string_type result;
      string_type name;
 
@@ -131,7 +84,7 @@
             break;
          case '&': // we now have the name/value pair, so save it
             // **FIXME** have to have .c_str() ?
- data_map_[name.c_str()] = result;
+ context_->data_map[name.c_str()] = result;
             result.clear();
             name.clear();
             break;
@@ -142,7 +95,7 @@
 #if defined(BOOST_CGI_KEEP_EMPTY_VARS)
       // save the last param (it won't have a trailing &)
       if( !name.empty() )
- data_map_[name.c_str()] = result;
+ context_->data_map[name.c_str()] = result;
 #endif // BOOST_CGI_KEEP_EMPTY_VARS
      return ec;
     }
@@ -153,19 +106,10 @@
       form_parser::parse_multipart_form(boost::system::error_code& ec)
     {
       parse_boundary_marker(ec);
-
- std::cerr<< "Parsed boundary marker" << std::endl;
       move_to_start_of_first_part(ec);
- std::cerr<< (ec ? "Error finding first multipart section" : "Moved to start of actual data") << std::endl;
 
- if (ec && ec != boost::asio::error::eof)
- return ec;
-
- do {
+ while(!ec && !context_->stdin_parsed)
         parse_form_part(ec);
- }while( //!impl_.stdin_parsed_
- bytes_left_ // != 0
- );//&& ec != boost::asio::error::eof );
 
       return ec;
     }
@@ -175,228 +119,98 @@
     boost::system::error_code
       form_parser::parse_form_part(boost::system::error_code& ec)
     {
- if (!parse_form_part_meta_data(ec)
- && !parse_form_part_data(ec))
- return ec;
+ namespace algo = boost::algorithm;
 
- return ec;
- }
+ string_type marker(
+ string_type("--") + context_->boundary_markers.front());
+ string_type& buffer(context_->buffer);
+ std::size_t& offset (context_->offset);
+
+ std::size_t end = buffer.find("\r\n\r\n", offset);
+ if (end == string_type::npos)
+ return ec = common::error::multipart_meta_data_not_terminated;
+
+ string_type meta (buffer.substr(offset,end-offset));
+
+ std::cerr<< "Meta info: " << meta << std::endl;
 
- BOOST_CGI_INLINE
- boost::system::error_code
- form_parser::parse_form_part_data(boost::system::error_code& ec)
- {
- std::cerr<< "In form_parser::parse_form_part_data" << std::endl;
- std::string regex("^(.*?)" // the data
- "\\x0D\\x0A" // CR LF
- "--" "(");
- if (boundary_markers.size() > 1)
+ // sic - short-cut check for Content-Disposition.
+ std::size_t pos1 = meta.find("isposition:"); // sic
+ std::size_t pos2 = meta.find(";", pos1);
+ std::size_t pos3 = meta.find("name=");
+ std::size_t pos4 = meta.find(";", pos3);
+ std::size_t pos5 = meta.find("\r\n");
+ std::size_t pos6 = meta.find("filename=", pos2);
+
+ if (pos3 == string_type::npos)
+ pos3 = meta.find("\r\n");
+ string_type field_name (meta.substr(pos3+5, pos4-pos3-5));
+ algo::trim_if(field_name, algo::is_any_of("\" "));
+
+ string_type content_disposition (meta.substr(pos1+11, pos2-pos1-11));
+
+ common::form_part part;
+ part.name = field_name;
+ part.content_disposition = content_disposition;
+
+ std::size_t next_pos = buffer.find(string_type("\r\n") + marker, end);
+
+ if (pos6 == string_type::npos)
       {
- std::list<std::string>::iterator i(boundary_markers.begin());
- regex = regex + "(?:" + *i + ")";
- ++i;
- for(; i != boundary_markers.end(); ++i)
- {
- regex = regex + "|(?:" + *i + ")";
- }
+ string_type content (
+ buffer.substr(meta.length()+4, next_pos-meta.length()-4));
+
+ // Load the data to the request's post map.
+ context_->data_map[part.name.c_str()] = content;
       }
       else
       {
- regex += *boundary_markers.begin();
- }
-
- regex += ")(--)?[ ]*(?:\\x0D\\x0A)?";
- boost::regex re(regex);
-
- typedef buffer_type::iterator buffer_iter;
-
- boost::match_results<buffer_iter> matches;
-
- std::size_t offset = offset_;
-
- //int runs = 0;
- buffer_iter begin(buffer_.begin() + offset);
- buffer_iter end(buffer_.end());
- std::cerr<< "Current buffer (a) :{ " << std::string(begin,end) << " }: " << std::endl;
-
- for(;;)
- {
- if (!boost::regex_search(begin, end, matches, re
- , boost::match_default
- | boost::match_partial))
- {
- return boost::system::error_code(345, boost::system::system_category);
- }
- else
- {
- if (matches[1].matched)
- {
- form_parts_.back().buffer_
- // = boost::range_iterator<;
- = std::make_pair(matches[1].first, matches[1].second);
- // **FIXME**
- data_map_[form_parts_.back().name.c_str()] = matches[1];
- //std::ofstream of("c:/cc/log/post_vars.log");
- //of<< "var == " << matches[1] << std::endl;
- offset_ = offset + matches[0].length();
- pos_ = matches[0].second;
-
- if (matches[3].matched)
- {
- bytes_left_ = 0; // stop reading completely.
- //impl_.stdin_parsed_ = true;
- }
- return ec;
- }
- else
- {
- std::size_t bytes_read
- = callback_(ec);
- //impl_.client_.read_some(prepare(64), ec);
-
- if (bytes_read == 0 && bytes_left_ == 0) // **FIXME**
- {
- //stdin_data_read_ = true;
- return ec;
- }
-
- begin = buffer_.begin() + offset;
- end = buffer_.end();
-
- if (ec)
- return ec;
- }
+ string_type filename (meta.substr(pos6+9, pos5-pos6-9));
+ algo::trim_if(filename, algo::is_any_of("\" "));
+ // Load the filename as the value on the request's post map.
+ context_->data_map[part.name.c_str()] = filename;
+ // Empty parameters could probably be left out, but setting even
+ // an empty variable is consistent with the rest of the library.
+ // **FIXME** Might be useful to respect BOOST_CGI_KEEP_EMPTY_VARS
+ // here. Leaving that out as it would not be expected, AFAIK.
+ if (!filename.empty())
+ {
+ part.filename = filename;
+ // Load the data to a local file.
+ string_type content (
+ buffer.substr(meta.length()+4, next_pos-meta.length()-4));
+ //boost::mt19937 rng(time(NULL));
+ string_type randomatter (
+ boost::lexical_cast<string_type>(time(NULL)));
+ string_type user_ip (context_->random_string);
+ string_type internal_filename(
+ BOOST_CGI_UPLOAD_DIRECTORY+filename+"."+user_ip+"."+randomatter);
+ part.path = internal_filename;
+ std::cerr<< "Internal filename: " << internal_filename
+ << std::endl;
+ std::ofstream file (
+ internal_filename.c_str()
+ , std::ios::out | std::ios::binary);
+ file<< content;
+ file.flush();
         }
       }
-
- return ec;
- }
-
- BOOST_CGI_INLINE
- boost::system::error_code
- form_parser::parse_form_part_meta_data(boost::system::error_code& ec)
- {
- // Oh dear this is ugly. The move to Boost.Spirit will have to be sooner than planned.
- // (it's a nested, recursive pattern, which regexes don't suit, apparently)
- boost::regex re( "(?:" // [IGNORE] the line may be empty, as meta-data is optional
- "^"
- "([-\\w]+)" // name
- ":[ ^]*" // separator
- "([-/\\w]+)" // optional(?) value
- ""
- "(?:"
- ";"
- "[ ]*" // additional name/value pairs (don't capture)
- "([-\\w]+)" // name
- "[ \\x0D\\x0A]*=[ \\x0D\\x0A]*" // separator
- "(?:\"?([-.\\w]*)\"?)" // value may be empty
- ")?"
- "(?:"
- ";"
- "[ ]*" // additional name/value pairs (don't capture)
- "([-\\w]+)" // name
- "[ \\x0D\\x0A]*=[ \\x0D\\x0A]*" // separator
- "(?:\"?([-.\\w]*)\"?)" // value may be empty
- ")?" // mark the extra n/v pairs optional
- "(?:\\x0D\\x0A)"
- ")"
- "(?:"
- "([-\\w]+)" // name
- ":[ ^]*" // separator
- "([-/\\w]+)" // optional(?) value
- ""
- "(?:"
- ";"
- "[ ]*" // additional name/value pairs (don't capture)
- "([-\\w]+)" // name
- "[ \\x0D\\x0A]*=[ \\x0D\\x0A]*" // separator
- "(?:\"?([-.\\w]*)\"?)" // value may be empty
- ")?"
- "(?:"
- ";"
- "[ ]*" // additional name/value pairs (don't capture)
- "([-\\w]+)" // name
- "[ \\x0D\\x0A]*=[ \\x0D\\x0A]*" // separator
- "(?:\"?([-.\\w]*)\"?)" // value may be empty
- ")?" // mark the extra n/v pairs optional
- "(?:\\x0D\\x0A)" // followed by the end of the line
- ")?"
- "(\\x0D\\x0A)"); // followed by the 'header termination' line
-
- boost::regex re2("([^\\n\\r]+?)\\r\\n\\r\\n");
-
- typedef buffer_type::iterator buffer_iter;
-
- boost::match_results<buffer_iter> matches;
-
- std::size_t offset = offset_;
- pos_ = buffer_.begin();
- int runs = 0;
-
- std::size_t bytes_read = 0;
- for(;;)
- {
- buffer_iter begin(buffer_.begin() + offset);
- buffer_iter end(buffer_.end());
- std::cerr<< "Current buffer (b) :{ " << std::string(begin,end) << " }: " << std::endl;
-
- if (!boost::regex_search(begin, end, matches, re2
- , boost::match_default | boost::match_partial))
- {
- std::cerr<< "Read all stdin." << std::endl;
- stdin_parsed_ = true;
- return ec;
- }
- if (matches[0].matched)
- {
- common::form_part part;
- for ( unsigned int i = 1
- ; i < matches.size()
- && matches[i].matched
- && !matches[i].str().empty()
- ; i+=1)
- {
- if (matches[i].str() == "name")
- {
- part.name = matches[i+1];
- }
- else
- {
- part.meta_data_[matches[i]]
- = std::make_pair(matches[i+1].first, matches[i+1].second);
- }
- std::cerr<< "Adding form part with name :{ " << part.name << " }: " << std::endl;
- form_parts_.push_back(part);
- }
-
- std::cerr<< " num matches = " << matches.size() << std::endl;
- std::cerr<< "matches[13] :{ " << matches[13].str() << " }: " << std::endl;
-
- if (matches[13].str() == "\r\n")
- {
- offset_ = offset + matches[0].length();
- offset += matches[0].length();
- pos_ = matches[0].second;
- std::cerr<< "stuff :{ " << matches[0].str() << " }: " << std::endl;
- return ec;
- }
- else
- {
- std::cerr<< "oh no" << std::endl;
- throw std::runtime_error("Invalid POST data (header wasn't terminated as expected)");
- }
-
- }else{
- bytes_read = callback_(ec);
- if (ec) return ec;
- if (++runs > 40)
- {
- std::cerr<< "Done 40 runs; bailing out" << std::endl;
- break;
- }
- }
+ context_->form_parts.push_back(part);
+
+ buffer.erase(0, next_pos+marker.length()+2);
+ if (buffer.length() >= 2
+ && buffer.substr(0,2) == "--")
+ {
+ //ec = common::error::eof;
+ context_->stdin_parsed = true;
+ context_->bytes_left = 0;
       }
- std::cerr<< " -- Done form part meta data. -- " << std::endl;
+ else
+ if (buffer.length() == 0)
+ context_->bytes_left = 0;
+
+ buffer.erase(0,2);
+
       return ec;
     }
 
@@ -404,65 +218,19 @@
     boost::system::error_code
       form_parser::move_to_start_of_first_part(boost::system::error_code& ec)
     {
- //std::cerr<< "In func: " << boundary_markers.front() << std::endl;
- boost::regex re("(?:"//(?:.*?)?" // optional leading characters
- //"(?:\\x0D\\x0A)|^" // start of line
- //"[\\x0D\\x0A^\\<]*?"
- "("
- "--" + boundary_markers.front() + // two dashes and our marker
- ")"
- "(--)?" // optional two dashes
- "[ \\r\\n]*?\\r\\n)");
- // on the first marker.
-
- typedef buffer_type::iterator buffer_iter;
- std::cerr<< "Regex :{ " << re << " }: " << std::endl;
-
- boost::match_results<buffer_iter> matches;
-
- // get data into our buffer until we reach the first boundary marker.
- int runs = 0;
- std::size_t offset = 0;
- std::size_t bytes_read = 0;
- for(;;)
- {
- // The function object stored in `callback_` is used to read data.
- bytes_read = callback_(ec);
-
- std::cerr<< "Read " << bytes_read << " bytes from the socket (offset = " << offset << ")." << std::endl
- << "Current buffer :{ " << std::string(buffer_.begin(), buffer_.end()) << " }: " << std::endl;
+ string_type marker(
+ string_type("--") + context_->boundary_markers.front() + "\r\n");
+ string_type& buffer(context_->buffer);
 
- //if (bytes_read == 0) ec = common::error::multipart_form_boundary_not_found;
- if (ec || bytes_read == 0) return ec;
-
- buffer_iter begin(buffer_.begin());// + offset);
- buffer_iter end(buffer_.end());
- if (!boost::regex_search(begin, end //impl.buffer_.begin(), impl.buffer_.end()
- , matches, re, boost::match_default | boost::match_partial))
- {
- offset = buffer_.size();
- continue;
- }
- else
- {
- std::cerr<< "Matches :{ " << matches[0].str() << " }: " << std::endl;
+ std::size_t pos = buffer.find(marker);
+
+ if (pos == string_type::npos)
+ ec = common::error::multipart_form_boundary_not_found;
+ else
+ buffer.erase(0, pos+marker.length());
+
+ ec = boost::system::error_code();
 
- if (matches[1].matched)
- {
- buffer_.erase(buffer_.begin(), matches[0].second);
- offset_ = 0;
- pos_ = buffer_.begin();
- return ec;
- }
- else
- {
- if (++runs > 10)
- return ec = common::error::multipart_form_boundary_not_found;
- continue;
- }
- }
- }
- // skip that line and then erase the buffer
       return ec;
     }
 
@@ -470,37 +238,19 @@
     boost::system::error_code
       form_parser::parse_boundary_marker(boost::system::error_code& ec)
     {
- //BOOST_ASSERT(!content_type.empty());
-
- // **FIXME** (don't use Boost.Regex)
- std::cerr<< " :{ " << content_type_ << " }: " << std::endl;
+ string_type& ctype(context_->content_type);
+ string_type& marker(context_->boundary_marker);
       
- /*
- std::string::size_type sz = content_type_.find("=");
- if (sz == std::string::npos)
- return boost::system::error_code(666, boost::system::system_category);
-
- std::string::size_type sz2 = content_type_.find("\r", sz);
- boundary_marker = content_type_.substr(sz+1);
- // New boundary markers are added to the front of the list.
- boundary_markers.push_front(boundary_marker);
- /*
- std::cerr<< "Need string:: " << content_type_.substr(sz+1) << " (" << sz << "," << (sz2) << ")";
- */
- boost::regex re("; ?boundary=\"?([^\"\\r]+)\"?(\\r\\n)?");
- boost::smatch match_results;
- if (!boost::regex_search(content_type_, match_results, re))
- return boost::system::error_code(666, boost::system::system_category);
-
- boundary_marker = match_results[1].str();
- // New boundary markers are added to the front of the list.
- boundary_markers.push_front(match_results[1].str());
- std::cerr<< "boundary marker :{ " << boundary_marker << " }: " << std::endl;
+ marker.assign(ctype.substr(ctype.find("boundary=")+9));
+ boost::algorithm::trim(marker);
+ if (marker.empty())
+ ec = common::error::no_boundary_marker;
+ else
+ context_->boundary_markers.push_front(marker);
 
       return ec;
     }
 
-
  } // namespace detail
 } // namespace cgi
 

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-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -69,7 +69,7 @@
   template<typename T> BOOST_CGI_INLINE
   basic_response<T>::basic_response(http::status_code sc)
     : buffer_(new common::streambuf())
- , ostream_(buffer_.get())
+ , ostream_(buffer_.get(), std::ios::out | std::ios::binary)
     , http_status_(sc)
     , headers_terminated_(false)
     , charset_("ISO-8859-1")
@@ -84,8 +84,9 @@
   template<typename T> BOOST_CGI_INLINE
   basic_response<T>::basic_response(common::streambuf* buf,
       http::status_code sc)
- : ostream_(buf)
+ : ostream_(buf, std::ios::out | std::ios::binary)
     , http_status_(sc)
+ , headers_terminated_(false)
     , charset_("ISO-8859-1")
   {
   }

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/utility/commit.hpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/utility/commit.hpp (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/utility/commit.hpp 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -3,18 +3,31 @@
 #define BOOST_CGI_COMMIT_HPP_INCLUDED_
 
 #include <map>
+#include <boost/system/error_code.hpp>
 ///////////////////////////////////////////////////////////
 #include "boost/cgi/common/return.hpp"
+#include "boost/cgi/detail/throw_error.hpp"
 
 namespace cgi {
  namespace common {
 
     /// Send a response to a reqest and close off the request.
     template<typename Request, typename Response>
- int commit(Request& req, Response& resp, int program_status)
+ int commit(Request& req, Response& resp, int program_status = 0)
     {
- resp.send(req.client());
- return req.close(resp.status(), program_status);
+ boost::system::error_code ec;
+ int ret (commit(req, resp, program_status, ec));
+ detail::throw_error(ec);
+ return ret;
+ }
+
+ /// Send a response to a reqest and close off the request.
+ template<typename Request, typename Response>
+ int commit(Request& req, Response& resp, int program_status
+ , boost::system::error_code& ec)
+ {
+ resp.send(req.client(), ec);
+ return ec ? -1 : req.close(resp.status(), program_status, ec);
     }
 
  } // namespace common

Added: sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/0.fcgi_template/fcgi_file_browser.vcproj
==============================================================================
--- (empty file)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/0.fcgi_template/fcgi_file_browser.vcproj 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -0,0 +1,195 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="fcgi_echo"
+ ProjectGUID="{6DA098F9-2F63-42F4-A732-48E6B35ECD1F}"
+ RootNamespace="fcgi_hello_world"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE; _SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\..\..\..\example\fcgi\echo\main.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/Boost.CGI.sln
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/Boost.CGI.sln (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/Boost.CGI.sln 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -25,6 +25,14 @@
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fcgi_amortization", "fcgi_amortization\fcgi_amortization.vcproj", "{2AE71DB6-3200-42EE-B024-1C2F4519F2B2}"
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fcgi_echo_threaded", "fcgi_echo_threaded\fcgi_echo_threaded.vcproj", "{519DFDA7-DC31-410E-BD9A-F17AADA41354}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fcgi_echo_debug", "fcgi_echo_debug\fcgi_echo_debug.vcproj", "{A79970AC-68D3-4BE1-9F79-ECF075045F87}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fcgi_file_browser", "fcgi_file_browser\fcgi_file_browser.vcproj", "{54333641-E5E5-4B30-A9D4-1054BFA95511}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cgi_file_browser", "cgi_file_browser\cgi_file_browser.vcproj", "{FFF275FA-323A-4699-9D04-A5C9BDD6048B}"
+EndProject
 Global
         GlobalSection(SolutionConfigurationPlatforms) = preSolution
                 Debug|Win32 = Debug|Win32
@@ -78,6 +86,22 @@
                 {2AE71DB6-3200-42EE-B024-1C2F4519F2B2}.Debug|Win32.Build.0 = Debug|Win32
                 {2AE71DB6-3200-42EE-B024-1C2F4519F2B2}.Release|Win32.ActiveCfg = Release|Win32
                 {2AE71DB6-3200-42EE-B024-1C2F4519F2B2}.Release|Win32.Build.0 = Release|Win32
+ {519DFDA7-DC31-410E-BD9A-F17AADA41354}.Debug|Win32.ActiveCfg = Debug|Win32
+ {519DFDA7-DC31-410E-BD9A-F17AADA41354}.Debug|Win32.Build.0 = Debug|Win32
+ {519DFDA7-DC31-410E-BD9A-F17AADA41354}.Release|Win32.ActiveCfg = Release|Win32
+ {519DFDA7-DC31-410E-BD9A-F17AADA41354}.Release|Win32.Build.0 = Release|Win32
+ {A79970AC-68D3-4BE1-9F79-ECF075045F87}.Debug|Win32.ActiveCfg = Debug|Win32
+ {A79970AC-68D3-4BE1-9F79-ECF075045F87}.Debug|Win32.Build.0 = Debug|Win32
+ {A79970AC-68D3-4BE1-9F79-ECF075045F87}.Release|Win32.ActiveCfg = Release|Win32
+ {A79970AC-68D3-4BE1-9F79-ECF075045F87}.Release|Win32.Build.0 = Release|Win32
+ {54333641-E5E5-4B30-A9D4-1054BFA95511}.Debug|Win32.ActiveCfg = Debug|Win32
+ {54333641-E5E5-4B30-A9D4-1054BFA95511}.Debug|Win32.Build.0 = Debug|Win32
+ {54333641-E5E5-4B30-A9D4-1054BFA95511}.Release|Win32.ActiveCfg = Release|Win32
+ {54333641-E5E5-4B30-A9D4-1054BFA95511}.Release|Win32.Build.0 = Release|Win32
+ {FFF275FA-323A-4699-9D04-A5C9BDD6048B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {FFF275FA-323A-4699-9D04-A5C9BDD6048B}.Debug|Win32.Build.0 = Debug|Win32
+ {FFF275FA-323A-4699-9D04-A5C9BDD6048B}.Release|Win32.ActiveCfg = Release|Win32
+ {FFF275FA-323A-4699-9D04-A5C9BDD6048B}.Release|Win32.Build.0 = Release|Win32
         EndGlobalSection
         GlobalSection(SolutionProperties) = preSolution
                 HideSolutionNode = FALSE

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_ctemplate_cookie_game/acgi_ctemplate_cookie_game.vcproj
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/acgi_ctemplate_cookie_game/acgi_ctemplate_cookie_game.vcproj (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/acgi_ctemplate_cookie_game/acgi_ctemplate_cookie_game.vcproj 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -64,6 +64,8 @@
                                 LinkIncremental="2"
                                 GenerateDebugInformation="true"
                                 SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
                                 TargetMachine="1"
                         />
                         <Tool
@@ -162,7 +164,7 @@
                         />
                         <Tool
                                 Name="VCPostBuildEventTool"
- CommandLine="copy &quot;$(TargetPath)&quot; &quot;c:\code\c++\boost.cgi\cgi-bin\$(TargetName)&quot;&#x0D;&#x0A;copy &quot;$(SolutionDir)\..\..\..\..\example\acgi\cookie_game2\style.css&quot; &quot;c:\code\c++\boost.cgi\htdocs\css\style.css&quot;&#x0D;&#x0A;copy &quot;$(SolutionDir)\..\..\..\..\example\acgi\cookie_game2\main.js&quot; &quot;c:\code\c++\boost.cgi\htdocs\js\main.js&quot;&#x0D;&#x0A;copy &quot;$(SolutionDir)\..\..\..\..\example\acgi\cookie_game2\index.html&quot; &quot;c:\code\c++\boost.cgi\templates\index.html&quot;"
+ CommandLine="copy &quot;$(TargetPath)&quot; &quot;c:\code\c++\boost.cgi\cgi-bin\$(TargetName)&quot;&#x0D;&#x0A;copy &quot;$(SolutionDir)\..\..\..\..\example\acgi\cookie_game2\style.css&quot; &quot;c:\code\c++\boost.cgi\htdocs\css\style.css&quot;&#x0D;&#x0A;copy &quot;$(SolutionDir)\..\..\..\..\example\acgi\cookie_game2\main.js&quot; &quot;c:\code\c++\boost.cgi\htdocs\js\main.js&quot;&#x0D;&#x0A;copy &quot;$(SolutionDir)\..\..\..\..\example\acgi\cookie_game2\index.html&quot; &quot;c:\code\c++\boost.cgi\templates\index.html&quot;&#x0D;&#x0A;"
                         />
                 </Configuration>
         </Configurations>

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/cgi_ctemplate_debug_server/cgi_ctemplate_debug_server.vcproj
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/cgi_ctemplate_debug_server/cgi_ctemplate_debug_server.vcproj (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/cgi_ctemplate_debug_server/cgi_ctemplate_debug_server.vcproj 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -87,7 +87,7 @@
                         />
                         <Tool
                                 Name="VCPostBuildEventTool"
- CommandLine="copy &quot;$(TargetPath)&quot; &quot;c:\code\c++\boost.cgi\cgi-bin\$(TargetName)&quot;&#x0D;&#x0A;copy &quot;$(SolutionDir)\..\..\..\..\example\cgi\DebugServer2\debug_view.css&quot; &quot;c:\code\c++\boost.cgi\htdocs\css\debug_view.css&quot;&#x0D;&#x0A;copy &quot;$(SolutionDir)\..\..\..\..\example\cgi\DebugServer2\debug_view.js&quot; &quot;c:\code\c++\boost.cgi\htdocs\js\debug_view.js&quot;&#x0D;&#x0A;copy &quot;$(SolutionDir)\..\..\..\..\example\cgi\DebugServer2\debug_view.html&quot; &quot;c:\code\c++\boost.cgi\templates\debug_view.html&quot;&#x0D;&#x0A;"
+ CommandLine="copy &quot;$(TargetPath)&quot; &quot;c:\code\c++\boost.cgi\cgi-bin\$(TargetName)&quot;&#x0D;&#x0A;copy &quot;$(SolutionDir)\..\..\..\..\example\cgi\DebugServer2\debug_view.css&quot; &quot;c:\code\c++\boost.cgi\htdocs\css\debug_view.css&quot;&#x0D;&#x0A;copy &quot;$(SolutionDir)\..\..\..\..\example\cgi\DebugServer2\debug_view.js&quot; &quot;c:\code\c++\boost.cgi\htdocs\js\debug_view.js&quot;&#x0D;&#x0A;copy &quot;$(SolutionDir)\..\..\..\..\example\cgi\DebugServer2\debug_view.html&quot; &quot;c:\code\c++\boost.cgi\templates\debug_view.html&quot;&#x0D;&#x0A;copy &quot;$(SolutionDir)\..\..\..\..\example\cgi\DebugServer2\default_view.html&quot; &quot;c:\code\c++\boost.cgi\templates\default_view.html&quot;&#x0D;&#x0A;"
                         />
                 </Configuration>
                 <Configuration

Added: sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/cgi_file_browser/cgi_file_browser.vcproj
==============================================================================
--- (empty file)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/cgi_file_browser/cgi_file_browser.vcproj 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -0,0 +1,198 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="cgi_file_browser"
+ ProjectGUID="{FFF275FA-323A-4699-9D04-A5C9BDD6048B}"
+ RootNamespace="cgi_echo"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="libboost_system-vc90-mt-gd-1_38.lib"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories="C:\Boost\lib"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="copy &quot;$(TargetPath)&quot; &quot;c:\code\c++\boost.cgi\cgi-bin\$(TargetName)&quot;"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ PreprocessorDefinitions="_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="copy &quot;$(TargetPath)&quot; &quot;c:\code\c++\boost.cgi\cgi-bin\$(TargetName)&quot;"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\..\..\..\example\cgi\echo\main.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/fcgi_amortization/fcgi_amortization.vcproj
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/fcgi_amortization/fcgi_amortization.vcproj (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/fcgi_amortization/fcgi_amortization.vcproj 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -66,6 +66,8 @@
                                 LinkIncremental="2"
                                 GenerateDebugInformation="true"
                                 SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
                                 TargetMachine="1"
                         />
                         <Tool

Added: sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/fcgi_echo_threaded/fcgi_echo_threaded.vcproj
==============================================================================
--- (empty file)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/fcgi_echo_threaded/fcgi_echo_threaded.vcproj 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -0,0 +1,195 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="fcgi_echo_threaded"
+ ProjectGUID="{519DFDA7-DC31-410E-BD9A-F17AADA41354}"
+ RootNamespace="fcgi_hello_world"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_SCL_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\..\..\..\example\fcgi\echo_threaded\main.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>

Added: sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/fcgi_file_browser/fcgi_file_browser.vcproj
==============================================================================
--- (empty file)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/fcgi_file_browser/fcgi_file_browser.vcproj 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -0,0 +1,195 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="fcgi_file_browser"
+ ProjectGUID="{54333641-E5E5-4B30-A9D4-1054BFA95511}"
+ RootNamespace="fcgi_hello_world"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE; _SCL_SECURE_NO_WARNINGS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\..\..\..\example\fcgi\file_browser\main.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/doc/src/design.qbk
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/doc/src/design.qbk (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/doc/src/design.qbk 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -1,3 +1,10 @@
+[/
+ / Copyright (c) 2008 Darren Garvey
+ /
+ / 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)
+ /]
+
 
 [section:design Design Decisions]
 
@@ -9,4 +16,4 @@
 
 [endsect]
 
-[endsect]
\ No newline at end of file
+[endsect]

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/doc/src/user_guide/tutorial/quickstart.qbk
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/doc/src/user_guide/tutorial/quickstart.qbk (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/doc/src/user_guide/tutorial/quickstart.qbk 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -7,21 +7,7 @@
 
 [section:quickstart Quickstart: 'Scripting']
 
-CGI
-is
-a
-simple
-protocol:
-you
-read
-__POST__
-data
-from
-`stdin`,
-other
-data
-from
-environment variables (ie. via [@http://tinyurl.com/3cqrd5 `::getenv()`]) and write your output to `stdout`. This section introduces the '__CGI__' interface, which offers a subset of the library's functionality. This is not essential reading, but it is recommended that you at least scan through it as the techniques still apply to the rest of the library. Afterwards, if you wish to scale your program to __FastCGI__ or __SCGI__, or just provide a custom logging layer or asynchronous read/writes (with vanilla CGI) then the rest of the tutorial will show you how to.
+CGI is a simple protocol: you read __POST__ data from `stdin`, other data from environment variables (ie. via [@http://tinyurl.com/3cqrd5 `::getenv()`]) and write your output to `stdout`. This section introduces the '__CGI__' interface, which offers a subset of the library's functionality. This is not essential reading, but it is recommended that you at least scan through it as the techniques still apply to the rest of the library. Afterwards, if you wish to scale your program to __FastCGI__ or __SCGI__, or just provide a custom logging layer or asynchronous read/writes (with vanilla CGI) then the rest of the tutorial will show you how to.
 
 [h3 10 minute intro]
 

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/acgi/cookie_game/main.cpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/acgi/cookie_game/main.cpp (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/acgi/cookie_game/main.cpp 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -180,20 +180,22 @@
 {
     resp<< "<div class=\"cookies\">";
     if (data.empty())
- resp<< "<span class='value'>None found</span>";
- else {
- resp<< "<ul class=\"nvpair\">";
- for(typename MapT::const_iterator iter=data.begin(), end = data.end(); iter != end; ++iter)
- {
- resp<< "<li class=\"name\">"
- << iter->first
- << "</li>"
- "<li class=\"value\">"
- << iter->second
- << "</li>";
- }
- resp<< "</ul>"
- "<div class=\"clear\"></div>";
+ resp<< "<span class=\"value\">None found</span>";
+ else
+ {
+ resp<< "<ul class=\"nvpair\">";
+ for(typename MapT::const_iterator iter=data.begin(), end = data.end();
+ iter != end; ++iter)
+ {
+ resp<< "<li class=\"name\">"
+ << iter->first
+ << "</li>"
+ "<li class=\"value\">"
+ << iter->second
+ << "</li>";
+ }
+ resp<< "</ul>"
+ "<div class=\"clear\"></div>";
     }
     resp<< "</div>";
 }
@@ -209,7 +211,7 @@
   response resp;
   resp<< content_type("text/plain");
 
- if (has_key(req.form, "reset") && req.form["reset"] == "true")
+ if (req.form.count("reset") && req.form["reset"] == "true")
   {
     resp<< cookie("name")
         << redirect(req, req.script_name()); // redirect them.
@@ -217,14 +219,14 @@
     return 0;
   }
 
- if (has_key(req.form, "name"))
+ if (req.form.count("name"))
   {
- if (has_key(req.form, "del"))
+ if (req.form.count("del"))
       resp<< cookie(req.form["name"]);
     else
       resp<< cookie(req.form["name"], req.form["value"]);
     resp<< redirect(req, req.script_name());
- return_(resp, req, http::ok);
+ return commit(req, resp);
   }
 
   resp<< content_type("text/html")
@@ -240,32 +242,43 @@
          "<body>";
 
   // First, see if they have a cookie set
- if (has_key(req.cookies, "name"))
+ if (req.cookies.count("name"))
       resp<< "<h1>Hello again " << req.cookies["name"] << "</h1>"
           << "<p><a href='?reset=true'><input type='submit' value='Reset' /></a></p>";
   else
     resp<< "<h1>Hello there.</h1>";
 
- resp<< "<p>You can add cookies using the form below. If you add a cookie value for 'name', it will show up above.</p>"
- "<p>Here is list of the cookies you currently have:</p>";
+ resp<< "<p>"
+ "You can add cookies using the form below. If you add a cookie "
+ "value for 'name', it will show up above."
+ "</p>"
+ "<p>Here is list of the cookies you currently have:</p>";
   
   print_formatted_data(resp, req.cookies);
   
- resp<< "<form method='get' action='" << req.script_name() << "' id='getform'>"
+ resp<< "<form method=get action='" << req.script_name() << "' id=getform>"
            "<label for='name' class='name'>Name:</label>"
- "<input id='name' name='name' class='value' type='text' value='" << req.form["name"] << "'>""</input>"
+ "<input id='name' name='name' class='value' type='text' value='"
+ << req.form["name"] << "'>"
+ "</input>"
            "<label for='value' class='name'>Value:</label>"
- "<input id='value' name='value' class='value' type='text' value='" << req.form["value"] << "'>""</input>"
+ "<input id='value' name='value' class='value' type='text' value='"
+ << req.form["value"] << "'>"
+ "</input>"
            "<label for='del' class='name'>Delete this cookie?</label>"
            "<input id='del' name='del' class='value' type='checkbox'></input>"
            "<div class='clear'></div>"
            "<input type='submit'></input>"
          "</form>"
- "<input type='submit' onclick='switch_method(\"getform\"); switch_value(this); return false;' value='Switch to POST'></input>"
+ "<input type='submit' "
+ "onclick='switch_method(\"getform\"); "
+ "switch_value(this); return false;' "
+ "value='Switch to POST'>"
+ "</input>"
          "</body>"
          "</html>";
 
- return_(resp, req, http::ok);
+ return commit(req, resp);
 }
 //]
 

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/acgi/cookie_game2/main.cpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/acgi/cookie_game2/main.cpp (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/acgi/cookie_game2/main.cpp 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -21,7 +21,7 @@
 //
 #include <boost/cgi/acgi.hpp>
 #include <boost/cgi/utility.hpp>
-#include <google/template.h>
+#include <ctemplate/template.h>
 #include <boost/throw_exception.hpp>
 #include <boost/system/system_error.hpp>
 #include <boost/filesystem.hpp>
@@ -41,10 +41,10 @@
 // The types we use. Only here because this is an example.
 
 // Uses cTemplate, from Google. It's simple and powerful.
-typedef google::Template stencil_type;
+typedef ctemplate::Template stencil_type;
 // You will usually load a template and then populate variables in it
 // using a TemplateDictionary.
-typedef google::TemplateDictionary dictionary_type;
+typedef ctemplate::TemplateDictionary dictionary_type;
 // The acgi and fcgi parts of the CGI library use a `service` class to
 // manage asynchronous dispatching (eg. async I/O). If you're not interested
 // in async I/O, you can just use the plain cgi stuff (which is the same as
@@ -74,7 +74,7 @@
 {
   if (!fs::exists(filename))
     throw std::runtime_error(std::string("Template file not found: '") + fs::path(filename).string() + "'");
- return google::Template::GetTemplate(filename, google::STRIP_WHITESPACE);
+ return ctemplate::Template::GetTemplate(filename, ctemplate::STRIP_WHITESPACE);
 }
 
 // Show the data in the passed map, updating the passed dictionary.

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/cgi/DebugServer2/TracebackServer.cpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/cgi/DebugServer2/TracebackServer.cpp (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/cgi/DebugServer2/TracebackServer.cpp 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -59,7 +59,7 @@
 {
     stop_timer();
     response_type resp2;
- template_ = google::Template::GetTemplate(TBS_TEMPLATE__DEBUG_VIEW, google::STRIP_WHITESPACE);
+ template_ = ctemplate::Template::GetTemplate(TBS_TEMPLATE__DEBUG_VIEW, ctemplate::STRIP_WHITESPACE);
     dictionary_type dict("debug_view");
     dict.SetValue("ERROR", error);
     expand_map(dict, request[boost::cgi::env], "Environment Data");

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/cgi/DebugServer2/TracebackServer.hpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/cgi/DebugServer2/TracebackServer.hpp (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/cgi/DebugServer2/TracebackServer.hpp 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -6,7 +6,7 @@
 #undef min
 #undef max
 #include <boost/chrono/process_times.hpp>
-#include <google/template.h>
+#include <ctemplate/template.h>
 //#include <boost/chrono/chrono.hpp>
 
 /// A server which catches some runtime errors in your app.
@@ -23,20 +23,21 @@
  */
 class TracebackServer
 {
- typedef boost::cgi::request request_type;
- typedef boost::cgi::response response_type;
- typedef boost::function<int (request_type&, response_type&)> callback_type;
+ typedef boost::cgi::request request_type;
+ typedef boost::cgi::response response_type;
+ typedef boost::function<
+ int (request_type&, response_type&)> callback_type;
     //typedef Timer<boost::chrono::high_resolution_clock> timer_type;
- typedef boost::chrono::process_timer timer_type;
- typedef google::Template template_type;
- typedef google::TemplateDictionary dictionary_type;
+ typedef boost::chrono::process_timer timer_type;
+ typedef ctemplate::Template template_type;
+ typedef ctemplate::TemplateDictionary dictionary_type;
 
     timer_type timer_;
     template_type* template_;
     boost::chrono::process_times stop_times_;
 public: // member variables
     bool show_times;
-public:
+public: // functions
     TracebackServer(void);
     ~TracebackServer(void);
 

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/cgi/DebugServer2/ctemplate.cpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/cgi/DebugServer2/ctemplate.cpp (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/cgi/DebugServer2/ctemplate.cpp 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -2,7 +2,7 @@
 #include <iostream>
 #include <boost/cgi/cgi.hpp>
 #include <boost/cgi/utility.hpp>
-#include <google/template.h>
+#include <ctemplate/template.h>
 #include "TracebackServer.hpp"
 #include <cmath>
 
@@ -23,16 +23,21 @@
     */
     
     // Load the HTML template and strip all whitespace...
- google::Template* tmpl = google::Template::GetTemplate("../templates/default_view.html", google::STRIP_WHITESPACE);
- // Since this is a really basic template, this is all we need to load. We can expand it into a string.
+ ctemplate::Template* tmpl
+ = ctemplate::Template::GetTemplate(
+ "../templates/default_view.html", ctemplate::STRIP_WHITESPACE);
+ // Since this is a really basic template, this is all we need to load.
+ // We can expand it into a string.
     std::string output;
     tmpl->Expand(&output, NULL);
     resp<< header("X-Custom-Header: some value")
         << content_type("text/html")
         << output;
 
- if (req[form]["badger"] == "bait!") throw std::runtime_error("AOUHFAEOUHAEOUHAEOUHOUH!!!!!!");
- else if (has_key(req[form], "spam")) return 33;
+ if (req[form]["badger"] == "bait!")
+ throw std::runtime_error("AOUHFAEOUHAEOUHAEOUHOUH!!!!!!");
+ else if (has_key(req[form], "spam"))
+ return -1;
     return 0;
 }
 

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/cgi/echo/main.cpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/cgi/echo/main.cpp (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/cgi/echo/main.cpp 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -1,60 +1,301 @@
 // -- main.hpp --
 //
-// Copyright (c) Darren Garvey 2007.
+// 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)
 //
 ////////////////////////////////////////////////////////////////
 //
-//[cgi_echo
+//[cgi_file_browser
 //
-// This example simply echoes all variables back to the user. ie.
-// the environment and the parsed GET, POST and cookie variables.
-// Note that GET and cookie variables come from the environment
-// variables QUERY_STRING and HTTP_COOKIE respectively.
+// This example is a simple browser-based file browser.
 //
+///////////////////////////////////////////////////////////
+#include <istream>
+#include <fstream>
+#include <boost/filesystem.hpp>
+#include <boost/shared_array.hpp>
+#include <boost/algorithm/string/find.hpp>
+#include <boost/algorithm/string/case_conv.hpp>
+///////////////////////////////////////////////////////////
+#include "boost/cgi/cgi.hpp"
+#include "boost/cgi/utility/commit.hpp"
 
-#include <boost/cgi/cgi.hpp>
-
+using std::cerr;
+using std::endl;
+using std::ifstream;
 using namespace boost::cgi;
+namespace fs = boost::filesystem;
+namespace algo = boost::algorithm;
 
-//
-// This function writes the title and map contents to the ostream in an
-// HTML-encoded format (to make them easier on the eye).
-//
-template<typename OStreamT, typename MapT>
-void show_map_contents(OStreamT& os, MapT& m, const std::string& title)
+
+/// Get the MIME type of the file.
+/**
+ * @returns The MIME type as a string. Returns an empty string if the
+ * file type isn't recognised / supported.
+ */
+std::string get_mime_type(fs::path const& file)
 {
- os<< "<h3>" << title << "</h3>";
+ std::string filetype (file.filename());
+ // Note: we want the string after the '.'
+ std::size_t pos (filetype.rfind(".")+1);
+ if (pos == std::string::npos)
+ return "";
+
+ filetype = filetype.substr(pos);
+ algo::to_lower(filetype);
   
- if (m.empty())
- os<< "NONE<br />";
+ /// Ordinary text files.
+ if (filetype == "ini" || filetype == "txt" || filetype == "conf")
+ return "text/plain";
+ else
+ if (filetype == "js")
+ return "application/javascript";
+ else
+ if (filetype == "json")
+ return "application/json";
+ else
+ if (filetype == "css")
+ return "text/css";
+ else
+ /// Structured text files.
+ if (filetype == "html" || filetype == "htm")
+ return "text/html";
+ else
+ if (filetype == "xml")
+ return "text/xml";
+ else
+ if (filetype == "csv")
+ return "text/csv";
+ else
+ if (filetype == "rtf")
+ return "text/rtf";
+ else
+ /// Image files.
+ if (filetype == "jpg" || filetype == "jpeg")
+ return "image/jpeg";
+ else
+ if (filetype == "gif")
+ return "image/gif";
+ else
+ if (filetype == "bmp")
+ return "image/x-ms-bmp";
+ else
+ if (filetype == "png")
+ return "image/png";
+ else
+ if (filetype == "tiff")
+ return "image/tiff";
+ else
+ /// Audio files.
+ if (filetype == "ogg")
+ return "audio/ogg";
+ else
+ if (filetype == "mp3")
+ return "audio/mpeg";
+ else
+ /// Video files.
+ if (filetype == "avi")
+ return "video/x-msvideo";
+ else
+ /// Rich media files.
+ if (filetype == "pdf")
+ return "application/pdf";
+ else
+ if (filetype == "doc")
+ return "application/msword";
+ else
+ if (filetype == "swf")
+ return "application/x-shockwave-flash";
+ else
+ if (filetype == "xls")
+ return "application/vnd.ms-excel";
+ /// Compressed files.
+ else
+ if (filetype == "zip")
+ return "application/zip";
+ else
+ if (filetype == "tar")
+ return "application/x-tar";
+ /// Other files.
   else
- for (typename MapT::const_iterator i = m.begin(); i != m.end(); ++i)
- os<< "<b>" << i->first << "</b> = <i>"
- << i->second << "</i><br />";
+ if (filetype == "pl")
+ return "application/x-perl";
+ else
+ if (filetype == "py")
+ return "application/x-python";
+ else
+ if (filetype == "exe" || filetype == "dll" || filetype == "sys" ||
+ filetype == "chm" || filetype == "lib" || filetype == "pdb" ||
+ filetype == "obj" || filetype == "dep" || filetype == "idb" ||
+ filetype == "pyd" || filetype == "sqm" || filetype == "idb" ||
+ filetype == "asm" || filetype == "suo" || filetype == "sbr")
+ return ""; // Not allowed to download these file types.
+
+ return "text/plain";
 }
 
-int main()
+template<typename Response, typename Client>
+void show_file(Response& resp, Client& client, fs::path const& file)
+{
+ if (!fs::exists(file))
+ resp<< "File not found.";
+ else
+ {
+ boost::uintmax_t size (fs::file_size(file));
+ cerr<< "size: " << size << endl;
+ if (size > 200000000L) // Files must be < 200MB
+ resp<< "File too large.";
+ else
+ {
+ /// Check the file type is allowed.
+ std::string mime_type (get_mime_type(file));
+ if (!mime_type.empty())
+ {
+ std::string ctype (content_type(mime_type).content + "\r\n\r\n");
+ //write(client, boost::asio::buffer(ctype));
+ /// Open the file and read it as binary data.
+ ifstream ifs (file.string().c_str(), std::ios::binary);
+ if (ifs.is_open())
+ {
+ resp<< content_type(mime_type);
+ //resp.flush(client);
+ boost::uintmax_t bufsize = 500;
+ boost::uintmax_t read_bytes;
+ char buf[500];
+ ifs.seekg(0, std::ios::beg);
+ while (!ifs.eof() && size > 0)
+ {
+ ifs.read(buf, size < bufsize ? size : bufsize);
+ read_bytes = ifs.gcount();
+ size -= read_bytes;
+ resp.write(buf, read_bytes);
+ //write(client, boost::asio::buffer(buf, read_bytes));
+ //resp.flush(client);
+ }
+ //resp.send(client);
+ }
+ }
+ else
+ resp<< "File type not allowed.";
+ }
+ }
+}
+
+template<typename Response>
+void show_paths(Response& resp, fs::path const& parent, bool recursive = true)
+{
+ if (!fs::exists(parent))
+ {
+ resp<< "File does not exist\n";
+ return;
+ }
+
+ resp<< "<ul>";
+ if (fs::is_directory(parent))
+ {
+ resp<< parent << "\n";
+ resp<< "<li class=\"directory\"><a href=\"?dir="
+ << parent.string() << "\">.</a></li>\n";
+ if (fs::is_directory(parent.parent_path()))
+ resp<< "<li class=\"directory\"><a href=\"?dir="
+ << parent.parent_path().string() << "\">..</a></li>\n";
+ for (fs::directory_iterator iter(parent), end; iter != end; ++iter)
+ {
+ if (fs::is_directory(*iter))
+ {
+ resp<< "<li class=\"directory\"><a href=\"?dir="
+ << iter->string() << "\">" << iter->path() << "</a></li>\n";
+ if (recursive)
+ show_paths(resp, iter->path(), recursive);
+ }
+ else
+ {
+ // display filename only.
+ resp<< "<li class=\"file\"><a href=\"?file="
+ << iter->string() << "\">" << iter->path().filename()
+ << "</a>";
+ //if (fs::is_regular_file(iter->status()))
+ // resp<< " [" << fs::file_size(iter->path()) << " bytes]";
+ resp<< "</li>\n";
+ }
+ }
+ }
+ else
+ {
+ resp<< "<li class=\"file\">" << "<a href=\"?file="
+ << parent.string() << "\">" << parent << "</li>\n";
+ }
+ resp<< "</ul>";
+}
+
+/// This function accepts and handles a single request.
+template<typename Request>
+int handle_request(Request& req)
 {
- request req(parse_all); // A basic CGI request auto-parses everything (including POST data).
+ boost::system::error_code ec;
+
+ //
+ // Load in the request data so we can access it easily.
+ //
+ req.load(parse_all); // Read and parse STDIN (ie. POST) data.
+
+ //
+ // Construct a `response` object (makes writing/sending responses easier).
+ //
   response resp;
 
- resp<< "Request id = " << req.id() << "<p/>";
+ if (req.get.count("file"))
+ {
+ show_file(resp, req.client(), req.get["file"]);
+ //return req.close(http::ok, 0);
+ }
+ else
+ if (req.get.count("dir"))
+ {
+ //
+ // Responses in CGI programs require at least a 'Content-type' header.
+ // The library provides helpers for several common headers:
+ //
+ resp<< content_type("text/html");
+
+ // You can also stream text to a response.
+ // All of this just prints out the form
+ resp<< "<html>"
+ "<head><title>CGI File Browser Example</title><head>"
+ "<body>";
 
- show_map_contents(resp, req.env, "Environment Variables");
- show_map_contents(resp, req.form, "Form [" + req.request_method() + "] Variables");
- show_map_contents(resp, req.cookies, "Cookie Variables");
+ show_paths(resp, req.get["dir"], req.get["recurse"] == "1");
 
- // Note that this (and any other) HTTP header can go either before or after
- // the response contents.
- resp<< content_type("text/html");
+ resp<< "</body></html>";
+ }
+ else
+ resp<< content_type("text/plain")
+ << "No path specified.\n";
 
- // Send the response to the client associated with the request.
- resp.send(req.client());
+ resp<< header("CGI-client", "fcgi_file_browser");
+ return commit(req, resp, 0);
+}
 
- return 0;
+int main()
+{
+try {
+
+ request req;
+ return handle_request(req);
+
+}catch(boost::system::system_error const& se){
+ // This is the type of error thrown by the library.
+ cerr<< "[fcgi] System error: " << se.what() << endl;
+ return -1;
+}catch(std::exception const& e){
+ // Catch any other exceptions
+ cerr<< "[fcgi] Exception: " << e.what() << endl;
+ return -1;
+}catch(...){
+ cerr<< "[fcgi] Uncaught exception!" << endl;
+ return -1;
+}
 }
 //]
-

Copied: sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/cgi/file_browser/main.cpp (from r55954, /sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/cgi/echo/main.cpp)
==============================================================================
--- /sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/cgi/echo/main.cpp (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/cgi/file_browser/main.cpp 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -19,33 +19,98 @@
 
 using namespace boost::cgi;
 
+// The styling information for the page, just to make things look nicer.
+static const char* gCSS_text =
+"body { padding: 0; margin: 3%; border-color: #efe; }"
+".var_map_title"
+ "{ font-weight: bold; font-size: large; }"
+".var_map"
+ "{ border: 1px dotted; padding: 2px 3px 2px 3px; margin-bottom: 3%; }"
+".var_pair"
+ "{ border-top: 1px dotted; overflow: auto; padding: 0; margin: 0; }"
+".var_name"
+ "{ position: relative; float: left; width: 30%; font-weight: bold; }"
+".var_value"
+ "{ position: relative; float: left; width: 65%; left: 1%;"
+ " border-left: 1px solid; padding: 0 5px 0 5px;"
+ " overflow: auto; white-space: pre; }"
+;
+
 //
 // This function writes the title and map contents to the ostream in an
 // HTML-encoded format (to make them easier on the eye).
 //
-template<typename OStreamT, typename MapT>
-void show_map_contents(OStreamT& os, MapT& m, const std::string& title)
+template<typename OStream, typename Request, typename Map>
+void format_map(OStream& os, Request& req, Map& m, const std::string& title)
 {
- os<< "<h3>" << title << "</h3>";
-
+ os<< "<div class=\"var_map\">"
+ "<div class=\"var_map_title\">"
+ << title
+ << "</div>";
+
   if (m.empty())
- os<< "NONE<br />";
+ os<< "<div class=\"var_pair\">EMPTY</div>";
   else
- for (typename MapT::const_iterator i = m.begin(); i != m.end(); ++i)
- os<< "<b>" << i->first << "</b> = <i>"
- << i->second << "</i><br />";
+ for (typename Map::const_iterator i = m.begin(); i != m.end(); ++i)
+ {
+ os<< "<div class=\"var_pair\">"
+ "<div class=\"var_name\">"
+ << i->first
+ << "</div>"
+ "<div class=\"var_value\">"
+ << i->second
+ << (req.is_file(i->first) ? " (file)" : "")
+ << "</div>"
+ "</div>";
+ }
+ os<< "</div>";
 }
 
+std::size_t process_id()
+{
+#if defined(BOOST_WINDOWS)
+ return _getpid();
+#else
+ return getpid();
+#endif
+}
+
+
 int main()
 {
- request req(parse_all); // A basic CGI request auto-parses everything (including POST data).
+ // A basic CGI request auto-parses everything (including POST data).
+ request req(parse_all);
   response resp;
 
- resp<< "Request id = " << req.id() << "<p/>";
-
- show_map_contents(resp, req.env, "Environment Variables");
- show_map_contents(resp, req.form, "Form [" + req.request_method() + "] Variables");
- show_map_contents(resp, req.cookies, "Cookie Variables");
+ // You can also stream text to a response.
+ // All of this just prints out the form
+ resp<< "<html>"
+ "<head>"
+ "<title>CGI Echo Example</title>"
+ "<style type=\"text/css\">"
+ << gCSS_text <<
+ "</style>"
+ "<head>"
+ "<body>"
+ "Request ID = " << req.id() << "<br />"
+ "Process ID = " << process_id() << "<br />"
+ "<form method=post enctype=\"multipart/form-data\">"
+ "<input type=text name=name value='"
+ << req.post["name"] << "' />"
+ "<br />"
+ "<input type=text name=hello value='"
+ << req.post["hello"] << "' />"
+ "<br />"
+ "<input type=file name=user_file />"
+ "<input type=hidden name=cmd value=multipart_test />"
+ "<br />"
+ "<input type=submit value=submit />"
+ "</form><p />";
+
+ format_map(resp, req, req.env, "Environment Variables");
+ //format_map(resp, req, req.get, "GET Variables");
+ format_map(resp, req, req.form, "Form [" + req.request_method() + "] Variables");
+ format_map(resp, req, req.cookies, "Cookie Variables");
 
   // Note that this (and any other) HTTP header can go either before or after
   // the response contents.

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/fcgi/amortization/main.cpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/fcgi/amortization/main.cpp (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/fcgi/amortization/main.cpp 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -23,7 +23,7 @@
 #include <boost/cgi/fcgi.hpp>
 #include <boost/cgi/utility.hpp>
 #include <boost/algorithm/string/regex.hpp>
-#include <google/template.h>
+#include <ctemplate/template.h>
 
 using namespace boost::fcgi;
 
@@ -35,9 +35,10 @@
   return amt;
 }
 
-/// This function fills the dictionary and sub-dictionaries with relevant values.
+/// This function fills a dictionary.
 template<typename Request>
-void fill_amortization_dictionary(google::TemplateDictionary& dict, Request& req)
+void fill_amortization_dictionary(
+ ctemplate::TemplateDictionary& dict, Request& req)
 {
   dict.SetValue("LoanAmt", has_key(req.post, "LoanAmt")
       ? "$250,000" : req.post["LoanAmt"]);
@@ -56,12 +57,14 @@
     dict.ShowSection("NotAmortize");
   else
   {
- double P = boost::lexical_cast<double>(string_from_currency(req.post["LoanAmt"]));
+ double P = boost::lexical_cast<double>(
+ string_from_currency(req.post["LoanAmt"]));
     double i = boost::lexical_cast<double>(req.post["YearlyIntRate"]) / 1200;
     double n = boost::lexical_cast<double>(req.post["TermYrs"]) * 12;
     double monthly_payments = (P*i) / (1 - std::pow((1+i), -n));
     
- google::TemplateDictionary* sub_dict = dict.AddSectionDictionary("RegPmtSummary");
+ ctemplate::TemplateDictionary* sub_dict
+ = dict.AddSectionDictionary("RegPmtSummary");
     sub_dict->ShowSection("RegPmtSummary");
     sub_dict->SetFormattedValue("MonthlyPmt", "%.2f", monthly_payments);
 
@@ -74,7 +77,8 @@
     double principal_paid;
     double total_interest = 0;
     do{
- google::TemplateDictionary* sub_dict2 = dict.AddSectionDictionary("PaymentEntry");
+ ctemplate::TemplateDictionary* sub_dict2
+ = dict.AddSectionDictionary("PaymentEntry");
       sub_dict2->ShowSection("PaymentEntry");
       sub_dict2->SetFormattedValue("Payment", "%.2f", monthly_payments);
       sub_dict2->SetIntValue("ROW_NUM", ++row_num);
@@ -89,20 +93,22 @@
 
     }while(balance > 0);
 
- sub_dict->SetFormattedValue("RegPmt_TotalIntPd", "%.2f", total_interest);
- sub_dict->SetFormattedValue("RegPmt_TotalPmts", "%.2f", total_interest + P);
+ sub_dict->SetFormattedValue(
+ "RegPmt_TotalIntPd", "%.2f", total_interest);
+ sub_dict->SetFormattedValue(
+ "RegPmt_TotalPmts", "%.2f", total_interest + P);
   }
 }
 
 template<typename Request>
 int write_amortization_template(Request& req, response& resp)
 {
- google::TemplateDictionary dict("amortization");
+ ctemplate::TemplateDictionary dict("amortization");
 
   fill_amortization_dictionary(dict, req);
 
- google::Template* tmpl
- = google::Template::GetTemplate("../templates/amortization.html", google::STRIP_WHITESPACE);
+ ctemplate::Template* tmpl
+ = ctemplate::Template::GetTemplate("../templates/amortization.html", ctemplate::STRIP_WHITESPACE);
 
   std::string h("Content-type: text/html\r\n\r\n");
   write(req.client(), buffer(h));
@@ -154,8 +160,8 @@
     response resp;
     ++num;
 
- // Accepting on a closed request is fine (and more efficient than constantly
- // creating/destructing request objects). You must call close() first though!
+ // Accepting on a closed request is fine (and more efficient than
+ // constantly creating/destructing request objects).
     a.accept(req);
 
     req.load(parse_all);
@@ -165,23 +171,11 @@
   
     ret = write_amortization_template(req, resp);
 
- resp.send(req.client(), ec);
-
- ret = ret ? ret : req.close(resp.status(), 0, ec);
+ ret = commit(req, resp, 0, ec);
   }
   return ret;
 }
 
-void accept_requests(acceptor& a)
-{
- for(;;)
- {
- // Keep handling requests until something goes wrong.
- if (handle_request(a))
- break;
- }
-}
-
 int main()
 {
   try{
@@ -189,7 +183,13 @@
     service s;
     acceptor a(s, 8010); // Listen on port 8010.
 
- accept_requests(a);
+ for(;;)
+ {
+ // Keep handling requests until something goes wrong.
+ // An exception will be thrown.
+ if (handle_request(a))
+ break;
+ }
     
     return 0;
 

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-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -21,12 +21,9 @@
 #include "boost/cgi/fcgi.hpp"
 #include "boost/cgi/utility/commit.hpp"
 
-using namespace std;
+//using namespace std;
 using namespace boost::fcgi;
 
-// This is a file to put internal logging info into
-#define LOG_FILE "/var/www/log/fcgi_echo.txt"
-
 // The styling information for the page, just to make things look nicer.
 static const char* gCSS_text =
 "body { padding: 0; margin: 3%; border-color: #efe; }"
@@ -42,14 +39,16 @@
     "{ position: relative; float: left; width: 65%; left: 1%;"
      " border-left: 1px solid; padding: 0 5px 0 5px;"
      " overflow: auto; white-space: pre; }"
+".clear"
+ "{ clear: both; }"
 ;
 
 //
 // This function writes the title and map contents to the ostream in an
 // HTML-encoded format (to make them easier on the eye).
 //
-template<typename OStreamT, typename MapT>
-void format_map(OStreamT& os, MapT& m, const std::string& title)
+template<typename OStream, typename Request, typename Map>
+void format_map(OStream& os, Request& req, Map& m, const std::string& title)
 {
   os<< "<div class=\"var_map\">"
          "<div class=\"var_map_title\">"
@@ -59,7 +58,7 @@
   if (m.empty())
     os<< "<div class=\"var_pair\">EMPTY</div>";
   else
- for (typename MapT::const_iterator i = m.begin(); i != m.end(); ++i)
+ for (typename Map::const_iterator i = m.begin(); i != m.end(); ++i)
     {
       os<< "<div class=\"var_pair\">"
              "<div class=\"var_name\">"
@@ -67,10 +66,11 @@
         << "</div>"
              "<div class=\"var_value\">"
         << i->second
+ << (req.is_file(i->first) ? " (file)" : "")
         << "</div>"
            "</div>";
     }
- os<< "</div>";
+ os<< "<div class=\"clear\"></div></div>";
 }
 
 std::size_t process_id()
@@ -117,7 +117,7 @@
          "<body>"
            "Request ID = " << req.id() << "<br />"
            "Process ID = " << process_id() << "<br />"
- "<form method=post>" // enctype=\"multipart/form-data\">"
+ "<form method=post enctype=\"multipart/form-data\">"
              "<input type=text name=name value='"
       << req.post["name"] << "' />"
              "<br />"
@@ -134,26 +134,21 @@
   // Use the function defined above to show some of the request data.
   // (this function isn't part of the library)
   //
- format_map(resp, req.env, "Environment Variables");
- format_map(resp, req.get, "GET Variables");
- format_map(resp, req.post, "POST Variables");
- format_map(resp, req.cookies, "Cookie Variables");
+ format_map(resp, req, req.env, "Environment Variables");
+ format_map(resp, req, req.get, "GET Variables");
+ format_map(resp, req, req.post, "POST Variables");
+ format_map(resp, req, req.cookies, "Cookie Variables");
 
- // Print the complete buffer containing the POST data and the FastCGI params.
+ // Print the buffer containing the POST data and the FastCGI params.
   resp<< "<pre>";
- BOOST_FOREACH(char& ch, req.post_buffer())
- {
- resp<< ch;
- }
- // << req.get_buffer()
+ resp<< std::string(req.post_buffer().begin(), req.post_buffer().end());
   resp<< "</pre>";
 
   //
   // Response headers can be added at any time before send/flushing it:
   //
   resp<< "Response content-length == "
- << resp.content_length() // the content-length (returns std::size_t)
- ;//<< content_length(resp); // a content-length header
+ << resp.content_length(); // the content-length (returns std::size_t)
 
   // This function finishes up:
   return commit(req, resp, 0);
@@ -178,10 +173,10 @@
   
   using boost::asio::ip::tcp;
 
- //tcp::endpoint endpoint(tcp::v4(), 8009);
   // Make an `acceptor` for accepting requests through.
- acceptor a(s, 8009); // The acceptor is for accepting requests.
- cerr<< "Listening" << endl;
+ acceptor a(s, 8009); // Accept requests on port 8009.
+ //cerr<< "Listening" << endl;
+ //cerr<< "is_cgi ? " << a.is_cgi() << endl;
 
   //
   // After the initial setup, we can enter a loop to handle one request at a
@@ -199,8 +194,7 @@
     for (;;)
     {
       a.accept(req);
- cerr<< "is_cgi ? " << a.is_cgi() << endl;
- cerr<< "Accepted" << endl;
+ //cerr<< "Accepted" << endl;
       ret = handle_request(req);
       if (ret)
         break;
@@ -217,14 +211,14 @@
 
 }catch(boost::system::system_error const& se){
   // This is the type of error thrown by the library.
- cerr<< "[fcgi] System error: " << se.what() << endl;
+ //cerr<< "[fcgi] System error: " << se.what() << endl;
   return 1313;
-}catch(exception const& e){
+}catch(std::exception const& e){
   // Catch any other exceptions
- cerr<< "[fcgi] Exception: " << e.what() << endl;
+ //cerr<< "[fcgi] Exception: " << e.what() << endl;
   return 666;
 }catch(...){
- cerr<< "[fcgi] Uncaught exception!" << endl;
+ //cerr<< "[fcgi] Uncaught exception!" << endl;
   return 667;
 }
 }

Added: sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/fcgi/file_browser/main.cpp
==============================================================================
--- (empty file)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/fcgi/file_browser/main.cpp 2009-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -0,0 +1,334 @@
+// -- main.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)
+//
+////////////////////////////////////////////////////////////////
+//
+//[fcgi_file_browser
+//
+// This example is a simple browser-based file browser.
+//
+///////////////////////////////////////////////////////////
+#include <fstream>
+#include <boost/filesystem.hpp>
+#include <boost/algorithm/string/find.hpp>
+///////////////////////////////////////////////////////////
+#include "boost/cgi/fcgi.hpp"
+#include "boost/cgi/utility/commit.hpp"
+
+using std::cerr;
+using std::endl;
+using std::ifstream;
+using namespace boost::fcgi;
+namespace fs = boost::filesystem;
+namespace algo = boost::algorithm;
+
+
+std::size_t process_id()
+{
+#if defined(BOOST_WINDOWS)
+ return _getpid();
+#else
+ return getpid();
+#endif
+}
+
+/// Get the MIME type of the file.
+/**
+ * @returns The MIME type as a string. Returns an empty string if the
+ * file type isn't recognised / supported.
+ */
+std::string get_mime_type(fs::path const& file)
+{
+ std::string filetype (file.filename());
+ // Note: we want the string after the '.'
+ std::size_t pos (filetype.rfind(".")+1);
+ if (pos == std::string::npos)
+ return "";
+
+ filetype = filetype.substr(pos);
+ algo::to_lower(filetype);
+
+ /// Ordinary text files.
+ if (filetype == "ini" || filetype == "txt" || filetype == "conf")
+ return "text/plain";
+ else
+ if (filetype == "js")
+ return "application/javascript";
+ else
+ if (filetype == "json")
+ return "application/json";
+ else
+ if (filetype == "css")
+ return "text/css";
+ else
+ /// Structured text files.
+ if (filetype == "html" || filetype == "htm")
+ return "text/html";
+ else
+ if (filetype == "xml")
+ return "text/xml";
+ else
+ if (filetype == "csv")
+ return "text/csv";
+ else
+ if (filetype == "rtf")
+ return "text/rtf";
+ else
+ /// Image files.
+ if (filetype == "jpg" || filetype == "jpeg")
+ return "image/jpeg";
+ else
+ if (filetype == "gif")
+ return "image/gif";
+ else
+ if (filetype == "bmp")
+ return "image/x-ms-bmp";
+ else
+ if (filetype == "png")
+ return "image/png";
+ else
+ if (filetype == "tiff")
+ return "image/tiff";
+ else
+ /// Audio files.
+ if (filetype == "ogg")
+ return "audio/ogg";
+ else
+ if (filetype == "mp3")
+ return "audio/mpeg";
+ else
+ /// Video files.
+ if (filetype == "avi")
+ return "video/x-msvideo";
+ else
+ /// Rich media files.
+ if (filetype == "pdf")
+ return "application/pdf";
+ else
+ if (filetype == "doc")
+ return "application/msword";
+ else
+ if (filetype == "swf")
+ return "application/x-shockwave-flash";
+ else
+ if (filetype == "xls")
+ return "application/vnd.ms-excel";
+ /// Compressed files.
+ else
+ if (filetype == "zip")
+ return "application/zip";
+ else
+ if (filetype == "tar")
+ return "application/x-tar";
+ /// Other files.
+ else
+ if (filetype == "pl")
+ return "application/x-perl";
+ else
+ if (filetype == "py")
+ return "application/x-python";
+ else
+ if (filetype == "exe" || filetype == "dll" || filetype == "sys" ||
+ filetype == "chm" || filetype == "lib" || filetype == "pdb" ||
+ filetype == "obj" || filetype == "dep" || filetype == "idb" ||
+ filetype == "pyd" || filetype == "sqm" || filetype == "idb" ||
+ filetype == "asm" || filetype == "suo" || filetype == "sbr")
+ return ""; // Not allowed to download these file types.
+
+ return "text/plain";
+}
+
+template<typename Response, typename Client>
+void show_file(Response& resp, Client& client, fs::path const& file)
+{
+ if (!fs::exists(file))
+ resp<< "File not found.";
+ else
+ {
+ boost::uintmax_t size (fs::file_size(file));
+ cerr<< "size: " << size << endl;
+ if (size > 200000000L) // Files must be < 200MB
+ resp<< "File too large.";
+ else
+ {
+ /// Check the file type is allowed.
+ std::string mime_type (get_mime_type(file));
+ if (!mime_type.empty())
+ {
+ cerr<< "MIME-type: " << mime_type << endl;
+ std::string ctype (content_type(mime_type).content + "\r\n\r\n");
+ //write(client, boost::asio::buffer(ctype));
+ /// Open the file and read it as binary data.
+ ifstream ifs (file.string().c_str(), std::ios::binary);
+ if (ifs.is_open())
+ {
+ resp<< content_type(mime_type);
+ //resp.flush(client);
+ boost::uintmax_t bufsize = 100;
+ boost::uintmax_t read_bytes;
+ char buf[100];
+ ifs.seekg(0, std::ios::beg);
+ while (!ifs.eof() && size > 0)
+ {
+ ifs.read(buf, size < bufsize ? size : bufsize);
+ read_bytes = ifs.gcount();
+ size -= read_bytes;
+ //if (resp.content_length() + read_bytes >= 65000)
+ // resp.flush(client);
+ resp.write(buf, read_bytes);
+ //write(client, boost::asio::buffer(buf, read_bytes));
+ //resp.flush(client);
+ }
+ resp.send(client);
+ cerr<< "Content-length: " << resp.content_length() << endl;
+ }
+ }
+ else
+ resp<< "File type not allowed.";
+ }
+ }
+}
+
+template<typename Response>
+void show_paths(Response& resp, fs::path const& parent, bool recursive = true)
+{
+ if (!fs::exists(parent))
+ {
+ resp<< "File does not exist\n";
+ return;
+ }
+
+ resp<< "<ul>";
+ if (fs::is_directory(parent))
+ {
+ resp<< parent << "\n";
+ resp<< "<li class=\"directory\"><a href=\"?dir="
+ << parent.string() << "\">.</a></li>\n";
+ if (fs::is_directory(parent.parent_path()))
+ resp<< "<li class=\"directory\"><a href=\"?dir="
+ << parent.parent_path().string() << "\">..</a></li>\n";
+ for (fs::directory_iterator iter(parent), end; iter != end; ++iter)
+ {
+ if (fs::is_directory(*iter))
+ {
+ resp<< "<li class=\"directory\"><a href=\"?dir="
+ << iter->string() << "\">" << iter->path() << "</a></li>\n";
+ if (recursive)
+ show_paths(resp, iter->path(), recursive);
+ }
+ else
+ {
+ // display filename only.
+ resp<< "<li class=\"file\"><a href=\"?file="
+ << iter->string() << "\">" << iter->path().filename()
+ << "</a>";
+ //if (fs::is_regular_file(iter->status()))
+ // resp<< " [" << fs::file_size(iter->path()) << " bytes]";
+ resp<< "</li>\n";
+ }
+ }
+ }
+ else
+ {
+ resp<< "<li class=\"file\">" << "<a href=\"?file="
+ << parent.string() << "\">" << parent << "</li>\n";
+ }
+ resp<< "</ul>";
+}
+
+/// This function accepts and handles a single request.
+template<typename Request>
+int handle_request(Request& req)
+{
+ boost::system::error_code ec;
+
+ //
+ // Load in the request data so we can access it easily.
+ //
+ req.load(parse_all); // Read and parse STDIN (ie. POST) data.
+
+ //
+ // Construct a `response` object (makes writing/sending responses easier).
+ //
+ response resp;
+
+ if (req.get.count("file"))
+ {
+ show_file(resp, req.client(), req.get["file"]);
+ req.close(resp.status(), 0);
+ return 0; //commit(req, resp);
+ }
+ else
+ if (req.get.count("dir"))
+ {
+ //
+ // Responses in CGI programs require at least a 'Content-type' header.
+ // The library provides helpers for several common headers:
+ //
+ resp<< content_type("text/html");
+
+ // You can also stream text to a response.
+ // All of this just prints out the form
+ resp<< "<html>"
+ "<head><title>FastCGI File Browser Example</title><head>"
+ "<body>";
+
+ show_paths(resp, req.get["dir"], req.get["recurse"] == "1");
+
+ resp<< "</body></html>";
+ }
+ else
+ resp<< content_type("text/plain")
+ << "No path specified.\n";
+
+ //resp<< header("FastCGI-client", "fcgi_file_browser");
+ return commit(req, resp);
+}
+
+int main()
+{
+try {
+
+ // Make a `service` (more about this in other examples).
+ service s;
+
+ using boost::asio::ip::tcp;
+
+ // Accept requests on port 8001. You should configure your HTTP
+ // server to try to connect on this port.
+ acceptor a(s, 8001);
+
+ int ret(0);
+ for (;;)
+ {
+ request req(s);
+
+ for (;;)
+ {
+ a.accept(req);
+ if (0 != handle_request(req))
+ break;
+ req.clear();
+ }
+ }
+
+ return ret;
+
+}catch(boost::system::system_error const& se){
+ // This is the type of error thrown by the library.
+ cerr<< "[fcgi] System error: " << se.what() << endl;
+ return -1;
+}catch(std::exception const& e){
+ // Catch any other exceptions
+ cerr<< "[fcgi] Exception: " << e.what() << endl;
+ return -1;
+}catch(...){
+ cerr<< "[fcgi] Uncaught exception!" << endl;
+ return -1;
+}
+}
+//]

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-09-16 19:05:41 EDT (Wed, 16 Sep 2009)
@@ -29,6 +29,7 @@
 {
   // This is a minimal response. The content_type(...) may go before or after
   // the response text.
+ req.load(parse_env);
   resp<< content_type("text/plain")
       << "Hello there, universe.";
 
@@ -63,12 +64,13 @@
   try
   {
     service s; // This becomes useful with async operations.
- acceptor a(s, (unsigned short)8008); // The acceptor is for accepting requests
+ acceptor a(s, 8008); // The acceptor is for accepting requests
 
     for (;;)
     {
- request req(s); // Our request (reusing this when possible saves expensive
- // construction/destruction of the request's memory).
+ // Reusing a request object when possible saves repeated
+ // construction/destruction of the request's memory.
+ request req(s);
     
       for (;;) // Handle requests until something goes wrong
               // (an exception will be thrown).


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