redrack-session 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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