passenger 3.0.19 → 3.0.21

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of passenger might be problematic. Click here for more details.

@@ -25,9 +25,9 @@ module PhusionPassenger
25
25
  ###### Version numbers ######
26
26
 
27
27
  # Phusion Passenger version number. Don't forget to edit ext/common/Constants.h too.
28
- VERSION_STRING = '3.0.19'
28
+ VERSION_STRING = '3.0.21'
29
29
 
30
- PREFERRED_NGINX_VERSION = '1.2.6'
30
+ PREFERRED_NGINX_VERSION = '1.2.9'
31
31
  PREFERRED_PCRE_VERSION = '8.31'
32
32
  STANDALONE_INTERFACE_VERSION = 1
33
33
 
@@ -453,6 +453,9 @@ private
453
453
  trap(signal, handler)
454
454
  end
455
455
  end
456
+
457
+ class IgnoreException < StandardError
458
+ end
456
459
 
457
460
  def accept_and_process_next_request(socket_wrapper, channel, buffer)
458
461
  select_result = select(@selectable_sockets, nil, nil, @select_timeout)
@@ -509,17 +512,20 @@ private
509
512
 
510
513
  if headers
511
514
  prepare_request(headers)
515
+ ignore = false
512
516
  begin
513
517
  if headers[REQUEST_METHOD] == PING
514
518
  process_ping(headers, input_stream, connection)
515
519
  else
516
520
  process_request(headers, input_stream, connection, full_http_response)
517
521
  end
522
+ rescue IgnoreException
523
+ ignore = true
518
524
  rescue Exception
519
525
  has_error = true
520
526
  raise
521
527
  ensure
522
- finalize_request(headers, has_error)
528
+ finalize_request(headers, has_error) if !ignore
523
529
  end
524
530
  end
525
531
  return true
@@ -22,6 +22,7 @@
22
22
  # THE SOFTWARE.
23
23
 
24
24
  require 'rbconfig'
25
+ require 'tmpdir'
25
26
  require 'phusion_passenger'
26
27
  require 'phusion_passenger/packaging'
27
28
  require 'phusion_passenger/platform_info'
@@ -117,6 +118,12 @@ module Dependencies # :nodoc: all
117
118
  end
118
119
  end
119
120
 
121
+ def self.create_temp_files(name1, name2, dir = PlatformInfo.tmpexedir)
122
+ Dir.mktmpdir("passenger.", dir) do |subdir|
123
+ yield "#{subdir}/#{name1}", "#{subdir}/#{name2}"
124
+ end
125
+ end
126
+
120
127
  GCC = Dependency.new do |dep|
121
128
  dep.name = "GNU C++ compiler"
122
129
  dep.define_checker do |result|
@@ -456,9 +463,7 @@ module Dependencies # :nodoc: all
456
463
  Curl_Dev = Dependency.new do |dep|
457
464
  dep.name = "Curl development headers with SSL support"
458
465
  dep.define_checker do |result|
459
- source_file = "#{PlatformInfo.tmpexedir}/passenger-curl-check.c"
460
- output_file = "#{PlatformInfo.tmpexedir}/passenger-curl-check"
461
- begin
466
+ Dependencies.create_temp_files("check.c", "check") do |source_file, output_file|
462
467
  found = true
463
468
  File.open(source_file, 'w') do |f|
464
469
  f.puts("#include <curl/curl.h>")
@@ -482,9 +487,6 @@ module Dependencies # :nodoc: all
482
487
  found = false
483
488
  end
484
489
  result.found(found)
485
- ensure
486
- File.unlink(source_file) rescue nil
487
- File.unlink(output_file) rescue nil
488
490
  end
489
491
  end
490
492
  dep.install_instructions = "Please download Curl from <b>http://curl.haxx.se/libcurl</b> " +
@@ -514,22 +516,17 @@ module Dependencies # :nodoc: all
514
516
  OpenSSL_Dev = Dependency.new do |dep|
515
517
  dep.name = "OpenSSL development headers"
516
518
  dep.define_checker do |result|
