This class provides a CookieJar object for Mongrels. Just initialize
with response and request objects and then treat like a hash. Does not
depend on cgi.rb

ry
# Provides a Rails-like CookieJar class for Mongrels. (ry dahl, 1187362405)
# Unit tests at the bottom of this file. To execute the unit tests, use
#   ruby -r rubygems cookies_for_mongrels.rb

require 'mongrel'

class Time
  # Abbreviated day-of-week names specified by RFC 822
  RFC822_DAYS = %w[ Sun Mon Tue Wed Thu Fri Sat ]
  # Abbreviated month names specified by RFC 822
  RFC822_MONTHS = %w[ Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ]
  
  # Strange Cookie Expire time format
  def gmt_rfc822
    t = self.clone.gmtime
    return format("%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT", 
      RFC822_DAYS[t.wday], t.day, RFC822_MONTHS[t.month-1], t.year, t.hour, t.min, t.sec)
  end
end
 
module Mongrel
  module Const # :nodoc:
    HTTP_COOKIE = 'HTTP_COOKIE'.freeze
    SET_COOKIE = 'Set-Cookie'.freeze
    COOKIE_VALUE_EXPIRES = "%s=%s; path=/; expires=%s".freeze # as in Merb
    COOKIE_VALUE = "%s=%s; path=/".freeze
    COOKIE_EXPIRED_TIME  = Time.at(0).freeze
    COOKIE_SEPARATOR = ';,'
  end
  
  class CookieJar
    def initialize(request, response)
      @response = response
      @cookies = HttpRequest.query_parse(
        request.params[Const::HTTP_COOKIE], Const::COOKIE_SEPARATOR)
    end
    
    # Returns the value of the cookie by +name+ -- or nil if no such cookie 
    # exists. You set new cookies using either the cookie method
    # or cookies[]= (for simple name/value cookies without options).
    def [](name)
      @cookies[name]
    end
    
    # Determines if a cookie key has been given by request. Does not include 
    # cookies which have been set during this request    
    def has_key?(name)
      @cookies.has_key?(name)
    end
    
    # Gives the size of the number of cookies read. Does not include cookies
    # which have been set during this request
    def size
      @cookies.size
    end
    
    # Removes the cookie on the client machine by setting the value to an 
    # empty string and setting its expiration date into the past.  
    def delete(name)
      set_cookie(name, nil, COOKIE_EXPIRED_TIME)
    end
    
    # Sets a (name, value) pair to be stored on as a cookie on the clients
    # computer. Optionally provide a Time object as an expiration date.
    def set(name, value, expires = nil)
      params = [name.to_s, HttpRequest.escape(value)]
      @response.header[Const::SET_COOKIE] =
        if expires
          params << expires.gmt_rfc822 
          Const::COOKIE_VALUE_EXPIRES % params
        else
          Const::COOKIE_VALUE % params
        end
    end
    alias_method :[]=, :set
  end
end


if __FILE__ == $0
  require 'test/unit'
  require 'ostruct'
  require 'cgi'
  include Mongrel
  class CookieJarTest < Test::Unit::TestCase
    # Wdy, DD Mon YYYY HH:MM:SS GMT
    RFC1123_REGEXP = %r{\w\w\w, \d\d \w\w\w \d\d\d\d \d\d:\d\d:\d\d GMT}
    
    def request_mock(cookie_string)
      OpenStruct.new(:params => {'HTTP_COOKIE' => cookie_string})
    end
    
    def setup
      @out = StringIO.new
      @response = HttpResponse.new(@out)
    end
    
    def test_blank_request
      request = request_mock nil
      cookies = CookieJar.new(request, @response)
      assert_nil cookies['hello']
    end
    
    def test_set_single
      request = request_mock ''
      cookies = CookieJar.new(request, @response)
      assert_nil cookies['hello']
      cookies['hello'] = 'world'
      @response.send_header
      @out.rewind
      assert_match 'Set-Cookie: hello=world; path=/', @out.read
    end
    
    def test_set_multiple
      request = request_mock ''
      cookies = CookieJar.new(request, @response)
      assert_nil cookies['hello']
      cookies['hello'] = 'world'
      cookies['world'] = 'hello'
      @response.send_header
      @out.rewind
      s = @out.read
      assert_match %r{Set-Cookie: hello=world; path=/}, s
      assert_match %r{Set-Cookie: world=hello; path=/}, s
      assert_no_match %r{expires}, s
    end
    
    def test_set_with_expires
      request = request_mock ''
      cookies = CookieJar.new(request, @response)
      cookies.set('hello', 'world', Time.now)
      cookies.set('world', 'hello', Time.now)      
      @response.send_header
      @out.rewind
      s = @out.read
      assert_match %r{Set-Cookie: hello=world; path=/; expires=}, s
      assert_match %r{Set-Cookie: world=hello; path=/; expires=}, s
      assert_match RFC1123_REGEXP, s
    end
    
    def test_read
      request = request_mock 'hello=world; my name is=haaaaaapy; world=hello'
      cookies = CookieJar.new(request, @response)
      assert cookies.has_key?('hello')
      assert_equal 'world', cookies['hello']
      assert_equal 'haaaaaapy', cookies['my name is']
      assert_equal 'hello', cookies['world']
      assert_equal 3, cookies.size
    end
  end
end
_______________________________________________
Mongrel-users mailing list
Mongrel-users@rubyforge.org
http://rubyforge.org/mailman/listinfo/mongrel-users

Reply via email to