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.

Files changed (254) hide show
  1. data/DEVELOPERS.TXT +13 -3
  2. data/Rakefile +42 -33
  3. data/bin/passenger-install-apache2-module +1 -2
  4. data/bin/passenger-install-nginx-module +7 -19
  5. data/bin/passenger-status +64 -15
  6. data/bin/passenger-stress-test +2 -2
  7. data/doc/ApplicationPool algorithm.txt +26 -22
  8. data/doc/Users guide Apache.html +374 -149
  9. data/doc/Users guide Apache.txt +318 -51
  10. data/doc/Users guide Nginx.html +13 -13
  11. data/doc/Users guide Nginx.txt +7 -2
  12. data/doc/cxxapi/Bucket_8h-source.html +62 -25
  13. data/doc/cxxapi/Configuration_8h-source.html +343 -326
  14. data/doc/cxxapi/DirectoryMapper_8h-source.html +12 -12
  15. data/doc/cxxapi/Hooks_8h-source.html +1 -1
  16. data/doc/cxxapi/annotated.html +1 -1
  17. data/doc/cxxapi/classHooks-members.html +1 -1
  18. data/doc/cxxapi/classHooks.html +1 -1
  19. data/doc/cxxapi/classPassenger_1_1DirectoryMapper-members.html +2 -2
  20. data/doc/cxxapi/classPassenger_1_1DirectoryMapper.html +9 -9
  21. data/doc/cxxapi/classes.html +1 -1
  22. data/doc/cxxapi/definitions_8h-source.html +1 -1
  23. data/doc/cxxapi/files.html +1 -1
  24. data/doc/cxxapi/functions.html +2 -2
  25. data/doc/cxxapi/functions_func.html +2 -2
  26. data/doc/cxxapi/graph_legend.html +1 -1
  27. data/doc/cxxapi/group__Configuration.html +1 -1
  28. data/doc/cxxapi/group__Core.html +1 -1
  29. data/doc/cxxapi/group__Hooks.html +1 -1
  30. data/doc/cxxapi/group__Support.html +1 -1
  31. data/doc/cxxapi/main.html +1 -1
  32. data/doc/cxxapi/modules.html +1 -1
  33. data/doc/rdoc/classes/ConditionVariable.html +194 -0
  34. data/doc/rdoc/classes/Exception.html +120 -0
  35. data/doc/rdoc/classes/GC.html +113 -0
  36. data/doc/rdoc/classes/IO.html +169 -0
  37. data/doc/rdoc/classes/PhusionPassenger.html +238 -0
  38. data/doc/rdoc/classes/PhusionPassenger/AbstractInstaller.html +153 -0
  39. data/doc/rdoc/classes/PhusionPassenger/AbstractRequestHandler.html +517 -0
  40. data/doc/rdoc/classes/PhusionPassenger/AbstractServer.html +719 -0
  41. data/doc/rdoc/classes/PhusionPassenger/AbstractServer/ServerAlreadyStarted.html +97 -0
  42. data/doc/rdoc/classes/PhusionPassenger/AbstractServer/ServerError.html +96 -0
  43. data/doc/rdoc/classes/PhusionPassenger/AbstractServer/ServerNotStarted.html +97 -0
  44. data/doc/rdoc/classes/PhusionPassenger/AbstractServer/UnknownMessage.html +96 -0
  45. data/doc/rdoc/classes/PhusionPassenger/AbstractServerCollection.html +598 -0
  46. data/doc/rdoc/classes/PhusionPassenger/AdminTools.html +140 -0
  47. data/doc/rdoc/classes/PhusionPassenger/AdminTools/ControlProcess.html +317 -0
  48. data/doc/rdoc/classes/PhusionPassenger/AdminTools/ControlProcess/Instance.html +138 -0
  49. data/doc/rdoc/classes/PhusionPassenger/AppInitError.html +154 -0
  50. data/doc/rdoc/classes/PhusionPassenger/Application.html +283 -0
  51. data/doc/rdoc/classes/PhusionPassenger/ConsoleTextTemplate.html +172 -0
  52. data/doc/rdoc/classes/PhusionPassenger/FrameworkInitError.html +145 -0
  53. data/doc/rdoc/classes/PhusionPassenger/HTMLTemplate.html +175 -0
  54. data/doc/rdoc/classes/PhusionPassenger/InitializationError.html +141 -0
  55. data/doc/rdoc/classes/PhusionPassenger/InvalidPath.html +92 -0
  56. data/doc/rdoc/classes/PhusionPassenger/MessageChannel.html +489 -0
  57. data/doc/rdoc/classes/PhusionPassenger/NativeSupport.html +350 -0
  58. data/doc/rdoc/classes/PhusionPassenger/Rack.html +91 -0
  59. data/doc/rdoc/classes/PhusionPassenger/Rack/ApplicationSpawner.html +188 -0
  60. data/doc/rdoc/classes/PhusionPassenger/Rack/RequestHandler.html +194 -0
  61. data/doc/rdoc/classes/PhusionPassenger/Railz.html +95 -0
  62. data/doc/rdoc/classes/PhusionPassenger/Railz/ApplicationSpawner.html +442 -0
  63. data/doc/rdoc/classes/PhusionPassenger/Railz/ApplicationSpawner/Error.html +98 -0
  64. data/doc/rdoc/classes/PhusionPassenger/Railz/CGIFixed.html +200 -0
  65. data/doc/rdoc/classes/PhusionPassenger/Railz/FrameworkSpawner.html +436 -0
  66. data/doc/rdoc/classes/PhusionPassenger/Railz/FrameworkSpawner/Error.html +98 -0
  67. data/doc/rdoc/classes/PhusionPassenger/Railz/RequestHandler.html +155 -0
  68. data/doc/rdoc/classes/PhusionPassenger/SpawnManager.html +402 -0
  69. data/doc/rdoc/classes/PhusionPassenger/UnknownError.html +125 -0
  70. data/doc/rdoc/classes/PhusionPassenger/Utils.html +805 -0
  71. data/doc/rdoc/classes/PhusionPassenger/VersionNotFound.html +140 -0
  72. data/doc/rdoc/classes/PhusionPassenger/WSGI.html +89 -0
  73. data/doc/rdoc/classes/PhusionPassenger/WSGI/ApplicationSpawner.html +188 -0
  74. data/doc/rdoc/classes/PlatformInfo.html +831 -0
  75. data/doc/rdoc/classes/RakeExtensions.html +197 -0
  76. data/doc/rdoc/classes/Signal.html +131 -0
  77. data/doc/rdoc/created.rid +1 -0
  78. data/doc/rdoc/files/DEVELOPERS_TXT.html +255 -0
  79. data/doc/rdoc/files/README.html +157 -0
  80. data/doc/rdoc/files/ext/phusion_passenger/native_support_c.html +92 -0
  81. data/doc/rdoc/files/lib/phusion_passenger/abstract_installer_rb.html +129 -0
  82. data/doc/rdoc/files/lib/phusion_passenger/abstract_request_handler_rb.html +131 -0
  83. data/doc/rdoc/files/lib/phusion_passenger/abstract_server_collection_rb.html +126 -0
  84. data/doc/rdoc/files/lib/phusion_passenger/abstract_server_rb.html +130 -0
  85. data/doc/rdoc/files/lib/phusion_passenger/admin_tools/control_process_rb.html +130 -0
  86. data/doc/rdoc/files/lib/phusion_passenger/admin_tools_rb.html +122 -0
  87. data/doc/rdoc/files/lib/phusion_passenger/application_rb.html +127 -0
  88. data/doc/rdoc/files/lib/phusion_passenger/console_text_template_rb.html +126 -0
  89. data/doc/rdoc/files/lib/phusion_passenger/constants_rb.html +122 -0
  90. data/doc/rdoc/files/lib/phusion_passenger/dependencies_rb.html +134 -0
  91. data/doc/rdoc/files/lib/phusion_passenger/events_rb.html +122 -0
  92. data/doc/rdoc/files/lib/phusion_passenger/exceptions_rb.html +122 -0
  93. data/doc/rdoc/files/lib/phusion_passenger/html_template_rb.html +126 -0
  94. data/doc/rdoc/files/lib/phusion_passenger/message_channel_rb.html +122 -0
  95. data/doc/rdoc/files/lib/phusion_passenger/packaging_rb.html +122 -0
  96. data/doc/rdoc/files/lib/phusion_passenger/platform_info_rb.html +127 -0
  97. data/doc/rdoc/files/lib/phusion_passenger/rack/application_spawner_rb.html +133 -0
  98. data/doc/rdoc/files/lib/phusion_passenger/rack/request_handler_rb.html +127 -0
  99. data/doc/rdoc/files/lib/phusion_passenger/railz/application_spawner_rb.html +143 -0
  100. data/doc/rdoc/files/lib/phusion_passenger/railz/cgi_fixed_rb.html +126 -0
  101. data/doc/rdoc/files/lib/phusion_passenger/railz/framework_spawner_rb.html +145 -0
  102. data/doc/rdoc/files/lib/phusion_passenger/railz/request_handler_rb.html +127 -0
  103. data/doc/rdoc/files/lib/phusion_passenger/simple_benchmarking_rb.html +122 -0
  104. data/doc/rdoc/files/lib/phusion_passenger/spawn_manager_rb.html +161 -0
  105. data/doc/rdoc/files/lib/phusion_passenger/utils_rb.html +175 -0
  106. data/doc/rdoc/files/lib/phusion_passenger/wsgi/application_spawner_rb.html +129 -0
  107. data/doc/rdoc/files/misc/rake/extensions_rb.html +130 -0
  108. data/doc/rdoc/fr_class_index.html +90 -0
  109. data/doc/rdoc/fr_file_index.html +76 -0
  110. data/doc/rdoc/fr_method_index.html +200 -0
  111. data/doc/rdoc/index.html +26 -0
  112. data/doc/rdoc/rdoc-style.css +187 -0
  113. data/doc/users_guide_snippets/rackup_specifications.txt +2 -8
  114. data/ext/apache2/Bucket.cpp +71 -38
  115. data/ext/apache2/Bucket.h +53 -16
  116. data/ext/apache2/Configuration.cpp +15 -0
  117. data/ext/apache2/Configuration.h +19 -2
  118. data/ext/apache2/DirectoryMapper.h +10 -10
  119. data/ext/apache2/Hooks.cpp +334 -74
  120. data/ext/boost/mpl/apply.hpp +5 -1
  121. data/ext/boost/mpl/apply_wrap.hpp +5 -2
  122. data/ext/boost/mpl/aux_/full_lambda.hpp +5 -1
  123. data/ext/boost/mpl/bind.hpp +5 -1
  124. data/ext/common/Application.h +11 -31
  125. data/ext/common/ApplicationPool.h +2 -1
  126. data/ext/common/ApplicationPoolServer.h +61 -20
  127. data/ext/common/ApplicationPoolServerExecutable.cpp +132 -4
  128. data/ext/common/ApplicationPoolStatusReporter.h +189 -65
  129. data/ext/common/Base64.cpp +143 -0
  130. data/ext/common/Base64.h +57 -0
  131. data/ext/common/CachedFileStat.cpp +25 -82
  132. data/ext/common/CachedFileStat.h +11 -125
  133. data/ext/common/CachedFileStat.hpp +243 -0
  134. data/ext/common/Exceptions.h +13 -0
  135. data/ext/common/FileChangeChecker.h +209 -0
  136. data/ext/common/Logging.h +3 -2
  137. data/ext/common/MessageChannel.h +10 -10
  138. data/ext/common/PoolOptions.h +72 -5
  139. data/ext/common/SpawnManager.h +11 -8
  140. data/ext/common/StandardApplicationPool.h +38 -39
  141. data/ext/common/StaticString.h +1 -0
  142. data/ext/common/StringListCreator.h +83 -0
  143. data/ext/common/SystemTime.h +3 -2
  144. data/ext/common/Timer.h +88 -0
  145. data/ext/common/Utils.cpp +161 -42
  146. data/ext/common/Utils.h +62 -31
  147. data/ext/common/Version.h +1 -1
  148. data/ext/nginx/Configuration.c +0 -4
  149. data/ext/nginx/ContentHandler.c +8 -6
  150. data/ext/nginx/HelperServer.cpp +45 -55
  151. data/ext/nginx/HttpStatusExtractor.h +4 -0
  152. data/ext/nginx/StaticContentHandler.c +25 -5
  153. data/ext/nginx/config +3 -0
  154. data/ext/nginx/ngx_http_passenger_module.c +72 -17
  155. data/ext/nginx/ngx_http_passenger_module.h +2 -2
  156. data/lib/phusion_passenger/abstract_request_handler.rb +15 -7
  157. data/lib/phusion_passenger/abstract_server.rb +16 -2
  158. data/lib/phusion_passenger/admin_tools/control_process.rb +36 -25
  159. data/lib/phusion_passenger/constants.rb +1 -1
  160. data/lib/phusion_passenger/dependencies.rb +10 -0
  161. data/lib/phusion_passenger/platform_info.rb +1 -1
  162. data/lib/phusion_passenger/rack/application_spawner.rb +21 -2
  163. data/lib/phusion_passenger/rack/request_handler.rb +10 -0
  164. data/lib/phusion_passenger/railz/application_spawner.rb +38 -2
  165. data/lib/phusion_passenger/railz/framework_spawner.rb +26 -28
  166. data/lib/phusion_passenger/railz/request_handler.rb +5 -1
  167. data/lib/phusion_passenger/spawn_manager.rb +6 -2
  168. data/lib/phusion_passenger/utils.rb +79 -27
  169. data/misc/rake/cplusplus.rb +5 -5
  170. data/test/ApplicationPoolServerTest.cpp +42 -0
  171. data/test/ApplicationPoolTest.cpp +255 -267
  172. data/test/Base64Test.cpp +48 -0
  173. data/test/CachedFileStatTest.cpp +243 -103
  174. data/test/FileChangeCheckerTest.cpp +331 -0
  175. data/test/PoolOptionsTest.cpp +80 -0
  176. data/test/UtilsTest.cpp +5 -17
  177. data/test/integration_tests/apache2_tests.rb +15 -4
  178. data/test/integration_tests/mycook_spec.rb +3 -4
  179. data/test/oxt/syscall_interruption_test.cpp +2 -14
  180. data/test/ruby/abstract_server_collection_spec.rb +1 -1
  181. data/test/ruby/abstract_server_spec.rb +35 -1
  182. data/test/ruby/rack/application_spawner_spec.rb +23 -6
  183. data/test/ruby/rails/application_spawner_spec.rb +6 -6
  184. data/test/ruby/rails/framework_spawner_spec.rb +6 -5
  185. data/test/ruby/rails/minimal_spawner_spec.rb +19 -0
  186. data/test/ruby/rails/spawner_error_handling_spec.rb +62 -7
  187. data/test/ruby/spawn_manager_spec.rb +10 -7
  188. data/test/ruby/spawn_server_spec.rb +1 -1
  189. data/test/ruby/utils_spec.rb +193 -20
  190. data/test/ruby/wsgi/application_spawner_spec.rb +3 -1
  191. data/test/stub/apache2/httpd.conf.erb +3 -0
  192. data/test/stub/rack/config.ru +1 -1
  193. data/test/stub/rails_apps/mycook/app/controllers/welcome_controller.rb +8 -0
  194. data/test/support/Support.cpp +84 -0
  195. data/test/support/Support.h +66 -8
  196. data/test/support/config.rb +14 -2
  197. data/test/support/test_helper.rb +5 -0
  198. data/vendor/rack-1.0.0-git/lib/rack/auth/openid.rb +123 -116
  199. data/vendor/rack-1.0.0-git/lib/rack/cascade.rb +17 -12
  200. data/vendor/rack-1.0.0-git/lib/rack/commonlogger.rb +34 -43
  201. data/vendor/rack-1.0.0-git/lib/rack/handler/cgi.rb +1 -1
  202. data/vendor/rack-1.0.0-git/lib/rack/handler/fastcgi.rb +1 -1
  203. data/vendor/rack-1.0.0-git/lib/rack/handler/lsws.rb +1 -1
  204. data/vendor/rack-1.0.0-git/lib/rack/handler/mongrel.rb +1 -1
  205. data/vendor/rack-1.0.0-git/lib/rack/handler/scgi.rb +1 -1
  206. data/vendor/rack-1.0.0-git/lib/rack/handler/webrick.rb +1 -1
  207. data/vendor/rack-1.0.0-git/lib/rack/mock.rb +4 -17
  208. data/vendor/rack-1.0.0-git/lib/rack/request.rb +3 -9
  209. data/vendor/rack-1.0.0-git/lib/rack/rewindable_input.rb +2 -0
  210. data/vendor/rack-1.0.0-git/lib/rack/utils.rb +38 -12
  211. metadata +231 -186
  212. data/ext/common/FileChecker.h +0 -112
  213. data/test/FileCheckerTest.cpp +0 -79
  214. data/test/stub/minimal-railsapp/README +0 -3
  215. data/test/stub/minimal-railsapp/config/application.rb +0 -0
  216. data/test/stub/minimal-railsapp/config/environment.rb +0 -3
  217. data/test/stub/minimal-railsapp/vendor/rails/actionmailer/lib/action_mailer.rb +0 -0
  218. data/test/stub/minimal-railsapp/vendor/rails/actionpack/lib/action_controller.rb +0 -10
  219. data/test/stub/minimal-railsapp/vendor/rails/actionpack/lib/action_pack.rb +0 -0
  220. data/test/stub/minimal-railsapp/vendor/rails/actionpack/lib/action_view.rb +0 -0
  221. data/test/stub/minimal-railsapp/vendor/rails/activerecord/lib/active_record.rb +0 -7
  222. data/test/stub/minimal-railsapp/vendor/rails/activeresource/lib/active_resource.rb +0 -0
  223. data/test/stub/minimal-railsapp/vendor/rails/activesupport/lib/active_support.rb +0 -17
  224. data/test/stub/minimal-railsapp/vendor/rails/activesupport/lib/active_support/whiny_nil.rb +0 -0
  225. data/test/stub/minimal-railsapp/vendor/rails/railties/lib/dispatcher.rb +0 -0
  226. data/test/stub/minimal-railsapp/vendor/rails/railties/lib/initializer.rb +0 -8
  227. data/test/stub/minimal-railsapp/vendor/rails/railties/lib/ruby_version_check.rb +0 -1
  228. data/test/stub/railsapp/app/controllers/application.rb +0 -12
  229. data/test/stub/railsapp/app/controllers/bar_controller.rb +0 -5
  230. data/test/stub/railsapp/app/controllers/bar_controller_1.txt +0 -5
  231. data/test/stub/railsapp/app/controllers/bar_controller_2.txt +0 -5
  232. data/test/stub/railsapp/app/controllers/foo_controller.rb +0 -9
  233. data/test/stub/railsapp/app/helpers/application_helper.rb +0 -3
  234. data/test/stub/railsapp/config/boot.rb +0 -108
  235. data/test/stub/railsapp/config/database.yml +0 -19
  236. data/test/stub/railsapp/config/environment.rb +0 -59
  237. data/test/stub/railsapp/config/environments/development.rb +0 -18
  238. data/test/stub/railsapp/config/environments/production.rb +0 -19
  239. data/test/stub/railsapp/config/initializers/inflections.rb +0 -10
  240. data/test/stub/railsapp/config/initializers/mime_types.rb +0 -5
  241. data/test/stub/railsapp/config/routes.rb +0 -35
  242. data/test/stub/railsapp/public/useless.txt +0 -1
  243. data/test/stub/railsapp2/app/controllers/application.rb +0 -12
  244. data/test/stub/railsapp2/app/controllers/foo_controller.rb +0 -5
  245. data/test/stub/railsapp2/app/helpers/application_helper.rb +0 -3
  246. data/test/stub/railsapp2/config/boot.rb +0 -108
  247. data/test/stub/railsapp2/config/database.yml +0 -19
  248. data/test/stub/railsapp2/config/environment.rb +0 -59
  249. data/test/stub/railsapp2/config/environments/development.rb +0 -18
  250. data/test/stub/railsapp2/config/environments/production.rb +0 -19
  251. data/test/stub/railsapp2/config/initializers/inflections.rb +0 -10
  252. data/test/stub/railsapp2/config/initializers/mime_types.rb +0 -5
  253. data/test/stub/railsapp2/config/routes.rb +0 -35
  254. 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 CachedMultiFileStat object used for caching stat() calls.
67
+ * A CachedFileStat object used for caching stat() calls.
68
68
  */
69
- extern CachedMultiFileStat *passenger_stat_cache;
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
- @main_loop_thread.raise(Interrupt.new("Cleaning up"))
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 !@main_loop_running
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
- file_descriptors_to_leave_open = [0, 1, 2, @child_socket.fileno]
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
- reload
83
- return @status
84
- end
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 domains
92
- reload
93
- return @domains
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 instances
97
- return domains.map do |domain|
98
- domain[:instances]
99
- end.flatten
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
- private
103
- def reload
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
- @domains = []
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
- @domains << d
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.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: The specified Ruby on Rails framework could not be loaded.
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
- # The following options are allowed:
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
- # - InvalidAppRoot: +app_root+ doesn't appear to be a valid Ruby on Rails application root.
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
- #print_exception(self.class.to_s, e.child_exception)
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 ArgumentError, AppInitError, ApplicationSpawner::Error => e
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