517
- source_file = "#{PlatformInfo.tmpexedir}/passenger-openssl-check.c"
518
- object_file = "#{PlatformInfo.tmpexedir}/passenger-openssl-check.o"
519
- begin
519
+ Dependencies.create_temp_files("check.c", "check.o") do |source_file, output_file|
520
520
  File.open(source_file, 'w') do |f|
521
521
  f.write("#include <openssl/ssl.h>")
522
522
  end
523
523
  Dir.chdir(File.dirname(source_file)) do
524
- if system("(gcc #{ENV['CFLAGS']} -c '#{source_file}') >/dev/null 2>/dev/null")
524
+ if system("(gcc #{ENV['CFLAGS']} -c '#{source_file}' -o '#{output_file}') >/dev/null 2>/dev/null")
525
525
  result.found
526
526
  else
527
527
  result.not_found
528
528
  end
529
529
  end
530
- ensure
531
- File.unlink(source_file) rescue nil
532
- File.unlink(object_file) rescue nil
533
530
  end
534
531
  end
535
532
  if RUBY_PLATFORM =~ /linux/
@@ -546,22 +543,17 @@ module Dependencies # :nodoc: all
546
543
  Zlib_Dev = Dependency.new do |dep|
547
544
  dep.name = "Zlib development headers"
548
545
  dep.define_checker do |result|
549
- source_file = "#{PlatformInfo.tmpexedir}/zlib-check.c"
550
- object_file = "#{PlatformInfo.tmpexedir}/zlib-check.o"
551
- begin
546
+ Dependencies.create_temp_files("check.c", "check.o") do |source_file, output_file|
552
547
  File.open(source_file, 'w') do |f|
553
548
  f.write("#include <zlib.h>")
554
549
  end
555
550
  Dir.chdir(File.dirname(source_file)) do
556
- if system("(g++ -c zlib-check.c) >/dev/null 2>/dev/null")
551
+ if system("(g++ -c '#{source_file}' -o '#{output_file}') >/dev/null 2>/dev/null")
557
552
  result.found
558
553
  else
559
554
  result.not_found
560
555
  end
561
556
  end
562
- ensure
563
- File.unlink(source_file) rescue nil
564
- File.unlink(object_file) rescue nil
565
557
  end
566
558
  end
567
559
  if RUBY_PLATFORM =~ /linux/
@@ -21,6 +21,8 @@
21
21
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
22
  # THE SOFTWARE.
23
23
 
24
+ require 'tmpdir'
25
+
24
26
  module PhusionPassenger
25
27
 
26
28
  # This module autodetects various platform-specific information, and
@@ -263,15 +265,12 @@ public
263
265
  else
264
266
  raise ArgumentError,"Unsupported language '#{language}'"
265
267
  end
266
- filename = File.join("#{tmpexedir}/passenger-compile-check-#{Process.pid}.c")
267
- File.open(filename, "w") do |f|
268
- f.puts(source)
269
- end
270
- begin
268
+ Dir.mktmpdir("passenger.", tmpexedir) do |dir|
269
+ filename = File.join(dir, "check.c")
270
+ File.open(filename, "w") do |f|
271
+ f.puts(source)
272
+ end
271
273
  return system("(#{compiler} #{flags} -c '#{filename}' -o '#{filename}.o') >/dev/null 2>/dev/null")
272
- ensure
273
- File.unlink(filename) rescue nil
274
- File.unlink("#{filename}.o") rescue nil
275
274
  end
276
275
  end
277
276
  private_class_method :try_compile
@@ -284,15 +283,12 @@ public
284
283
  else
285
284
  raise ArgumentError,"Unsupported language '#{language}'"
286
285
  end
287
- filename = File.join("#{tmpexedir}/passenger-link-check-#{Process.pid}.c")
288
- File.open(filename, "w") do |f|
289
- f.puts(source)
290
- end
291
- begin
286
+ Dir.mktmpdir("passenger.", tmpexedir) do |dir|
287
+ filename = File.join(dir, "check.c")
288
+ File.open(filename, "w") do |f|
289
+ f.puts(source)
290
+ end
292
291
  return system("(#{compiler} #{flags} '#{filename}' -o '#{filename}.out') >/dev/null 2>/dev/null")
