passenger 2.2.2 → 2.2.3
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.
- data/DEVELOPERS.TXT +13 -3
- data/Rakefile +42 -33
- data/bin/passenger-install-apache2-module +1 -2
- data/bin/passenger-install-nginx-module +7 -19
- data/bin/passenger-status +64 -15
- data/bin/passenger-stress-test +2 -2
- data/doc/ApplicationPool algorithm.txt +26 -22
- data/doc/Users guide Apache.html +374 -149
- data/doc/Users guide Apache.txt +318 -51
- data/doc/Users guide Nginx.html +13 -13
- data/doc/Users guide Nginx.txt +7 -2
- data/doc/cxxapi/Bucket_8h-source.html +62 -25
- data/doc/cxxapi/Configuration_8h-source.html +343 -326
- data/doc/cxxapi/DirectoryMapper_8h-source.html +12 -12
- data/doc/cxxapi/Hooks_8h-source.html +1 -1
- data/doc/cxxapi/annotated.html +1 -1
- data/doc/cxxapi/classHooks-members.html +1 -1
- data/doc/cxxapi/classHooks.html +1 -1
- data/doc/cxxapi/classPassenger_1_1DirectoryMapper-members.html +2 -2
- data/doc/cxxapi/classPassenger_1_1DirectoryMapper.html +9 -9
- data/doc/cxxapi/classes.html +1 -1
- data/doc/cxxapi/definitions_8h-source.html +1 -1
- data/doc/cxxapi/files.html +1 -1
- data/doc/cxxapi/functions.html +2 -2
- data/doc/cxxapi/functions_func.html +2 -2
- data/doc/cxxapi/graph_legend.html +1 -1
- data/doc/cxxapi/group__Configuration.html +1 -1
- data/doc/cxxapi/group__Core.html +1 -1
- data/doc/cxxapi/group__Hooks.html +1 -1
- data/doc/cxxapi/group__Support.html +1 -1
- data/doc/cxxapi/main.html +1 -1
- data/doc/cxxapi/modules.html +1 -1
- data/doc/rdoc/classes/ConditionVariable.html +194 -0
- data/doc/rdoc/classes/Exception.html +120 -0
- data/doc/rdoc/classes/GC.html +113 -0
- data/doc/rdoc/classes/IO.html +169 -0
- data/doc/rdoc/classes/PhusionPassenger.html +238 -0
- data/doc/rdoc/classes/PhusionPassenger/AbstractInstaller.html +153 -0
- data/doc/rdoc/classes/PhusionPassenger/AbstractRequestHandler.html +517 -0
- data/doc/rdoc/classes/PhusionPassenger/AbstractServer.html +719 -0
- data/doc/rdoc/classes/PhusionPassenger/AbstractServer/ServerAlreadyStarted.html +97 -0
- data/doc/rdoc/classes/PhusionPassenger/AbstractServer/ServerError.html +96 -0
- data/doc/rdoc/classes/PhusionPassenger/AbstractServer/ServerNotStarted.html +97 -0
- data/doc/rdoc/classes/PhusionPassenger/AbstractServer/UnknownMessage.html +96 -0
- data/doc/rdoc/classes/PhusionPassenger/AbstractServerCollection.html +598 -0
- data/doc/rdoc/classes/PhusionPassenger/AdminTools.html +140 -0
- data/doc/rdoc/classes/PhusionPassenger/AdminTools/ControlProcess.html +317 -0
- data/doc/rdoc/classes/PhusionPassenger/AdminTools/ControlProcess/Instance.html +138 -0
- data/doc/rdoc/classes/PhusionPassenger/AppInitError.html +154 -0
- data/doc/rdoc/classes/PhusionPassenger/Application.html +283 -0
- data/doc/rdoc/classes/PhusionPassenger/ConsoleTextTemplate.html +172 -0
- data/doc/rdoc/classes/PhusionPassenger/FrameworkInitError.html +145 -0
- data/doc/rdoc/classes/PhusionPassenger/HTMLTemplate.html +175 -0
- data/doc/rdoc/classes/PhusionPassenger/InitializationError.html +141 -0
- data/doc/rdoc/classes/PhusionPassenger/InvalidPath.html +92 -0
- data/doc/rdoc/classes/PhusionPassenger/MessageChannel.html +489 -0
- data/doc/rdoc/classes/PhusionPassenger/NativeSupport.html +350 -0
- data/doc/rdoc/classes/PhusionPassenger/Rack.html +91 -0
- data/doc/rdoc/classes/PhusionPassenger/Rack/ApplicationSpawner.html +188 -0
- data/doc/rdoc/classes/PhusionPassenger/Rack/RequestHandler.html +194 -0
- data/doc/rdoc/classes/PhusionPassenger/Railz.html +95 -0
- data/doc/rdoc/classes/PhusionPassenger/Railz/ApplicationSpawner.html +442 -0
- data/doc/rdoc/classes/PhusionPassenger/Railz/ApplicationSpawner/Error.html +98 -0
- data/doc/rdoc/classes/PhusionPassenger/Railz/CGIFixed.html +200 -0
- data/doc/rdoc/classes/PhusionPassenger/Railz/FrameworkSpawner.html +436 -0
- data/doc/rdoc/classes/PhusionPassenger/Railz/FrameworkSpawner/Error.html +98 -0
- data/doc/rdoc/classes/PhusionPassenger/Railz/RequestHandler.html +155 -0
- data/doc/rdoc/classes/PhusionPassenger/SpawnManager.html +402 -0
- data/doc/rdoc/classes/PhusionPassenger/UnknownError.html +125 -0
- data/doc/rdoc/classes/PhusionPassenger/Utils.html +805 -0
- data/doc/rdoc/classes/PhusionPassenger/VersionNotFound.html +140 -0
- data/doc/rdoc/classes/PhusionPassenger/WSGI.html +89 -0
- data/doc/rdoc/classes/PhusionPassenger/WSGI/ApplicationSpawner.html +188 -0
- data/doc/rdoc/classes/PlatformInfo.html +831 -0
- data/doc/rdoc/classes/RakeExtensions.html +197 -0
- data/doc/rdoc/classes/Signal.html +131 -0
- data/doc/rdoc/created.rid +1 -0
- data/doc/rdoc/files/DEVELOPERS_TXT.html +255 -0
- data/doc/rdoc/files/README.html +157 -0
- data/doc/rdoc/files/ext/phusion_passenger/native_support_c.html +92 -0
- data/doc/rdoc/files/lib/phusion_passenger/abstract_installer_rb.html +129 -0
- data/doc/rdoc/files/lib/phusion_passenger/abstract_request_handler_rb.html +131 -0
- data/doc/rdoc/files/lib/phusion_passenger/abstract_server_collection_rb.html +126 -0
- data/doc/rdoc/files/lib/phusion_passenger/abstract_server_rb.html +130 -0
- data/doc/rdoc/files/lib/phusion_passenger/admin_tools/control_process_rb.html +130 -0
- data/doc/rdoc/files/lib/phusion_passenger/admin_tools_rb.html +122 -0
- data/doc/rdoc/files/lib/phusion_passenger/application_rb.html +127 -0
- data/doc/rdoc/files/lib/phusion_passenger/console_text_template_rb.html +126 -0
- data/doc/rdoc/files/lib/phusion_passenger/constants_rb.html +122 -0
- data/doc/rdoc/files/lib/phusion_passenger/dependencies_rb.html +134 -0
- data/doc/rdoc/files/lib/phusion_passenger/events_rb.html +122 -0
- data/doc/rdoc/files/lib/phusion_passenger/exceptions_rb.html +122 -0
- data/doc/rdoc/files/lib/phusion_passenger/html_template_rb.html +126 -0
- data/doc/rdoc/files/lib/phusion_passenger/message_channel_rb.html +122 -0
- data/doc/rdoc/files/lib/phusion_passenger/packaging_rb.html +122 -0
- data/doc/rdoc/files/lib/phusion_passenger/platform_info_rb.html +127 -0
- data/doc/rdoc/files/lib/phusion_passenger/rack/application_spawner_rb.html +133 -0
- data/doc/rdoc/files/lib/phusion_passenger/rack/request_handler_rb.html +127 -0
- data/doc/rdoc/files/lib/phusion_passenger/railz/application_spawner_rb.html +143 -0
- data/doc/rdoc/files/lib/phusion_passenger/railz/cgi_fixed_rb.html +126 -0
- data/doc/rdoc/files/lib/phusion_passenger/railz/framework_spawner_rb.html +145 -0
- data/doc/rdoc/files/lib/phusion_passenger/railz/request_handler_rb.html +127 -0
- data/doc/rdoc/files/lib/phusion_passenger/simple_benchmarking_rb.html +122 -0
- data/doc/rdoc/files/lib/phusion_passenger/spawn_manager_rb.html +161 -0
- data/doc/rdoc/files/lib/phusion_passenger/utils_rb.html +175 -0
- data/doc/rdoc/files/lib/phusion_passenger/wsgi/application_spawner_rb.html +129 -0
- data/doc/rdoc/files/misc/rake/extensions_rb.html +130 -0
- data/doc/rdoc/fr_class_index.html +90 -0
- data/doc/rdoc/fr_file_index.html +76 -0
- data/doc/rdoc/fr_method_index.html +200 -0
- data/doc/rdoc/index.html +26 -0
- data/doc/rdoc/rdoc-style.css +187 -0
- data/doc/users_guide_snippets/rackup_specifications.txt +2 -8
- data/ext/apache2/Bucket.cpp +71 -38
- data/ext/apache2/Bucket.h +53 -16
- data/ext/apache2/Configuration.cpp +15 -0
- data/ext/apache2/Configuration.h +19 -2
- data/ext/apache2/DirectoryMapper.h +10 -10
- data/ext/apache2/Hooks.cpp +334 -74
- data/ext/boost/mpl/apply.hpp +5 -1
- data/ext/boost/mpl/apply_wrap.hpp +5 -2
- data/ext/boost/mpl/aux_/full_lambda.hpp +5 -1
- data/ext/boost/mpl/bind.hpp +5 -1
- data/ext/common/Application.h +11 -31
- data/ext/common/ApplicationPool.h +2 -1
- data/ext/common/ApplicationPoolServer.h +61 -20
- data/ext/common/ApplicationPoolServerExecutable.cpp +132 -4
- data/ext/common/ApplicationPoolStatusReporter.h +189 -65
- data/ext/common/Base64.cpp +143 -0
- data/ext/common/Base64.h +57 -0
- data/ext/common/CachedFileStat.cpp +25 -82
- data/ext/common/CachedFileStat.h +11 -125
- data/ext/common/CachedFileStat.hpp +243 -0
- data/ext/common/Exceptions.h +13 -0
- data/ext/common/FileChangeChecker.h +209 -0
- data/ext/common/Logging.h +3 -2
- data/ext/common/MessageChannel.h +10 -10
- data/ext/common/PoolOptions.h +72 -5
- data/ext/common/SpawnManager.h +11 -8
- data/ext/common/StandardApplicationPool.h +38 -39
- data/ext/common/StaticString.h +1 -0
- data/ext/common/StringListCreator.h +83 -0
- data/ext/common/SystemTime.h +3 -2
- data/ext/common/Timer.h +88 -0
- data/ext/common/Utils.cpp +161 -42
- data/ext/common/Utils.h +62 -31
- data/ext/common/Version.h +1 -1
- data/ext/nginx/Configuration.c +0 -4
- data/ext/nginx/ContentHandler.c +8 -6
- data/ext/nginx/HelperServer.cpp +45 -55
- data/ext/nginx/HttpStatusExtractor.h +4 -0
- data/ext/nginx/StaticContentHandler.c +25 -5
- data/ext/nginx/config +3 -0
- data/ext/nginx/ngx_http_passenger_module.c +72 -17
- data/ext/nginx/ngx_http_passenger_module.h +2 -2
- data/lib/phusion_passenger/abstract_request_handler.rb +15 -7
- data/lib/phusion_passenger/abstract_server.rb +16 -2
- data/lib/phusion_passenger/admin_tools/control_process.rb +36 -25
- data/lib/phusion_passenger/constants.rb +1 -1
- data/lib/phusion_passenger/dependencies.rb +10 -0
- data/lib/phusion_passenger/platform_info.rb +1 -1
- data/lib/phusion_passenger/rack/application_spawner.rb +21 -2
- data/lib/phusion_passenger/rack/request_handler.rb +10 -0
- data/lib/phusion_passenger/railz/application_spawner.rb +38 -2
- data/lib/phusion_passenger/railz/framework_spawner.rb +26 -28
- data/lib/phusion_passenger/railz/request_handler.rb +5 -1
- data/lib/phusion_passenger/spawn_manager.rb +6 -2
- data/lib/phusion_passenger/utils.rb +79 -27
- data/misc/rake/cplusplus.rb +5 -5
- data/test/ApplicationPoolServerTest.cpp +42 -0
- data/test/ApplicationPoolTest.cpp +255 -267
- data/test/Base64Test.cpp +48 -0
- data/test/CachedFileStatTest.cpp +243 -103
- data/test/FileChangeCheckerTest.cpp +331 -0
- data/test/PoolOptionsTest.cpp +80 -0
- data/test/UtilsTest.cpp +5 -17
- data/test/integration_tests/apache2_tests.rb +15 -4
- data/test/integration_tests/mycook_spec.rb +3 -4
- data/test/oxt/syscall_interruption_test.cpp +2 -14
- data/test/ruby/abstract_server_collection_spec.rb +1 -1
- data/test/ruby/abstract_server_spec.rb +35 -1
- data/test/ruby/rack/application_spawner_spec.rb +23 -6
- data/test/ruby/rails/application_spawner_spec.rb +6 -6
- data/test/ruby/rails/framework_spawner_spec.rb +6 -5
- data/test/ruby/rails/minimal_spawner_spec.rb +19 -0
- data/test/ruby/rails/spawner_error_handling_spec.rb +62 -7
- data/test/ruby/spawn_manager_spec.rb +10 -7
- data/test/ruby/spawn_server_spec.rb +1 -1
- data/test/ruby/utils_spec.rb +193 -20
- data/test/ruby/wsgi/application_spawner_spec.rb +3 -1
- data/test/stub/apache2/httpd.conf.erb +3 -0
- data/test/stub/rack/config.ru +1 -1
- data/test/stub/rails_apps/mycook/app/controllers/welcome_controller.rb +8 -0
- data/test/support/Support.cpp +84 -0
- data/test/support/Support.h +66 -8
- data/test/support/config.rb +14 -2
- data/test/support/test_helper.rb +5 -0
- data/vendor/rack-1.0.0-git/lib/rack/auth/openid.rb +123 -116
- data/vendor/rack-1.0.0-git/lib/rack/cascade.rb +17 -12
- data/vendor/rack-1.0.0-git/lib/rack/commonlogger.rb +34 -43
- data/vendor/rack-1.0.0-git/lib/rack/handler/cgi.rb +1 -1
- data/vendor/rack-1.0.0-git/lib/rack/handler/fastcgi.rb +1 -1
- data/vendor/rack-1.0.0-git/lib/rack/handler/lsws.rb +1 -1
- data/vendor/rack-1.0.0-git/lib/rack/handler/mongrel.rb +1 -1
- data/vendor/rack-1.0.0-git/lib/rack/handler/scgi.rb +1 -1
- data/vendor/rack-1.0.0-git/lib/rack/handler/webrick.rb +1 -1
- data/vendor/rack-1.0.0-git/lib/rack/mock.rb +4 -17
- data/vendor/rack-1.0.0-git/lib/rack/request.rb +3 -9
- data/vendor/rack-1.0.0-git/lib/rack/rewindable_input.rb +2 -0
- data/vendor/rack-1.0.0-git/lib/rack/utils.rb +38 -12
- metadata +231 -186
- data/ext/common/FileChecker.h +0 -112
- data/test/FileCheckerTest.cpp +0 -79
- data/test/stub/minimal-railsapp/README +0 -3
- data/test/stub/minimal-railsapp/config/application.rb +0 -0
- data/test/stub/minimal-railsapp/config/environment.rb +0 -3
- data/test/stub/minimal-railsapp/vendor/rails/actionmailer/lib/action_mailer.rb +0 -0
- data/test/stub/minimal-railsapp/vendor/rails/actionpack/lib/action_controller.rb +0 -10
- data/test/stub/minimal-railsapp/vendor/rails/actionpack/lib/action_pack.rb +0 -0
- data/test/stub/minimal-railsapp/vendor/rails/actionpack/lib/action_view.rb +0 -0
- data/test/stub/minimal-railsapp/vendor/rails/activerecord/lib/active_record.rb +0 -7
- data/test/stub/minimal-railsapp/vendor/rails/activeresource/lib/active_resource.rb +0 -0
- data/test/stub/minimal-railsapp/vendor/rails/activesupport/lib/active_support.rb +0 -17
- data/test/stub/minimal-railsapp/vendor/rails/activesupport/lib/active_support/whiny_nil.rb +0 -0
- data/test/stub/minimal-railsapp/vendor/rails/railties/lib/dispatcher.rb +0 -0
- data/test/stub/minimal-railsapp/vendor/rails/railties/lib/initializer.rb +0 -8
- data/test/stub/minimal-railsapp/vendor/rails/railties/lib/ruby_version_check.rb +0 -1
- data/test/stub/railsapp/app/controllers/application.rb +0 -12
- data/test/stub/railsapp/app/controllers/bar_controller.rb +0 -5
- data/test/stub/railsapp/app/controllers/bar_controller_1.txt +0 -5
- data/test/stub/railsapp/app/controllers/bar_controller_2.txt +0 -5
- data/test/stub/railsapp/app/controllers/foo_controller.rb +0 -9
- data/test/stub/railsapp/app/helpers/application_helper.rb +0 -3
- data/test/stub/railsapp/config/boot.rb +0 -108
- data/test/stub/railsapp/config/database.yml +0 -19
- data/test/stub/railsapp/config/environment.rb +0 -59
- data/test/stub/railsapp/config/environments/development.rb +0 -18
- data/test/stub/railsapp/config/environments/production.rb +0 -19
- data/test/stub/railsapp/config/initializers/inflections.rb +0 -10
- data/test/stub/railsapp/config/initializers/mime_types.rb +0 -5
- data/test/stub/railsapp/config/routes.rb +0 -35
- data/test/stub/railsapp/public/useless.txt +0 -1
- data/test/stub/railsapp2/app/controllers/application.rb +0 -12
- data/test/stub/railsapp2/app/controllers/foo_controller.rb +0 -5
- data/test/stub/railsapp2/app/helpers/application_helper.rb +0 -3
- data/test/stub/railsapp2/config/boot.rb +0 -108
- data/test/stub/railsapp2/config/database.yml +0 -19
- data/test/stub/railsapp2/config/environment.rb +0 -59
- data/test/stub/railsapp2/config/environments/development.rb +0 -18
- data/test/stub/railsapp2/config/environments/production.rb +0 -19
- data/test/stub/railsapp2/config/initializers/inflections.rb +0 -10
- data/test/stub/railsapp2/config/initializers/mime_types.rb +0 -5
- data/test/stub/railsapp2/config/routes.rb +0 -35
- data/test/stub/railsapp2/public/useless.txt +0 -1
@@ -64,9 +64,9 @@ extern ngx_str_t passenger_helper_server_password;
|
|
64
64
|
extern const char passenger_helper_server_socket[NGX_MAX_PATH];
|
65
65
|
|
66
66
|
/**
|
67
|
-
* A
|
67
|
+
* A CachedFileStat object used for caching stat() calls.
|
68
68
|
*/
|
69
|
-
extern
|
69
|
+
extern CachedFileStat *passenger_stat_cache;
|
70
70
|
|
71
71
|
#endif /* _PASSENGER_NGINX_MODULE_H_ */
|
72
72
|
|
@@ -97,8 +97,6 @@ class AbstractRequestHandler
|
|
97
97
|
IGNORE = 'IGNORE' # :nodoc:
|
98
98
|
DEFAULT = 'DEFAULT' # :nodoc:
|
99
99
|
NULL = "\0" # :nodoc:
|
100
|
-
CONTENT_LENGTH = 'CONTENT_LENGTH' # :nodoc:
|
101
|
-
HTTP_CONTENT_LENGTH = 'HTTP_CONTENT_LENGTH' # :nodoc:
|
102
100
|
X_POWERED_BY = 'X-Powered-By' # :nodoc:
|
103
101
|
REQUEST_METHOD = 'REQUEST_METHOD' # :nodoc:
|
104
102
|
PING = 'ping' # :nodoc:
|
@@ -144,11 +142,13 @@ class AbstractRequestHandler
|
|
144
142
|
@socket.close_on_exec!
|
145
143
|
@owner_pipe = owner_pipe
|
146
144
|
@previous_signal_handlers = {}
|
145
|
+
@main_loop_generation = 0
|
147
146
|
@main_loop_thread_lock = Mutex.new
|
148
147
|
@main_loop_thread_cond = ConditionVariable.new
|
149
148
|
@memory_limit = options["memory_limit"] || 0
|
150
149
|
@iterations = 0
|
151
150
|
@processed_requests = 0
|
151
|
+
@main_loop_running = false
|
152
152
|
end
|
153
153
|
|
154
154
|
# Clean up temporary stuff created by the request handler.
|
@@ -160,7 +160,9 @@ class AbstractRequestHandler
|
|
160
160
|
# may be called at any time, and it will stop the main loop thread.
|
161
161
|
def cleanup
|
162
162
|
if @main_loop_thread
|
163
|
-
@
|
163
|
+
@main_loop_thread_lock.synchronize do
|
164
|
+
@graceful_termination_pipe[1].close rescue nil
|
165
|
+
end
|
164
166
|
@main_loop_thread.join
|
165
167
|
end
|
166
168
|
@socket.close rescue nil
|
@@ -182,6 +184,7 @@ class AbstractRequestHandler
|
|
182
184
|
@graceful_termination_pipe[1].close_on_exec!
|
183
185
|
|
184
186
|
@main_loop_thread_lock.synchronize do
|
187
|
+
@main_loop_generation += 1
|
185
188
|
@main_loop_running = true
|
186
189
|
@main_loop_thread_cond.broadcast
|
187
190
|
end
|
@@ -226,10 +229,11 @@ class AbstractRequestHandler
|
|
226
229
|
raise
|
227
230
|
end
|
228
231
|
ensure
|
229
|
-
@graceful_termination_pipe[0].close rescue nil
|
230
|
-
@graceful_termination_pipe[1].close rescue nil
|
231
232
|
revert_signal_handlers
|
232
233
|
@main_loop_thread_lock.synchronize do
|
234
|
+
@graceful_termination_pipe[0].close rescue nil
|
235
|
+
@graceful_termination_pipe[1].close rescue nil
|
236
|
+
@main_loop_generation += 1
|
233
237
|
@main_loop_running = false
|
234
238
|
@main_loop_thread_cond.broadcast
|
235
239
|
end
|
@@ -238,11 +242,12 @@ class AbstractRequestHandler
|
|
238
242
|
|
239
243
|
# Start the main loop in a new thread. This thread will be stopped by #cleanup.
|
240
244
|
def start_main_loop_thread
|
245
|
+
current_generation = @main_loop_generation
|
241
246
|
@main_loop_thread = Thread.new do
|
242
247
|
main_loop
|
243
248
|
end
|
244
249
|
@main_loop_thread_lock.synchronize do
|
245
|
-
while
|
250
|
+
while @main_loop_generation == current_generation
|
246
251
|
@main_loop_thread_cond.wait(@main_loop_thread_lock)
|
247
252
|
end
|
248
253
|
end
|
@@ -399,6 +404,10 @@ private
|
|
399
404
|
undef rewind if respond_to?(:rewind)
|
400
405
|
end
|
401
406
|
|
407
|
+
# Set encoding for Ruby 1.9 compatibility.
|
408
|
+
client.set_encoding(Encoding::BINARY) if client.respond_to?(:set_encoding)
|
409
|
+
client.binmode
|
410
|
+
|
402
411
|
return client
|
403
412
|
else
|
404
413
|
# The other end of the owner pipe has been closed, or the
|
@@ -422,7 +431,6 @@ private
|
|
422
431
|
return
|
423
432
|
end
|
424
433
|
headers = Hash[*headers_data.split(NULL)]
|
425
|
-
headers[CONTENT_LENGTH] = headers[HTTP_CONTENT_LENGTH]
|
426
434
|
return [headers, socket]
|
427
435
|
rescue SecurityError => e
|
428
436
|
STDERR.puts("*** Passenger RequestHandler: HTTP header size exceeded maximum.")
|
@@ -124,7 +124,7 @@ class AbstractServer
|
|
124
124
|
if started?
|
125
125
|
raise ServerAlreadyStarted, "Server is already started"
|
126
126
|
end
|
127
|
-
|
127
|
+
|
128
128
|
@parent_socket, @child_socket = UNIXSocket.pair
|
129
129
|
before_fork
|
130
130
|
@pid = fork
|
@@ -138,7 +138,12 @@ class AbstractServer
|
|
138
138
|
# on a white list of file descriptors. That proved to be way too fragile:
|
139
139
|
# too many file descriptors are being left open even though they shouldn't
|
140
140
|
# be. So now we close file descriptors based on a black list.
|
141
|
-
|
141
|
+
#
|
142
|
+
# Note that STDIN, STDOUT and STDERR may be temporarily set to
|
143
|
+
# different file descriptors than 0, 1 and 2, e.g. in unit tests.
|
144
|
+
# We don't want to close these either.
|
145
|
+
file_descriptors_to_leave_open = [0, 1, 2, @child_socket.fileno,
|
146
|
+
fileno_of(STDIN), fileno_of(STDOUT), fileno_of(STDERR)].compact.uniq
|
142
147
|
NativeSupport.close_all_file_descriptors(file_descriptors_to_leave_open)
|
143
148
|
# In addition to closing the file descriptors, one must also close
|
144
149
|
# the associated IO objects. This is to prevent IO.close from
|
@@ -151,6 +156,9 @@ class AbstractServer
|
|
151
156
|
# clear all open file handles.
|
152
157
|
Gem.clear_paths
|
153
158
|
|
159
|
+
# Reseed pseudo-random number generator for security reasons.
|
160
|
+
srand
|
161
|
+
|
154
162
|
start_synchronously(@child_socket)
|
155
163
|
rescue Interrupt
|
156
164
|
# Do nothing.
|
@@ -292,6 +300,12 @@ protected
|
|
292
300
|
def quit_main
|
293
301
|
@done = true
|
294
302
|
end
|
303
|
+
|
304
|
+
def fileno_of(io)
|
305
|
+
return io.fileno
|
306
|
+
rescue
|
307
|
+
return nil
|
308
|
+
end
|
295
309
|
|
296
310
|
private
|
297
311
|
# Reset all signal handlers to default. This is called in the child process,
|
@@ -23,6 +23,7 @@
|
|
23
23
|
|
24
24
|
require 'rexml/document'
|
25
25
|
require 'fileutils'
|
26
|
+
require 'socket'
|
26
27
|
require 'phusion_passenger/admin_tools'
|
27
28
|
require 'phusion_passenger/message_channel'
|
28
29
|
|
@@ -79,37 +80,30 @@ class ControlProcess
|
|
79
80
|
end
|
80
81
|
|
81
82
|
def status
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
def xml
|
87
|
-
reload
|
88
|
-
return @xml
|
83
|
+
connect do |channel|
|
84
|
+
channel.write("status")
|
85
|
+
return channel.read_scalar
|
86
|
+
end
|
89
87
|
end
|
90
88
|
|
91
|
-
def
|
92
|
-
|
93
|
-
|
89
|
+
def backtraces
|
90
|
+
connect do |channel|
|
91
|
+
channel.write("backtraces")
|
92
|
+
return channel.read_scalar
|
93
|
+
end
|
94
94
|
end
|
95
95
|
|
96
|
-
def
|
97
|
-
|
98
|
-
|
99
|
-
|
96
|
+
def xml
|
97
|
+
connect do |channel|
|
98
|
+
channel.write("status_xml")
|
99
|
+
return channel.read_scalar
|
100
|
+
end
|
100
101
|
end
|
101
102
|
|
102
|
-
|
103
|
-
|
104
|
-
return if @status
|
105
|
-
File.open("#{path}/info/status.fifo", 'r') do |f|
|
106
|
-
channel = MessageChannel.new(f)
|
107
|
-
@status = channel.read_scalar
|
108
|
-
@xml = channel.read_scalar
|
109
|
-
end
|
110
|
-
doc = REXML::Document.new(@xml)
|
103
|
+
def domains
|
104
|
+
doc = REXML::Document.new(xml)
|
111
105
|
|
112
|
-
|
106
|
+
domains = []
|
113
107
|
doc.elements.each("info/domains/domain") do |domain|
|
114
108
|
instances = []
|
115
109
|
d = {
|
@@ -130,7 +124,24 @@ private
|
|
130
124
|
end
|
131
125
|
instances << i
|
132
126
|
end
|
133
|
-
|
127
|
+
domains << d
|
128
|
+
end
|
129
|
+
return domains
|
130
|
+
end
|
131
|
+
|
132
|
+
def instances
|
133
|
+
return domains.map do |domain|
|
134
|
+
domain[:instances]
|
135
|
+
end.flatten
|
136
|
+
end
|
137
|
+
|
138
|
+
private
|
139
|
+
def connect
|
140
|
+
channel = MessageChannel.new(UNIXSocket.new("#{path}/info/status.socket"))
|
141
|
+
begin
|
142
|
+
yield channel
|
143
|
+
ensure
|
144
|
+
channel.close
|
134
145
|
end
|
135
146
|
end
|
136
147
|
end
|
@@ -24,7 +24,7 @@
|
|
24
24
|
module PhusionPassenger
|
25
25
|
# Phusion Passenger version number.
|
26
26
|
# Don't forget to edit ext/common/Version.h too.
|
27
|
-
VERSION_STRING = '2.2.
|
27
|
+
VERSION_STRING = '2.2.3'
|
28
28
|
|
29
29
|
DEFAULT_FRAMEWORK_SPAWNER_MAX_IDLE_TIME = 30 * 60
|
30
30
|
DEFAULT_APP_SPAWNER_MAX_IDLE_TIME = 10 * 60
|
@@ -296,6 +296,16 @@ module Dependencies # :nodoc: all
|
|
296
296
|
result.found(PlatformInfo.apu_config)
|
297
297
|
end
|
298
298
|
end
|
299
|
+
if RUBY_PLATFORM =~ /linux/
|
300
|
+
case PlatformInfo.linux_distro
|
301
|
+
when :ubuntu, :debian
|
302
|
+
dep.install_command = "apt-get install libaprutil1-dev"
|
303
|
+
end
|
304
|
+
elsif RUBY_PLATFORM =~ /darwin/
|
305
|
+
dep.install_instructions = "Please install Apache from MacPorts, which will " <<
|
306
|
+
"provide APU automatically. <b>Or</b>, if you're installing against MacOS X's " <<
|
307
|
+
"default provided Apache, then please install the OS X Developer SDK."
|
308
|
+
end
|
299
309
|
dep.website = "http://httpd.apache.org/"
|
300
310
|
dep.website_comments = "APR Utility is an integrated part of Apache."
|
301
311
|
end
|
@@ -339,7 +339,7 @@ public
|
|
339
339
|
# _GLIBCPP__PTHREADS is for fixing Boost compilation on OpenBSD.
|
340
340
|
flags = ["-D_REENTRANT -I/usr/local/include"]
|
341
341
|
if RUBY_PLATFORM =~ /solaris/
|
342
|
-
flags << '-D_XOPEN_SOURCE=500 -D_XPG4_2 -D__EXTENSIONS__ -D__SOLARIS__'
|
342
|
+
flags << '-D_XOPEN_SOURCE=500 -D_XPG4_2 -D__EXTENSIONS__ -D__SOLARIS__ -D_FILE_OFFSET_BITS=64'
|
343
343
|
flags << '-DBOOST_HAS_STDINT_H' unless RUBY_PLATFORM =~ /solaris2.9/
|
344
344
|
flags << '-D__SOLARIS9__ -DBOOST__STDC_CONSTANT_MACROS_DEFINED' if RUBY_PLATFORM =~ /solaris2.9/
|
345
345
|
flags << '-mcpu=ultrasparc' if RUBY_PLATFORM =~ /sparc/
|
@@ -49,6 +49,8 @@ class ApplicationSpawner
|
|
49
49
|
# Application object will be returned, which represents the spawned
|
50
50
|
# application.
|
51
51
|
#
|
52
|
+
# Accepts the same options as Railz::ApplicationSpawner#initialize.
|
53
|
+
#
|
52
54
|
# Raises:
|
53
55
|
# - AppInitError: The Rack application raised an exception or called
|
54
56
|
# exit() during startup.
|
@@ -70,7 +72,7 @@ class ApplicationSpawner
|
|
70
72
|
Process.waitpid(pid) rescue nil
|
71
73
|
|
72
74
|
channel = MessageChannel.new(a)
|
73
|
-
unmarshal_and_raise_errors(channel, "rack")
|
75
|
+
unmarshal_and_raise_errors(channel, !!options["print_exceptions"], "rack")
|
74
76
|
|
75
77
|
# No exception was raised, so spawning succeeded.
|
76
78
|
pid, socket_name, socket_type = channel.read
|
@@ -83,13 +85,19 @@ class ApplicationSpawner
|
|
83
85
|
end
|
84
86
|
|
85
87
|
private
|
86
|
-
|
87
88
|
def run(channel, app_root, options)
|
88
89
|
$0 = "Rack: #{app_root}"
|
89
90
|
app = nil
|
90
91
|
success = report_app_init_status(channel) do
|
91
92
|
ENV['RACK_ENV'] = options["environment"]
|
93
|
+
if options["base_uri"] && options["base_uri"] != "/"
|
94
|
+
ENV['RACK_BASE_URI'] = options["base_uri"]
|
95
|
+
ENV['RAILS_RELATIVE_URL_ROOT'] = options["base_uri"]
|
96
|
+
end
|
92
97
|
Dir.chdir(app_root)
|
98
|
+
if options["environment_variables"]
|
99
|
+
set_passed_environment_variables(options["environment_variables"])
|
100
|
+
end
|
93
101
|
if options["lower_privilege"]
|
94
102
|
lower_privilege('config.ru', options["lowest_user"])
|
95
103
|
end
|
@@ -116,6 +124,17 @@ private
|
|
116
124
|
end
|
117
125
|
end
|
118
126
|
end
|
127
|
+
|
128
|
+
def set_passed_environment_variables(encoded_environment_variables)
|
129
|
+
env_vars_string = encoded_environment_variables.unpack("m").first
|
130
|
+
# Prevent empty string as last item from b0rking the Hash[...] statement.
|
131
|
+
# See comment in Hooks.cpp (sendHeaders) for details.
|
132
|
+
env_vars_string << "_\0_"
|
133
|
+
env_vars = Hash[*env_vars_string.split("\0")]
|
134
|
+
env_vars.each_pair do |key, value|
|
135
|
+
ENV[key] = value
|
136
|
+
end
|
137
|
+
end
|
119
138
|
|
120
139
|
def load_rack_app
|
121
140
|
rackup_code = ::File.read("config.ru")
|
@@ -45,6 +45,9 @@ class RequestHandler < AbstractRequestHandler
|
|
45
45
|
PATH_INFO = "PATH_INFO" # :nodoc:
|
46
46
|
REQUEST_URI = "REQUEST_URI" # :nodoc:
|
47
47
|
QUESTION_MARK = "?" # :nodoc:
|
48
|
+
QUERY_STRING = "QUERY_STRING" # :nodoc:
|
49
|
+
CONTENT_LENGTH = "CONTENT_LENGTH" # :nodoc:
|
50
|
+
HTTP_CONTENT_LENGTH = "HTTP_CONTENT_LENGTH" # :nodoc:
|
48
51
|
HTTPS = "HTTPS" # :nodoc:
|
49
52
|
HTTPS_DOWNCASE = "https" # :nodoc:
|
50
53
|
HTTP = "http" # :nodoc:
|
@@ -70,8 +73,15 @@ protected
|
|
70
73
|
env[RACK_MULTITHREAD] = false
|
71
74
|
env[RACK_MULTIPROCESS] = true
|
72
75
|
env[RACK_RUN_ONCE] = false
|
76
|
+
env[QUERY_STRING] ||= ""
|
73
77
|
env[PATH_INFO] ||= env[REQUEST_URI].split(QUESTION_MARK, 2).first
|
74
78
|
env[PATH_INFO].sub!(/^#{Regexp.escape(env[SCRIPT_NAME])}/, "")
|
79
|
+
if env[HTTP_CONTENT_LENGTH] && env[CONTENT_LENGTH]
|
80
|
+
env.delete(HTTP_CONTENT_LENGTH)
|
81
|
+
elsif env[HTTP_CONTENT_LENGTH] && !env[CONTENT_LENGTH]
|
82
|
+
env[CONTENT_LENGTH] = env[HTTP_CONTENT_LENGTH]
|
83
|
+
env.delete(HTTP_CONTENT_LENGTH)
|
84
|
+
end
|
75
85
|
if env[HTTPS] == YES || env[HTTPS] == ON || env[HTTPS] == ONE
|
76
86
|
env[RACK_URL_SCHEME] = HTTPS_DOWNCASE
|
77
87
|
else
|
@@ -84,6 +84,20 @@ class ApplicationSpawner < AbstractServer
|
|
84
84
|
# - +environment+:
|
85
85
|
# Allows one to specify the RAILS_ENV environment to use.
|
86
86
|
#
|
87
|
+
# - +environment_variables+:
|
88
|
+
# Environment variables which should be passed to the spawned application.
|
89
|
+
# This is NULL-seperated string of key-value pairs, encoded in base64.
|
90
|
+
# The last byte in the unencoded data must be a NULL.
|
91
|
+
#
|
92
|
+
# - +base_uri+:
|
93
|
+
# The base URI on which this application is deployed. It equals "/"
|
94
|
+
# string if the application is deployed on the root URI. It must not
|
95
|
+
# equal the empty string.
|
96
|
+
#
|
97
|
+
# - +print_exceptions+:
|
98
|
+
# Whether exceptions that have occurred during application initialization
|
99
|
+
# should be printed to STDERR. The default is true.
|
100
|
+
#
|
87
101
|
# All other options will be passed on to RequestHandler.
|
88
102
|
def initialize(app_root, options = {})
|
89
103
|
super()
|
@@ -93,6 +107,9 @@ class ApplicationSpawner < AbstractServer
|
|
93
107
|
@lower_privilege = @options["lower_privilege"]
|
94
108
|
@lowest_user = @options["lowest_user"]
|
95
109
|
@environment = @options["environment"]
|
110
|
+
@encoded_environment_variables = @options["environment_variables"]
|
111
|
+
@base_uri = @options["base_uri"] if @options["base_uri"] && @options["base_uri"] != "/"
|
112
|
+
@print_exceptions = @options["print_exceptions"]
|
96
113
|
self.max_idle_time = DEFAULT_APP_SPAWNER_MAX_IDLE_TIME
|
97
114
|
assert_valid_app_root(@app_root)
|
98
115
|
define_message_handler(:spawn_application, :handle_spawn_application)
|
@@ -144,7 +161,11 @@ class ApplicationSpawner < AbstractServer
|
|
144
161
|
channel = MessageChannel.new(b)
|
145
162
|
success = report_app_init_status(channel) do
|
146
163
|
ENV['RAILS_ENV'] = @environment
|
164
|
+
ENV['RAILS_RELATIVE_URL_ROOT'] = @base_uri
|
147
165
|
Dir.chdir(@app_root)
|
166
|
+
if @encoded_environment_variables
|
167
|
+
set_passed_environment_variables
|
168
|
+
end
|
148
169
|
if @lower_privilege
|
149
170
|
lower_privilege('config/environment.rb', @lowest_user)
|
150
171
|
end
|
@@ -170,7 +191,7 @@ class ApplicationSpawner < AbstractServer
|
|
170
191
|
Process.waitpid(pid) rescue nil
|
171
192
|
|
172
193
|
channel = MessageChannel.new(a)
|
173
|
-
unmarshal_and_raise_errors(channel)
|
194
|
+
unmarshal_and_raise_errors(channel, @print_exceptions)
|
174
195
|
|
175
196
|
# No exception was raised, so spawning succeeded.
|
176
197
|
pid, socket_name, socket_type = channel.read
|
@@ -191,7 +212,7 @@ class ApplicationSpawner < AbstractServer
|
|
191
212
|
def start
|
192
213
|
super
|
193
214
|
begin
|
194
|
-
unmarshal_and_raise_errors(server)
|
215
|
+
unmarshal_and_raise_errors(server, @print_exceptions)
|
195
216
|
rescue IOError, SystemCallError, SocketError => e
|
196
217
|
stop
|
197
218
|
raise Error, "The application spawner server exited unexpectedly: #{e}"
|
@@ -216,11 +237,15 @@ protected
|
|
216
237
|
report_app_init_status(client) do
|
217
238
|
$0 = "Passenger ApplicationSpawner: #{@app_root}"
|
218
239
|
ENV['RAILS_ENV'] = @environment
|
240
|
+
ENV['RAILS_RELATIVE_URL_ROOT'] = @base_uri
|
219
241
|
if defined?(RAILS_ENV)
|
220
242
|
Object.send(:remove_const, :RAILS_ENV)
|
221
243
|
Object.const_set(:RAILS_ENV, ENV['RAILS_ENV'])
|
222
244
|
end
|
223
245
|
Dir.chdir(@app_root)
|
246
|
+
if @encoded_environment_variables
|
247
|
+
set_passed_environment_variables
|
248
|
+
end
|
224
249
|
if @lower_privilege
|
225
250
|
lower_privilege('config/environment.rb', @lowest_user)
|
226
251
|
end
|
@@ -229,6 +254,17 @@ protected
|
|
229
254
|
end
|
230
255
|
|
231
256
|
private
|
257
|
+
def set_passed_environment_variables
|
258
|
+
env_vars_string = @encoded_environment_variables.unpack("m").first
|
259
|
+
# Prevent empty string as last item from b0rking the Hash[...] statement.
|
260
|
+
# See comment in Hooks.cpp (sendHeaders) for details.
|
261
|
+
env_vars_string << "_\0_"
|
262
|
+
env_vars = Hash[*env_vars_string.split("\0")]
|
263
|
+
env_vars.each_pair do |key, value|
|
264
|
+
ENV[key] = value
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
232
268
|
def preload_application
|
233
269
|
Object.const_set(:RAILS_ROOT, @canonicalized_app_root)
|
234
270
|
if defined?(::Rails::Initializer)
|
@@ -58,6 +58,9 @@ class FrameworkSpawner < AbstractServer
|
|
58
58
|
# this version is actually installed.
|
59
59
|
# - <tt>:vendor</tt>: The directory to the vendor Rails framework to use. This is
|
60
60
|
# usually something like "/webapps/foo/vendor/rails".
|
61
|
+
# - <tt>:print_framework_loading_exceptions</tt>:
|
62
|
+
# Whether exceptions that have occurred while loading the Ruby on Rails framework
|
63
|
+
# should be printed to STDERR. The default is true.
|
61
64
|
#
|
62
65
|
# It is not allowed to specify both +version+ and +vendor+.
|
63
66
|
#
|
@@ -72,6 +75,11 @@ class FrameworkSpawner < AbstractServer
|
|
72
75
|
end
|
73
76
|
@version = options[:version]
|
74
77
|
@vendor = options[:vendor]
|
78
|
+
if options.has_key?(:print_framework_loading_exceptions)
|
79
|
+
@print_framework_loading_exceptions = options[:print_framework_loading_exceptions]
|
80
|
+
else
|
81
|
+
@print_framework_loading_exceptions = true
|
82
|
+
end
|
75
83
|
if !@version && !@vendor
|
76
84
|
raise ArgumentError, "Either the 'version' or the 'vendor' option must specified"
|
77
85
|
elsif @version && @vendor
|
@@ -87,7 +95,7 @@ class FrameworkSpawner < AbstractServer
|
|
87
95
|
# Overrided from AbstractServer#start.
|
88
96
|
#
|
89
97
|
# May raise these additional exceptions:
|
90
|
-
# - FrameworkInitError:
|
98
|
+
# - FrameworkInitError: An error occurred while loading the specified Ruby on Rails framework.
|
91
99
|
# - FrameworkSpawner::Error: The FrameworkSpawner server exited unexpectedly.
|
92
100
|
def start
|
93
101
|
super
|
@@ -109,6 +117,9 @@ class FrameworkSpawner < AbstractServer
|
|
109
117
|
"#{child_exception.class} (#{child_exception.message})"
|
110
118
|
end
|
111
119
|
options = { :vendor => @vendor, :version => @version }
|
120
|
+
if @print_framework_loading_exceptions
|
121
|
+
print_exception(self.class.to_s, child_exception)
|
122
|
+
end
|
112
123
|
raise FrameworkInitError.new(message, child_exception, options)
|
113
124
|
end
|
114
125
|
rescue IOError, SystemCallError, SocketError
|
@@ -122,23 +133,7 @@ class FrameworkSpawner < AbstractServer
|
|
122
133
|
# When successful, an Application object will be returned, which represents
|
123
134
|
# the spawned RoR application.
|
124
135
|
#
|
125
|
-
#
|
126
|
-
# - +lower_privilege+ and +lowest_user+:
|
127
|
-
# If +lower_privilege+ is true, then ApplicationSpawner will attempt to
|
128
|
-
# switch to the user who owns the application's <tt>config/environment.rb</tt>,
|
129
|
-
# and to the default group of that user.
|
130
|
-
#
|
131
|
-
# If that user doesn't exist on the system, or if that user is root,
|
132
|
-
# then ApplicationSpawner will attempt to switch to the username given by
|
133
|
-
# +lowest_user+ (and to the default group of that user).
|
134
|
-
# If +lowest_user+ doesn't exist either, or if switching user failed
|
135
|
-
# (because the current process does not have the privilege to do so),
|
136
|
-
# then ApplicationSpawner will continue without reporting an error.
|
137
|
-
#
|
138
|
-
# - +environment+:
|
139
|
-
# Allows one to specify the RAILS_ENV environment to use.
|
140
|
-
#
|
141
|
-
# All other options will be passed on to ApplicationSpawner and RequestHandler.
|
136
|
+
# All options accepted by ApplicationSpawner.new and RequestHandler.new are accepted.
|
142
137
|
#
|
143
138
|
# FrameworkSpawner will internally cache the code of applications, in order to
|
144
139
|
# speed up future spawning attempts. This implies that, if you've changed
|
@@ -148,7 +143,7 @@ class FrameworkSpawner < AbstractServer
|
|
148
143
|
#
|
149
144
|
# Raises:
|
150
145
|
# - AbstractServer::ServerNotStarted: The FrameworkSpawner server hasn't already been started.
|
151
|
-
# -
|
146
|
+
# - InvalidPath: +app_root+ doesn't appear to be a valid Ruby on Rails application root.
|
152
147
|
# - AppInitError: The application raised an exception or called exit() during startup.
|
153
148
|
# - ApplicationSpawner::Error: The ApplicationSpawner server exited unexpectedly.
|
154
149
|
# - FrameworkSpawner::Error: The FrameworkSpawner server exited unexpectedly.
|
@@ -156,8 +151,12 @@ class FrameworkSpawner < AbstractServer
|
|
156
151
|
assert_valid_app_root(app_root)
|
157
152
|
options = sanitize_spawn_options(options)
|
158
153
|
options["app_root"] = app_root
|
154
|
+
# No need for the ApplicationSpawner to print exceptions. All
|
155
|
+
# exceptions raised by the ApplicationSpawner are sent back here,
|
156
|
+
# so we just need to decide here whether we want to print it.
|
157
|
+
print_exceptions = options["print_exceptions"]
|
158
|
+
options["print_exceptions"] = false
|
159
159
|
|
160
|
-
exception_to_propagate = nil
|
161
160
|
begin
|
162
161
|
server.write("spawn_application", *options.to_a.flatten)
|
163
162
|
result = server.read
|
@@ -166,8 +165,10 @@ class FrameworkSpawner < AbstractServer
|
|
166
165
|
end
|
167
166
|
if result[0] == 'exception'
|
168
167
|
e = unmarshal_exception(server.read_scalar)
|
169
|
-
if e.respond_to?(:child_exception) && e.child_exception
|
170
|
-
|
168
|
+
if print_exceptions && e.respond_to?(:child_exception) && e.child_exception
|
169
|
+
print_exception(self.class.to_s, e.child_exception)
|
170
|
+
elsif print_exceptions
|
171
|
+
print_exception(self.class.to_s, e)
|
171
172
|
end
|
172
173
|
raise e
|
173
174
|
else
|
@@ -276,10 +277,7 @@ private
|
|
276
277
|
end
|
277
278
|
|
278
279
|
def handle_spawn_application(*options)
|
279
|
-
options = Hash[*options]
|
280
|
-
options["lower_privilege"] = options["lower_privilege"] == "true"
|
281
|
-
options["app_spawner_timeout"] = options["app_spawner_timeout"].to_i
|
282
|
-
options["memory_limit"] = options["memory_limit"].to_i
|
280
|
+
options = sanitize_spawn_options(Hash[*options])
|
283
281
|
|
284
282
|
app = nil
|
285
283
|
app_root = options["app_root"]
|
@@ -293,10 +291,10 @@ private
|
|
293
291
|
spawner.start
|
294
292
|
spawner
|
295
293
|
end
|
296
|
-
rescue
|
294
|
+
rescue InvalidPath, AppInitError, ApplicationSpawner::Error => e
|
297
295
|
client.write('exception')
|
298
296
|
client.write_scalar(marshal_exception(e))
|
299
|
-
if e.child_exception.is_a?(LoadError)
|
297
|
+
if e.respond_to?(:child_exception) && e.child_exception.is_a?(LoadError)
|
300
298
|
# A source file failed to load, maybe because of a
|
301
299
|
# missing gem. If that's the case then the sysadmin
|
302
300
|
# will install probably the gem. So we clear RubyGems's
|