redis-session-store 0.4.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 56bc245a6348c77dc89fd0f9cafcb190ce55bf0a
4
- data.tar.gz: 39c2e4dacfb2bdf3ffdb2ab661199cca1f41bac8
3
+ metadata.gz: 9148a3bedfc1ab56951717dccdaed7c30e33e356
4
+ data.tar.gz: ca00490849f6276f4262ddfa100fa8d90c819087
5
5
  SHA512:
6
- metadata.gz: 3c3766b71ff8e0c3d1e1e89497a6cf7e7b59c2cba3a199e7e94f59cd246deb9762df2e3d78fc420cd835cacebfb9eaeeae7cb7809262211fcb4c0aecb7b992a9
7
- data.tar.gz: 3dcf04844ab54396592dbae1ac820f600fa73d0147b6695582dc6ae0c4596ab8bedfef2a7c0dc89a4c7c42a73e8a833292a7d11401520c55a5c4737be16ad670
6
+ metadata.gz: fdbe30259d8e8eb71a650a73c59f613f830276f913d0e5bd062b5212db29704aa3ff56d7b5d443e95fabdd441085065a5ca8b02aa0c4b998264c3efeb4685cd9
7
+ data.tar.gz: ad31abd62bb1eb5b093aa03ba1e0f2c11bc197e3e3ff395bb78dabfb1d7659ef2a06f05435cd03a3db060510700a8a1f4ca509cd6561849e017de2014f2e068c
@@ -0,0 +1,103 @@
1
+ redis-session-store history
2
+ ===========================
3
+
4
+ ## v0.5.0 (2014-03-16)
5
+
6
+ * Keep generating session IDs until one is found that doesn't collide
7
+ with existing session IDs
8
+ * Add support for `on_sid_collision` handler option
9
+ * Add support for `on_redis_down` handler option
10
+ * **BACKWARD INCOMPATIBLE** Drop support for `:raise_errors` option
11
+
12
+ ## v0.4.2 (2014-03-14)
13
+
14
+ * Renaming `load_session` method to not conflict with AbstractStore
15
+
16
+ ## v0.4.1 (yanked) (2014-03-13)
17
+
18
+ * Regenerate session ID when session is missing
19
+
20
+ ## v0.4.0 (2014-02-19)
21
+
22
+ * Add support for `ENV_SESSION_OPTIONS_KEY` rack env option
23
+ * Add support for `:raise_errors` session option (kinda like Dalli)
24
+ * Increasing test coverage
25
+
26
+ ## v0.3.1 (2014-02-19)
27
+
28
+ * Add `#destroy_session` method
29
+ * Clean up remaining RuboCop offenses
30
+ * Documentation updates
31
+
32
+ ## v0.3.0 (2014-02-13)
33
+
34
+ * Rails 3 compatibility
35
+ * Switch from minitest to rspec
36
+ * Add test coverage
37
+ * RuboCop cleanup
38
+
39
+ ## v0.2.4 (2014-03-16)
40
+
41
+ * Keep generating session IDs until one is found that doesn't collide
42
+ with existing session IDs
43
+
44
+ ## v0.2.3 (2014-03-14)
45
+
46
+ * Renaming `load_session` method to not conflict with AbstractStore
47
+
48
+ ## v0.2.2 (yanked) (2014-03-13)
49
+
50
+ * Regenerate session ID when session is missing
51
+
52
+ ## v0.2.1 (2013-09-17)
53
+
54
+ * Add explicit MIT license metadata in gemspec
55
+
56
+ ## v0.2.0 (2013-09-13)
57
+
58
+ * Use `@redis.setex` when expiry provided, else `@redis.set`
59
+ * Gemfile, gemspec, and git updates
60
+ * Nest redis-specific options inside a `:redis` key of session options
61
+ * Add `#destroy` method
62
+ * Rescue only `Errno::ECONNREFUSED` exceptions
63
+ * Handle `nil` cookies during `#destroy`
64
+ * Add Travis integration
65
+ * Add some minimal tests to ensure backward compatibility session options
66
+
67
+ ## v0.1.9 (2012-03-06)
68
+
69
+ ## v0.1.8 (2010-12-09)
70
+
71
+ * Remove use of `@redis.pipelined`
72
+
73
+ ## v0.1.7 (2010-12-08)
74
+
75
+ * Using latest redis gem API
76
+
77
+ ## v0.1.6 (2010-04-18)
78
+
79
+ * Using pipelined format with `set` and `expire`
80
+ * Changing default port from 6370 to 6379
81
+
82
+ ## v0.1.5 (2010-04-07)
83
+
84
+ ## v0.1.4 (2010-03-26)
85
+
86
+ * Changed redis parameter from `:server` to `:host`
87
+
88
+ ## v0.1.3 (2009-12-30)
89
+
90
+ * Documentation updates
91
+
92
+ ## v0.1.2 (2009-12-30)
93
+
94
+ * Documentation updates
95
+
96
+ ## v0.1.1 (2009-12-30)
97
+
98
+ * library file renamed to `redis-session-store.rb` to play nicely with
99
+ rails require
100
+
101
+ ## v0.1 (2009-12-30)
102
+
103
+ * first working version
data/README.md CHANGED
@@ -19,8 +19,8 @@ only suitable for Rails applications. For other frameworks or
19
19
  drop-in support for caching, check out
