1#
2# cookie.rb -- Cookie class
3#
4# Author: IPR -- Internet Programming with Ruby -- writers
5# Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
6# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
7# reserved.
8#
9# $IPR: cookie.rb,v 1.16 2002/09/21 12:23:35 gotoyuzo Exp $
10
11require 'time'
12require 'webrick/httputils'
13
14module WEBrick
15
16  ##
17  # Processes HTTP cookies
18
19  class Cookie
20
21    ##
22    # The cookie name
23
24    attr_reader :name
25
26    ##
27    # The cookie value
28
29    attr_accessor :value
30
31    ##
32    # The cookie version
33
34    attr_accessor :version
35
36    ##
37    # The cookie domain
38    attr_accessor :domain
39
40    ##
41    # The cookie path
42
43    attr_accessor :path
44
45    ##
46    # Is this a secure cookie?
47
48    attr_accessor :secure
49
50    ##
51    # The cookie comment
52
53    attr_accessor :comment
54
55    ##
56    # The maximum age of the cookie
57
58    attr_accessor :max_age
59
60    #attr_accessor :comment_url, :discard, :port
61
62    ##
63    # Creates a new cookie with the given +name+ and +value+
64
65    def initialize(name, value)
66      @name = name
67      @value = value
68      @version = 0     # Netscape Cookie
69
70      @domain = @path = @secure = @comment = @max_age =
71      @expires = @comment_url = @discard = @port = nil
72    end
73
74    ##
75    # Sets the cookie expiration to the time +t+.  The expiration time may be
76    # a false value to disable expiration or a Time or HTTP format time string
77    # to set the expiration date.
78
79    def expires=(t)
80      @expires = t && (t.is_a?(Time) ? t.httpdate : t.to_s)
81    end
82
83    ##
84    # Retrieves the expiration time as a Time
85
86    def expires
87      @expires && Time.parse(@expires)
88    end
89
90    ##
91    # The cookie string suitable for use in an HTTP header
92
93    def to_s
94      ret = ""
95      ret << @name << "=" << @value
96      ret << "; " << "Version=" << @version.to_s if @version > 0
97      ret << "; " << "Domain="  << @domain  if @domain
98      ret << "; " << "Expires=" << @expires if @expires
99      ret << "; " << "Max-Age=" << @max_age.to_s if @max_age
100      ret << "; " << "Comment=" << @comment if @comment
101      ret << "; " << "Path="    << @path if @path
102      ret << "; " << "Secure"   if @secure
103      ret
104    end
105
106    ##
107    # Parses a Cookie field sent from the user-agent.  Returns an array of
108    # cookies.
109
110    def self.parse(str)
111      if str
112        ret = []
113        cookie = nil
114        ver = 0
115        str.split(/[;,]\s+/).each{|x|
116          key, val = x.split(/=/,2)
117          val = val ? HTTPUtils::dequote(val) : ""
118          case key
119          when "$Version"; ver = val.to_i
120          when "$Path";    cookie.path = val
121          when "$Domain";  cookie.domain = val
122          when "$Port";    cookie.port = val
123          else
124            ret << cookie if cookie
125            cookie = self.new(key, val)
126            cookie.version = ver
127          end
128        }
129        ret << cookie if cookie
130        ret
131      end
132    end
133
134    ##
135    # Parses the cookie in +str+
136
137    def self.parse_set_cookie(str)
138      cookie_elem = str.split(/;/)
139      first_elem = cookie_elem.shift
140      first_elem.strip!
141      key, value = first_elem.split(/=/, 2)
142      cookie = new(key, HTTPUtils.dequote(value))
143      cookie_elem.each{|pair|
144        pair.strip!
145        key, value = pair.split(/=/, 2)
146        if value
147          value = HTTPUtils.dequote(value.strip)
148        end
149        case key.downcase
150        when "domain"  then cookie.domain  = value
151        when "path"    then cookie.path    = value
152        when "expires" then cookie.expires = value
153        when "max-age" then cookie.max_age = Integer(value)
154        when "comment" then cookie.comment = value
155        when "version" then cookie.version = Integer(value)
156        when "secure"  then cookie.secure = true
157        end
158      }
159      return cookie
160    end
161
162    ##
163    # Parses the cookies in +str+
164
165    def self.parse_set_cookies(str)
166      return str.split(/,(?=[^;,]*=)|,$/).collect{|c|
167        parse_set_cookie(c)
168      }
169    end
170  end
171end
172