rack-session-xfile 0.10.1 → 1.0.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: 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.