20
20
  [redis-store](http://github.com/jodosha/redis-store/)
21
21
 
22
- Compatibility
23
- -------------
22
+ Rails 2 Compatibility
23
+ ---------------------
24
24
 
25
25
  This gem is currently only compatible with Rails 3+. If you need
26
26
  Rails 2 compatibility, be sure to pin to a lower version like so:
@@ -44,17 +44,41 @@ In your Rails app, throw in an initializer with the following contents:
44
44
 
45
45
  ``` ruby
46
46
  My::Application.config.session_store = :redis_session_store, {
47
- :key => 'your_session_key',
48
- :redis => {
49
- :db => 2,
50
- :expire_after => 120.minutes,
51
- :key_prefix => "myapp:session:",
52
- :host => 'host', # Redis host name, default is localhost
53
- :port => 12345 # Redis port, default is 6379
47
+ key: 'your_session_key',
48
+ redis: {
49
+ db: 2,
50
+ expire_after: 120.minutes,
51
+ key_prefix: 'myapp:session:',
52
+ host: 'host', # Redis host name, default is localhost
53
+ port: 12345 # Redis port, default is 6379
54
54
  }
55
55
  }
56
56
  ```
57
-
57
+
58
+ ### Session ID collision handling
59
+
60
+ If you want to handle cases where the generated session ID (sid)
61
+ collides with an existing session ID, a custom callable handler may be
62
+ provided as `on_sid_collision`:
63
+
64
+ ``` ruby
65
+ My::Application.config.session_store = :redis_session_store, {
66
+ # ... other options ...
67
+ on_sid_collision: ->(sid) { Rails.logger.warn("SID collision! #{sid}") }
68
+ }
69
+ ```
70
+
71
+ ### Redis unavailability handling
72
+
73
+ If you want to handle cases where Redis is unavailable, a custom
74
+ callable handler may be provided as `on_redis_down`:
75
+
76
+ ``` ruby
77
+ My::Application.config.session_store = :redis_session_store, {
78
+ # ... other options ...
79
+ on_redis_down: ->(e, env, sid) { do_something_will_ya!(e) }
80
+ }
81
+ ```
58
82
 
59
83
  Contributing, Authors, & License
60
84
  --------------------------------
@@ -4,7 +4,7 @@ require 'redis'
4
4
  # Redis session storage for Rails, and for Rails only. Derived from
5
5
  # the MemCacheStore code, simply dropping in Redis instead.
6
6
  class RedisSessionStore < ActionDispatch::Session::AbstractStore
7
- VERSION = '0.4.2'
7
+ VERSION = '0.5.0'
8
8
 
9
9
  # ==== Options
10
10
  # * +:key+ - Same as with the other cookie stores, key name
@@ -14,18 +14,22 @@ class RedisSessionStore < ActionDispatch::Session::AbstractStore
14
14
  # * +:db+ - Database number, defaults to 0.
15
15
  # * +:key_prefix+ - Prefix for keys used in Redis, e.g. +myapp:+
16
16
  # * +:expire_after+ - A number in seconds for session timeout
17
+ # * +:on_sid_collision:+ - Called with SID string when generated SID collides
18
+ # * +:on_redis_down:+ - Called with err, env, and SID on Errno::ECONNREFUSED
17
19
  #
18
20
  # ==== Examples
19
21
  #
20
22
  # My::Application.config.session_store = :redis_session_store, {
21
- # :key => 'your_session_key',
22
- # :redis => {
23
- # :db => 2,
24
- # :expire_after => 120.minutes,
25
- # :key_prefix => "myapp:session:",
26
- # :host => 'host', # Redis host name, default is localhost
27
- # :port => 12345 # Redis port, default is 6379
28
- # }
23
+ # key: 'your_session_key',
24
+ # redis: {
25
+ # db: 2,
26
+ # expire_after: 120.minutes,
27
+ # key_prefix: 'myapp:session:',
28
+ # host: 'host', # Redis host name, default is localhost
29
+ # port: 12345 # Redis port, default is 6379
30
+ # },
31
+ # on_sid_collision: ->(sid) { logger.warn("SID collision! #{sid}") },
32
+ # on_redis_down: ->(*a) { logger.error("Redis down! #{a.inspect}") }
29
33
  # }
30
34
  #
31
35
  def initialize(app, options = {})
@@ -36,17 +40,33 @@ class RedisSessionStore < ActionDispatch::Session::AbstractStore
36
40
  @default_options.merge!(namespace: 'rack:session')
37
41
  @default_options.merge!(redis_options)
38
42
  @redis = Redis.new(redis_options)
39
- @raise_errors = !options[:raise_errors].nil?
43
+ @on_sid_collision = options[:on_sid_collision]
44
+ @on_redis_down = options[:on_redis_down]
40
45
  end
41
46
 
47
+ attr_accessor :on_sid_collision, :on_redis_down
48
+
42
49
  private
43
50
 
44
- attr_reader :redis, :key, :default_options, :raise_errors
51
+ attr_reader :redis, :key, :default_options
45
52
 
46
53
  def prefixed(sid)
47
54
  "#{default_options[:key_prefix]}#{sid}"
48
55
  end
49
56
 
57
+ def generate_sid
58
+ loop do
59
+ sid = super
60
+ break sid unless sid_collision?(sid)
61
+ end
62
+ end
63
+
64
+ def sid_collision?(sid)
65
+ !!redis.get(prefixed(sid)).tap do |value| # rubocop: disable DoubleNegation
66
+ on_sid_collision.call(sid) if value && on_sid_collision
67
+ end
68
+ end
69
+
50
70
  def get_session(env, sid)
51
71
  unless sid && (session = load_session_from_redis(sid))
52
72
  sid = generate_sid
@@ -55,7 +75,7 @@ class RedisSessionStore < ActionDispatch::Session::AbstractStore
55
75
 
56
76
  [sid, session]
57
77
  rescue Errno::ECONNREFUSED => e
58
- raise e if raise_errors
78
+ on_redis_down.call(e, env, sid) if on_redis_down
59
79
  [generate_sid, {}]
60
80
  end
61
81
 
@@ -73,7 +93,7 @@ class RedisSessionStore < ActionDispatch::Session::AbstractStore
73
93
  end
74
94
  return sid
75
95
  rescue Errno::ECONNREFUSED => e
76
- raise e if raise_errors
96
+ on_redis_down.call(e, env, sid) if on_redis_down
77
97
  return false
78
98
  end
79
99
 
@@ -84,12 +104,12 @@ class RedisSessionStore < ActionDispatch::Session::AbstractStore
84
104
  end
85
105
 
86
106
  def destroy(env)
87
- if env['rack.request.cookie_hash'] && env['rack.request.cookie_hash'][key]
88
- redis.del(prefixed(env['rack.request.cookie_hash'][key]))
107
+ if env['rack.request.cookie_hash'] &&
108
+ (sid = env['rack.request.cookie_hash'][key])
109
+ redis.del(prefixed(sid))
89
110
  end
90
111
  rescue Errno::ECONNREFUSED => e
91
- raise e if raise_errors
92
- Rails.logger.warn("RedisSessionStore#destroy: #{e.message}")
112
+ on_redis_down.call(e, env, sid) if on_redis_down
93
113
  false
94
114
  end
95
115
  end
@@ -135,15 +135,23 @@ describe RedisSessionStore do
135
135
  end
136
136
 
137
137
  context 'when redis is down' do
138
- before { store.stub(:redis).and_raise(Errno::ECONNREFUSED) }
138
+ before do
139
+ store.stub(:redis).and_raise(Errno::ECONNREFUSED)
140
+ store.on_redis_down = ->(*a) { @redis_down_handled = true }
141
+ end
139
142
 
140
143
  it 'returns false' do
141
144
  store.send(:set_session, env, session_id, session_data, options)
142
145
  .should eq(false)
143
146
  end
144
147
 
145
- context 'when :raise_errors option is truthy' do
146
- let(:options) { { raise_errors: true } }
148
+ it 'calls the on_redis_down handler' do
149
+ store.send(:set_session, env, session_id, session_data, options)
150
+ expect(@redis_down_handled).to be_true
151
+ end
152
+
153
+ context 'when :on_redis_down re-raises' do
154
+ before { store.on_redis_down = ->(e, *) { fail e } }
147
155
 
148
156
  it 'explodes' do
149
157
  expect do
@@ -160,11 +168,13 @@ describe RedisSessionStore do
160
168
  key_prefix: 'customprefix::'
161
169
  }
