$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
From: lists.drrngrvy_at_[hidden]
Date: 2007-10-08 16:32:31
Author: drrngrvy
Date: 2007-10-08 16:32:31 EDT (Mon, 08 Oct 2007)
New Revision: 39816
URL: http://svn.boost.org/trac/boost/changeset/39816
Log:
Adding test for cgi::cookie and modifying the cookie class to be more realistic
Added:
   sandbox/SOC/2007/cgi/libs/cgi/test/run/cookie.cpp   (contents, props changed)
   sandbox/SOC/2007/cgi/libs/cgi/test/run/response.cpp   (contents, props changed)
Properties modified: 
   sandbox/SOC/2007/cgi/   (props changed)
Text files modified: 
   sandbox/SOC/2007/cgi/boost/cgi/cookie.hpp         |   113 ++++++++++++++++++++++++++++++++++----- 
   sandbox/SOC/2007/cgi/boost/cgi/response.hpp       |     9 --                                      
   sandbox/SOC/2007/cgi/libs/cgi/test/run/Jamfile.v2 |     2                                         
   3 files changed, 101 insertions(+), 23 deletions(-)
Modified: sandbox/SOC/2007/cgi/boost/cgi/cookie.hpp
==============================================================================
--- sandbox/SOC/2007/cgi/boost/cgi/cookie.hpp	(original)
+++ sandbox/SOC/2007/cgi/boost/cgi/cookie.hpp	2007-10-08 16:32:31 EDT (Mon, 08 Oct 2007)
@@ -10,46 +10,127 @@
 #define CGI_COOKIE_HPP_INCLUDED__
 
 #include <string>
+#include <boost/system/error_code.hpp>
+#include <boost/tokenizer/
 
 namespace cgi {
 
-  /// A `cookie` object that can be streamed to a `response` object
+  template<typename String> struct basic_cookie;
+  
+  // typedefs for common usage
+  typedef basic_cookie<std::string> cookie;
+  typedef basic_cookie<std::wstring> wcookie;
+
+  /// A `basic_cookie<>` object that can be (out-) streamed
   /**
    * Either set the parameters in the constructor, or set them directly.
    * Note: If you want to set the parameters individually, remember that each
    * parameter must NOT have a trailing semi-colon!
    *
    * TODO
-   * - Add 'domain' attribute
-   * - Add 'HttpOnly' attribute
-   * - Data should be URL-encoded
+   * - Data should be URL-encoded, or maybe provide an overload for url_decode
+   *   that takes an HttpCookie?
+   * - Add to_string() ?
    */
-  struct cookie
+  template<typename String>
+  struct basic_cookie
   {
-    cookie() {}
+    typedef String string_type;
+
+    basic_cookie() {}
 
     /// Delete the cookie named `_name`.
-    cookie(const std::string& _name)
-      : content(_name + "=")
-      , expires("Fri, 07 May 1824 16:30:00 GMT")
+    basic_cookie(const string_type& _name)
+      : content(_name)
+      , value()
+      , expires("Fri, 05-Jun-1989 15:30:00 GMT")
+      , path("/")
+      , secure(false)
+      , http_only(false)
     {
     }
 
     /// Create a cookie.
-    cookie(const std::string& _name, const std::string& _val
-          , const std::string& _expires = ""
-          , const std::string& _path = "")
-      : content(_name + "=" + _val)
+    basic_cookie(const string_type& _name, const string_type& _val
+                , const string_type& _expires = ""
+                , const string_type& _path = "/"
+                , const string_type& _domain = ""
+                , bool _secure = false
+                , bool HttpOnly = false)
+      : content(_name)
+      , value(_val)
       , expires(_expires)
       , path(_path)
+      , domain(_domain)
+      , secure(_secure)
+      , http_only(HttpOnly)
+    {
+    }
+
+    string_type name;
+    string_type value;
+    string_type expires;
+    string_type path;
+    string_type domain;
+    bool secure;
+    bool http_only;
+
+    /// Create a cookie from a const char*
+    /**
+     * Rules taken from: http://wp.netscape.com/newsref/std/cookie_spec.html
+     *
+     * Assumes:
+     * - Parts of the cookie are delimited by '; '. ie. if there is no space,
+     *   or multiple spaces after the semi-colon, this function won't work...
+     */
+    /* Actually, I'm omitting these functions for now, just had a though...
+    static basic_cookie<string_type>
+      from_string(const char* str, boost::system::error_code& ec)
+    {
+      typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+      boost::char_separator<char> sep(";=");
+      tokenizer tokens(str, sep);
+      for (tokenizer::iterator iter = tokens.begin();
+           iter != tokens.end(); ++iter)
+      {
+
+      }
+      return ck;
+    }
+
+    static basic_cookie<string_type> from_string(const char* str)
+    {
+      boost::system::error_code ec;
+      cookie ck = from_string(ec);
+      detail::throw_error(ec);
+      return ck;
+    }
+
+    static basic_cookie<string_type> from_string(std::string& str)
     {
+      return from_string(str.c_str());
     }
 
-    std::string content;
-    std::string expires;
-    std::string path;
+    static basic_cookie<string_type>
+      from_string(std::string& str, boost::system::error_code& ec)
+    {
+      return from_string(str.c_str(), ec);
+    }
+    */
   };
 
+  template<typename OutStream, typename Cookie>
+    OutStream& operator<<(OutStream& os, Cookie ck)
+  {
+    os<< ck.name << "=" << ck.value;
+    if (!ck.expires.empty()) os<< "; expires=" << ck.expires;
+    if (!ck.path.empty()   ) os<< "; path="    << ck.path;
+    if (!ck.domain.empty() ) os<< "; domain="  << ck.domain;
+    if ( secure            ) os<< "; secure";
+    if ( ck.http_only      ) os<< "; HttpOnly";
+    return os;
+  }
+
 } // namespace cgi
 
 #endif // CGI_COOKIE_HPP_INCLUDED__
