OSDN Git Service

240e6c8dbe5718bab6f554d95e6cabdc6b7f5161
[redminele/redminele.git] / ruby / lib / ruby / gems / 1.8 / gems / rack-1.1.2 / lib / rack / session / cookie.rb
1 require 'openssl'
2 require 'rack/request'
3 require 'rack/response'
4
5 module Rack
6
7   module Session
8
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.
13     #
14     # Example:
15     #
16     #     use Rack::Session::Cookie, :key => 'rack.session',
17     #                                :domain => 'foo.com',
18     #                                :path => '/',
19     #                                :expire_after => 2592000,
20     #                                :secret => 'change_me'
21     #
22     #     All parameters are optional.
23
24     class Cookie
25
26       def initialize(app, options={})
27         @app = app
28         @key = options[:key] || "rack.session"
29         @secret = options[:secret]
30         @default_options = {:domain => nil,
31           :path => "/",
32           :expire_after => nil}.merge(options)
33       end
34
35       def call(env)
36         load_session(env)
37         status, headers, body = @app.call(env)
38         commit_session(env, status, headers, body)
39       end
40
41       private
42
43       def load_session(env)
44         request = Rack::Request.new(env)
45         session_data = request.cookies[@key]
46
47         if @secret && session_data
48           session_data, digest = session_data.split("--")
49           session_data = nil  unless digest == generate_hmac(session_data)
50         end
51
52         begin
53           session_data = session_data.unpack("m*").first
54           session_data = Marshal.load(session_data)
55           env["rack.session"] = session_data
56         rescue
57           env["rack.session"] = Hash.new
58         end
59
60         env["rack.session.options"] = @default_options.dup
61       end
62
63       def commit_session(env, status, headers, body)
64         session_data = Marshal.dump(env["rack.session"])
65         session_data = [session_data].pack("m*")
66
67         if @secret
68           session_data = "#{session_data}--#{generate_hmac(session_data)}"
69         end
70
71         if session_data.size > (4096 - @key.size)
72           env["rack.errors"].puts("Warning! Rack::Session::Cookie data size exceeds 4K. Content dropped.")
73         else
74           options = env["rack.session.options"]
75           cookie = Hash.new
76           cookie[:value] = session_data
77           cookie[:expires] = Time.now + options[:expire_after] unless options[:expire_after].nil?
78           Utils.set_cookie_header!(headers, @key, cookie.merge(options))
79         end
80
81         [status, headers, body]
82       end
83
84       def generate_hmac(data)
85         OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, @secret, data)
86       end
87
88     end
89   end
90 end