162
170
  end
171
+
163
172
  let(:fake_key) { 'thisisarediskey' }
164
173
 
165
174
  it 'should retrieve the prefixed key from redis' do
166
175
  redis = double('redis')
167
176
  store.stub(redis: redis)
177
+ store.stub(generate_sid: fake_key)
168
178
  expect(redis).to receive(:get).with("#{options[:key_prefix]}#{fake_key}")
169
179
 
170
180
  store.send(:get_session, double('env'), fake_key)
@@ -186,8 +196,8 @@ describe RedisSessionStore do
186
196
  .to eq('foop')
187
197
  end
188
198
 
189
- context 'when :raise_errors option is truthy' do
190
- let(:options) { { raise_errors: true } }
199
+ context 'when :on_redis_down re-raises' do
200
+ before { store.on_redis_down = ->(e, *) { fail e } }
191
201
 
192
202
  it 'explodes' do
193
203
  expect do
@@ -224,8 +234,8 @@ describe RedisSessionStore do
224
234
  expect(store.send(:destroy, env)).to be_false
225
235
  end
226
236
 
227
- context 'when :raise_errors option is truthy' do
228
- let(:options) { { raise_errors: true } }
237
+ context 'when :on_redis_down re-raises' do
238
+ before { store.on_redis_down = ->(e, *) { fail e } }
229
239
 
