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