Modified: sandbox/SOC/2007/cgi/boost/cgi/response.hpp
==============================================================================
--- sandbox/SOC/2007/cgi/boost/cgi/response.hpp	(original)
+++ sandbox/SOC/2007/cgi/boost/cgi/response.hpp	2007-10-08 16:32:31 EDT (Mon, 08 Oct 2007)
@@ -78,17 +78,12 @@
   }
 
   template<>
-  response& operator<<(response& resp, const cookie& c)
+  response& operator<<(response& resp, const cookie& ck)
   {
     // Note: the 'set-cookie' isn't part of the cookie object since
     // the cookie can also be set after the headers have been sent.
     // See http://tinyurl.com/33znkj
-    resp<< "Set-cookie: " << c.content << "; ";
-    if (!c.expires.empty())
-      resp<< c.expires << "; ";
-    if (!c.path.empty())
-      resp<< c.path << "; ";
-    return resp<< "\r\n";
+    return resp<< "Set-cookie: " << ck << "\r\n";
   }
 
 } // namespace cgi
Modified: sandbox/SOC/2007/cgi/libs/cgi/test/run/Jamfile.v2
==============================================================================
--- sandbox/SOC/2007/cgi/libs/cgi/test/run/Jamfile.v2	(original)
+++ sandbox/SOC/2007/cgi/libs/cgi/test/run/Jamfile.v2	2007-10-08 16:32:31 EDT (Mon, 08 Oct 2007)
@@ -6,4 +6,6 @@
 test-suite run_test_suite
   :
     #[ run [ glob *.cpp ] ]
+    
+    [ run cookie.cpp ]
   ;
