rack-session-xfile 0.10.1 → 1.0.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: 64d96bd5bb35fd04da4c0c2b7cd7f697f367617f
4
- data.tar.gz: 81f1f785803a8447c899da0441fff97dc4d81766
3
+ metadata.gz: 155a1b34b938b76714dc113c9563c6682c5aa6b1
4
+ data.tar.gz: 12fe040425c0b65a29159fb4ea810e95fc8123e7
5
5
  SHA512:
6
- metadata.gz: 2ea0309035a48c736404d70b5669056b18735a8c578da6badb5296d058a53aa54279721ff74d485d492f9f0fd07481db6a2cb584bc159c78c53183f6c4fa76a6
7
- data.tar.gz: ee252d4880ff8e137c9718395d391b1a639d89ba24c1c314c3cc8b3bb51f592bf64c76dd7239451f9c584b1fb138370a3ab9957e6325e46a5a18da661b4ffe0b
6
+ metadata.gz: '08a5a07e0fb3405ee3edaee1f12bf7a506fb341abea2f80db682f08104c452590701214d5a48847e6fbaa7952f5f8c7bd92825dd82b85ddb22e5c189c90947af'
7
+ data.tar.gz: 2a83b4923d9c3aaab1203870280ed08b10a24d5c2b95a4efcaa8bbcce69a06c30cec57c776bf6988cd16f965e19ab020af62bf8d519c83ac6aa56916cd196909
@@ -128,28 +128,34 @@ or open an issue on the bug tracker.
128
128
 
129
129
  == Links
130
130
 
131
- Homepage :: http://ecentryx.com/gems/rack-session-xfile
131
+ Homepage :: https://ecentryx.com/gems/rack-session-xfile
132
132
  Ruby Gem :: https://rubygems.org/gems/rack-session-xfile
133
133
  Source Code :: https://bitbucket.org/pachl/rack-session-xfile/src
134
134
  Bug Tracker :: https://bitbucket.org/pachl/rack-session-xfile/issues
135
135
 
136
136
  == Compatibility
137
137
 
