passenger 4.0.49 → 4.0.50

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.

Files changed (77) hide show
  1. checksums.yaml +8 -8
  2. checksums.yaml.gz.asc +7 -7
  3. data.tar.gz.asc +7 -7
  4. data/CHANGELOG +7 -0
  5. data/build/test_basics.rb +1 -0
  6. data/ext/common/ApplicationPool2/Options.h +42 -39
  7. data/ext/common/Constants.h +1 -1
  8. data/helper-scripts/classic-rails-loader.rb +2 -1
  9. data/helper-scripts/classic-rails-preloader.rb +2 -1
  10. data/helper-scripts/node-loader.js +27 -5
  11. data/helper-scripts/rack-loader.rb +2 -1
  12. data/helper-scripts/rack-preloader.rb +2 -1
  13. data/helper-scripts/wsgi-loader.py +30 -7
  14. data/lib/phusion_passenger.rb +1 -1
  15. data/lib/phusion_passenger/active_support3_extensions/init.rb +1 -0
  16. data/lib/phusion_passenger/preloader_shared_helpers.rb +31 -9
  17. data/lib/phusion_passenger/request_handler.rb +31 -24
  18. data/lib/phusion_passenger/utils.rb +21 -9
  19. data/test/ruby/rails4.1/loader_spec.rb +28 -0
  20. data/test/ruby/rails4.1/preloader_spec.rb +34 -0
  21. data/test/ruby/request_handler_spec.rb +27 -25
  22. data/test/stub/rails4.1/.gitignore +16 -0
  23. data/test/stub/rails4.1/Gemfile +45 -0
  24. data/test/stub/rails4.1/Gemfile.lock +129 -0
  25. data/test/stub/rails4.1/README.rdoc +28 -0
  26. data/test/stub/rails4.1/Rakefile +6 -0
  27. data/test/stub/rails4.1/app/assets/images/.keep +0 -0
  28. data/test/stub/rails4.1/app/assets/javascripts/application.js +16 -0
  29. data/test/stub/rails4.1/app/assets/stylesheets/application.css +13 -0
  30. data/test/stub/rails4.1/app/controllers/application_controller.rb +5 -0
  31. data/test/stub/rails4.1/app/controllers/concerns/.keep +0 -0
  32. data/test/stub/rails4.1/app/helpers/application_helper.rb +2 -0
  33. data/test/stub/rails4.1/app/mailers/.keep +0 -0
  34. data/test/stub/rails4.1/app/models/.keep +0 -0
  35. data/test/stub/rails4.1/app/models/concerns/.keep +0 -0
  36. data/test/stub/rails4.1/app/views/layouts/application.html.erb +14 -0
  37. data/test/stub/rails4.1/bin/bundle +3 -0
  38. data/test/stub/rails4.1/bin/rails +4 -0
  39. data/test/stub/rails4.1/bin/rake +4 -0
  40. data/test/stub/rails4.1/config.ru +4 -0
  41. data/test/stub/rails4.1/config/application.rb +23 -0
  42. data/test/stub/rails4.1/config/boot.rb +4 -0
  43. data/test/stub/rails4.1/config/database.yml +25 -0
  44. data/test/stub/rails4.1/config/environment.rb +5 -0
  45. data/test/stub/rails4.1/config/environments/development.rb +29 -0
  46. data/test/stub/rails4.1/config/environments/production.rb +80 -0
  47. data/test/stub/rails4.1/config/environments/test.rb +36 -0
  48. data/test/stub/rails4.1/config/initializers/backtrace_silencers.rb +7 -0
  49. data/test/stub/rails4.1/config/initializers/filter_parameter_logging.rb +4 -0
  50. data/test/stub/rails4.1/config/initializers/inflections.rb +16 -0
  51. data/test/stub/rails4.1/config/initializers/mime_types.rb +5 -0
  52. data/test/stub/rails4.1/config/initializers/passenger.rb +5 -0
  53. data/test/stub/rails4.1/config/initializers/secret_token.rb +12 -0
  54. data/test/stub/rails4.1/config/initializers/session_store.rb +3 -0
  55. data/test/stub/rails4.1/config/initializers/wrap_parameters.rb +14 -0
  56. data/test/stub/rails4.1/config/locales/en.yml +23 -0
  57. data/test/stub/rails4.1/config/routes.rb +57 -0
  58. data/test/stub/rails4.1/db/seeds.rb +7 -0
  59. data/test/stub/rails4.1/lib/assets/.keep +0 -0
  60. data/test/stub/rails4.1/lib/tasks/.keep +0 -0
  61. data/test/stub/rails4.1/log/.keep +0 -0
  62. data/test/stub/rails4.1/public/404.html +58 -0
  63. data/test/stub/rails4.1/public/422.html +58 -0
  64. data/test/stub/rails4.1/public/500.html +57 -0
  65. data/test/stub/rails4.1/public/favicon.ico +0 -0
  66. data/test/stub/rails4.1/public/robots.txt +5 -0
  67. data/test/stub/rails4.1/test/controllers/.keep +0 -0
  68. data/test/stub/rails4.1/test/fixtures/.keep +0 -0
  69. data/test/stub/rails4.1/test/helpers/.keep +0 -0
  70. data/test/stub/rails4.1/test/integration/.keep +0 -0
  71. data/test/stub/rails4.1/test/mailers/.keep +0 -0
  72. data/test/stub/rails4.1/test/models/.keep +0 -0
  73. data/test/stub/rails4.1/test/test_helper.rb +15 -0
  74. data/test/stub/rails4.1/vendor/assets/javascripts/.keep +0 -0
  75. data/test/stub/rails4.1/vendor/assets/stylesheets/.keep +0 -0
  76. metadata +58 -2
  77. metadata.gz.asc +7 -7
