3 require 'rack/response'
9 # Rack::Session::Cookie provides simple cookie based session management.
10 # The session is a Ruby Hash stored as base64 encoded marshalled data
11 # set to :key (default: rack.session).
12 # When the secret key is set, cookie data is checked for data integrity.
16 # use Rack::Session::Cookie, :key => 'rack.session',
17 # :domain => 'foo.com',
19 # :expire_after => 2592000,
20 # :secret => 'change_me'
22 # All parameters are optional.
26 def initialize(app
, options
={})
28 @key = options
[:key] || "rack.session"
29 @secret = options
[:secret]
30 @default_options = {:domain => nil,
32 :expire_after => nil}.merge(options
)
37 status
, headers
, body
= @app.call(env)
38 commit_session(env, status
, headers
, body
)
44 request
= Rack
::Request.new(env)
45 session_data
= request
.cookies
[@key]
47 if @secret && session_data
48 session_data
, digest
= session_data
.split("--")
49 session_data
= nil unless digest
== generate_hmac(session_data
)
53 session_data
= session_data
.unpack("m*").first
54 session_data
= Marshal
.load(session_data
)
55 env["rack.session"] = session_data
57 env["rack.session"] = Hash
.new
60 env["rack.session.options"] = @default_options.dup
63 def commit_session(env, status
, headers
, body
)
64 session_data
= Marshal
.dump(env["rack.session"])
65 session_data
= [session_data
].pack("m*")
68 session_data
= "#{session_data}--#{generate_hmac(session_data)}"
71 if session_data
.size
> (4096 - @key.size
)
72 env["rack.errors"].puts("Warning! Rack::Session::Cookie data size exceeds 4K. Content dropped.")
73 [status
, headers
, body
]
75 options
= env["rack.session.options"]
77 cookie
[:value] = session_data
78 cookie
[:expires] = Time
.now
+ options
[:expire_after] unless options
[:expire_after].nil?
79 response
= Rack
::Response.new(body
, status
, headers
)
80 response
.set_cookie(@key, cookie
.merge(options
))
85 def generate_hmac(data)
86 OpenSSL
::HMAC.hexdigest(OpenSSL
::Digest::SHA1.new
, @secret, data)