138
- Rack::Session::XFile was developed and tested on
139
- OpenBSD[http://www.openbsd.org] 5.6
138
+ Rack::Session::XFile was originally developed and tested on
139
+ OpenBSD[https://www.openbsd.org] 5.6
140
140
  using Ruby[https://www.ruby-lang.org] 2.1.2
141
141
  and Rack[https://github.com/rack/rack] 1.6.0.
142
142
 
143
+ Currently, Rack::Session::XFile is compatible with Rack 2.0 and Ruby 2.2+ only.
144
+
143
145
  == History
144
146
 
145
147
  1. 2015-01-29, v0.10.0: First public release
146
148
  * XFile ran in production for more than a year before public release.
147
149
 
150
+ 2. 2017-06-07, v1.0.0
151
+ * Update for compatibility with Rack 2.0 and Ruby 2.2+
152
+ (breaks compatibility with Rack 1.x; use XFile 0.10.x)
153
+
148
154
  == License
149
155
 
150
- ({ISC License}[http://opensource.org/licenses/ISC])
156
+ ({ISC License}[https://opensource.org/licenses/ISC])
151
157
 
152
- Copyright (c) 2015, Clint Pachl <pachl@ecentryx.com>
158
+ Copyright (c) 2014-2017, Clint Pachl <pachl@ecentryx.com>
153
159
 
154
160
  Permission to use, copy, modify, and/or distribute this software for any purpose
155
161
  with or without fee is hereby granted, provided that the above copyright notice
@@ -4,15 +4,15 @@ require 'tmpdir'
4
4
  module Rack
5
5
  module Session
6
6
 
7
- class XFile < Abstract::ID
7
+ class XFile < Abstract::Persisted
8
8
 
9
- VERSION = '0.10.1'
9
+ VERSION = '1.0.0'
10
10
 
11
11
  File = ::File # override Rack::File
12
12
 
13
13
  SIDCharacters = [*(0..9), *(:a..:z), *(:A..:Z)].map!(&:to_s)
14
14
 
15
- Abstract::ID::DEFAULT_OPTIONS.merge! \
15
+ DEFAULT_OPTIONS = Abstract::Persisted::DEFAULT_OPTIONS.merge \
16
16
  session_dir: File.join(Dir.tmpdir, 'xfile-sessions'),
17
17
  user_agent_filter: nil,
18
18
  key: 'xid'
@@ -20,32 +20,32 @@ module Rack
20
20
  def initialize(app, options = {})
21
21
  super
22
22
  @mutex = Mutex.new
23
- @session_dir = @default_options[:session_dir]
24
- @ua_filter = @default_options[:user_agent_filter]
25
- @sid_nbytes = @default_options[:sidbits] / 8
23
+ @session_dir = default_options[:session_dir]
24
+ @ua_filter = default_options[:user_agent_filter]
25
+ @sid_nbytes = default_options[:sidbits] / 8
26
26
  setup_directories
27
27
  check_permissions
28
28
  end
29
29
 
30
- def set_session(env, sid, session, options)
31
- critical_section(env) do
32
- write_session(sid, session)
30
+ def write_session(req, sid, session, options)
31
+ critical_section(req) do
32
+ write_session_file(sid, session)
33
33
  end
34
34
  end
35
35
 
36
- def get_session(env, sid)
37
- critical_section(env) do
38
- return [nil, {}] if filter_request(env, sid)
36
+ def find_session(req, sid)
37
+ return [nil, {}] if filter_request(req, sid)
39
38
 
40
- unless sid and session = read_session(sid)
39
+ critical_section(req) do
40
+ unless sid and session = read_session_file(sid)
41
41
  sid, session = generate_sid, {}
42
42
  end
43
43
  [sid, session]
44
44
  end
45
45
  end
46
-
47
- def destroy_session(env, sid, options)
48
- critical_section(env) do
46
+
47
+ def delete_session(req, sid, options)
48
+ critical_section(req) do
49
49
  File.unlink(session_file(sid)) rescue nil
50
50
  generate_sid unless options[:drop]
51
51
  end
@@ -63,8 +63,8 @@ module Rack
63
63
  # Some systems do not implement, or implement correctly, advisory file
64
64
  # locking for threads; therefore a mutex lock must encompass file locks.
65
65
  #
66
- def critical_section(env)
67
- @mutex.lock if env['rack.multithread']
66
+ def critical_section(req)
67
+ @mutex.lock if req.multithread?
68
68
  yield
69
69
  ensure
70
70
  @mutex.unlock if @mutex.locked?
@@ -74,7 +74,6 @@ module Rack
74
74
  # Atomically generate a unique session ID and allocate the resource file.
75
75
  # Returns the session ID.
76
76
  # --
77
- # NOTE
78
77
  # The sid is also a filename. Only SIDCharacters are allowed in the sid.
79
78
  # If +super+ is called it returns a HEX sid, which is a subset.
80
79
  #
@@ -90,7 +89,7 @@ module Rack
90
89
  #
91
90
  # Read session from file using a shared lock.
92
91
  #
93
- def read_session(sid)
92
+ def read_session_file(sid)
94
93
  File.open(session_file(sid)) do |f|
95
94
  f.flock(File::LOCK_SH)
96
95
  begin
@@ -106,7 +105,7 @@ module Rack
106
105
  #
107
106
  # Write session to file using an exclusive lock.
108
107
  #
109
- def write_session(sid, session)
108
+ def write_session_file(sid, session)
110
109
  File.open(session_file(sid), 'r+') do |f|
111
110
  f.flock(File::LOCK_EX)
112
111
  f.write(Marshal.dump(session))
@@ -115,7 +114,7 @@ module Rack
115
114
  end
116
115
  sid
117
116
  rescue => e
118
- warn "#{self.class} cannot set session: #{e.message}"
117
+ warn "#{self.class} cannot write session: #{e.message}"
119
118
  false
120
119
  end
121
120
 
@@ -135,20 +134,14 @@ module Rack
135
134
  #
136
135
  # sid bit range: 62^10-62^50 (approx. 2^60-2^297)
137
136
  #
138
- def filter_request(env, sid)
139
- request = nil
140
-
141
- if @ua_filter
142
- request = Request.new(env)
143
- if request.user_agent =~ @ua_filter
144
- return request.session.options[:skip] = true
145
- end
137
+ def filter_request(req, sid)
138
+ if @ua_filter and req.user_agent =~ @ua_filter
139
+ return req.session.options[:skip] = true
146
140
  end
147
141
 
148
142
  if sid and sid !~ /^[a-zA-Z0-9]{10,50}$/
149
143
  warn "#{self.class} SID=#{sid}: tampered sid detected."
150
- request ||= Request.new(env)
151
- request.session.options[:skip] = true
144
+ req.session.options[:skip] = true
152
145
  end
153
146
  end
154
147
 
@@ -10,10 +10,6 @@ describe Rack::Session::XFile do
10
10
  %[{"counter"=>#{number}}]
11
11
  end
12
12
 
13
- def empty_session
14
- '{}'
15
- end
16
-
17
13
  def set_sid id
18
14
  if id =~ TheSession
19
15
  {'HTTP_COOKIE' => id}
@@ -26,7 +22,7 @@ describe Rack::Session::XFile do
26
22
  def create_session data = nil
27
23
  app = Rack::Session::XFile.new(nil)
28
24
  sid = app.send(:generate_sid)
29
- app.set_session({}, sid, (data || {sid: sid}), {})
25
+ app.write_session(EMPTY_REQUEST, sid, (data || {sid: sid}), {})
30
26
  sid
31
27
  end
32
28
 
@@ -37,13 +33,18 @@ describe Rack::Session::XFile do
37
33
  session_bits = Rack::Session::XFile::DEFAULT_OPTIONS[:sidbits]
38
34
  session_chars = (session_bits / 8 / 3.0 * 4).ceil # urlsafe_base64 length
39
35
  TheSession = /^#{@session_key}=[0-9a-zA-Z]{#{session_chars}};/
36
+ SESSION = 'rack.session'.freeze
37
+ SESSION_OPTS = 'rack.session.options'.freeze
38
+ EMPTY_SESSION = '{}'.freeze
39
+ EMPTY_REQUEST = Rack::Request.new({}).freeze
40
+
40
41
 
41
42
  # Apps
42
43
 
43
44
  incrementor = lambda do |env|
44
- env['rack.session']['counter'] ||= 0
45
- env['rack.session']['counter'] += 1
46
- Rack::Response.new(env['rack.session'].inspect).to_a
45
+ env[SESSION]['counter'] ||= 0
46
+ env[SESSION]['counter'] += 1
47
+ Rack::Response.new(env[SESSION].inspect).to_a
47
48
  end
48
49
 
49
50
  noop = lambda do |env|
@@ -51,26 +52,26 @@ describe Rack::Session::XFile do
51
52
  end
52
53
 
53
54
  read_session_id = lambda do |env|
54
- Rack::Response.new(env['rack.session'].id).to_a
55
+ Rack::Response.new(env[SESSION].id).to_a
55
56
  end
56
57
 
57
58
  read_session = lambda do |env|
58
- env['rack.session'].send(:load_for_read!)
59
- Rack::Response.new(env['rack.session'].inspect).to_a
59
+ env[SESSION].send(:load_for_read!)
60
+ Rack::Response.new(env[SESSION].inspect).to_a
60
61
  end
61
62
 
62
63
  defer_session = lambda do |env|
63
- env['rack.session.options'][:defer] = true
64
+ env[SESSION_OPTS][:defer] = true
64
65
  incrementor.call(env)
65
66
  end
66
67
 
67
68
  drop_session = lambda do |env|
68
- env['rack.session.options'][:drop] = true
69
+ env[SESSION_OPTS][:drop] = true
69
70
  incrementor.call(env)
70
71
  end
71
72
 
72
73
  renew_session = lambda do |env|
73
- env['rack.session.options'][:renew] = true
74
+ env[SESSION_OPTS][:renew] = true
74
75
  incrementor.call(env)
75
76
  end
76
77
 
@@ -149,24 +150,25 @@ describe Rack::Session::XFile do
149
150
  @warnings.first.should.include 'group owned/accessible'
150
151
  end
151
152
 
152
- it 'returns false when setting session if cannot serialize data' do
153
+ it 'returns false when writing session if cannot serialize data' do
153
154
  obj = Object.new
154
155
  def obj.singleton() nil end
155
- nonserializable_session = { data: obj }
156
+ nonserializable = { data: obj }
156
157
 
157
158
  sid = create_session
158
159
  app = Rack::Session::XFile.new(noop)
159
- app.set_session({}, sid, nonserializable_session, {}).should.be.false
160
+ app.write_session(EMPTY_REQUEST, sid, nonserializable, {}).
161
+ should.be.false
160
162
  @warnings.count.should.equal 1
161
- @warnings.first.should.match /cannot set session.*singleton can't be dumped/
163
+ @warnings.first.should.include 'cannot write session: singleton'
162
164
  end
163
165
 
164
- it 'returns false when setting session if sid is nonexistent' do
166
+ it 'returns false when writing session if sid is nonexistent' do
165
167
  sid = 'nonexistent'
166
168
  app = Rack::Session::XFile.new(noop)
167
- app.set_session({}, sid, {}, {}).should.be.false
169
+ app.write_session(EMPTY_REQUEST, sid, {}, {}).should.be.false
168
170
  @warnings.count.should.equal 1
169
- @warnings.first.should.match /cannot set session.*No such file/
171
+ @warnings.first.should.include 'cannot write session: No such file'
170
172
  end
171
173
 
172
174
  it 'creates new xfile session' do
@@ -206,7 +208,7 @@ describe Rack::Session::XFile do
206
208
 
207
209
  it 'merges session data from middleware in front' do
208
210
  app = Rack::Session::XFile.new(incrementor)
209
- res = Rack::MockRequest.new(app).get('/', 'rack.session' => {foo: 'bar'})
211
+ res = Rack::MockRequest.new(app).get('/', SESSION => {foo: 'bar'})
210
212
  res.body.should.match /counter/
211
213
  res.body.should.match /foo/
212
214
  end
@@ -214,8 +216,9 @@ describe Rack::Session::XFile do
214
216
  it 'creates new session when xfile is nonexistent' do
215
217
  app = Rack::Session::XFile.new(read_session)
216
218
  res = Rack::MockRequest.new(app).get('/', set_sid('nonexistent'))
217
- res.body.should.equal empty_session
219
+ res.body.should.equal EMPTY_SESSION
218
220
  res['Set-Cookie'].should.match TheSession
221
+ app.session_count.should.equal 1
219
222
  end
220
223
 
221
224
  it 'creates new session when xfile is empty' do
@@ -226,7 +229,7 @@ describe Rack::Session::XFile do
226
229
  File.size(xfile).should.be.zero
227
230
 
228
231
  res = Rack::MockRequest.new(app).get('/', set_sid(sid))
229
- res.body.should.equal empty_session
232
+ res.body.should.equal EMPTY_SESSION
230
233
  res['Set-Cookie'].should.be.nil # because sid already exists
231
234
  app.session_count.should.equal 1
232
235
  File.size(xfile).should.not.be.zero
@@ -244,7 +247,7 @@ describe Rack::Session::XFile do
244
247
  corrupt_data = Marshal.dump(session_data).insert(i, 'FUBAR')
245
248
  File.write(session_file, corrupt_data)
246
249
  res = Rack::MockRequest.new(app).get('/', set_sid(sid))
247
- res.body.should.equal empty_session
250
+ res.body.should.equal EMPTY_SESSION
248
251
  res['Set-Cookie'].should.be.nil
249
252
  end
250
253
 
@@ -258,12 +261,12 @@ describe Rack::Session::XFile do
258
261
  app = Rack::Session::XFile.new(read_session)
259
262
 
260
263
  res1 = Rack::MockRequest.new(app).get('/', set_sid('%2e%2e%2f%2e%2e%2f%00'))
261
- res1.body.should.equal empty_session
264
+ res1.body.should.equal EMPTY_SESSION
262
265
  res1['Set-Cookie'].should.be.nil
263
266
  app.session_count.should.be.zero
264
267
 
265
268
  res2 = Rack::MockRequest.new(app).get('/', set_sid('../../../../etc/passwd'))
266
- res2.body.should.equal empty_session
269
+ res2.body.should.equal EMPTY_SESSION
267
270
  res2['Set-Cookie'].should.be.nil
268
271
  app.session_count.should.be.zero
269
272
 
@@ -3,7 +3,7 @@ Gem::Specification.new do |s|
3
3
  s.version = File.read('lib/rack/session/xfile.rb')[/VERSION = '(.*)'/, 1]
4
4
  s.author = 'Clint Pachl'
5
5
  s.email = 'pachl@ecentryx.com'
6
- s.homepage = 'http://ecentryx.com/gems/rack-session-xfile'
6
+ s.homepage = 'https://ecentryx.com/gems/rack-session-xfile'
7
7
  s.license = 'ISC'
8
8
  s.summary = 'File-based session management with eXclusive R/W locking.'
9
9
  s.description = <<-EOS
@@ -13,7 +13,7 @@ suitable for multi-threaded and multi-process applications.
13
13
  EOS
14
14
  s.files = Dir['Rakefile', 'README*', '*.gemspec', 'lib/**/*.rb', 'spec/*']
15
15
  s.test_files = Dir['spec/spec_*.rb']
16
- s.required_ruby_version = '>= 1.9.2'
17
- s.add_runtime_dependency 'rack', '~> 1.5'
16
+ s.required_ruby_version = '>= 2.2'
17
+ s.add_runtime_dependency 'rack', '~> 2.0'
18
18
  s.add_development_dependency 'bacon', '~> 1.2'
19
19
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-session-xfile
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Clint Pachl
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-30 00:00:00.000000000 Z
11
+ date: 2017-06-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.5'
19
+ version: '2.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
- version: '1.5'
26
+ version: '2.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bacon
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -53,7 +53,7 @@ files:
53
53
  - lib/rack/session/xfile.rb
54
54
  - spec/spec_xfile.rb
55
55
  - xfile.gemspec
56
- homepage: http://ecentryx.com/gems/rack-session-xfile
56
+ homepage: https://ecentryx.com/gems/rack-session-xfile
57
57
  licenses:
58
58
  - ISC
59
59
  metadata: {}
@@ -65,7 +65,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: 1.9.2
68
+ version: '2.2'
69
69
  required_rubygems_version: !ruby/object:Gem::Requirement
70
70
  requirements:
71
71
  - - ">="
@@ -73,7 +73,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
73
73
  version: '0'
74
74
  requirements: []
75
75
  rubyforge_project:
76
- rubygems_version: 2.2.2
76
+ rubygems_version: 2.6.11
77
77
  signing_key:
78
78
  specification_version: 4
79
79
  summary: File-based session management with eXclusive R/W locking.