@@ -112,7 +112,7 @@ class RequestHandler
112
112
  @server_sockets = {}
113
113
 
114
114
  if should_use_unix_sockets?
115
- @main_socket_address, @main_socket = create_unix_socket_on_filesystem
115
+ @main_socket_address, @main_socket = create_unix_socket_on_filesystem(options)
116
116
  else
117
117
  @main_socket_address, @main_socket = create_tcp_socket
118
118
  end
@@ -159,11 +159,14 @@ class RequestHandler
159
159
  end
160
160
  @main_loop_thread.join
161
161
  end
162
- @server_sockets.each_value do |value|
163
- address, type, socket = value
164
- socket.close rescue nil
165
- if type == 'unix'
166
- File.unlink(address) rescue nil
162
+ @server_sockets.each_value do |info|
163
+ socket = info[:socket]
164
+ type = get_socket_address_type(info[:address])
165
+
166
+ socket.close if !socket.closed?
167
+ if type == :unix
168
+ filename = info[:address].sub(/^unix:/, '')
169
+ File.unlink(filename) rescue nil
167
170
  end
168
171
  end
169
172
  @owner_pipe.close rescue nil
@@ -316,24 +319,28 @@ private
316
319
  return !@force_http_session && ruby_engine != "jruby"
317
320
  end
318
321
 
319
- def create_unix_socket_on_filesystem
320
- while true
321
- begin
322
- if defined?(NativeSupport)
323
- unix_path_max = NativeSupport::UNIX_PATH_MAX
324
- else
325
- unix_path_max = 100
326
- end
327
- socket_address = "#{passenger_tmpdir}/backends/ruby.#{generate_random_id(:base64)}"
328
- socket_address = socket_address.slice(0, unix_path_max - 10)
329
- socket = UNIXServer.new(socket_address)
330
- socket.listen(BACKLOG_SIZE)
331
- socket.close_on_exec!
332
- File.chmod(0600, socket_address)
333
- return ["unix:#{socket_address}", socket]
334
- rescue Errno::EADDRINUSE
335
- # Do nothing, try again with another name.
336
- end
322
+ def create_unix_socket_on_filesystem(options)
323
+ if defined?(NativeSupport)
324
+ unix_path_max = NativeSupport::UNIX_PATH_MAX
325
+ else
326
+ unix_path_max = options.fetch('UNIX_PATH_MAX', 100)
327
+ end
328
+ if options['generation_dir']
329
+ socket_dir = "#{options['generation_dir']}/backends"
330
+ socket_prefix = "ruby"
331
+ else
332
+ socket_dir = Dir.tmpdir
333
+ socket_prefix = "PsgRubyApp"
334
+ end
335
+
336
+ retry_at_most(128, Errno::EADDRINUSE) do
337
+ socket_address = "#{socket_dir}/#{socket_prefix}.#{generate_random_id(:base64)}"
338
+ socket_address = socket_address.slice(0, unix_path_max - 10)
339
+ socket = UNIXServer.new(socket_address)
340
+ socket.listen(BACKLOG_SIZE)
341
+ socket.close_on_exec!
342
+ File.chmod(0600, socket_address)
343
+ ["unix:#{socket_address}", socket]
337
344
  end
338
345
  end
339
346
 
@@ -27,7 +27,7 @@ module PhusionPassenger
27
27
  # Utility functions.
28
28
  module Utils
