Skip to content

Commit bbbad30

Browse files
committed
[fix] Remove the undocumented and unsafe jruby.rack.env.gem_path = false init parameter option
Changes the `false` value to behave the same way as empty, and not touch ENV['GEM_PATH'] or Gem.path at all. Previously this allowed you to alter Gem.path without touching the ENV['GEM_PATH']'. This was unsafe with Bundler 1.6+ (so for a long time), because many things may cause Gem.path to be recalculated from env, including bundler initialisations, restarts and later changes within an application's boot hooks. Furthermore the behaviour varied wildly depending on whether Rubygems was initialised prior to the Rack booter, or afterwards, even without bundler causing indeterminism and issues similar to jruby/warbler#575 I cannot find any reference to use of this value on GitHub, or discussion, and it would not work at all with modern JRuby/bundler so removing it, because it helps avoid further issues. Note that it was added in 2fd826b and then the default changed back in d3ee8f0 shortly after when issues were discovered, so given it's undocumented/unsupported, it is unlikely to be relied upon by anyone.
1 parent 71e25f2 commit bbbad30

File tree

4 files changed

+47
-46
lines changed

4 files changed

+47
-46
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
- Add missing block-only signature for debug logging
2525
- update (bundled) rack to 2.2.20
2626
- Ensure rack boot process leaves ENV['GEM_PATH'] and Gem.paths in a consistent state
27+
- Remove undocumented and unsafe jruby.rack.env.gem_path = false option (unusable on Bundler 1.6+)
2728

2829
## 1.2.5
2930

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,13 @@ as context init parameters in web.xml or as VM-wide system properties.
233233
this option to en empty string (or 'false') it acts as if the ENV hash was
234234
cleared out (similar to the now removed `jruby.rack.ignore.env` option).
235235
- `jruby.runtime.env.rubyopt`: Set to true to cause ENV['RUBYOPT']
236-
to be retained even when using `jruby.runtime.env` to override environemnt (similar to how the removed `jruby.rack.ignore.env` option behaved by default).
236+
to be retained even when using `jruby.runtime.env` to override the environment.
237+
- `jruby.rack.env.gem_path`: If set to `true` (the default) jruby-rack will
238+
ensure ENV['GEM_PATH'] is altered to include the `gem.path` above. If you set it to a
239+
value, this value will be used as GEM_PATH, overriding the environment and
240+
ignoring `gem.path` etc. By setting this option to en empty string the ENV['GEM_PATH'] will
241+
not be modified by jruby-rack at all and will retain its original values implied by
242+
the process environment and `jruby.runtime.env` setting.
237243
- `jruby.rack.logging`: Specify the logging device to use. Defaults to
238244
`servlet_context`. See below.
239245
- `jruby.rack.request.size.initial.bytes`: Initial size for request body memory

src/main/ruby/jruby/rack/booter.rb

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -98,55 +98,45 @@ def boot!
9898
protected
9999

100100
def adjust_gem_path
101-
gem_path = self.gem_path
101+
desired_gem_path = self.gem_path
102+
102103
case set_gem_path = env_gem_path
103-
when true then
104-
if env_path = ENV['GEM_PATH']
105-
if gem_path.nil? || gem_path.empty?
106-
return # keep ENV['GEM_PATH'] as is
107-
elsif env_path != gem_path
108-
separator = File::PATH_SEPARATOR
109-
unless env_path.split(separator).include?(gem_path)
110-
ENV['GEM_PATH'] = "#{gem_path}#{separator}#{env_path}"
111-
end
112-
end
113-
else
114-
ENV['GEM_PATH'] = gem_path
115-
end
116-
when false then
117-
begin
118-
require 'rubygems' unless defined? Gem.path
119-
rescue LoadError
104+
when true then # default behaviour
105+
if (current_env_gem_path = ENV['GEM_PATH'])
106+
# keep ENV['GEM_PATH'] as is if we have nothing to do
107+
return if desired_gem_path.nil? || desired_gem_path.empty?
108+
return if current_env_gem_path == desired_gem_path
109+
return if current_env_gem_path.split(File::PATH_SEPARATOR).include?(desired_gem_path)
110+
111+
# need to prepend it
112+
ENV['GEM_PATH'] = "#{desired_gem_path}#{File::PATH_SEPARATOR}#{current_env_gem_path}"
120113
else
121-
return if gem_path.nil? || gem_path.empty?
122-
Gem.path.unshift(gem_path) unless Gem.path.include?(gem_path)
114+
ENV['GEM_PATH'] = desired_gem_path
123115
end
124-
return false
125-
when nil then # org.jruby.rack.RackLogger::DEBUG
126-
if gem_path && ! gem_path.empty? &&
127-
( ! defined?(Gem.path) || ! Gem.path.include?(gem_path) )
128-
@rack_context.log("Gem.path won't be updated although seems configured: #{gem_path}")
116+
when nil then
117+
if desired_gem_path && !desired_gem_path.empty? && (!defined?(Gem.path) || !Gem.path.include?(desired_gem_path) )
118+
@rack_context.log("Gem.path won't be updated although seems configured: #{desired_gem_path}")
129119
end
130-
return nil
131-
else # 'jruby.rack.env.gem_path' "forced" to an explicit value
120+
return nil # do nothing to ENV['GEM_PATH']
121+
else # "forced" to an explicit value
132122
ENV['GEM_PATH'] = set_gem_path
133123
end
134124
# Whenever we touch ENV['GEM_PATH`], ensure we clear any cached paths. All other cases should exit early.
135125
Gem.clear_paths if defined?(Gem.clear_paths)
136126
end
137127

