redis-session-store 0.4.2 → 0.5.0

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.
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