29
29
  extend self # Make methods available as class methods.
30
-
30
+
31
31
  def self.included(klass)
32
32
  # When included into another class, make sure that Utils
33
33
  # methods are made private.
@@ -35,7 +35,7 @@ module Utils
35
35
  klass.send(:private, method_name)
36
36
  end
37
37
  end
38
-
38
+
39
39
  # Generate a long, cryptographically secure random ID string, which
40
40
  # is also a valid filename.
41
41
  def generate_random_id(method)
@@ -56,7 +56,19 @@ module Utils
56
56
  raise ArgumentError, "Invalid method #{method.inspect}"
57
57
  end
58
58
  end
59
-
59
+
60
+ def retry_at_most(n, *exceptions)
61
+ n.times do |i|
62
+ begin
63
+ return yield
64
+ rescue *exceptions
65
+ if i == n - 1
66
+ raise
67
+ end
68
+ end
69
+ end
70
+ end
71
+
60
72
  def home_dir
61
73
  Etc.getpwuid(Process.uid).dir
62
74
  end
@@ -77,7 +89,7 @@ module Utils
77
89
  end
78
90
  end
79
91
  end
80
-
92
+
81
93
  def get_socket_address_type(address)
82
94
  if address =~ %r{^unix:.}
83
95
  return :unix
@@ -87,7 +99,7 @@ module Utils
87
99
  return :unknown
88
100
  end
89
101
  end
90
-
102
+
91
103
  def connect_to_server(address)
92
104
  case get_socket_address_type(address)
93
105
  when :unix
@@ -100,7 +112,7 @@ module Utils
100
112
  raise ArgumentError, "Unknown socket address type for '#{address}'."
101
113
  end
102
114
  end
103
-
115
+
104
116
  def local_socket_address?(address)
105
117
  case get_socket_address_type(address)
106
118
  when :unix
@@ -112,7 +124,7 @@ module Utils
112
124
  raise ArgumentError, "Unknown socket address type for '#{address}'."
113
125
  end
114
126
  end
115
-
127
+
116
128
  # Checks whether the given process exists.
117
129
  def process_is_alive?(pid)
118
130
  begin
@@ -138,7 +150,7 @@ module Utils
138
150
  object.instance_variable_set("@#{key}", options[key])
139
151
  end
140
152
  end
141
-
153
+
142
154
  # Returns a string which reports the backtraces for all threads,
143
155
  # or if that's not supported the backtrace for the current thread.
144
156
  def global_backtrace_report
@@ -178,7 +190,7 @@ module Utils
178
190
  end
179
191
  return output
180
192
  end
181
-
193
+
182
194
  ####################################
183
195
  end
184
196
 
@@ -0,0 +1,28 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require 'ruby/shared/loader_sharedspec'
3
+ require 'ruby/shared/rails/union_station_extensions_sharedspec'
4
+
5
+ if RUBY_VERSION_INT >= 190
6
+ module PhusionPassenger
7
+
8
+ describe "Rack loader with Rails 4.1" do
9
+ include LoaderSpecHelper
10
+
11
+ before :each do
12
+ @stub = register_stub(RackStub.new("rails4.1"))
13
+ end
14
+
15
+ def start(options = {})
16
+ @loader = Loader.new(["ruby", "#{PhusionPassenger.helper_scripts_dir}/rack-loader.rb"], @stub.app_root)
17
+ return @loader.start(options)
18
+ end
19
+
20
+ def rails_version
21
+ return "4.1"
22
+ end
23
+
24
+ include_examples "Union Station extensions for Rails"
25
+ end
26
+
27
+ end # module PhusionPassenger
28
+ end
@@ -0,0 +1,34 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require 'ruby/shared/loader_sharedspec'
3
+ require 'ruby/shared/rails/union_station_extensions_sharedspec'
4
+
5
+ if RUBY_VERSION_INT >= 190
6
+ module PhusionPassenger
7
+
8
+ describe "Rack loader with Rails 4.1" do
9
+ include LoaderSpecHelper
10
+
11
+ before :each do
12
+ @stub = register_stub(RackStub.new("rails4.1"))
13
+ end
14
+
15
+ def start(options = {})
16
+ @preloader = Preloader.new(["ruby", "#{PhusionPassenger.helper_scripts_dir}/rack-preloader.rb"], @stub.app_root)
17
+ result = @preloader.start(options)
18
+ if result[:status] == "Ready"
19
+ @loader = @preloader.spawn(options)
20
+ return @loader.start(options)
21
+ else
22
+ return result
23
+ end
24
+ end
25
+
26
+ def rails_version
27
+ return "4.1"
28
+ end
29
+
30
+ include_examples "Union Station extensions for Rails"
31
+ end
32
+
33
+ end # module PhusionPassenger
34
+ end
@@ -20,16 +20,18 @@ describe RequestHandler do
20
20
  preinitialize if respond_to?(:preinitialize)