138-
# @return whether to update Gem.path and/or the environment GEM_PATH
139-
# - true (default) forces ENV['GEM_PATH'] to be updated due compatibility
140-
# Bundler 1.6 fails to revolve gems correctly when Gem.path is updated
141-
# instead of the ENV['GEM_PATH'] environment variable
142-
# - false disables ENV['GEM_PATH'] mangling for good (updates Gem.path)
128+
# @return whether to update the environment GEM_PATH
129+
# - true (default) forces ENV['GEM_PATH'] to be updated to include the `gem.path` above.
130+
# If you set it to a non-empty value, GEM_PATH will be forced to an explicit value,
131+
# overriding the environment and ignoring `gem.path`, `gem.home` etc.
143132
#
144-
# - if not specified Gem.path will be updated based on setting
133+
# - By setting this option to an empty string the ENV['GEM_PATH'] should not be modified
134+
# at all and will retain its original values implied by the process environment and
135+
# `jruby.runtime.env` setting.
145136
def env_gem_path
146137
gem_path = @rack_context.getInitParameter('jruby.rack.env.gem_path')
147138
return true if gem_path.nil? || gem_path.to_s == 'true'
148-
return false if gem_path.to_s == 'false'
149-
return nil if gem_path.empty? # set to an empty disables mangling
139+
return nil if gem_path.empty? || gem_path.to_s == 'false' # treat false as "don't touch either ENV or Gem.path"
150140
gem_path
151141
end
152142
private :env_gem_path

src/spec/ruby/jruby/rack/booter_spec.rb

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -101,16 +101,6 @@
101101
expect(booter.rack_env).to eq 'production'
102102
end
103103

104-
it "prepends gem_path to Gem.path (when configured to not mangle with ENV)" do
105-
Gem.path.replace ['/opt/gems']
106-
expect(@rack_context).to receive(:getInitParameter).with("jruby.rack.env.gem_path").and_return 'false'
107-
108-
booter.gem_path = "wsjar:file:/opt/deploy/sample.war!/WEB-INF/gems"
109-
booter.boot!
110-
111-
expect(Gem.path).to eql ['wsjar:file:/opt/deploy/sample.war!/WEB-INF/gems', '/opt/gems']
112-
end
113-
114104
it "prepends gem_path to Gem.path if not already present" do
115105
ENV['GEM_PATH'] = "file:/home/gems#{File::PATH_SEPARATOR}/usr/local/gems"
116106
Gem.clear_paths
@@ -159,6 +149,20 @@
159149
expect(Gem.path).to start_with ["/opt/gems"]
160150
end
161151

152+
it "does not prepend gem_path to ENV['GEM_PATH'] if jruby.rack.gem_path set to false" do
153+
ENV['GEM_PATH'] = '/opt/gems'
154+
Gem.clear_paths
155+
156+
expect(@rack_context).to receive(:getInitParameter).with("jruby.rack.env.gem_path").and_return 'false'
157+
expect(@rack_context).to receive(:getRealPath).with("/WEB-INF").and_return "/opt/deploy/sample.war!/WEB-INF"
158+
expect(@rack_context).to receive(:getRealPath).with("/WEB-INF/gems").and_return "/opt/deploy/sample.war!/WEB-INF/gems"
159+
160+
booter.boot!
161+
162+
expect(ENV['GEM_PATH']).to eq "/opt/gems"
163+
expect(Gem.path).to start_with ["/opt/gems"]
164+
end
165+
162166
it "prepends gem_path to ENV['GEM_PATH'] if not already present" do
163167
ENV['GEM_PATH'] = "/home/gems#{File::PATH_SEPARATOR}/usr/local/gems"
164168
Gem.clear_paths

0 commit comments

Comments
 (0)