293
- ensure
294
- File.unlink(filename) rescue nil
295
- File.unlink("#{filename}.out") rescue nil
296
292
  end
297
293
  end
298
294
  private_class_method :try_link
@@ -305,17 +301,16 @@ public
305
301
  else
306
302
  raise ArgumentError,"Unsupported language '#{language}'"
307
303
  end
308
- filename = File.join("#{tmpexedir}/passenger-compile-check-#{Process.pid}.c")
309
- File.open(filename, "w") do |f|
310
- f.puts(source)
311
- end
312
- begin
304
+ Dir.mktmpdir("passenger.", tmpexedir) do |dir|
305
+ filename = File.join(dir, "check.c")
306
+ File.open(filename, "w") do |f|
307
+ f.puts(source)
308
+ end
313
309
  if system("(#{compiler} #{flags} '#{filename}' -o '#{filename}.out') >/dev/null 2>/dev/null")
314
310
  if Process.respond_to?(:spawn)
315
311
  pid = Process.spawn("#{filename}.out",
316
312
  :out => ["/dev/null", "w"],
317
313
  :err => ["/dev/null", "w"])
318
-
319
314
  else
320
315
  pid = fork do
321
316
  STDOUT.reopen("/dev/null", "w")
@@ -328,9 +323,6 @@ public
328
323
  else
329
324
  return false
330
325
  end
331
- ensure
332
- File.unlink(filename) rescue nil
333
- File.unlink("#{filename}.out") rescue nil
334
326
  end
335
327
  end
336
328
  private_class_method :try_compile_and_run
@@ -285,16 +285,7 @@ module PlatformInfo
285
285
  # headers are placed into the same directory as the Apache headers,
286
286
  # and so 'apr-config' and 'apu-config' won't be necessary in that case.
287
287
  def self.apr_config_needed_for_building_apache_modules?
288
- filename = File.join("#{tmpexedir}/passenger-platform-check-#{Process.pid}.c")
289
- File.open(filename, "w") do |f|
290
- f.puts("#include <apr.h>")
291
- end
292
- begin
293
- return !system("(gcc #{apache2_module_cflags(false)} -c '#{filename}' -o '#{filename}.o') >/dev/null 2>/dev/null")
294
- ensure
295
- File.unlink(filename) rescue nil
296
- File.unlink("#{filename}.o") rescue nil
297
- end
288
+ return !try_compile(:c, "#include <apr.h>", apache2_module_cflags(false))
298
289
  end
299
290
  memoize :apr_config_needed_for_building_apache_modules?
300
291
 
@@ -1,4 +1,4 @@
1
- # Phusion Passenger - http://www.modrails.com/
1
+ # Phusion Passenger - https://www.phusionpassenger.com/
2
2
  # Copyright (c) 2010 Phusion
3
3
  #
4
4
  # "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
@@ -48,29 +48,54 @@ module PlatformInfo
48
48
  def self.ruby_command
49
49
  if in_rvm?
50
50
  name = rvm_ruby_string
51
- dir = rvm_path
52
- if name && dir
53
- filename = "#{dir}/wrappers/#{name}/ruby"
54
- if File.exist?(filename)
55
- contents = File.open(filename, 'rb') do |f|
56
- f.read
57
- end
58
- # Old wrapper scripts reference $HOME which causes
59
- # things to blow up when run by a different user.
60
- if contents.include?("$HOME")
51
+ dirs = rvm_paths
52
+ if name && dirs
53
+ dirs.each do |dir|
54
+ filename = "#{dir}/wrappers/#{name}/ruby"
55
+ if File.exist?(filename)
56
+ contents = File.open(filename, 'rb') do |f|
57
+ f.read
58
+ end
59
+ # Old wrapper scripts reference $HOME which causes
60
+ # things to blow up when run by a different user.
61
+ if contents.include?("$HOME")
62
+ filename = nil
63
+ end
64
+ else
61
65
  filename = nil
62
66
  end
63
- else
64
- filename = nil
67
+ if filename
68
+ return filename
69
+ end
65
70
  end