21
21
  @old_passenger_tmpdir = Utils.passenger_tmpdir
22
22
  Utils.passenger_tmpdir = "request_handler_spec.tmp"
23
+ Utils.passenger_tmpdir
23
24
  @owner_pipe = IO.pipe
24
25
  @options ||= {}
25
26
  @thread_handler = Class.new(DummyThreadHandler)
26
27
  @options = {
27
28
  "app_group_name" => "foobar",
28
- "thread_handler" => @thread_handler
29
+ "thread_handler" => @thread_handler,
30
+ "generation_dir" => "request_handler_spec.tmp"
29
31
  }.merge(@options)
30
32
  @request_handler = RequestHandler.new(@owner_pipe[1], @options)
31
33
  end
32
-
34
+
33
35
  after :each do
34
36
  stop_request_handler
35
37
  Utils.passenger_tmpdir = @old_passenger_tmpdir
@@ -44,12 +46,12 @@ describe RequestHandler do
44
46
  @request_handler = nil
45
47
  end
46
48
  end
47
-
49
+
48
50
  def connect(socket_name = :main)
49
51
  address = @request_handler.server_sockets[socket_name][:address]
50
52
  return Utils.connect_to_server(address)
51
53
  end
52
-
54
+
53
55
  def send_binary_request(socket, env)
54
56
  channel = MessageChannel.new(socket)
55
57
  data = ""
@@ -59,7 +61,7 @@ describe RequestHandler do
59
61
  end
60
62
  channel.write_scalar(data)
61
63
  end
62
-
64
+
63
65
  it "exits if the owner pipe is closed" do
64
66
  @request_handler.start_main_loop_thread
65
67
  @owner_pipe[0].close
@@ -74,7 +76,7 @@ describe RequestHandler do
74
76
  Dir["request_handler_spec.tmp/backends/*"].should_not be_empty
75
77
  end
76
78
  end
77
-
79
+
78
80
  specify "the main socket rejects headers that are too large" do
79
81
  stderr = StringIO.new
80
82
  DebugLogging.log_level = 0
@@ -95,7 +97,7 @@ describe RequestHandler do
95
97
  client.close rescue nil
96
98
  end
97
99
  end
98
-
100
+
99
101
  specify "the main socket rejects unauthenticated connections, if a connect password is supplied" do
100
102
  @request_handler.connect_password = "1234"
101
103
  @request_handler.start_main_loop_thread
@@ -116,7 +118,7 @@ describe RequestHandler do
116
118
  client.close rescue nil
117
119
  end
118
120
  end
119
-
121
+
120
122
  it "accepts pings on the main server socket" do
121
123
  @request_handler.start_main_loop_thread
122
124
  client = connect
@@ -128,7 +130,7 @@ describe RequestHandler do
128
130
  client.close
129
131
  end
130
132
  end
131
-
133
+
132
134
  it "accepts pings on the HTTP server socket" do
133
135
  @request_handler.start_main_loop_thread
134
136
  client = connect(:http)
@@ -141,7 +143,7 @@ describe RequestHandler do
141
143
  client.close
142
144
  end
143
145
  end
144
-
146
+
145
147
  specify "the HTTP socket rejects headers that are too large" do
146
148
  stderr = StringIO.new
147
149
  DebugLogging.log_level = 0
@@ -163,7 +165,7 @@ describe RequestHandler do
163
165
  client.close rescue nil
164
166
  end
165
167
  end
166
-
168
+
167
169
  specify "the HTTP socket rejects unauthenticated connections, if a connect password is supplied" do
168
170
  DebugLogging.log_level = -1
169
171
  @request_handler.connect_password = "1234"
@@ -522,23 +524,23 @@ describe RequestHandler do
522
524
  @logging_agent_password = "1234"
523
525
  @agent_pid, @socket_filename, @socket_address = spawn_logging_agent(@dump_file,
524
526
  @logging_agent_password)
525
-
527
+
526
528
  @union_station_core = UnionStation::Core.new(@socket_address, "logging",
527
529
  "1234", "localhost")
528
530
  @options = { "union_station_core" => @union_station_core }
529
531
  end
530
-
532
+
531
533
  after :each do
532
534
  if @agent_pid
533
535
  Process.kill('KILL', @agent_pid)
