redrack-session 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ # encoding: utf-8
2
+ source :rubygems
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (C) 2007, 2008, 2009, and 2010 by Christian Neukirchen
2
+ <purl.org/net/chneukirchen> and (C) 2011 by Kendall Gifford
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ this software and associated documentation files (the "Software"), to deal in
6
+ the Software without restriction, including without limitation the rights to
7
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8
+ the Software, and to permit persons to whom the Software is furnished to do so,
9
+ subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,40 @@
1
+ ## redrack-session
2
+
3
+ Redis session store for rack applications.
4
+
5
+ This provides browser sessions for your rack application, storing a unique
6
+ session ID in a cookie in the client's browser and the session data in a redis
7
+ server.
8
+
9
+ ### Usage
10
+
11
+ This gem may be used in much the same way as you might use the
12
+ `Rack::Session::Memcached` middleware provided by the rack gem, or any other
13
+ rack session middleware for that matter. Just add it to your rack middleware
14
+ stack and then you can read and write objects to the hash provided in
15
+ `env["rack.session"]`.
16
+
17
+ ### To Do
18
+
19
+ - Flush out this README and improvide inline code documentation
20
+ - Create redrack-cache gem
21
+ - Create redrack-throttle gem
22
+ - Create redrack-localize gem
23
+ - Create redrack gem to package all of the above as single rack middleware
24
+ - Create redrails-session gem
25
+ - Create redrails-throttle gem
26
+ - Create redrails-localize gem
27
+ - Create redrails gem to package all of the redrails-* gems above, linking all redrack-* middleware into a rails app
28
+
29
+ ### Credits and License
30
+
31
+ Though "authored" by myself (Kendall Gifford), this gem was heavily inspired by
32
+ by the `Rack::Session::Memcached` rack middleware included in the rack gem. The
33
+ RSpec tests were even more heavily inspired by the rack gem and are basically a
34
+ translation of the test cases in the rack codebase that test
35
+ `Rack::Session::Memcached`.
36
+
37
+ Licensed using the standard
38
+ [MIT License](http://en.wikipedia.org/wiki/MIT_License). See the file
39
+ [LICENSE](http://github.com/zettabyte/redrack-session/blob/master/LICENSE) in
40
+ the root folder of the project.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ # encoding: utf-8
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,2 @@
1
+ # encoding: utf-8
2
+ require "redrack/session"
@@ -0,0 +1,7 @@
1
+ # encoding: utf-8
2
+ module Redrack
3
+ module Session
4
+ autoload :VERSION, 'redrack/session/version'
5
+ autoload :Middleware, 'redrack/session/middleware'
6
+ end
7
+ end
@@ -0,0 +1,102 @@
1
+ # encoding: utf-8
2
+ require 'rack/session/abstract/id'
3
+ require 'redis'
4
+ require 'redis-namespace'
5
+
6
+ module Redrack
7
+ module Session
8
+ class Middleware < Rack::Session::Abstract::ID
9
+
10
+ attr_reader :redis # provide raw access to redis database (for testing)
11
+
12
+ # redis-specific default options (following the Abstract::ID pattern)
13
+ DEFAULT_OPTIONS = Rack::Session::Abstract::ID::DEFAULT_OPTIONS.merge(
14
+ :redis_password => nil, # optional authentication password for redis server
15
+ :redis_namespace => nil, # optional namespace under which session keys are stored
16
+ :redis_path => nil, # specify this if connecting to redis server via socket
17
+ :redis_host => "127.0.0.1", # hostname or IP of redis database server
18
+ :redis_port => 6379, # port to connect to redis database server
19
+ :redis_database => 0, # default redis database to hold sessions
20
+ :redis_timeout => 5 # default redis connection timeout (seconds)
21
+ )
22
+
23
+ def initialize(app, options = {})
24
+ super
25
+ @mutex = Mutex.new
26
+
27
+ # process redis-specific options
28
+ if @default_options[:redis_path].is_a?(String)
29
+ redis_options = { :path => @default_options[:redis_path] }
30
+ else
31
+ redis_options = {
32
+ :host => (@default_options[:redis_host] || "127.0.0.1"),
33
+ :port => (@default_options[:redis_port] || 6379)
34
+ }
35
+ end
36
+ redis_options[:db] = @default_options[:redis_database] || 0
37
+ redis_options[:timeout] = @default_options[:redis_timeout] || 5
38
+ redis_options[:password] = @default_options[:redis_password] if @default_options[:redis_password].is_a?(String)
39
+
40
+ # create connection to our redis database and ensure we're connected
41
+ @redis = ::Redis.new(redis_options.merge(:thread_safe => true))
42
+ @redis.ping
43
+
44
+ # store session keys under specified namespace (if any)
45
+ if @default_options[:redis_namespace]
46
+ @redis = ::Redis::Namespace.new(@default_options[:redis_namespace], :redis => @redis)
47
+ end
48
+ end
49
+
50
+ private
51
+ def generate_sid
52
+ # Atomically test if sid available and reserve it if it is
53
+ sid = super # first iteration
54
+ sid = super until @redis.setnx(sid, Marshal.dump({}))
55
+ # Set our allocated sid to expire if it isn't used any time soon
56
+ expiry = (@default_options[:expire_after] || 0).to_i
57
+ @redis.expire(sid, expiry <= 0 ? 600 : expiry)
58
+ sid
59
+ end
60
+
61
+ def get_session(env, sid)
62
+ with_lock(env, [nil, {}]) do
63
+ if sid and @redis.exists(sid)
64
+ session = Marshal.load(@redis.get(sid))
65
+ else
66
+ sid, session = generate_sid, {}
67
+ end
68
+ [sid, session]
69
+ end
70
+ end
71
+
72
+ def set_session(env, session_id, new_session, options)
73
+ expiry = options[:expire_after]
74
+ expiry = expiry.nil? ? 0 : expiry + 1
75
+
76
+ with_lock(env, false) do
77
+ @redis.del(session_id)
78
+ @redis.set(session_id, Marshal.dump(new_session.to_hash))
79
+ @redis.expire(session_id, expiry) if expiry > 0
80
+ session_id
81
+ end
82
+ end
83
+
84
+ def destroy_session(env, session_id, options)
85
+ with_lock(env) do
86
+ @redis.del(session_id)
87
+ generate_sid unless options[:drop]
88
+ end
89
+ end
90
+
91
+ def with_lock(env, default = nil)
92
+ @mutex.lock if env["rack.multithread"]
93
+ yield
94
+ rescue
95
+ default
96
+ ensure
97
+ @mutex.unlock if @mutex.locked?
98
+ end
99
+
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,6 @@
1
+ # encoding: utf-8
2
+ module Redrack
3
+ module Session
4
+ VERSION = "0.0.1"
5
+ end
6
+ end
@@ -0,0 +1,28 @@
1
+ # encoding: utf-8
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "redrack/session/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "redrack-session"
7
+ s.version = Redrack::Session::VERSION
8
+ s.authors = ["Kendall Gifford"]
9
+ s.email = ["zettabyte@gmail.com"]
10
+ s.homepage = "https://github.com/zettabyte/redrack-session"
11
+ s.summary = "Redis session store for rack applications."
12
+ s.description = <<-DESC.gsub(/^\s*/, "")
13
+ Redis session store for rack applications.
14
+
15
+ This was inspired by the Rack::Session::Memcached session store.
16
+ DESC
17
+
18
+ s.files = `git ls-files`.split("\n")
19
+ s.test_files = `git ls-files -- spec/*`.split("\n")
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_development_dependency "bundler", "~> 1.0.21"
23
+ s.add_development_dependency "rspec", "~> 2.7.0"
24
+ s.add_development_dependency "rack-test", "~> 0.6.1"
25
+ s.add_runtime_dependency "rack", "~> 1.3.5"
26
+ s.add_runtime_dependency "redis", "~> 2.2.2"
27
+ s.add_runtime_dependency "redis-namespace", "~> 1.1.0"
28
+ end
@@ -0,0 +1,195 @@
1
+ # encoding: utf-8
2
+ require File.expand_path("../../spec_helper", __FILE__)
3
+
4
+ module Redrack
5
+ describe Session do
6
+
7
+ it "faults on no connection" do
8
+ expect { app(:redis_host => "nosuchserver") }.to raise_error(SocketError)
9
+ end
10
+
11
+ it "connects to existing server" do
12
+ expect { app() }.to_not raise_error
13
+ end
14
+
15
+ it "passes options to Redis" do
16
+ main_app = Redrack::Session::Middleware.new(Redrack::Session::RackApp.new, :redis_namespace => "test:rack:session")
17
+ main_app.redis.namespace.should == "test:rack:session"
18
+ end
19
+
20
+ it "creates a new cookie" do
21
+ get "/"
22
+ rack_mock_session.cookie_jar["rack.session"].should be_a(String)
23
+ end
24
+
25
+ it "determines session from a cookie" do
26
+ get("/add") { |r| r.body.should match /Session Counter: 1/ }
27
+ get("/add") { |r| r.body.should match /Session Counter: 2/ }
28
+ get("/add") { |r| r.body.should match /Session Counter: 3/ }
29
+ end
30
+
31
+ it "determines session only from a cookie by default" do
32
+ get "/add"
33
+ sid = rack_mock_session.cookie_jar["rack.session"]
34
+ clear_cookies
35
+ get("/add", "rack.session" => sid) { |r| r.body.should match /Session Counter: 1/ }
36
+ sid = rack_mock_session.cookie_jar["rack.session"]
37
+ clear_cookies
38
+ get("/add", "rack.session" => sid) { |r| r.body.should match /Session Counter: 1/ }
39
+ end
40
+
41
+ it "determines session from params" do
42
+ mock_session = Rack::MockSession.new(app(:cookie_only => false))
43
+ session = Rack::Test::Session.new(mock_session)
44
+ session.get "/add"
45
+ sid = mock_session.cookie_jar["rack.session"]
46
+ session.clear_cookies
47
+ session.get("/add", "rack.session" => sid) { |r| r.body.should match /Session Counter: 2/ }
48
+ session.get("/add", "rack.session" => sid) { |r| r.body.should match /Session Counter: 3/ }
49
+ end
50
+
51
+ it "survives nonexistant cookies" do
52
+ rack_mock_session.set_cookie("rack.session=badsessionid")
53
+ get("/add") { |r| r.body.should match /Session Counter: 1/ }
54
+ rack_mock_session.cookie_jar["rack.session"].should_not match /badsessionid/
55
+ end
56
+
57
+ it "maintains freshness" do
58
+ mock_session = Rack::MockSession.new(app(:expire_after => 3))
59
+ session = Rack::Test::Session.new(mock_session)
60
+ session.get("/add") { |r| r.body.should match /Session Counter: 1/ }
61
+ sid = mock_session.cookie_jar["rack.session"]
62
+ session.get("/add") { |r| r.body.should match /Session Counter: 2/ }
63
+ mock_session.cookie_jar["rack.session"].should == sid
64
+ puts "Sleeping to expire session..." if $DEBUG
65
+ sleep 5
66
+ session.get("/add") { |r| r.body.should match /Session Counter: 1/ }
67
+ mock_session.cookie_jar["rack.session"].should_not == sid
68
+ end
69
+
70
+ it "does not send the same session id if it did not change" do
71
+ get("/add") { |r| r.body.should match /Session Counter: 1/ }
72
+ sid = rack_mock_session.cookie_jar["rack.session"]
73
+ get("/add") do |r|
74
+ r.headers["Set-Cookie"].should be_nil
75
+ r.body.should match /Session Counter: 2/
76
+ end
77
+ get("/add") do |r|
78
+ r.headers["Set-Cookie"].should be_nil
79
+ r.body.should match /Session Counter: 3/
80
+ end
81
+ end
82
+
83
+ it "deletes cookies with :drop option" do
84
+ main_mock_session = Rack::MockSession.new(app())
85
+ drop_mock_session = Rack::MockSession.new(drop_app())
86
+ main_session = Rack::Test::Session.new(main_mock_session)
87
+ drop_session = Rack::Test::Session.new(drop_mock_session)
88
+ main_session.get("/add") { |r| r.body.should match /Session Counter: 1/ }
89
+ sid = main_mock_session.cookie_jar["rack.session"]
90
+ drop_mock_session.set_cookie("rack.session=#{sid}")
91
+ drop_session.get("/add") do |r|
92
+ r.header["Set-Cookie"].should be_nil
93
+ r.body.should match /Session Counter: 2/
94
+ end
95
+ main_session.get("/add") { |r| r.body.should match /Session Counter: 1/ }
96
+ main_mock_session.cookie_jar["rack.session"].should_not == sid
97
+ end
98
+
99
+ it "provides new session id with :renew option" do
100
+ main_mock_session = Rack::MockSession.new(app())
101
+ renew_mock_session = Rack::MockSession.new(renew_app())
102
+ main_session = Rack::Test::Session.new(main_mock_session)
103
+ renew_session = Rack::Test::Session.new(renew_mock_session)
104
+ main_session.get("/add") { |r| r.body.should match /Session Counter: 1/ }
105
+ old_sid = main_mock_session.cookie_jar["rack.session"]
106
+ renew_mock_session.set_cookie("rack.session=#{old_sid}")
107
+ renew_session.get("/add") { |r| r.body.should match /Session Counter: 2/ }
108
+ new_sid = renew_mock_session.cookie_jar["rack.session"]
109
+ new_sid.should_not == old_sid
110
+ main_mock_session.clear_cookies
111
+ main_mock_session.set_cookie("rack.session=#{new_sid}")
112
+ main_session.get("/add") { |r| r.body.should match /Session Counter: 3/ }
113
+ main_mock_session.clear_cookies
114
+ main_mock_session.set_cookie("rack.session=#{old_sid}")
115
+ main_session.get("/add") { |r| r.body.should match /Session Counter: 1/ }
116
+ end
117
+
118
+ it "omits cookie with :defer option" do
119
+ mock_session = Rack::MockSession.new(defer_app())
120
+ session = Rack::Test::Session.new(mock_session)
121
+ session.get("/add") { |r| r.body.should match /Session Counter: 1/ }
122
+ mock_session.cookie_jar["rack.session"].should be_nil
123
+ end
124
+
125
+ it "updates deep hashes correctly" do
126
+ main_app = Redrack::Session::Middleware.new(Redrack::Session::RackApp.new)
127
+ mock_session = Rack::MockSession.new(main_app)
128
+ session = Rack::Test::Session.new(mock_session)
129
+ session.get("/set-deep-hash")
130
+ sid = mock_session.cookie_jar["rack.session"]
131
+ first = main_app.redis.get(sid)
132
+ session.get("/mutate-deep-hash")
133
+ first.should_not equal(main_app.redis.get(sid))
134
+ end
135
+
136
+ it "cleanly merges sessions when multithreaded" do
137
+ mutex = Mutex.new
138
+ count = 0
139
+ main_app = Redrack::Session::Middleware.new(Redrack::Session::RackApp.new)
140
+ main_mock_session = Rack::MockSession.new(main_app)
141
+ thread_mock_session = Rack::MockSession.new(threaded_app())
142
+ main_session = Rack::Test::Session.new(main_mock_session)
143
+ thread_session = Rack::Test::Session.new(thread_mock_session)
144
+ random_thread_count = lambda { rand(7).to_i + 5 }
145
+ main_session.get("/add") { |r| r.body.should match /Session Counter: 1/ }
146
+ sid = main_mock_session.cookie_jar["rack.session"]
147
+ thread_mock_session.set_cookie("rack.session=#{sid}")
148
+
149
+ # do several, multi-threaded requests...
150
+ num_threads = random_thread_count.call
151
+ threads = (1..num_threads).map do |i|
152
+ Thread.new(thread_session, thread_mock_session) do |session, mock|
153
+ mutex.synchronize { count += 1 }
154
+ session.get("/add", {}, "rack.multithreaded" => true)
155
+ [mock.last_response.body, mock.cookie_jar["rack.session"]]
156
+ end
157
+ end
158
+ sleep 1 until mutex.synchronize { count == num_threads }
159
+ threads.each { |thread| sleep 1 until thread.stop? }
160
+ requests = threads.reverse.map { |t| t.run.join.value }
161
+ count = 2
162
+ requests.each do |response|
163
+ response.first.should match /Session Counter: #{count}/
164
+ response.last.should == sid
165
+ count += 1
166
+ end
167
+
168
+ # verify all our timestamps were written by the threaded_app
169
+ session = Marshal.load(main_app.redis.get(sid))
170
+ session.size.should == num_threads + 1
171
+ session["counter"].should == num_threads + 1
172
+
173
+ # test multi-threaded session element deletion
174
+ old_threads = num_threads
175
+ num_threads = random_thread_count.call
176
+ threads = (1..num_threads).map do |i|
177
+ Thread.new(main_session, main_mock_session) do |session, mock|
178
+ session.get("/drop-counter", {}, "rack.multithreaded" => true)
179
+ [mock.last_response.body, mock.cookie_jar["rack.session"]]
180
+ end
181
+ end
182
+ requests = threads.reverse.map { |t| t.join.value }
183
+ requests.each do |response|
184
+ response.first.should match /Session Foo: bar/
185
+ response.last.should == sid
186
+ end
187
+ session = Marshal.load(main_app.redis.get(sid))
188
+ session.size.should == old_threads + 1
189
+ session["foo"].should == "bar"
190
+ session["counter"].should be_nil
191
+
192
+ end
193
+
194
+ end
195
+ end
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+ require 'rubygems'
3
+ require 'bundler/setup'
4
+ require 'redrack-session'
5
+ require 'rspec'
6
+
7
+ #
8
+ # Load all support files...
9
+ #
10
+ Dir[File.join(File.expand_path("..", __FILE__), "support", "**", "*.rb")].each { |f| require f }
11
+
12
+ #
13
+ # Configure RSpec to include Rack::Test methods and to always provide easy
14
+ # access to an instance of our test rack app, wrapped with the middleware we're
15
+ # testing (Redrack::Session::Middleware) and Rack::Lint.
16
+ #
17
+ RSpec.configure do |config|
18
+ require 'rack/test'
19
+ config.include Rack::Test::Methods
20
+
21
+ def app(options = {})
22
+ Redrack::Session::RackApp.app(options)
23
+ end
24
+
25
+ def drop_app(options = {})
26
+ Redrack::Session::RackApp.drop_app(options)
27
+ end
28
+
29
+ def renew_app(options = {})
30
+ Redrack::Session::RackApp.renew_app(options)
31
+ end
32
+
33
+ def defer_app(options = {})
34
+ Redrack::Session::RackApp.defer_app(options)
35
+ end
36
+
37
+ def threaded_app(options = {})
38
+ Redrack::Session::RackApp.threaded_app(options)
39
+ end
40
+
41
+ end
@@ -0,0 +1,121 @@
1
+ # encoding: utf-8
2
+ require 'redrack-session'
3
+
4
+ #
5
+ # Define simple rack application that expects to be used with the
6
+ # Redrack::Session middleware in an underlying layer for testing our middleware.
7
+ #
8
+ module Redrack
9
+ module Session
10
+ class RackApp
11
+
12
+ #
13
+ # Rack application definition
14
+ #
15
+ def call(env)
16
+ request = Rack::Request.new(env)
17
+ session = env["rack.session"]
18
+ session["counter"] ||= 0 # Always at least initialize the session
19
+ if request.path == "/add"
20
+ session["counter"] += 1 # Add one to counter
21
+ elsif request.path == "/set-deep-hash"
22
+ session[:a] = :b
23
+ session[:c] = { :d => :e }
24
+ session[:f] = { :g => { :h => :i } }
25
+ elsif request.path == "/mutate-deep-hash"
26
+ session[:f][:g][:h] = :j
27
+ elsif request.path == "/drop-counter"
28
+ session.delete "counter"
29
+ session["foo"] = "bar"
30
+ end
31
+ Rack::Response.new do |response|
32
+ response.write "<!doctype html>\n<html>\n<head><title>Redrack::Session Test App</title></head>\n<body>\n<pre>"
33
+ if session["counter"]
34
+ response.write "Session Counter: #{session["counter"]}"
35
+ elsif session["foo"]
36
+ response.write "Session Foo: #{session["foo"]}"
37
+ else
38
+ response.write "Nothing"
39
+ end
40
+ response.write "\n</pre>\n</body>\n</html>\n"
41
+ end.finish
42
+ end
43
+
44
+ #
45
+ # Define helper class method that creates an instance of our simple rack
46
+ # application with our session middleware available.
47
+ #
48
+ def self.app(options = {})
49
+ Rack::Lint.new(Redrack::Session::Middleware.new(new, options))
50
+ end
51
+
52
+ #
53
+ # Define helper class that gets an instance of our simple rack app wrapped
54
+ # in a context that sets "rack.session.options" :drop setting to true.
55
+ #
56
+ def self.drop_app(options = {})
57
+ main_app = new()
58
+ drop_middleware = proc { |env| env["rack.session.options"][:drop] = true; main_app.call(env) }
59
+ Rack::Lint.new(Rack::Utils::Context.new(Redrack::Session::Middleware.new(main_app, options), drop_middleware))
60
+ end
61
+
62
+ #
63
+ # Define helper class that gets an instance of our simple rack app wrapped
64
+ # in a context that sets "rack.session.options" :renew setting to true.
65
+ #
66
+ def self.renew_app(options = {})
67
+ main_app = new()
68
+ renew_middleware = proc { |env| env["rack.session.options"][:renew] = true; main_app.call(env) }
69
+ Rack::Lint.new(Rack::Utils::Context.new(Redrack::Session::Middleware.new(main_app, options), renew_middleware))
70
+ end
71
+
72
+ #
73
+ # Define helper class that gets an instance of our simple rack app wrapped
74
+ # in a context that sets "rack.session.options" :defer setting to true.
75
+ #
76
+ def self.defer_app(options = {})
77
+ main_app = new()
78
+ defer_middleware = proc { |env| env["rack.session.options"][:defer] = true; main_app.call(env) }
79
+ Rack::Lint.new(Rack::Utils::Context.new(Redrack::Session::Middleware.new(main_app, options), defer_middleware))
80
+ end
81
+
82
+ #
83
+ # Define helper class that gets an instance of our simple rack app wrapped
84
+ # in a context that emulates the disconjoinment of multithreaded access.
85
+ #
86
+ def self.threaded_app(options = {})
87
+ main_app = new()
88
+ threaded_middleware = proc do |env|
89
+ Thread.stop
90
+ env["rack.session"][(Time.now.usec * rand).to_i] = true
91
+ main_app.call(env)
92
+ end
93
+ Rack::Lint.new(Rack::Utils::Context.new(Redrack::Session::Middleware.new(main_app, options), threaded_middleware))
94
+ end
95
+
96
+ end
97
+ end
98
+ end
99
+
100
+ #
101
+ # If "running" this file, then run an instance of Redrack::Session::RackApp in
102
+ # WEBrick. Got this "trick" from the Rack::Lobster example rack app.
103
+ #
104
+ if $0 == __FILE__
105
+ require 'rack'
106
+
107
+ # Exit when asked...
108
+ %w{ HUP INT TERM }.each do |sig|
109
+ trap(sig) do
110
+ STDERR.puts "Recieved signal: #{sig}"
111
+ Rack::Handler::WEBrick.shutdown
112
+ end
113
+ end
114
+
115
+ # Run WEBrick server...
116
+ Rack::Handler::WEBrick.run(
117
+ Rack::ShowExceptions.new(Redrack::Session::RackApp.app),
118
+ :Port => 3000 # use default rails development port
119
+ )
120
+
121
+ end
metadata ADDED
@@ -0,0 +1,131 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: redrack-session
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Kendall Gifford
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-11-02 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: &16870880 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 1.0.21
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *16870880
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ requirement: &16870340 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 2.7.0
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *16870340
36
+ - !ruby/object:Gem::Dependency
37
+ name: rack-test
38
+ requirement: &16869800 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 0.6.1
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *16869800
47
+ - !ruby/object:Gem::Dependency
48
+ name: rack
49
+ requirement: &16869260 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 1.3.5
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: *16869260
58
+ - !ruby/object:Gem::Dependency
59
+ name: redis
60
+ requirement: &16868580 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ~>
64
+ - !ruby/object:Gem::Version
65
+ version: 2.2.2
66
+ type: :runtime
67
+ prerelease: false
68
+ version_requirements: *16868580
69
+ - !ruby/object:Gem::Dependency
70
+ name: redis-namespace
71
+ requirement: &16867500 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ version: 1.1.0
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: *16867500
80
+ description: ! 'Redis session store for rack applications.
81
+
82
+ This was inspired by the Rack::Session::Memcached session store.
83
+
84
+ '
85
+ email:
86
+ - zettabyte@gmail.com
87
+ executables: []
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - .gitignore
92
+ - Gemfile
93
+ - LICENSE
94
+ - README.md
95
+ - Rakefile
96
+ - lib/redrack-session.rb
97
+ - lib/redrack/session.rb
98
+ - lib/redrack/session/middleware.rb
99
+ - lib/redrack/session/version.rb
100
+ - redrack-session.gemspec
101
+ - spec/redrack/session_spec.rb
102
+ - spec/spec_helper.rb
103
+ - spec/support/rack_app.rb
104
+ homepage: https://github.com/zettabyte/redrack-session
105
+ licenses: []
106
+ post_install_message:
107
+ rdoc_options: []
108
+ require_paths:
109
+ - lib
110
+ required_ruby_version: !ruby/object:Gem::Requirement
111
+ none: false
112
+ requirements:
113
+ - - ! '>='
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ none: false
118
+ requirements:
119
+ - - ! '>='
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ requirements: []
123
+ rubyforge_project:
124
+ rubygems_version: 1.8.10
125
+ signing_key:
126
+ specification_version: 3
127
+ summary: Redis session store for rack applications.
128
+ test_files:
129
+ - spec/redrack/session_spec.rb
130
+ - spec/spec_helper.rb
131
+ - spec/support/rack_app.rb