230
240
  it 'explodes' do
231
241
  expect do
@@ -238,13 +248,40 @@ describe RedisSessionStore do
238
248
 
239
249
  context 'when destroyed via #destroy_session' do
240
250
  it 'deletes the prefixed key from redis' do
241
- redis = double('redis')
242
- sid = store.send(:generate_sid)
251
+ redis = double('redis', get: nil)
243
252
  store.stub(redis: redis)
253
+ sid = store.send(:generate_sid)
244
254
  expect(redis).to receive(:del).with("#{options[:key_prefix]}#{sid}")
245
255
 
246
256
  store.send(:destroy_session, {}, sid, nil)
247
257
  end
248
258
  end
249
259
  end
260
+
261
+ describe 'generating a sid' do
262
+ before { store.on_sid_collision = ->(sid) { @sid = sid } }
263
+
264
+ context 'when the generated sid is unique' do
265
+ before do
266
+ redis = double('redis', get: nil)
267
+ store.stub(redis: redis)
268
+ end
269
+
270
+ it 'returns the sid' do
271
+ expect(store.send(:generate_sid)).to_not be_nil
272
+ end
273
+ end
274
+
275
+ context 'when there is a generated sid collision' do
276
+ before do
277
+ redis = double('redis', get: 'herp a derp')
278
+ store.stub(redis: redis)
279
+ end
280
+
281
+ it 'passes the colliding sid to the collision handler' do
282
+ store.send(:sid_collision?, 'whatever')
283
+ expect(@sid).to eql('whatever')
284
+ end
285
+ end
286
+ end
250
287
  end
metadata CHANGED
@@ -1,97 +1,97 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis-session-store
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mathias Meyer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-03-14 00:00:00.000000000 Z
11
+ date: 2014-03-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: fakeredis
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '>='
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - '>='
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - '>='
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rubocop
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - '>='
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - '>='
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: simplecov
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - '>='
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
89
  version: '0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - '>='
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  description: A drop-in replacement for e.g. MemCacheStore to store Rails sessions
@@ -105,12 +105,13 @@ extra_rdoc_files:
105
105
  - AUTHORS.md
106
106
  - CONTRIBUTING.md
107
107
  files:
108
- - .gitignore
109
- - .rspec
110
- - .rubocop.yml
111
- - .simplecov
112
- - .travis.yml
108
+ - ".gitignore"
109
+ - ".rspec"
110
+ - ".rubocop.yml"
111
+ - ".simplecov"
112
+ - ".travis.yml"
113
113
  - AUTHORS.md
114
+ - CHANGELOG.md
114
115
  - CONTRIBUTING.md
115
116
  - Gemfile
116
117
  - LICENSE
@@ -131,17 +132,17 @@ require_paths:
131
132
  - lib
132
133
  required_ruby_version: !ruby/object:Gem::Requirement
133
134
  requirements:
134
- - - '>='
135
+ - - ">="
135
136
  - !ruby/object:Gem::Version
136
137
  version: '0'
137
138
  required_rubygems_version: !ruby/object:Gem::Requirement
138
139
  requirements:
139
- - - '>='
140
+ - - ">="
140
141
  - !ruby/object:Gem::Version
141
142
  version: '0'
142
143
  requirements: []
143
144
  rubyforge_project:
144
- rubygems_version: 2.0.14
145
+ rubygems_version: 2.2.2
145
146
  signing_key:
146
147
  specification_version: 4
147
148
  summary: A drop-in replacement for e.g. MemCacheStore to store Rails sessions (and