66
- if filename
67
- return filename
68
- else
69
- STDERR.puts "Your RVM wrapper scripts are too old. Please " +
70
- "update them first by running 'rvm get head && " +
71
- "rvm reload && rvm repair all'."
72
- exit 1
71
+
72
+ # Correctness of these commands are confirmed by mpapis.
73
+ # If we ever encounter a case for which this logic is not sufficient,
74
+ # try mpapis' pseudo code:
75
+ #
76
+ # rvm_update_prefix = write_to rvm_path ? "" : "rvmsudo"
77
+ # rvm_gemhome_prefix = write_to GEM_HOME ? "" : "rvmsudo"
78
+ # repair_command = "#{rvm_update_prefix} rvm get stable && rvm reload && #{rvm_gemhome_prefix} rvm repair all"
79
+ # wrapper_command = "#{rvm_gemhome_prefix} rvm wrapper #{rvm_ruby_string} --no-prefix --all"
80
+ case rvm_installation_mode
81
+ when :single
82
+ repair_command = "rvm get stable && rvm reload && rvm repair all"
83
+ wrapper_command = "rvm wrapper #{rvm_ruby_string} --no-prefix --all"
84
+ when :multi
85
+ repair_command = "rvmsudo rvm get stable && rvm reload && rvmsudo rvm repair all"
86
+ wrapper_command = "rvmsudo rvm wrapper #{rvm_ruby_string} --no-prefix --all"
87
+ when :mixed
88
+ repair_command = "rvmsudo rvm get stable && rvm reload && rvm repair all"
89
+ wrapper_command = "rvm wrapper #{rvm_ruby_string} --no-prefix --all"
73
90
  end
91
+
92
+ STDERR.puts "Your RVM wrapper scripts are too old, or some " +
93
+ "wrapper scripts are missing. Please update/regenerate " +
94
+ "them first by running:\n\n" +
95
+ " #{repair_command}\n\n" +
96
+ "If that doesn't seem to work, please run:\n\n" +
97
+ " #{wrapper_command}"
98
+ exit 1
74
99
  else
75
100
  # Something's wrong with the user's RVM installation.
76
101
  # Raise an error so that the user knows this instead of
@@ -105,7 +130,7 @@ module PlatformInfo
105
130
  RUBY_ENGINE != "macruby" &&
106
131
  rb_config['target_os'] !~ /mswin|windows|mingw/
107
132
  end
108
-
133
+
109
134
  # Returns the correct 'gem' command for this Ruby interpreter.
110
135
  def self.gem_command
111
136
  return locate_ruby_tool('gem')
@@ -156,29 +181,39 @@ module PlatformInfo
156
181
  return bindir.include?('/.rvm/') || bindir.include?('/rvm/')
157
182
  end
158
183
 
159
- # If the current Ruby interpreter is managed by RVM, returns the
160
- # directory in which RVM places its working files. Otherwise returns
161
- # nil.
162
- def self.rvm_path
184
+ # If the current Ruby interpreter is managed by RVM, returns all
185
+ # directories in which RVM places its working files. This is usually
186
+ # ~/.rvm or /usr/local/rvm, but in mixed-mode installations there
187
+ # can be multiple such paths.
188
+ #
189
+ # Otherwise returns nil.
190
+ def self.rvm_paths
163
191
  if in_rvm?
192
+ result = []
164
193
  [ENV['rvm_path'], "~/.rvm", "/usr/local/rvm"].each do |path|
165
194
  next if path.nil?
166
195
  path = File.expand_path(path)
167
- script_path = File.join(path, 'scripts', 'rvm')
168
- return path if File.directory?(path) && File.exist?(script_path)
196
+ rubies_path = File.join(path, 'rubies')
197
+ if File.directory?(path) && File.directory?(rubies_path)
198
+ result << path
199
+ end
200
+ end
201
+ if result.empty?
202
+ # Failure to locate the RVM path is probably caused by the
203
+ # user customizing $rvm_path. Older RVM versions don't
204
+ # export $rvm_path, making us unable to detect its value.
205
+ STDERR.puts "Unable to locate the RVM path. Your RVM installation " +
206
+ "is probably too old. Please update it with " +
207
+ "'rvm get head && rvm reload && rvm repair all'."
208
+ exit 1
209
+ else
210
+ return result
169
211
  end