Added: sandbox/SOC/2007/cgi/libs/cgi/test/run/cookie.cpp
==============================================================================
--- (empty file)
+++ sandbox/SOC/2007/cgi/libs/cgi/test/run/cookie.cpp	2007-10-08 16:32:31 EDT (Mon, 08 Oct 2007)
@@ -0,0 +1,88 @@
+// Test the cgi::cookie class works as advertised
+
+/* TODO
+ * ----
+ * - Verify it works with other string types (std::wstring is probably enough)
+ */
+
+#define BOOST_TEST_MAIN
+#include <boost/test/unit_test.hpp>
+
+#include <sstream>
+#include "boost/cgi/cookie.hpp"
+
+
+BOOST_AUTO_TEST_CASE( cookie_constructor_delete )
+{
+  // Constructing a cookie with only a name should be a valid way to 
+  // delete the cookie. ie. set its value to NULL and give it a date
+  // in the past
+  using namespace cgi;
+
+  cookie ck("unwanted_cookie_name");
+  
+  BOOST_CHECK(ck.name      == "unwanted_cookie_name");
+  BOOST_CHECK(ck.value     == "");
+  BOOST_CHECK(ck.path      == "/");
+  // this one could be more robust (by using a generic RFC2616 date parser)
+  // see: http://www.apps.ietf.org/rfc/rfc2616.html#sec-3.3
+  BOOST_CHECK(ck.data      == "Fri, 05 Jun 1989 15:30:00 GMT");
+  BOOST_CHECK(ck.domain    == "");
+  BOOST_CHECK(ck.secure    == false);
+  BOOST_CHECK(ck.http_only == false);
+}
+
+BOOST_AUTO_TEST_CASE( cookie_constructor_full )
+{
+  // Check the full version of the constructor works (simple test)
+  using namespace cgi;
+
+  cookie ck("name", "value", "Wed, 03-Oct-2007 16:26:06 GMT"
+           , "/cookie", "example.com", false, true);
+
+  BOOST_CHECK(ck.name      == "name");
+  BOOST_CHECK(ck.value     == "value");
+  BOOST_CHECK(ck.path      == "/cookie");
+  // this one could be more robust (by using a generic RFC2616 date parser)
+  // see: http://www.apps.ietf.org/rfc/rfc2616.html#sec-3.3
+  BOOST_CHECK(ck.data      == "Wed, 03-Oct-2007 16:26:06 GMT");
+  BOOST_CHECK(ck.domain    == "example.com");
+  BOOST_CHECK(ck.secure    == false);
+  BOOST_CHECK(ck.http_only == true);
+}
+
+BOOST_AUTO_TEST_CASE( cookie_stream_operator )
+{
+  // Constructing a cookie with only a name should be a valid way to 
+  // delete the cookie. ie. set its value to NULL and give it a date
+  // in the past
+  using namespace cgi;
+  using namespace std;
+
+  string cookie_content(
+    "unwanted_cookie_name=; expires=Fri, 05-Jun-1989 15:30:00 GMT; path=/");
+
+  // First check the cookie below outputs the above string when streamed
+  // (don't continue if it doesn't: the rest of the test relies on this).
+  cookie ck("unwanted_cookie_name");
+  ostringstream oss;
+  oss<< ck;
+  BOOST_ASSERT(oss.str() == cookie_content);
+
+  // Now check if the string cookie_content can be turned into a cookie type,
+  // then streamed without being altered.
+  //cookie ck2(cookie::from_string(cookie_content));
+  //oss.clear();
+  //oss<< ck2;
+  //BOOST_CHECK(oss.str() == cookie_content);
+
+  // Now try a more complete cookie, using the detailed constructor
+  cookie_content = "name=value; expires=Wed, 03-Oct-2007 16:26:06 GMT;"
+                   " path=/cookie; domain=example.com; secure; HttpOnly";
+
+  cookie ck("name", "value", "Wed, 03-Oct-2007 16:26:06 GMT"
+           , "/cookie", "example.com", true, true);
+  oss.clear();
+  oss<< ck;
+  BOOST_CHECK(oss.str() == cookie_content);  
+}
Added: sandbox/SOC/2007/cgi/libs/cgi/test/run/response.cpp
==============================================================================
--- (empty file)
+++ sandbox/SOC/2007/cgi/libs/cgi/test/run/response.cpp	2007-10-08 16:32:31 EDT (Mon, 08 Oct 2007)
@@ -0,0 +1,10 @@
+// Test the cgi::response class works as advertised
+#define BOOST_TEST_MAIN
+#include <boost/test/unit_test.hpp>
+
+#include "boost/cgi/response.hpp"
+
+BOOST_AUTO_TEST_CASE( response_test )
+{
+  using namespace cgi;
+}
\ No newline at end of file