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
@@ -28,7 +28,10 @@ module Railz
|
|
28
28
|
|
29
29
|
# A request handler for Ruby on Rails applications.
|
30
30
|
class RequestHandler < AbstractRequestHandler
|
31
|
-
|
31
|
+
CONTENT_LENGTH = 'CONTENT_LENGTH' # :nodoc:
|
32
|
+
HTTP_CONTENT_LENGTH = 'HTTP_CONTENT_LENGTH' # :nodoc:
|
33
|
+
|
34
|
+
NINJA_PATCHING_LOCK = Mutex.new # :nodoc:
|
32
35
|
@@ninja_patched_action_controller = false
|
33
36
|
|
34
37
|
def initialize(owner_pipe, options = {})
|
@@ -41,6 +44,7 @@ class RequestHandler < AbstractRequestHandler
|
|
41
44
|
protected
|
42
45
|
# Overrided method.
|
43
46
|
def process_request(headers, input, output)
|
47
|
+
headers[CONTENT_LENGTH] = headers[HTTP_CONTENT_LENGTH]
|
44
48
|
cgi = CGIFixed.new(headers, input, output)
|
45
49
|
::Dispatcher.dispatch(cgi,
|
46
50
|
::ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS,
|
@@ -97,7 +97,7 @@ class SpawnManager < AbstractServer
|
|
97
97
|
#
|
98
98
|
# Other options are:
|
99
99
|
#
|
100
|
-
# ['lower_privilege', 'lowest_user' and '
|
100
|
+
# ['lower_privilege', 'lowest_user', 'environment', 'environment_variables', 'base_uri' and 'print_exceptions']
|
101
101
|
# See Railz::ApplicationSpawner.new for an explanation of these options.
|
102
102
|
#
|
103
103
|
# ['app_type']
|
@@ -234,7 +234,11 @@ private
|
|
234
234
|
else
|
235
235
|
key = "version:#{framework_version}"
|
236
236
|
create_spawner = proc do
|
237
|
-
|
237
|
+
framework_options = { :version => framework_version }
|
238
|
+
if options.has_key?(:print_framework_loading_exceptions)
|
239
|
+
framework_options[:print_framework_loading_exceptions] = options[:print_framework_loading_exceptions]
|
240
|
+
end
|
241
|
+
Railz::FrameworkSpawner.new(framework_options)
|
238
242
|
end
|
239
243
|
spawner_timeout = options["framework_spawner_timeout"]
|
240
244
|
end
|
@@ -154,10 +154,10 @@ protected
|
|
154
154
|
#
|
155
155
|
# +current_location+ is a string which describes where the code is
|
156
156
|
# currently at. Usually the current class name will be enough.
|
157
|
-
def print_exception(current_location, exception)
|
157
|
+
def print_exception(current_location, exception, destination = STDERR)
|
158
158
|
if !exception.is_a?(SystemExit)
|
159
|
-
|
160
|
-
|
159
|
+
destination.puts(exception.backtrace_string(current_location))
|
160
|
+
destination.flush if destination.respond_to?(:flush)
|
161
161
|
end
|
162
162
|
end
|
163
163
|
|
@@ -178,9 +178,11 @@ protected
|
|
178
178
|
if double_fork
|
179
179
|
pid2 = fork
|
180
180
|
if pid2.nil?
|
181
|
+
srand
|
181
182
|
yield
|
182
183
|
end
|
183
184
|
else
|
185
|
+
srand
|
184
186
|
yield
|
185
187
|
end
|
186
188
|
rescue Exception => e
|
@@ -201,9 +203,21 @@ protected
|
|
201
203
|
# Run the given block. A message will be sent through +channel+ (a
|
202
204
|
# MessageChannel object), telling the remote side whether the block
|
203
205
|
# raised an exception, called exit(), or succeeded.
|
204
|
-
#
|
205
|
-
#
|
206
|
-
|
206
|
+
#
|
207
|
+
# Anything written to $stderr and STDERR during execution of the block
|
208
|
+
# will be buffered. If <tt>write_stderr_contents_to</tt> is non-nil,
|
209
|
+
# then the buffered stderr data will be written to this object. In this
|
210
|
+
# case, <tt>write_stderr_contents_to</tt> must be an IO-like object.
|
211
|
+
# If <tt>write_stderr_contents_to</tt> is nil, then the stder data will
|
212
|
+
# be discarded.
|
213
|
+
#
|
214
|
+
# Returns whether the block succeeded, i.e. whether it didn't raise an
|
215
|
+
# exception.
|
216
|
+
#
|
217
|
+
# Exceptions are not propagated, except SystemExit and a few
|
218
|
+
# non-StandardExeption classes such as SignalException. Of the
|
219
|
+
# exceptions that are propagated, only SystemExit will be reported.
|
220
|
+
def report_app_init_status(channel, write_stderr_contents_to = STDERR)
|
207
221
|
begin
|
208
222
|
old_global_stderr = $stderr
|
209
223
|
old_stderr = STDERR
|
@@ -218,10 +232,13 @@ protected
|
|
218
232
|
Object.send(:remove_const, 'STDERR') rescue nil
|
219
233
|
Object.const_set('STDERR', old_stderr)
|
220
234
|
$stderr = old_global_stderr
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
235
|
+
tempfile.rewind
|
236
|
+
stderr_output = tempfile.read
|
237
|
+
tempfile.close rescue nil
|
238
|
+
|
239
|
+
if write_stderr_contents_to
|
240
|
+
write_stderr_contents_to.write(stderr_output)
|
241
|
+
write_stderr_contents_to.flush
|
225
242
|
end
|
226
243
|
end
|
227
244
|
channel.write('success')
|
@@ -247,10 +264,24 @@ protected
|
|
247
264
|
# received information, then an appropriate exception will be
|
248
265
|
# raised.
|
249
266
|
#
|
267
|
+
# If <tt>print_exception</tt> evaluates to true, then the
|
268
|
+
# exception message and the backtrace will also be printed.
|
269
|
+
# Where it is printed to depends on the type of
|
270
|
+
# <tt>print_exception</tt>:
|
271
|
+
# - If it responds to #puts, then the exception information will
|
272
|
+
# be printed using this method.
|
273
|
+
# - If it responds to #to_str, then the exception information
|
274
|
+
# will be appended to the file whose filename equals the return
|
275
|
+
# value of the #to_str call.
|
276
|
+
# - Otherwise, it will be printed to STDERR.
|
277
|
+
#
|
250
278
|
# Raises:
|
251
|
-
# - AppInitError
|
252
|
-
#
|
253
|
-
|
279
|
+
# - AppInitError: this class wraps the exception information
|
280
|
+
# received through the channel.
|
281
|
+
# - IOError, SystemCallError, SocketError: these errors are
|
282
|
+
# raised if an error occurred while receiving the information
|
283
|
+
# through the channel.
|
284
|
+
def unmarshal_and_raise_errors(channel, print_exception = nil, app_type = "rails")
|
254
285
|
args = channel.read
|
255
286
|
if args.nil?
|
256
287
|
raise EOFError, "Unexpected end-of-file detected."
|
@@ -259,8 +290,7 @@ protected
|
|
259
290
|
if status == 'exception'
|
260
291
|
child_exception = unmarshal_exception(channel.read_scalar)
|
261
292
|
stderr = channel.read_scalar
|
262
|
-
|
263
|
-
raise AppInitError.new(
|
293
|
+
exception = AppInitError.new(
|
264
294
|
"Application '#{@app_root}' raised an exception: " <<
|
265
295
|
"#{child_exception.class} (#{child_exception.message})",
|
266
296
|
child_exception,
|
@@ -269,9 +299,25 @@ protected
|
|
269
299
|
elsif status == 'exit'
|
270
300
|
child_exception = unmarshal_exception(channel.read_scalar)
|
271
301
|
stderr = channel.read_scalar
|
272
|
-
|
302
|
+
exception = AppInitError.new("Application '#{@app_root}' exited during startup",
|
273
303
|
child_exception, app_type, stderr.empty? ? nil : stderr)
|
304
|
+
else
|
305
|
+
exception = nil
|
306
|
+
end
|
307
|
+
|
308
|
+
if print_exception && exception
|
309
|
+
if print_exception.respond_to?(:puts)
|
310
|
+
print_exception(self.class.to_s, child_exception, print_exception)
|
311
|
+
elsif print_exception.respond_to?(:to_str)
|
312
|
+
filename = print_exception.to_str
|
313
|
+
File.open(filename, 'a') do |f|
|
314
|
+
print_exception(self.class.to_s, child_exception, f)
|
315
|
+
end
|
316
|
+
else
|
317
|
+
print_exception(self.class.to_s, child_exception)
|
318
|
+
end
|
274
319
|
end
|
320
|
+
raise exception if exception
|
275
321
|
end
|
276
322
|
|
277
323
|
# Lower the current process's privilege to the owner of the given file.
|
@@ -320,6 +366,10 @@ protected
|
|
320
366
|
end
|
321
367
|
end
|
322
368
|
|
369
|
+
def to_boolean(value)
|
370
|
+
return !(value.nil? || value == false || value == "false")
|
371
|
+
end
|
372
|
+
|
323
373
|
def sanitize_spawn_options(options)
|
324
374
|
defaults = {
|
325
375
|
"lower_privilege" => true,
|
@@ -328,12 +378,15 @@ protected
|
|
328
378
|
"app_type" => "rails",
|
329
379
|
"spawn_method" => "smart-lv2",
|
330
380
|
"framework_spawner_timeout" => -1,
|
331
|
-
"app_spawner_timeout" => -1
|
381
|
+
"app_spawner_timeout" => -1,
|
382
|
+
"print_exceptions" => true
|
332
383
|
}
|
333
384
|
options = defaults.merge(options)
|
334
|
-
options["lower_privilege"] = options["lower_privilege"]
|
385
|
+
options["lower_privilege"] = to_boolean(options["lower_privilege"])
|
335
386
|
options["framework_spawner_timeout"] = options["framework_spawner_timeout"].to_i
|
336
387
|
options["app_spawner_timeout"] = options["app_spawner_timeout"].to_i
|
388
|
+
# Force this to be a boolean for easy use with Utils#unmarshal_and_raise_errors.
|
389
|
+
options["print_exceptions"] = to_boolean(options["print_exceptions"])
|
337
390
|
return options
|
338
391
|
end
|
339
392
|
|
@@ -367,6 +420,8 @@ protected
|
|
367
420
|
def self.passenger_tmpdir=(dir)
|
368
421
|
@@passenger_tmpdir = dir
|
369
422
|
end
|
423
|
+
|
424
|
+
####################################
|
370
425
|
end
|
371
426
|
|
372
427
|
end # module PhusionPassenger
|
@@ -479,16 +534,13 @@ end
|
|
479
534
|
module Signal
|
480
535
|
# Like Signal.list, but only returns signals that we can actually trap.
|
481
536
|
def self.list_trappable
|
482
|
-
ruby_engine = defined?(RUBY_ENGINE) ? RUBY_ENGINE : "
|
537
|
+
ruby_engine = defined?(RUBY_ENGINE) ? RUBY_ENGINE : "ruby"
|
483
538
|
case ruby_engine
|
484
|
-
when "
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
result.delete("ALRM")
|
490
|
-
return result
|
491
|
-
end
|
539
|
+
when "ruby"
|
540
|
+
result = Signal.list
|
541
|
+
result.delete("ALRM")
|
542
|
+
result.delete("VTALRM")
|
543
|
+
return result
|
492
544
|
when "jruby"
|
493
545
|
result = Signal.list
|
494
546
|
result.delete("QUIT")
|
data/misc/rake/cplusplus.rb
CHANGED
@@ -23,11 +23,11 @@
|
|
23
23
|
|
24
24
|
# Rake functions for compiling/linking C++ stuff.
|
25
25
|
|
26
|
-
def compile_c(source, flags =
|
27
|
-
sh "#{
|
26
|
+
def compile_c(source, flags = "#{PlatformInfo.portability_cflags} #{EXTRA_CXXFLAGS}")
|
27
|
+
sh "#{CC} #{flags} -c #{source}"
|
28
28
|
end
|
29
29
|
|
30
|
-
def compile_cxx(source, flags =
|
30
|
+
def compile_cxx(source, flags = "#{PlatformInfo.portability_cflags} #{EXTRA_CXXFLAGS}")
|
31
31
|
sh "#{CXX} #{flags} -c #{source}"
|
32
32
|
end
|
33
33
|
|
@@ -43,11 +43,11 @@ def create_static_library(target, sources)
|
|
43
43
|
sh "ranlib #{target}"
|
44
44
|
end
|
45
45
|
|
46
|
-
def create_executable(target, sources, linkflags =
|
46
|
+
def create_executable(target, sources, linkflags = "#{PlatformInfo.portability_cflags} #{EXTRA_CXXFLAGS} #{PlatformInfo.portability_ldflags} #{EXTRA_LDFLAGS}")
|
47
47
|
sh "#{CXX} #{sources} -o #{target} #{linkflags}"
|
48
48
|
end
|
49
49
|
|
50
|
-
def create_shared_library(target, sources, flags =
|
50
|
+
def create_shared_library(target, sources, flags = "#{PlatformInfo.portability_cflags} #{EXTRA_CXXFLAGS} #{PlatformInfo.portability_ldflags} #{EXTRA_LDFLAGS}")
|
51
51
|
if RUBY_PLATFORM =~ /darwin/
|
52
52
|
shlib_flag = "-flat_namespace -bundle -undefined dynamic_lookup"
|
53
53
|
else
|
@@ -68,5 +68,47 @@ namespace tut {
|
|
68
68
|
}
|
69
69
|
}
|
70
70
|
}
|
71
|
+
|
72
|
+
/* A StringListCreator which not only returns a dummy value, but also
|
73
|
+
* increments a counter each time getItems() is called. */
|
74
|
+
class DummyStringListCreator: public StringListCreator {
|
75
|
+
public:
|
76
|
+
mutable int counter;
|
77
|
+
|
78
|
+
DummyStringListCreator() {
|
79
|
+
counter = 0;
|
80
|
+
}
|
81
|
+
|
82
|
+
virtual const StringListPtr getItems() const {
|
83
|
+
StringListPtr result = ptr(new StringList());
|
84
|
+
counter++;
|
85
|
+
result->push_back("hello");
|
86
|
+
result->push_back("world");
|
87
|
+
return result;
|
88
|
+
}
|
89
|
+
};
|
90
|
+
|
91
|
+
TEST_METHOD(5) {
|
92
|
+
// When calling get() with a PoolOptions object,
|
93
|
+
// options.environmentVariables->getItems() isn't called unless
|
94
|
+
// the pool had to spawn something.
|
95
|
+
ApplicationPoolServerPtr server = ptr(new ApplicationPoolServer(
|
96
|
+
"./ApplicationPoolServerExecutable",
|
97
|
+
"../bin/passenger-spawn-server"));
|
98
|
+
ApplicationPoolPtr pool = server->connect();
|
99
|
+
|
100
|
+
shared_ptr<DummyStringListCreator> strList = ptr(new DummyStringListCreator());
|
101
|
+
PoolOptions options("stub/rack");
|
102
|
+
options.appType = "rack";
|
103
|
+
options.environmentVariables = strList;
|
104
|
+
|
105
|
+
Application::SessionPtr session1 = pool->get(options);
|
106
|
+
session1.reset();
|
107
|
+
ensure_equals(strList->counter, 1);
|
108
|
+
|
109
|
+
session1 = pool->get(options);
|
110
|
+
session1.reset();
|
111
|
+
ensure_equals(strList->counter, 1);
|
112
|
+
}
|
71
113
|
}
|
72
114
|
|
@@ -12,7 +12,8 @@
|
|
12
12
|
* This file is used as a template to test the different ApplicationPool implementations.
|
13
13
|
* It is #included in StandardApplicationPoolTest.cpp and ApplicationServer_ApplicationPoolTest.cpp
|
14
14
|
*/
|
15
|
-
#ifdef USE_TEMPLATE
|
15
|
+
#ifdef USE_TEMPLATE
|
16
|
+
/** Create some stub request headers. */
|
16
17
|
static string createRequestHeaders(const char *uri = "/foo/new") {
|
17
18
|
string headers;
|
18
19
|
#define ADD_HEADER(name, value) \
|
@@ -25,29 +26,11 @@
|
|
25
26
|
ADD_HEADER("REQUEST_URI", uri);
|
26
27
|
ADD_HEADER("REQUEST_METHOD", "GET");
|
27
28
|
ADD_HEADER("REMOTE_ADDR", "localhost");
|
29
|
+
ADD_HEADER("SCRIPT_NAME", "");
|
28
30
|
ADD_HEADER("PATH_INFO", uri);
|
29
31
|
return headers;
|
30
32
|
}
|
31
33
|
|
32
|
-
static string readAll(int fd) {
|
33
|
-
string result;
|
34
|
-
char buf[1024 * 32];
|
35
|
-
ssize_t ret;
|
36
|
-
while (true) {
|
37
|
-
do {
|
38
|
-
ret = read(fd, buf, sizeof(buf));
|
39
|
-
} while (ret == -1 && errno == EINTR);
|
40
|
-
if (ret == 0) {
|
41
|
-
break;
|
42
|
-
} else if (ret == -1) {
|
43
|
-
throw SystemException("Cannot read from socket", errno);
|
44
|
-
} else {
|
45
|
-
result.append(buf, ret);
|
46
|
-
}
|
47
|
-
}
|
48
|
-
return result;
|
49
|
-
}
|
50
|
-
|
51
34
|
static Application::SessionPtr spawnRackApp(ApplicationPoolPtr pool, const char *appRoot) {
|
52
35
|
PoolOptions options;
|
53
36
|
options.appRoot = appRoot;
|
@@ -61,17 +44,17 @@
|
|
61
44
|
options.appType = "wsgi";
|
62
45
|
return pool->get(options);
|
63
46
|
}
|
64
|
-
|
47
|
+
|
65
48
|
TEST_METHOD(1) {
|
66
49
|
// Calling ApplicationPool.get() once should return a valid Session.
|
67
|
-
Application::SessionPtr session(pool
|
50
|
+
Application::SessionPtr session(spawnRackApp(pool, "stub/rack"));
|
68
51
|
session->sendHeaders(createRequestHeaders());
|
69
52
|
session->shutdownWriter();
|
70
53
|
|
71
54
|
int reader = session->getStream();
|
72
55
|
string result(readAll(reader));
|
73
56
|
session->closeStream();
|
74
|
-
ensure(result.find("hello world") != string::npos);
|
57
|
+
ensure(result.find("hello <b>world</b>") != string::npos);
|
75
58
|
}
|
76
59
|
|
77
60
|
TEST_METHOD(2) {
|
@@ -99,26 +82,29 @@
|
|
99
82
|
// If we call get() with an application root, then we call get() again before closing
|
100
83
|
// the session, then the pool should have spawned 2 apps in total.
|
101
84
|
Application::SessionPtr session(spawnRackApp(pool, "stub/rack"));
|
102
|
-
Application::SessionPtr session2(spawnRackApp(
|
85
|
+
Application::SessionPtr session2(spawnRackApp(pool2, "stub/rack"));
|
103
86
|
ensure_equals(pool->getCount(), 2u);
|
104
87
|
}
|
105
88
|
|
106
89
|
TEST_METHOD(5) {
|
107
90
|
// If we call get() twice with different application roots,
|
108
91
|
// then the pool should spawn two different apps.
|
109
|
-
|
110
|
-
|
92
|
+
TempDirCopy c1("stub/rack", "rackapp1.tmp");
|
93
|
+
TempDirCopy c2("stub/rack", "rackapp2.tmp");
|
94
|
+
replaceStringInFile("rackapp2.tmp/config.ru", "world", "world 2");
|
95
|
+
Application::SessionPtr session(spawnRackApp(pool, "rackapp1.tmp"));
|
96
|
+
Application::SessionPtr session2(spawnRackApp(pool2, "rackapp2.tmp"));
|
111
97
|
ensure_equals("Before the sessions were closed, both apps were busy", pool->getActive(), 2u);
|
112
98
|
ensure_equals("Before the sessions were closed, both apps were in the pool", pool->getCount(), 2u);
|
113
99
|
|
114
100
|
session->sendHeaders(createRequestHeaders());
|
115
101
|
string result(readAll(session->getStream()));
|
116
|
-
ensure("Session 1 belongs to the correct app", result.find("hello world") != string::npos);
|
102
|
+
ensure("Session 1 belongs to the correct app", result.find("hello <b>world</b>") != string::npos);
|
117
103
|
session.reset();
|
118
104
|
|
119
105
|
session2->sendHeaders(createRequestHeaders());
|
120
106
|
result = readAll(session2->getStream());
|
121
|
-
ensure("Session 2 belongs to the correct app", result.find("
|
107
|
+
ensure("Session 2 belongs to the correct app", result.find("hello <b>world 2</b>") != string::npos);
|
122
108
|
session2.reset();
|
123
109
|
}
|
124
110
|
|
@@ -126,12 +112,14 @@
|
|
126
112
|
// If we call get() twice with different application roots,
|
127
113
|
// and we close both sessions, then both 2 apps should still
|
128
114
|
// be in the pool.
|
129
|
-
|
130
|
-
|
115
|
+
TempDirCopy c1("stub/rack", "rackapp1.tmp");
|
116
|
+
TempDirCopy c2("stub/rack", "rackapp2.tmp");
|
117
|
+
Application::SessionPtr session(spawnRackApp(pool, "rackapp1.tmp"));
|
118
|
+
Application::SessionPtr session2(spawnRackApp(pool, "rackapp2.tmp"));
|
131
119
|
session.reset();
|
132
120
|
session2.reset();
|
133
|
-
ensure_equals(pool->getActive(), 0u);
|
134
|
-
ensure_equals(pool->getCount(), 2u);
|
121
|
+
ensure_equals("There are 0 active apps", pool->getActive(), 0u);
|
122
|
+
ensure_equals("There are 2 apps in total", pool->getCount(), 2u);
|
135
123
|
}
|
136
124
|
|
137
125
|
TEST_METHOD(7) {
|
@@ -150,26 +138,26 @@
|
|
150
138
|
// But the get() thereafter should not:
|
151
139
|
// ApplicationPool should have spawned a new instance
|
152
140
|
// after detecting that the original one died.
|
153
|
-
Application::SessionPtr session(pool
|
141
|
+
Application::SessionPtr session(spawnRackApp(pool, "stub/rack"));
|
154
142
|
kill(session->getPid(), SIGTERM);
|
155
143
|
session.reset();
|
156
144
|
try {
|
157
|
-
session = pool
|
145
|
+
session = spawnRackApp(pool, "stub/rack");
|
158
146
|
fail("ApplicationPool::get() is supposed to "
|
159
147
|
"throw an exception because we killed "
|
160
148
|
"the app instance.");
|
161
149
|
} catch (const exception &e) {
|
162
|
-
session = pool
|
150
|
+
session = spawnRackApp(pool, "stub/rack");
|
163
151
|
// Should not throw.
|
164
152
|
}
|
165
153
|
}
|
166
154
|
|
167
|
-
struct
|
155
|
+
struct PoolWaitTestThread {
|
168
156
|
ApplicationPoolPtr pool;
|
169
157
|
Application::SessionPtr &m_session;
|
170
158
|
bool &m_done;
|
171
159
|
|
172
|
-
|
160
|
+
PoolWaitTestThread(const ApplicationPoolPtr &pool,
|
173
161
|
Application::SessionPtr &session,
|
174
162
|
bool &done)
|
175
163
|
: m_session(session), m_done(done) {
|
@@ -194,12 +182,13 @@
|
|
194
182
|
Application::SessionPtr session3;
|
195
183
|
bool done;
|
196
184
|
|
197
|
-
thread
|
185
|
+
shared_ptr<thread> thr = ptr(new thread(PoolWaitTestThread(pool2, session3, done)));
|
198
186
|
usleep(500000);
|
199
|
-
ensure("ApplicationPool is waiting", !done);
|
187
|
+
ensure("ApplicationPool is still waiting", !done);
|
200
188
|
ensure_equals(pool->getActive(), 2u);
|
201
189
|
ensure_equals(pool->getCount(), 2u);
|
202
190
|
|
191
|
+
// Now release one slot from the pool.
|
203
192
|
session1.reset();
|
204
193
|
|
205
194
|
// Wait at most 10 seconds.
|
@@ -213,7 +202,7 @@
|
|
213
202
|
ensure_equals(pool->getCount(), 2u);
|
214
203
|
|
215
204
|
thr->join();
|
216
|
-
|
205
|
+
thr.reset();
|
217
206
|
}
|
218
207
|
|
219
208
|
TEST_METHOD(10) {
|
@@ -221,25 +210,27 @@
|
|
221
210
|
// * the pool is already full, but there are inactive apps
|
222
211
|
// (active < count && count == max)
|
223
212
|
// and
|
224
|
-
// * the application root is *not* already in the pool
|
213
|
+
// * the application root for this get() is *not* already in the pool
|
225
214
|
// then the an inactive app should be killed in order to
|
226
215
|
// satisfy this get() command.
|
216
|
+
TempDirCopy c1("stub/rack", "rackapp1.tmp");
|
217
|
+
TempDirCopy c2("stub/rack", "rackapp2.tmp");
|
227
218
|
pool->setMax(2);
|
228
|
-
Application::SessionPtr session1(pool
|
229
|
-
Application::SessionPtr session2(pool
|
219
|
+
Application::SessionPtr session1(spawnRackApp(pool, "rackapp1.tmp"));
|
220
|
+
Application::SessionPtr session2(spawnRackApp(pool, "rackapp1.tmp"));
|
230
221
|
session1.reset();
|
231
222
|
session2.reset();
|
232
223
|
|
233
224
|
ensure_equals(pool->getActive(), 0u);
|
234
225
|
ensure_equals(pool->getCount(), 2u);
|
235
|
-
session1 =
|
226
|
+
session1 = spawnRackApp(pool, "rackapp2.tmp");
|
236
227
|
ensure_equals(pool->getActive(), 1u);
|
237
228
|
ensure_equals(pool->getCount(), 2u);
|
238
229
|
}
|
239
230
|
|
240
231
|
TEST_METHOD(11) {
|
241
|
-
//
|
242
|
-
Application::SessionPtr session(pool
|
232
|
+
// A Session should still be usable after the pool has been destroyed.
|
233
|
+
Application::SessionPtr session(spawnRackApp(pool, "stub/rack"));
|
243
234
|
pool->clear();
|
244
235
|
pool.reset();
|
245
236
|
pool2.reset();
|
@@ -250,32 +241,27 @@
|
|
250
241
|
int reader = session->getStream();
|
251
242
|
string result(readAll(reader));
|
252
243
|
session->closeStream();
|
253
|
-
ensure(result.find("hello world") != string::npos);
|
244
|
+
ensure(result.find("hello <b>world</b>") != string::npos);
|
254
245
|
}
|
255
246
|
|
256
247
|
TEST_METHOD(12) {
|
257
248
|
// If tmp/restart.txt didn't exist but has now been created,
|
258
249
|
// then the applications under app_root should be restarted.
|
259
250
|
struct stat buf;
|
260
|
-
|
261
|
-
Application::SessionPtr
|
251
|
+
TempDirCopy c("stub/rack", "rackapp.tmp");
|
252
|
+
Application::SessionPtr session1 = spawnRackApp(pool, "rackapp.tmp");
|
253
|
+
Application::SessionPtr session2 = spawnRackApp(pool, "rackapp.tmp");
|
262
254
|
session1.reset();
|
263
255
|
session2.reset();
|
264
256
|
|
265
|
-
|
266
|
-
pool
|
257
|
+
touchFile("rackapp.tmp/tmp/restart.txt");
|
258
|
+
spawnRackApp(pool, "rackapp.tmp");
|
267
259
|
|
268
260
|
ensure_equals("No apps are active", pool->getActive(), 0u);
|
269
261
|
ensure_equals("Both apps are killed, and a new one was spawned",
|
270
262
|
pool->getCount(), 1u);
|
271
|
-
|
272
|
-
|
273
|
-
stat("stub/railsapp/tmp/restart.txt", &buf) == 0);
|
274
|
-
unlink("stub/railsapp/tmp/restart.txt");
|
275
|
-
} catch (...) {
|
276
|
-
unlink("stub/railsapp/tmp/restart.txt");
|
277
|
-
throw;
|
278
|
-
}
|
263
|
+
ensure("Restart file still exists",
|
264
|
+
stat("rackapp.tmp/tmp/restart.txt", &buf) == 0);
|
279
265
|
}
|
280
266
|
|
281
267
|
TEST_METHOD(13) {
|
@@ -284,56 +270,213 @@
|
|
284
270
|
// should still be restarted. However, a subsequent get()
|
285
271
|
// should not result in a restart.
|
286
272
|
pid_t old_pid;
|
273
|
+
TempDirCopy c("stub/rack", "rackapp.tmp");
|
274
|
+
TempDir d("rackapp.tmp/tmp/restart.txt");
|
275
|
+
Application::SessionPtr session = spawnRackApp(pool, "rackapp.tmp");
|
276
|
+
old_pid = session->getPid();
|
277
|
+
session.reset();
|
287
278
|
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
session = pool->get("stub/railsapp");
|
300
|
-
ensure("The app was restarted", session->getPid() != old_pid);
|
301
|
-
old_pid = session->getPid();
|
302
|
-
session.reset();
|
303
|
-
|
304
|
-
session = pool->get("stub/railsapp");
|
305
|
-
ensure_equals("The app was not restarted",
|
306
|
-
old_pid, session->getPid());
|
307
|
-
} catch (...) {
|
308
|
-
system("rmdir stub/railsapp/tmp/restart.txt");
|
309
|
-
throw;
|
310
|
-
}
|
279
|
+
touchFile("rackapp.tmp/tmp/restart.txt", 10);
|
280
|
+
|
281
|
+
session = spawnRackApp(pool, "rackapp.tmp");
|
282
|
+
ensure("The app was restarted", session->getPid() != old_pid);
|
283
|
+
old_pid = session->getPid();
|
284
|
+
session.reset();
|
285
|
+
|
286
|
+
session = spawnRackApp(pool, "rackapp.tmp");
|
287
|
+
ensure_equals("The app was not restarted",
|
288
|
+
old_pid, session->getPid());
|
311
289
|
}
|
312
290
|
|
313
291
|
TEST_METHOD(15) {
|
314
|
-
// Test whether restarting really results in code reload.
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
system("cp -f stub/railsapp/app/controllers/bar_controller_1.txt "
|
319
|
-
"stub/railsapp/app/controllers/bar_controller.rb");
|
320
|
-
Application::SessionPtr session = pool->get("stub/railsapp");
|
321
|
-
session->sendHeaders(createRequestHeaders("/bar"));
|
292
|
+
// Test whether restarting with restart.txt really results in code reload.
|
293
|
+
TempDirCopy c("stub/rack", "rackapp.tmp");
|
294
|
+
Application::SessionPtr session = spawnRackApp(pool, "rackapp.tmp");
|
295
|
+
session->sendHeaders(createRequestHeaders());
|
322
296
|
string result = readAll(session->getStream());
|
323
|
-
ensure(result.find("
|
297
|
+
ensure(result.find("hello <b>world</b>") != string::npos);
|
324
298
|
session.reset();
|
325
299
|
|
326
|
-
|
327
|
-
|
328
|
-
system("touch stub/railsapp/tmp/restart.txt");
|
300
|
+
touchFile("rackapp.tmp/tmp/restart.txt");
|
301
|
+
replaceStringInFile("rackapp.tmp/config.ru", "world", "world 2");
|
329
302
|
|
330
|
-
session = pool
|
331
|
-
session->sendHeaders(createRequestHeaders(
|
303
|
+
session = spawnRackApp(pool, "rackapp.tmp");
|
304
|
+
session->sendHeaders(createRequestHeaders());
|
332
305
|
result = readAll(session->getStream());
|
333
|
-
ensure("App code has been reloaded", result.find("
|
306
|
+
ensure("App code has been reloaded", result.find("hello <b>world 2</b>") != string::npos);
|
334
307
|
}
|
335
308
|
|
336
309
|
TEST_METHOD(16) {
|
310
|
+
// If tmp/always_restart.txt is present and is a file,
|
311
|
+
// then the application under app_root should be always restarted.
|
312
|
+
struct stat buf;
|
313
|
+
pid_t old_pid;
|
314
|
+
TempDirCopy c("stub/rack", "rackapp.tmp");
|
315
|
+
Application::SessionPtr session1 = spawnRackApp(pool, "rackapp.tmp");
|
316
|
+
Application::SessionPtr session2 = spawnRackApp(pool2, "rackapp.tmp");
|
317
|
+
session1.reset();
|
318
|
+
session2.reset();
|
319
|
+
|
320
|
+
touchFile("rackapp.tmp/tmp/always_restart.txt");
|
321
|
+
|
322
|
+
// This get() results in a restart.
|
323
|
+
session1 = spawnRackApp(pool, "rackapp.tmp");
|
324
|
+
old_pid = session1->getPid();
|
325
|
+
session1.reset();
|
326
|
+
ensure_equals("First restart: no apps are active", pool->getActive(), 0u);
|
327
|
+
ensure_equals("First restart: the first 2 apps were killed, and a new one was spawned",
|
328
|
+
pool->getCount(), 1u);
|
329
|
+
ensure("always_restart file has not been deleted",
|
330
|
+
stat("rackapp.tmp/tmp/always_restart.txt", &buf) == 0);
|
331
|
+
|
332
|
+
// This get() results in a restart as well.
|
333
|
+
session1 = spawnRackApp(pool, "rackapp.tmp");
|
334
|
+
ensure(old_pid != session1->getPid());
|
335
|
+
session1.reset();
|
336
|
+
ensure_equals("Second restart: no apps are active", pool->getActive(), 0u);
|
337
|
+
ensure_equals("Second restart: the last app was killed, and a new one was spawned",
|
338
|
+
pool->getCount(), 1u);
|
339
|
+
ensure("always_restart file has not been deleted",
|
340
|
+
stat("rackapp.tmp/tmp/always_restart.txt", &buf) == 0);
|
341
|
+
}
|
342
|
+
|
343
|
+
TEST_METHOD(17) {
|
344
|
+
// If tmp/always_restart.txt is present and is a directory,
|
345
|
+
// then the application under app_root should be always restarted.
|
346
|
+
struct stat buf;
|
347
|
+
pid_t old_pid;
|
348
|
+
TempDirCopy c("stub/rack", "rackapp.tmp");
|
349
|
+
Application::SessionPtr session1 = spawnRackApp(pool, "rackapp.tmp");
|
350
|
+
Application::SessionPtr session2 = spawnRackApp(pool, "rackapp.tmp");
|
351
|
+
session1.reset();
|
352
|
+
session2.reset();
|
353
|
+
|
354
|
+
TempDir d("rackapp.tmp/tmp/always_restart.txt");
|
355
|
+
|
356
|
+
// This get() results in a restart.
|
357
|
+
session1 = spawnRackApp(pool, "rackapp.tmp");
|
358
|
+
old_pid = session1->getPid();
|
359
|
+
session1.reset();
|
360
|
+
ensure_equals("First restart: no apps are active", pool->getActive(), 0u);
|
361
|
+
ensure_equals("First restart: the first 2 apps were killed, and a new one was spawned",
|
362
|
+
pool->getCount(), 1u);
|
363
|
+
ensure("always_restart directory has not been deleted",
|
364
|
+
stat("rackapp.tmp/tmp/always_restart.txt", &buf) == 0);
|
365
|
+
|
366
|
+
// This get() results in a restart as well.
|
367
|
+
session1 = spawnRackApp(pool, "rackapp.tmp");
|
368
|
+
ensure(old_pid != session1->getPid());
|
369
|
+
session1.reset();
|
370
|
+
ensure_equals("Second restart: no apps are active", pool->getActive(), 0u);
|
371
|
+
ensure_equals("Second restart: the last app was killed, and a new one was spawned",
|
372
|
+
pool->getCount(), 1u);
|
373
|
+
ensure("always_restart directory has not been deleted",
|
374
|
+
stat("rackapp.tmp/tmp/always_restart.txt", &buf) == 0);
|
375
|
+
}
|
376
|
+
|
377
|
+
TEST_METHOD(18) {
|
378
|
+
// Test whether restarting with tmp/always_restart.txt really results in code reload.
|
379
|
+
TempDirCopy c("stub/rack", "rackapp.tmp");
|
380
|
+
Application::SessionPtr session = spawnRackApp(pool, "rackapp.tmp");
|
381
|
+
session->sendHeaders(createRequestHeaders());
|
382
|
+
string result = readAll(session->getStream());
|
383
|
+
ensure(result.find("hello <b>world</b>") != string::npos);
|
384
|
+
session.reset();
|
385
|
+
|
386
|
+
touchFile("rackapp.tmp/tmp/always_restart.txt");
|
387
|
+
replaceStringInFile("rackapp.tmp/config.ru", "world", "world 2");
|
388
|
+
|
389
|
+
session = spawnRackApp(pool, "rackapp.tmp");
|
390
|
+
session->sendHeaders(createRequestHeaders());
|
391
|
+
result = readAll(session->getStream());
|
392
|
+
ensure("App code has been reloaded (1)", result.find("hello <b>world 2</b>") != string::npos);
|
393
|
+
session.reset();
|
394
|
+
|
395
|
+
replaceStringInFile("rackapp.tmp/config.ru", "world 2", "world 3");
|
396
|
+
session = spawnRackApp(pool, "rackapp.tmp");
|
397
|
+
session->sendHeaders(createRequestHeaders());
|
398
|
+
result = readAll(session->getStream());
|
399
|
+
ensure("App code has been reloaded (2)", result.find("hello <b>world 3</b>") != string::npos);
|
400
|
+
session.reset();
|
401
|
+
}
|
402
|
+
|
403
|
+
TEST_METHOD(19) {
|
404
|
+
// If tmp/restart.txt and tmp/always_restart.txt are present,
|
405
|
+
// the application under app_root should still be restarted and
|
406
|
+
// both files must be kept.
|
407
|
+
pid_t old_pid, pid;
|
408
|
+
struct stat buf;
|
409
|
+
TempDirCopy c("stub/rack", "rackapp.tmp");
|
410
|
+
Application::SessionPtr session1 = spawnRackApp(pool, "rackapp.tmp");
|
411
|
+
Application::SessionPtr session2 = spawnRackApp(pool2, "rackapp.tmp");
|
412
|
+
session1.reset();
|
413
|
+
session2.reset();
|
414
|
+
|
415
|
+
touchFile("rackapp.tmp/tmp/restart.txt");
|
416
|
+
touchFile("rackapp.tmp/tmp/always_restart.txt");
|
417
|
+
|
418
|
+
old_pid = spawnRackApp(pool, "rackapp.tmp")->getPid();
|
419
|
+
ensure("always_restart.txt file has not been deleted",
|
420
|
+
stat("rackapp.tmp/tmp/always_restart.txt", &buf) == 0);
|
421
|
+
ensure("restart.txt file has not been deleted",
|
422
|
+
stat("rackapp.tmp/tmp/restart.txt", &buf) == 0);
|
423
|
+
|
424
|
+
pid = spawnRackApp(pool, "rackapp.tmp")->getPid();
|
425
|
+
ensure("The app was restarted", pid != old_pid);
|
426
|
+
}
|
427
|
+
|
428
|
+
TEST_METHOD(20) {
|
429
|
+
// It should look for restart.txt in the directory given by
|
430
|
+
// the restartDir option, if available.
|
431
|
+
struct stat buf;
|
432
|
+
char path[1024];
|
433
|
+
PoolOptions options("stub/rack");
|
434
|
+
options.appType = "rack";
|
435
|
+
options.restartDir = string(getcwd(path, sizeof(path))) + "/stub/rack";
|
436
|
+
|
437
|
+
Application::SessionPtr session1 = pool->get(options);
|
438
|
+
Application::SessionPtr session2 = pool2->get(options);
|
439
|
+
session1.reset();
|
440
|
+
session2.reset();
|
441
|
+
|
442
|
+
DeleteFileEventually f("stub/rack/restart.txt");
|
443
|
+
touchFile("stub/rack/restart.txt");
|
444
|
+
|
445
|
+
pool->get(options);
|
446
|
+
|
447
|
+
ensure_equals("No apps are active", pool->getActive(), 0u);
|
448
|
+
ensure_equals("Both apps are killed, and a new one was spawned",
|
449
|
+
pool->getCount(), 1u);
|
450
|
+
ensure("Restart file still exists",
|
451
|
+
stat("stub/rack/restart.txt", &buf) == 0);
|
452
|
+
}
|
453
|
+
|
454
|
+
TEST_METHOD(21) {
|
455
|
+
// restartDir may also be a directory relative to the
|
456
|
+
// application root.
|
457
|
+
struct stat buf;
|
458
|
+
PoolOptions options("stub/rack");
|
459
|
+
options.appType = "rack";
|
460
|
+
options.restartDir = "public";
|
461
|
+
|
462
|
+
Application::SessionPtr session1 = pool->get(options);
|
463
|
+
Application::SessionPtr session2 = pool2->get(options);
|
464
|
+
session1.reset();
|
465
|
+
session2.reset();
|
466
|
+
|
467
|
+
DeleteFileEventually f("stub/rack/public/restart.txt");
|
468
|
+
touchFile("stub/rack/public/restart.txt");
|
469
|
+
|
470
|
+
pool->get(options);
|
471
|
+
|
472
|
+
ensure_equals("No apps are active", pool->getActive(), 0u);
|
473
|
+
ensure_equals("Both apps are killed, and a new one was spawned",
|
474
|
+
pool->getCount(), 1u);
|
475
|
+
ensure("Restart file still exists",
|
476
|
+
stat("stub/rack/public/restart.txt", &buf) == 0);
|
477
|
+
}
|
478
|
+
|
479
|
+
TEST_METHOD(22) {
|
337
480
|
// The cleaner thread should clean idle applications without crashing.
|
338
481
|
pool->setMaxIdleTime(1);
|
339
482
|
spawnRackApp(pool, "stub/rack");
|
@@ -345,7 +488,7 @@
|
|
345
488
|
ensure_equals("App should have been cleaned up", pool->getCount(), 0u);
|
346
489
|
}
|
347
490
|
|
348
|
-
TEST_METHOD(
|
491
|
+
TEST_METHOD(23) {
|
349
492
|
// MaxPerApp is respected.
|
350
493
|
pool->setMax(3);
|
351
494
|
pool->setMaxPerApp(1);
|
@@ -359,18 +502,20 @@
|
|
359
502
|
|
360
503
|
// We connect to stub/wsgi. Assert that the pool spawns a new
|
361
504
|
// instance for this app.
|
505
|
+
TempDirCopy c("stub/wsgi", "wsgiapp.tmp");
|
362
506
|
ApplicationPoolPtr pool3(newPoolConnection());
|
363
|
-
Application::SessionPtr session3 = spawnWsgiApp(pool3, "
|
507
|
+
Application::SessionPtr session3 = spawnWsgiApp(pool3, "wsgiapp.tmp");
|
364
508
|
ensure_equals(pool->getCount(), 2u);
|
365
509
|
}
|
366
510
|
|
367
|
-
TEST_METHOD(
|
511
|
+
TEST_METHOD(24) {
|
368
512
|
// Application instance is shutdown after 'maxRequests' requests.
|
369
|
-
PoolOptions options("stub/
|
513
|
+
PoolOptions options("stub/rack");
|
370
514
|
int reader;
|
371
515
|
pid_t originalPid;
|
372
516
|
Application::SessionPtr session;
|
373
517
|
|
518
|
+
options.appType = "rack";
|
374
519
|
options.maxRequests = 4;
|
375
520
|
pool->setMax(1);
|
376
521
|
session = pool->get(options);
|
@@ -411,7 +556,7 @@
|
|
411
556
|
}
|
412
557
|
};
|
413
558
|
|
414
|
-
TEST_METHOD(
|
559
|
+
TEST_METHOD(25) {
|
415
560
|
// If global queueing mode is enabled, then get() waits until
|
416
561
|
// there's at least one idle backend process for this application
|
417
562
|
// domain.
|
@@ -439,171 +584,14 @@
|
|
439
584
|
thr.join();
|
440
585
|
}
|
441
586
|
|
442
|
-
TEST_METHOD(
|
443
|
-
//
|
444
|
-
//
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
session2.reset();
|
451
|
-
|
452
|
-
system("touch stub/railsapp/tmp/always_restart.txt");
|
453
|
-
pool->get("stub/railsapp");
|
454
|
-
|
455
|
-
ensure_equals("No apps are active", pool->getActive(), 0u);
|
456
|
-
ensure_equals("Both apps are killed, and a new one was spawned",
|
457
|
-
pool->getCount(), 1u);
|
458
|
-
ensure("always_restart file has not been deleted",
|
459
|
-
stat("stub/railsapp/tmp/always_restart.txt", &buf) == 0);
|
460
|
-
unlink("stub/railsapp/tmp/always_restart.txt");
|
461
|
-
} catch (...) {
|
462
|
-
unlink("stub/railsapp/tmp/always_restart.txt");
|
463
|
-
throw;
|
464
|
-
}
|
465
|
-
}
|
466
|
-
|
467
|
-
TEST_METHOD(21) {
|
468
|
-
// If tmp/always_restart.txt is present and is a directory,
|
469
|
-
// then the application under app_root
|
470
|
-
// should be always restarted.
|
471
|
-
try {
|
472
|
-
struct stat buf;
|
473
|
-
Application::SessionPtr session1 = pool->get("stub/railsapp");
|
474
|
-
Application::SessionPtr session2 = pool2->get("stub/railsapp");
|
475
|
-
session1.reset();
|
476
|
-
session2.reset();
|
477
|
-
|
478
|
-
system("mkdir stub/railsapp/tmp/always_restart.txt");
|
479
|
-
pool->get("stub/railsapp");
|
480
|
-
|
481
|
-
ensure_equals("No apps are active", pool->getActive(), 0u);
|
482
|
-
ensure_equals("Both apps are killed, and a new one was spawned",
|
483
|
-
pool->getCount(), 1u);
|
484
|
-
ensure("always_restart file has not been deleted",
|
485
|
-
stat("stub/railsapp/tmp/always_restart.txt", &buf) == 0);
|
486
|
-
system("rmdir stub/railsapp/tmp/always_restart.txt");
|
487
|
-
} catch (...) {
|
488
|
-
system("rmdir stub/railsapp/tmp/always_restart.txt");
|
489
|
-
throw;
|
490
|
-
}
|
491
|
-
}
|
492
|
-
|
493
|
-
TEST_METHOD(22) {
|
494
|
-
// Test whether tmp/always_restart.txt really results in code reload.
|
495
|
-
DeleteFileEventually f1("stub/railsapp/app/controllers/bar_controller.rb");
|
496
|
-
DeleteFileEventually f2("stub/railsapp/tmp/always_restart.txt");
|
497
|
-
|
498
|
-
system("cp -f stub/railsapp/app/controllers/bar_controller_1.txt "
|
499
|
-
"stub/railsapp/app/controllers/bar_controller.rb");
|
500
|
-
Application::SessionPtr session = pool->get("stub/railsapp");
|
501
|
-
session->sendHeaders(createRequestHeaders("/bar"));
|
502
|
-
string result = readAll(session->getStream());
|
503
|
-
ensure(result.find("bar 1!") != string::npos);
|
504
|
-
session.reset();
|
505
|
-
|
506
|
-
system("cp -f stub/railsapp/app/controllers/bar_controller_2.txt "
|
507
|
-
"stub/railsapp/app/controllers/bar_controller.rb");
|
508
|
-
system("touch stub/railsapp/tmp/always_restart.txt");
|
509
|
-
session = pool->get("stub/railsapp");
|
510
|
-
session->sendHeaders(createRequestHeaders("/bar"));
|
511
|
-
result = readAll(session->getStream());
|
512
|
-
ensure("App code has been reloaded (1)", result.find("bar 2!") != string::npos);
|
513
|
-
session.reset();
|
514
|
-
|
515
|
-
system("cp -f stub/railsapp/app/controllers/bar_controller_1.txt "
|
516
|
-
"stub/railsapp/app/controllers/bar_controller.rb");
|
517
|
-
session = pool->get("stub/railsapp");
|
518
|
-
session->sendHeaders(createRequestHeaders("/bar"));
|
519
|
-
result = readAll(session->getStream());
|
520
|
-
ensure("App code has been reloaded (2)", result.find("bar 1!") != string::npos);
|
521
|
-
session.reset();
|
522
|
-
}
|
523
|
-
|
524
|
-
TEST_METHOD(23) {
|
525
|
-
// If tmp/restart.txt and tmp/always_restart.txt are present,
|
526
|
-
// the application under app_root should still be restarted and
|
527
|
-
// both files must be kept
|
528
|
-
try {
|
529
|
-
pid_t old_pid, pid;
|
530
|
-
struct stat buf;
|
531
|
-
Application::SessionPtr session1 = pool->get("stub/railsapp");
|
532
|
-
Application::SessionPtr session2 = pool2->get("stub/railsapp");
|
533
|
-
session1.reset();
|
534
|
-
session2.reset();
|
535
|
-
|
536
|
-
system("touch stub/railsapp/tmp/restart.txt");
|
537
|
-
system("touch stub/railsapp/tmp/always_restart.txt");
|
538
|
-
|
539
|
-
old_pid = pool->get("stub/railsapp")->getPid();
|
540
|
-
ensure("always_restart file has not been deleted",
|
541
|
-
stat("stub/railsapp/tmp/always_restart.txt", &buf) == 0);
|
542
|
-
|
543
|
-
ensure("Restart file has not been deleted",
|
544
|
-
stat("stub/railsapp/tmp/restart.txt", &buf) == 0);
|
545
|
-
|
546
|
-
pid = pool->get("stub/railsapp")->getPid();
|
547
|
-
ensure("The app was restarted", pid != old_pid);
|
548
|
-
|
549
|
-
unlink("stub/railsapp/tmp/restart.txt");
|
550
|
-
unlink("stub/railsapp/tmp/always_restart.txt");
|
551
|
-
} catch (...) {
|
552
|
-
unlink("stub/railsapp/tmp/restart.txt");
|
553
|
-
unlink("stub/railsapp/tmp/always_restart.txt");
|
554
|
-
throw;
|
555
|
-
}
|
556
|
-
}
|
557
|
-
|
558
|
-
TEST_METHOD(24) {
|
559
|
-
// It should look for restart.txt in the directory given by
|
560
|
-
// the restartDir option, if available.
|
561
|
-
struct stat buf;
|
562
|
-
char path[1024];
|
563
|
-
PoolOptions options("stub/rack");
|
564
|
-
options.appType = "rack";
|
565
|
-
options.restartDir = string(getcwd(path, sizeof(path))) + "/stub/rack";
|
566
|
-
|
567
|
-
Application::SessionPtr session1 = pool->get(options);
|
568
|
-
Application::SessionPtr session2 = pool2->get(options);
|
569
|
-
session1.reset();
|
570
|
-
session2.reset();
|
571
|
-
|
572
|
-
DeleteFileEventually f("stub/rack/restart.txt");
|
573
|
-
system("touch stub/rack/restart.txt");
|
574
|
-
|
575
|
-
pool->get(options);
|
576
|
-
|
577
|
-
ensure_equals("No apps are active", pool->getActive(), 0u);
|
578
|
-
ensure_equals("Both apps are killed, and a new one was spawned",
|
579
|
-
pool->getCount(), 1u);
|
580
|
-
ensure("Restart file still exists",
|
581
|
-
stat("stub/rack/restart.txt", &buf) == 0);
|
582
|
-
}
|
583
|
-
|
584
|
-
TEST_METHOD(25) {
|
585
|
-
// restartDir may also be a directory relative to the
|
586
|
-
// application root.
|
587
|
-
struct stat buf;
|
588
|
-
PoolOptions options("stub/rack");
|
589
|
-
options.appType = "rack";
|
590
|
-
options.restartDir = "public";
|
591
|
-
|
592
|
-
Application::SessionPtr session1 = pool->get(options);
|
593
|
-
Application::SessionPtr session2 = pool2->get(options);
|
594
|
-
session1.reset();
|
595
|
-
session2.reset();
|
596
|
-
|
597
|
-
DeleteFileEventually f("stub/rack/public/restart.txt");
|
598
|
-
system("touch stub/rack/public/restart.txt");
|
599
|
-
|
600
|
-
pool->get(options);
|
601
|
-
|
602
|
-
ensure_equals("No apps are active", pool->getActive(), 0u);
|
603
|
-
ensure_equals("Both apps are killed, and a new one was spawned",
|
604
|
-
pool->getCount(), 1u);
|
605
|
-
ensure("Restart file still exists",
|
606
|
-
stat("stub/rack/public/restart.txt", &buf) == 0);
|
587
|
+
TEST_METHOD(26) {
|
588
|
+
// When a previous application domain spinned down, and we touched
|
589
|
+
// restart.txt and try to spin up a new process for this domain,
|
590
|
+
// then any ApplicationSpawner/FrameworkSpawner processes should be
|
591
|
+
// killed first.
|
592
|
+
|
593
|
+
// TODO: to test this we first need to be able to move
|
594
|
+
// ApplicationPoolServer in-process so that we can use mock objects
|
607
595
|
}
|
608
596
|
|
609
597
|
/*************************************/
|