170
- # Failure to locate the RVM path is probably caused by the
171
- # user customizing $rvm_path. Older RVM versions don't
172
- # export $rvm_path, making us unable to detect its value.
173
- STDERR.puts "Unable to locate the RVM path. Your RVM installation " +
174
- "is probably too old. Please update it with " +
175
- "'rvm get head && rvm reload && rvm repair all'."
176
- exit 1
177
212
  else
178
213
  return nil
179
214
  end
180
215
  end
181
- memoize :rvm_path
216
+ memoize :rvm_paths
182
217
 
183
218
  # If the current Ruby interpreter is managed by RVM, returns the
184
219
  # RVM name which identifies the current Ruby interpreter plus the
@@ -200,8 +235,12 @@ module PlatformInfo
200
235
  # try various strategies...
201
236
 
202
237
  # $GEM_HOME usually contains the gem set name.
203
- if GEM_HOME && GEM_HOME.include?("rvm/gems/")
204
- return File.basename(GEM_HOME)
238
+ # It may be something like:
239
+ # /Users/hongli/.rvm/gems/ruby-1.9.3-p392
240
+ # But also:
241
+ # /home/bitnami/.rvm/gems/ruby-1.9.3-p385-perf@njist325/ruby/1.9.1
242
+ if GEM_HOME && GEM_HOME =~ %r{rvm/gems/(.+)}
243
+ return $1.sub(/\/.*/, '')
205
244
  end
206
245
 
207
246
  # User somehow managed to nuke $GEM_HOME. Extract info
@@ -227,6 +266,27 @@ module PlatformInfo
227
266
  return nil
228
267
  end
229
268
  memoize :rvm_ruby_string
269
+
270
+ # Returns the RVM installation mode:
271
+ # :single - RVM is installed in single-user mode.
272
+ # :multi - RVM is installed in multi-user mode.
273
+ # :mixed - RVM is in a mixed-mode installation.
274
+ # nil - The current Ruby interpreter is not using RVM.
275
+ def self.rvm_installation_mode
276
+ if in_rvm?
277
+ if ENV['rvm_path'] =~ /\.rvm/
278
+ return :single
279
+ else
280
+ if GEM_HOME =~ /\.rvm/
281
+ return :mixed
282
+ else
283
+ return :multi
284
+ end
285
+ end
286
+ else
287
+ return nil
288
+ end
289
+ end
230
290
 
231
291
  # Returns either 'sudo' or 'rvmsudo' depending on whether the current
232
292
  # Ruby interpreter is managed by RVM.
@@ -93,7 +93,21 @@ protected
93
93
  env[RACK_URL_SCHEME] = HTTP
94
94
  end
95
95
 
96
- status, headers, body = @app.call(env)
96
+ begin
97
+ status, headers, body = @app.call(env)
98
+ rescue => e
99
+ socket_wrapper = output
100
+ if socket_wrapper.source_of_exception?(e)
101
+ # Handled by AbstractRequestHandler
102
+ raise e
103
+ else
104
+ # It's a good idea to catch application exceptions here because
105
+ # otherwise maliciously crafted responses can crash the app,
106
+ # forcing it to be respawned, and thereby effectively DoSing it.
107
+ print_exception("Rack application object", e)
108
+ raise AbstractRequestHandler::IgnoreException.new
109
+ end
110
+ end
97
111
  begin
98
112
  if full_http_response
99
113
  output.write("HTTP/1.1 #{status.to_i.to_s} Whatever#{CRLF}")
@@ -139,6 +153,11 @@ protected
139
153
  rewindable_input.close
140
154
  end
141
155
  end
156
+
157
+ private
158
+ def should_swallow_app_error?(e, socket_wrapper)
159
+ return socket_wrapper && socket_wrapper.source_of_exception?(e) && e.is_a?(Errno::EPIPE)
160
+ end
142
161
  end
143
162
 
144
163
  end # module Rack