534
536
  Process.waitpid(@agent_pid)
535
537
  end
536
538
  end
537
-
539
+
538
540
  def base64(data)
539
541
  return [data].pack('m').gsub("\n", "")
540
542
  end
541
-
543
+
542
544
  it "makes the analytics log object available through the request env and a thread-local variable" do
543
545
  header_value = nil
544
546
  thread_value = nil
@@ -561,7 +563,7 @@ describe RequestHandler do
561
563
  thread_value.should be_kind_of(UnionStation::Transaction)
562
564
  header_value.should == thread_value
563
565
  end
564
-
566
+
565
567
  it "logs uncaught exceptions for requests that have a transaction ID" do
566
568
  reraised = false
567
569
  @thread_handler.any_instance.should_receive(:process_request).and_return do |headers, connection, full_http_response|
@@ -596,18 +598,18 @@ describe RequestHandler do
596
598
  reraised.should be_true
597
599
  end
598
600
  end
599
-
601
+
600
602
  describe "HTTP parsing" do
601
603
  before :each do
602
604
  @request_handler.start_main_loop_thread
603
605
  @client = connect(:http)
604
606
  @client.sync = true
605
607
  end
606
-
608
+
607
609
  after :each do
608
610
  @client.close if @client
609
611
  end
610
-
612
+
611
613
  it "correctly parses HTTP requests without query string" do
612
614
  @thread_handler.any_instance.should_receive(:process_request).and_return do |headers, connection, full_http_response|
613
615
  headers["REQUEST_METHOD"].should == "POST"
@@ -623,7 +625,7 @@ describe RequestHandler do
623
625
  headers["CONTENT_LENGTH"].should == "10"
624
626
  headers["CONTENT_TYPE"].should == "text/plain"
625
627
  end
626
-
628
+
627
629
  @client.write("POST /foo/bar HTTP/1.1\r\n")
628
630
  @client.write("Host: foo.com\r\n")
629
631
  @client.write("X-Foo-Bar: baz\r\n")
@@ -633,7 +635,7 @@ describe RequestHandler do
633
635
  @client.close_write
634
636
  @client.read
635
637
  end
636
-
638
+
637
639
  it "correctly parses HTTP requests with query string" do
638
640
  @thread_handler.any_instance.should_receive(:process_request).and_return do |headers, connection, full_http_response|
639
641
  headers["REQUEST_METHOD"].should == "POST"
@@ -649,7 +651,7 @@ describe RequestHandler do
649
651
  headers["CONTENT_LENGTH"].should == "10"
650
652
  headers["CONTENT_TYPE"].should == "text/plain"
651
653
  end
652
-
654
+
653
655
  @client.write("POST /foo/bar?hello=world&a=b+c HTTP/1.1\r\n")
654
656
  @client.write("Host: foo.com\r\n")
655
657
  @client.write("X-Foo-Bar: baz\r\n")
@@ -659,7 +661,7 @@ describe RequestHandler do
659
661
  @client.close_write
660
662
  @client.read
661
663
  end
662
-
664
+
663
665
  it "correct parses HTTP requests that come in arbitrary chunks" do
664
666
  @thread_handler.any_instance.should_receive(:process_request).and_return do |headers, connection, full_http_response|
665
667
  headers["REQUEST_METHOD"].should == "POST"
@@ -676,7 +678,7 @@ describe RequestHandler do
676
678
  headers["CONTENT_TYPE"].should == "text/plain"
677
679
  headers["HTTP_PLUS_SOME"].should be_nil
678
680
  end
679
-
681
+
680
682
  @client.write("POST /fo")
681
683
  sleep 0.001
682
684
  @client.write("o/bar?hello=world&a=b+c HT")
@@ -700,7 +702,7 @@ describe RequestHandler do
700
702
  @client.read
701
703
  end
702
704
  end
703
-
705
+
704
706
  ############################
705
707
  end
706
708
 
@@ -0,0 +1,16 @@
1
+ # See http://help.github.com/ignore-files/ for more about ignoring files.
2
+ #
3
+ # If you find yourself ignoring temporary files generated by your text editor
4
+ # or operating system, you probably want to add a global ignore instead:
5
+ # git config --global core.excludesfile '~/.gitignore_global'
6
+
7
+ # Ignore bundler config.
8
+ /.bundle
9
+
10
+ # Ignore the default SQLite database.
11
+ /db/*.sqlite3
12
+ /db/*.sqlite3-journal
13
+
14
+ # Ignore all logfiles and tempfiles.
15
+ /log/*.log
16
+ /tmp