colouringcode-passenger 0.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (170) hide show
  1. data/NEWS +129 -0
  2. data/Rakefile +2 -2
  3. data/bin/passenger-install-apache2-module +1 -0
  4. data/bin/passenger-install-nginx-module +4 -2
  5. data/ext/apache2/Hooks.cpp +4 -2
  6. data/ext/common/ApplicationPoolServer.h +1 -1
  7. data/ext/common/ApplicationPoolServerExecutable.cpp +1 -1
  8. data/ext/common/MessageChannel.h +48 -4
  9. data/ext/common/StandardApplicationPool.h +4 -2
  10. data/ext/common/Version.h +1 -1
  11. data/ext/nginx/Configuration.c +1 -1
  12. data/ext/nginx/HttpStatusExtractor.h +1 -0
  13. data/ext/nginx/ScgiRequestParser.h +1 -0
  14. data/ext/oxt/system_calls.cpp +11 -0
  15. data/ext/oxt/system_calls.hpp +2 -1
  16. data/ext/oxt/thread.hpp +97 -1
  17. data/ext/phusion_passenger/native_support.c +30 -1
  18. data/lib/phusion_passenger/constants.rb +1 -1
  19. data/lib/phusion_passenger/dependencies.rb +32 -0
  20. data/lib/phusion_passenger/message_channel.rb +45 -3
  21. data/lib/phusion_passenger/platform_info.rb +1 -1
  22. data/lib/phusion_passenger/rack/application_spawner.rb +10 -4
  23. data/lib/phusion_passenger/rack/request_handler.rb +2 -5
  24. data/lib/phusion_passenger/railz/application_spawner.rb +59 -7
  25. data/lib/phusion_passenger/utils.rb +70 -16
  26. data/{vendor/rack-1.0.0-git/lib/rack → lib/phusion_passenger/utils}/rewindable_input.rb +34 -9
  27. data/test/ApplicationPoolTest.cpp +1 -1
  28. data/test/MessageChannelTest.cpp +9 -1
  29. data/test/stub/message_channel.rb +1 -1
  30. data/test/stub/message_channel_2.rb +1 -1
  31. data/test/stub/message_channel_3.rb +2 -2
  32. metadata +43 -155
  33. data/doc/Architectural overview.html +0 -1
  34. data/doc/rdoc/classes/ConditionVariable.html +0 -194
  35. data/doc/rdoc/classes/Exception.html +0 -120
  36. data/doc/rdoc/classes/GC.html +0 -113
  37. data/doc/rdoc/classes/IO.html +0 -169
  38. data/doc/rdoc/classes/PhusionPassenger.html +0 -238
  39. data/doc/rdoc/classes/PhusionPassenger/AbstractInstaller.html +0 -153
  40. data/doc/rdoc/classes/PhusionPassenger/AbstractRequestHandler.html +0 -517
  41. data/doc/rdoc/classes/PhusionPassenger/AbstractServer.html +0 -719
  42. data/doc/rdoc/classes/PhusionPassenger/AbstractServer/ServerAlreadyStarted.html +0 -97
  43. data/doc/rdoc/classes/PhusionPassenger/AbstractServer/ServerError.html +0 -96
  44. data/doc/rdoc/classes/PhusionPassenger/AbstractServer/ServerNotStarted.html +0 -97
  45. data/doc/rdoc/classes/PhusionPassenger/AbstractServer/UnknownMessage.html +0 -96
  46. data/doc/rdoc/classes/PhusionPassenger/AbstractServerCollection.html +0 -598
  47. data/doc/rdoc/classes/PhusionPassenger/AdminTools.html +0 -140
  48. data/doc/rdoc/classes/PhusionPassenger/AdminTools/ControlProcess.html +0 -317
  49. data/doc/rdoc/classes/PhusionPassenger/AdminTools/ControlProcess/Instance.html +0 -138
  50. data/doc/rdoc/classes/PhusionPassenger/AppInitError.html +0 -154
  51. data/doc/rdoc/classes/PhusionPassenger/Application.html +0 -283
  52. data/doc/rdoc/classes/PhusionPassenger/ConsoleTextTemplate.html +0 -172
  53. data/doc/rdoc/classes/PhusionPassenger/FrameworkInitError.html +0 -145
  54. data/doc/rdoc/classes/PhusionPassenger/HTMLTemplate.html +0 -181
  55. data/doc/rdoc/classes/PhusionPassenger/InitializationError.html +0 -141
  56. data/doc/rdoc/classes/PhusionPassenger/InvalidPath.html +0 -92
  57. data/doc/rdoc/classes/PhusionPassenger/MessageChannel.html +0 -489
  58. data/doc/rdoc/classes/PhusionPassenger/NativeSupport.html +0 -350
  59. data/doc/rdoc/classes/PhusionPassenger/Rack.html +0 -91
  60. data/doc/rdoc/classes/PhusionPassenger/Rack/ApplicationSpawner.html +0 -188
  61. data/doc/rdoc/classes/PhusionPassenger/Rack/RequestHandler.html +0 -199
  62. data/doc/rdoc/classes/PhusionPassenger/Railz.html +0 -95
  63. data/doc/rdoc/classes/PhusionPassenger/Railz/ApplicationSpawner.html +0 -438
  64. data/doc/rdoc/classes/PhusionPassenger/Railz/ApplicationSpawner/Error.html +0 -98
  65. data/doc/rdoc/classes/PhusionPassenger/Railz/CGIFixed.html +0 -200
  66. data/doc/rdoc/classes/PhusionPassenger/Railz/FrameworkSpawner.html +0 -436
  67. data/doc/rdoc/classes/PhusionPassenger/Railz/FrameworkSpawner/Error.html +0 -98
  68. data/doc/rdoc/classes/PhusionPassenger/Railz/RequestHandler.html +0 -155
  69. data/doc/rdoc/classes/PhusionPassenger/SpawnManager.html +0 -402
  70. data/doc/rdoc/classes/PhusionPassenger/UnknownError.html +0 -125
  71. data/doc/rdoc/classes/PhusionPassenger/Utils.html +0 -803
  72. data/doc/rdoc/classes/PhusionPassenger/Utils/PseudoIO.html +0 -169
  73. data/doc/rdoc/classes/PhusionPassenger/VersionNotFound.html +0 -140
  74. data/doc/rdoc/classes/PhusionPassenger/WSGI.html +0 -89
  75. data/doc/rdoc/classes/PhusionPassenger/WSGI/ApplicationSpawner.html +0 -188
  76. data/doc/rdoc/classes/PlatformInfo.html +0 -866
  77. data/doc/rdoc/classes/RakeExtensions.html +0 -197
  78. data/doc/rdoc/classes/Signal.html +0 -131
  79. data/doc/rdoc/created.rid +0 -1
  80. data/doc/rdoc/files/DEVELOPERS_TXT.html +0 -255
  81. data/doc/rdoc/files/README.html +0 -175
  82. data/doc/rdoc/files/ext/phusion_passenger/native_support_c.html +0 -92
  83. data/doc/rdoc/files/lib/phusion_passenger/abstract_installer_rb.html +0 -129
  84. data/doc/rdoc/files/lib/phusion_passenger/abstract_request_handler_rb.html +0 -129
  85. data/doc/rdoc/files/lib/phusion_passenger/abstract_server_collection_rb.html +0 -126
  86. data/doc/rdoc/files/lib/phusion_passenger/abstract_server_rb.html +0 -128
  87. data/doc/rdoc/files/lib/phusion_passenger/admin_tools/control_process_rb.html +0 -130
  88. data/doc/rdoc/files/lib/phusion_passenger/admin_tools_rb.html +0 -122
  89. data/doc/rdoc/files/lib/phusion_passenger/application_rb.html +0 -127
  90. data/doc/rdoc/files/lib/phusion_passenger/console_text_template_rb.html +0 -126
  91. data/doc/rdoc/files/lib/phusion_passenger/constants_rb.html +0 -122
  92. data/doc/rdoc/files/lib/phusion_passenger/dependencies_rb.html +0 -134
  93. data/doc/rdoc/files/lib/phusion_passenger/events_rb.html +0 -122
  94. data/doc/rdoc/files/lib/phusion_passenger/exceptions_rb.html +0 -122
  95. data/doc/rdoc/files/lib/phusion_passenger/html_template_rb.html +0 -126
  96. data/doc/rdoc/files/lib/phusion_passenger/message_channel_rb.html +0 -120
  97. data/doc/rdoc/files/lib/phusion_passenger/packaging_rb.html +0 -122
  98. data/doc/rdoc/files/lib/phusion_passenger/platform_info_rb.html +0 -127
  99. data/doc/rdoc/files/lib/phusion_passenger/rack/application_spawner_rb.html +0 -133
  100. data/doc/rdoc/files/lib/phusion_passenger/rack/request_handler_rb.html +0 -125
  101. data/doc/rdoc/files/lib/phusion_passenger/railz/application_spawner_rb.html +0 -140
  102. data/doc/rdoc/files/lib/phusion_passenger/railz/cgi_fixed_rb.html +0 -126
  103. data/doc/rdoc/files/lib/phusion_passenger/railz/framework_spawner_rb.html +0 -145
  104. data/doc/rdoc/files/lib/phusion_passenger/railz/request_handler_rb.html +0 -125
  105. data/doc/rdoc/files/lib/phusion_passenger/simple_benchmarking_rb.html +0 -122
  106. data/doc/rdoc/files/lib/phusion_passenger/spawn_manager_rb.html +0 -159
  107. data/doc/rdoc/files/lib/phusion_passenger/utils_rb.html +0 -174
  108. data/doc/rdoc/files/lib/phusion_passenger/wsgi/application_spawner_rb.html +0 -129
  109. data/doc/rdoc/files/misc/rake/extensions_rb.html +0 -130
  110. data/doc/rdoc/fr_class_index.html +0 -91
  111. data/doc/rdoc/fr_file_index.html +0 -76
  112. data/doc/rdoc/fr_method_index.html +0 -205
  113. data/doc/rdoc/index.html +0 -26
  114. data/doc/rdoc/rdoc-style.css +0 -187
  115. data/vendor/README +0 -13
  116. data/vendor/README_FOR_PACKAGERS +0 -1
  117. data/vendor/rack-1.0.0-git/COPYING +0 -18
  118. data/vendor/rack-1.0.0-git/KNOWN-ISSUES +0 -18
  119. data/vendor/rack-1.0.0-git/README +0 -353
  120. data/vendor/rack-1.0.0-git/Rakefile +0 -164
  121. data/vendor/rack-1.0.0-git/lib/rack.rb +0 -90
  122. data/vendor/rack-1.0.0-git/lib/rack/adapter/camping.rb +0 -22
  123. data/vendor/rack-1.0.0-git/lib/rack/auth/abstract/handler.rb +0 -37
  124. data/vendor/rack-1.0.0-git/lib/rack/auth/abstract/request.rb +0 -37
  125. data/vendor/rack-1.0.0-git/lib/rack/auth/basic.rb +0 -58
  126. data/vendor/rack-1.0.0-git/lib/rack/auth/digest/md5.rb +0 -124
  127. data/vendor/rack-1.0.0-git/lib/rack/auth/digest/nonce.rb +0 -51
  128. data/vendor/rack-1.0.0-git/lib/rack/auth/digest/params.rb +0 -55
  129. data/vendor/rack-1.0.0-git/lib/rack/auth/digest/request.rb +0 -40
  130. data/vendor/rack-1.0.0-git/lib/rack/auth/openid.rb +0 -487
  131. data/vendor/rack-1.0.0-git/lib/rack/builder.rb +0 -63
  132. data/vendor/rack-1.0.0-git/lib/rack/cascade.rb +0 -41
  133. data/vendor/rack-1.0.0-git/lib/rack/chunked.rb +0 -49
  134. data/vendor/rack-1.0.0-git/lib/rack/commonlogger.rb +0 -52
  135. data/vendor/rack-1.0.0-git/lib/rack/conditionalget.rb +0 -47
  136. data/vendor/rack-1.0.0-git/lib/rack/content_length.rb +0 -29
  137. data/vendor/rack-1.0.0-git/lib/rack/content_type.rb +0 -23
  138. data/vendor/rack-1.0.0-git/lib/rack/deflater.rb +0 -96
  139. data/vendor/rack-1.0.0-git/lib/rack/directory.rb +0 -153
  140. data/vendor/rack-1.0.0-git/lib/rack/file.rb +0 -88
  141. data/vendor/rack-1.0.0-git/lib/rack/handler.rb +0 -69
  142. data/vendor/rack-1.0.0-git/lib/rack/handler/cgi.rb +0 -61
  143. data/vendor/rack-1.0.0-git/lib/rack/handler/evented_mongrel.rb +0 -8
  144. data/vendor/rack-1.0.0-git/lib/rack/handler/fastcgi.rb +0 -88
  145. data/vendor/rack-1.0.0-git/lib/rack/handler/lsws.rb +0 -55
  146. data/vendor/rack-1.0.0-git/lib/rack/handler/mongrel.rb +0 -84
  147. data/vendor/rack-1.0.0-git/lib/rack/handler/scgi.rb +0 -59
  148. data/vendor/rack-1.0.0-git/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
  149. data/vendor/rack-1.0.0-git/lib/rack/handler/thin.rb +0 -18
  150. data/vendor/rack-1.0.0-git/lib/rack/handler/webrick.rb +0 -67
  151. data/vendor/rack-1.0.0-git/lib/rack/head.rb +0 -19
  152. data/vendor/rack-1.0.0-git/lib/rack/lint.rb +0 -537
  153. data/vendor/rack-1.0.0-git/lib/rack/lobster.rb +0 -65
  154. data/vendor/rack-1.0.0-git/lib/rack/lock.rb +0 -16
  155. data/vendor/rack-1.0.0-git/lib/rack/methodoverride.rb +0 -27
  156. data/vendor/rack-1.0.0-git/lib/rack/mime.rb +0 -204
  157. data/vendor/rack-1.0.0-git/lib/rack/mock.rb +0 -184
  158. data/vendor/rack-1.0.0-git/lib/rack/recursive.rb +0 -57
  159. data/vendor/rack-1.0.0-git/lib/rack/reloader.rb +0 -106
  160. data/vendor/rack-1.0.0-git/lib/rack/request.rb +0 -248
  161. data/vendor/rack-1.0.0-git/lib/rack/response.rb +0 -183
  162. data/vendor/rack-1.0.0-git/lib/rack/session/abstract/id.rb +0 -142
  163. data/vendor/rack-1.0.0-git/lib/rack/session/cookie.rb +0 -91
  164. data/vendor/rack-1.0.0-git/lib/rack/session/memcache.rb +0 -109
  165. data/vendor/rack-1.0.0-git/lib/rack/session/pool.rb +0 -100
  166. data/vendor/rack-1.0.0-git/lib/rack/showexceptions.rb +0 -349
  167. data/vendor/rack-1.0.0-git/lib/rack/showstatus.rb +0 -106
  168. data/vendor/rack-1.0.0-git/lib/rack/static.rb +0 -38
  169. data/vendor/rack-1.0.0-git/lib/rack/urlmap.rb +0 -55
  170. data/vendor/rack-1.0.0-git/lib/rack/utils.rb +0 -522
@@ -30,6 +30,7 @@
30
30
  #include <string.h>
31
31
  #include <unistd.h>
32
32
  #include <errno.h>
33
+ #include <grp.h>
33
34
  #ifdef __OpenBSD__
34
35
  // OpenBSD needs this for 'struct iovec'. Apparently it isn't
35
36
  // always included by unistd.h and sys/types.h.
@@ -158,10 +159,14 @@ recv_fd(VALUE self, VALUE socket_fd) {
158
159
  }
159
160
 
160
161
  control_header = CMSG_FIRSTHDR(&msg);
162
+ if (control_header == NULL) {
163
+ rb_raise(rb_eIOError, "No valid file descriptor received.");
164
+ return Qnil;
165
+ }
161
166
  if (control_header->cmsg_len != EXPECTED_CMSG_LEN
162
167
  || control_header->cmsg_level != SOL_SOCKET
163
168
  || control_header->cmsg_type != SCM_RIGHTS) {
164
- rb_sys_fail("No valid file descriptor received.");
169
+ rb_raise(rb_eIOError, "No valid file descriptor received.");
165
170
  return Qnil;
166
171
  }
167
172
  #if defined(__APPLE__) || defined(__SOLARIS__) || defined(__arm__)
@@ -282,6 +287,29 @@ disable_stdio_buffering() {
282
287
  return Qnil;
283
288
  }
284
289
 
290
+ /**
291
+ * Ruby's implementations of initgroups, setgid and setuid are broken various ways,
292
+ * sigh...
293
+ * Ruby's setgid and setuid can't handle negative UIDs and initgroups is just broken.
294
+ * Work around it by using our own implementation.
295
+ */
296
+ static VALUE
297
+ switch_user(VALUE self, VALUE username, VALUE uid, VALUE gid) {
298
+ uid_t the_uid = NUM2LL(uid);
299
+ gid_t the_gid = NUM2LL(gid);
300
+
301
+ if (initgroups(RSTRING_PTR(username), the_gid) == -1) {
302
+ rb_sys_fail("initgroups");
303
+ }
304
+ if (setgid(the_gid) == -1) {
305
+ rb_sys_fail("setgid");
306
+ }
307
+ if (setuid(the_uid) == -1) {
308
+ rb_sys_fail("setuid");
309
+ }
310
+ return Qnil;
311
+ }
312
+
285
313
  /***************************/
286
314
 
287
315
  void
@@ -302,6 +330,7 @@ Init_native_support() {
302
330
  rb_define_singleton_method(mNativeSupport, "accept", f_accept, 1);
303
331
  rb_define_singleton_method(mNativeSupport, "close_all_file_descriptors", close_all_file_descriptors, 1);
304
332
  rb_define_singleton_method(mNativeSupport, "disable_stdio_buffering", disable_stdio_buffering, 0);
333
+ rb_define_singleton_method(mNativeSupport, "switch_user", switch_user, 3);
305
334
 
306
335
  /* The maximum length of a Unix socket path, including terminating null. */
307
336
  rb_define_const(mNativeSupport, "UNIX_PATH_MAX", INT2NUM(sizeof(addr.sun_path)));
@@ -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.7'
27
+ VERSION_STRING = '2.2.12'
28
28
 
29
29
  DEFAULT_FRAMEWORK_SPAWNER_MAX_IDLE_TIME = 30 * 60
30
30
  DEFAULT_APP_SPAWNER_MAX_IDLE_TIME = 10 * 60
@@ -357,6 +357,38 @@ module Dependencies # :nodoc: all
357
357
  dep.install_instructions = "Please install RubyGems first, then run <b>#{PlatformInfo::GEM || "gem"} install rack</b>"
358
358
  end
359
359
 
360
+ OpenSSL_Dev = Dependency.new do |dep|
361
+ dep.name = "OpenSSL development headers"
362
+ dep.define_checker do |result|
363
+ source_file = '/tmp/passenger-openssl-check.c'
364
+ object_file = '/tmp/passenger-openssl-check.o'
365
+ begin
366
+ File.open(source_file, 'w') do |f|
367
+ f.write("#include <openssl/ssl.h>")
368
+ end
369
+ Dir.chdir(File.dirname(source_file)) do
370
+ if system("(gcc #{ENV['CFLAGS']} -c '#{source_file}') >/dev/null 2>/dev/null")
371
+ result.found
372
+ else
373
+ result.not_found
374
+ end
375
+ end
376
+ ensure
377
+ File.unlink(source_file) rescue nil
378
+ File.unlink(object_file) rescue nil
379
+ end
380
+ end
381
+ if RUBY_PLATFORM =~ /linux/
382
+ tags = PlatformInfo.linux_distro_tags
383
+ if tags.include?(:debian)
384
+ dep.install_command = "apt-get install libssl-dev"
385
+ elsif tags.include?(:redhat)
386
+ dep.install_command = "yum install openssl-devel"
387
+ end
388
+ end
389
+ dep.website = "http://www.openssl.org/"
390
+ end
391
+
360
392
  Zlib_Dev = Dependency.new do |dep|
361
393
  dep.name = "Zlib development headers"
362
394
  dep.define_checker do |result|
@@ -193,8 +193,11 @@ class MessageChannel
193
193
  #
194
194
  # Might raise SystemCallError, IOError or SocketError when something
195
195
  # goes wrong.
196
- def recv_io
197
- return @io.recv_io
196
+ def recv_io(klass = IO, negotiate = true)
197
+ write("pass IO") if negotiate
198
+ io = @io.recv_io(klass)
199
+ write("got IO") if negotiate
200
+ return io
198
201
  end
199
202
 
200
203
  # Send an IO object (a file descriptor) over the channel. The other
@@ -204,7 +207,46 @@ class MessageChannel
204
207
  # Might raise SystemCallError, IOError or SocketError when something
205
208
  # goes wrong.
206
209
  def send_io(io)
207
- @io.send_io(io)
210
+ # We read a message before actually calling #send_io
211
+ # in order to prevent the other side from accidentally
212
+ # read()ing past the normal data and reading our file
213
+ # descriptor too.
214
+ #
215
+ # For example suppose that side A looks like this:
216
+ #
217
+ # read(fd, buf, 1024)
218
+ # read_io(fd)
219
+ #
220
+ # and side B:
221
+ #
222
+ # write(fd, buf, 100)
223
+ # send_io(fd_to_pass)
224
+ #
225
+ # If B completes both write() and send_io(), then A's read() call
226
+ # reads past the 100 bytes that B sent. On some platforms, like
227
+ # Linux, this will cause read_io() to fail. And it just so happens
228
+ # that Ruby's IO#read method slurps more than just the given amount
229
+ # of bytes.
230
+ result = read
231
+ if !result
232
+ raise EOFError, "End of stream"
233
+ elsif result != ["pass IO"]
234
+ raise IOError, "IO passing pre-negotiation header expected"
235
+ else
236
+ @io.send_io(io)
237
+ # Once you've sent the IO you expect to be able to close it on the
238
+ # sender's side, even if the other side hasn't read the IO yet.
239
+ # Not so: on some operating systems (I'm looking at you OS X) this
240
+ # can cause the receiving side to receive a bad file descriptor.
241
+ # The post negotiation protocol ensures that we block until the
242
+ # other side has really received the IO.
243
+ result = read
244
+ if !result
245
+ raise EOFError, "End of stream"
246
+ elsif result != ["got IO"]
247
+ raise IOError, "IO passing post-negotiation header expected"
248
+ end
249
+ end
208
250
  end
209
251
 
210
252
  # Return the file descriptor of the underlying IO object.
@@ -346,7 +346,7 @@ public
346
346
  flags << '-DBOOST_HAS_STDINT_H -D_GLIBCPP__PTHREADS'
347
347
  elsif RUBY_PLATFORM =~ /aix/
348
348
  flags << '-DOXT_DISABLE_BACKTRACES'
349
- elsif RUBY_PLATFORM =~ /(sparc-linux|arm-linux)/
349
+ elsif RUBY_PLATFORM =~ /(sparc-linux|arm-linux|sh4-linux)/
350
350
  # http://code.google.com/p/phusion-passenger/issues/detail?id=200
351
351
  # http://groups.google.com/group/phusion-passenger/t/6b904a962ee28e5c
352
352
  flags << '-DBOOST_SP_USE_PTHREADS'
@@ -21,10 +21,6 @@
21
21
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
22
  # THE SOFTWARE.
23
23
 
24
- rack_dir = File.expand_path(File.dirname(__FILE__) + "/../../../vendor/rack-1.0.0-git/lib")
25
- $LOAD_PATH.unshift(rack_dir) if !$LOAD_PATH.include?(rack_dir)
26
- require 'rack'
27
-
28
24
  require 'socket'
29
25
  require 'phusion_passenger/application'
30
26
  require 'phusion_passenger/events'
@@ -90,6 +86,7 @@ private
90
86
  app = nil
91
87
  success = report_app_init_status(channel) do
92
88
  ENV['RACK_ENV'] = options["environment"]
89
+ ENV['RAILS_ENV'] = options["environment"]
93
90
  if options["base_uri"] && options["base_uri"] != "/"
94
91
  ENV['RACK_BASE_URI'] = options["base_uri"]
95
92
  ENV['RAILS_RELATIVE_URL_ROOT'] = options["base_uri"]
@@ -101,6 +98,11 @@ private
101
98
  if options["lower_privilege"]
102
99
  lower_privilege('config.ru', options["lowest_user"])
103
100
  end
101
+ # Make sure RubyGems uses any new environment variable values
102
+ # that have been set now (e.g. $HOME, $GEM_HOME, etc) and that
103
+ # it is able to detect newly installed gems.
104
+ Gem.clear_paths
105
+ setup_bundler_support
104
106
  app = load_rack_app
105
107
  end
106
108
 
@@ -137,6 +139,10 @@ private
137
139
  end
138
140
 
139
141
  def load_rack_app
142
+ # Load Rack inside the spawned child process so that the spawn manager
143
+ # itself doesn't preload Rack. This is necessary because some broken
144
+ # Rails apps explicitly specify a Rack version as dependency.
145
+ require 'rack'
140
146
  rackup_code = ::File.read("config.ru")
141
147
  eval("Rack::Builder.new {( #{rackup_code}\n )}.to_app", TOPLEVEL_BINDING, "config.ru")
142
148
  end
@@ -22,11 +22,8 @@
22
22
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
23
  # THE SOFTWARE.
24
24
 
25
- rack_dir = File.expand_path(File.dirname(__FILE__) + "/../../../vendor/rack-1.0.0-git/lib")
26
- $LOAD_PATH.unshift(rack_dir) if !$LOAD_PATH.include?(rack_dir)
27
- require 'rack/rewindable_input'
28
-
29
25
  require 'phusion_passenger/abstract_request_handler'
26
+ require 'phusion_passenger/utils/rewindable_input'
30
27
 
31
28
  module PhusionPassenger
32
29
  module Rack
@@ -64,7 +61,7 @@ class RequestHandler < AbstractRequestHandler
64
61
  protected
65
62
  # Overrided method.
66
63
  def process_request(env, input, output)
67
- rewindable_input = ::Rack::RewindableInput.new(input)
64
+ rewindable_input = Utils::RewindableInput.new(input)
68
65
  begin
69
66
  env[RACK_VERSION] = RACK_VERSION_VALUE
70
67
  env[RACK_INPUT] = rewindable_input
@@ -161,6 +161,7 @@ class ApplicationSpawner < AbstractServer
161
161
  channel = MessageChannel.new(b)
162
162
  success = report_app_init_status(channel) do
163
163
  ENV['RAILS_ENV'] = @environment
164
+ ENV['RACK_ENV'] = @environment
164
165
  ENV['RAILS_RELATIVE_URL_ROOT'] = @base_uri
165
166
  Dir.chdir(@app_root)
166
167
  if @encoded_environment_variables
@@ -169,6 +170,11 @@ class ApplicationSpawner < AbstractServer
169
170
  if @lower_privilege
170
171
  lower_privilege('config/environment.rb', @lowest_user)
171
172
  end
173
+ # Make sure RubyGems uses any new environment variable values
174
+ # that have been set now (e.g. $HOME, $GEM_HOME, etc) and that
175
+ # it is able to detect newly installed gems.
176
+ Gem.clear_paths
177
+ setup_bundler_support
172
178
 
173
179
  require File.expand_path('config/environment')
174
180
  require 'dispatcher'
@@ -233,6 +239,7 @@ protected
233
239
  report_app_init_status(client) do
234
240
  $0 = "Passenger ApplicationSpawner: #{@app_root}"
235
241
  ENV['RAILS_ENV'] = @environment
242
+ ENV['RACK_ENV'] = @environment
236
243
  ENV['RAILS_RELATIVE_URL_ROOT'] = @base_uri
237
244
  if defined?(RAILS_ENV)
238
245
  Object.send(:remove_const, :RAILS_ENV)
@@ -245,6 +252,11 @@ protected
245
252
  if @lower_privilege
246
253
  lower_privilege('config/environment.rb', @lowest_user)
247
254
  end
255
+ # Make sure RubyGems uses any new environment variable values
256
+ # that have been set now (e.g. $HOME, $GEM_HOME, etc) and that
257
+ # it is able to detect newly installed gems.
258
+ Gem.clear_paths
259
+ setup_bundler_support
248
260
  preload_application
249
261
  end
250
262
  end
@@ -307,17 +319,28 @@ private
307
319
  if !defined?(Dispatcher)
308
320
  require 'dispatcher'
309
321
  end
322
+ # Rails 2.2+ uses application_controller.rb while older versions use application.rb.
310
323
  begin
311
324
  require_dependency 'application_controller'
312
- rescue LoadError
313
- require_dependency 'application'
325
+ rescue LoadError => e
326
+ begin
327
+ require_dependency 'application'
328
+ rescue LoadError
329
+ # Considering that most apps these das are written in Rails
330
+ # 2.2+, if application.rb cannot be loaded either then it
331
+ # probably just means that application_controller.rb threw
332
+ # a LoadError. So we raise the original error here; if the
333
+ # app is based on Rails < 2.2 then the error will make less
334
+ # sense but we can only choose one or the other.
335
+ raise e
336
+ end
314
337
  end
315
338
 
316
339
  # - No point in preloading the application sources if the garbage collector
317
340
  # isn't copy-on-write friendly.
318
341
  # - Rails >= 2.2 already preloads application sources by default, so no need
319
342
  # to do that again.
320
- if GC.copy_on_write_friendly? && !::Rails::Initializer.method_defined?(:load_application_classes)
343
+ if GC.copy_on_write_friendly? && !rails_will_preload_app_code?
321
344
  ['models','controllers','helpers'].each do |section|
322
345
  Dir.glob("app/#{section}}/*.rb").each do |file|
323
346
  require_dependency canonicalize_path(file)
@@ -325,11 +348,22 @@ private
325
348
  end
326
349
  end
327
350
  end
351
+
352
+ def rails_will_preload_app_code?
353
+ if defined?(Rails::Initializer)
354
+ return ::Rails::Initializer.method_defined?(:load_application_classes)
355
+ else
356
+ return defined?(::Rails3)
357
+ end
358
+ end
328
359
 
329
360
  def handle_spawn_application
361
+ a, b = UNIXSocket.pair
330
362
  safe_fork('application', true) do
331
363
  begin
332
- start_request_handler(client, true)
364
+ a.close
365
+ client.close
366
+ start_request_handler(MessageChannel.new(b), true)
333
367
  rescue SignalException => e
334
368
  if e.message != AbstractRequestHandler::HARD_TERMINATION_SIGNAL &&
335
369
  e.message != AbstractRequestHandler::SOFT_TERMINATION_SIGNAL
@@ -337,6 +371,17 @@ private
337
371
  end
338
372
  end
339
373
  end
374
+
375
+ b.close
376
+ worker_channel = MessageChannel.new(a)
377
+ info = worker_channel.read
378
+ owner_pipe = worker_channel.recv_io
379
+ client.write(*info)
380
+ client.send_io(owner_pipe)
381
+ ensure
382
+ a.close if a
383
+ b.close if b && !b.closed?
384
+ owner_pipe.close if owner_pipe
340
385
  end
341
386
 
342
387
  # Initialize the request handler and enter its main loop.
@@ -348,11 +393,18 @@ private
348
393
  $0 = "Rails: #{@app_root}"
349
394
  reader, writer = IO.pipe
350
395
  begin
351
- # Re-establish connection if a connection was established
396
+ # Clear or re-establish connection if a connection was established
352
397
  # in environment.rb. This prevents us from concurrently
353
398
  # accessing the same MySQL connection handle.
354
- if defined?(::ActiveRecord::Base) && ::ActiveRecord::Base.connected?
355
- ::ActiveRecord::Base.establish_connection
399
+ if defined?(::ActiveRecord::Base)
400
+ if ::ActiveRecord::Base.respond_to?(:clear_all_connections!)
401
+ ::ActiveRecord::Base.clear_all_connections!
402
+ elsif ::ActiveRecord::Base.respond_to?(:clear_active_connections!)
403
+ ::ActiveRecord::Base.clear_active_connections!
404
+ elsif ::ActiveRecord::Base.respond_to?(:connected?) &&
405
+ ::ActiveRecord::Base.connected?
406
+ ::ActiveRecord::Base.establish_connection
407
+ end
356
408
  end
357
409
 
358
410
  reader.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
@@ -32,6 +32,7 @@ require 'etc'
32
32
  require 'fcntl'
33
33
  require 'tempfile'
34
34
  require 'stringio'
35
+ require 'phusion_passenger/packaging'
35
36
  require 'phusion_passenger/exceptions'
36
37
  if !defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby"
37
38
  require 'phusion_passenger/native_support'
@@ -163,6 +164,59 @@ protected
163
164
  end
164
165
  end
165
166
 
167
+ def setup_bundler_support
168
+ # Rack::ApplicationSpawner depends on the 'rack' library, but the app
169
+ # might want us to use a bundled version instead of a
170
+ # gem/apt-get/yum/whatever-installed version. Therefore we must setup
171
+ # the correct load paths before requiring 'rack'.
172
+ #
173
+ # The most popular tool for bundling dependencies is Bundler. Bundler
174
+ # works as follows:
175
+ # - If the bundle is locked then a file .bundle/environment.rb exists
176
+ # which will setup the load paths.
177
+ # - If the bundle is not locked then the load paths must be set up by
178
+ # calling Bundler.setup.
179
+ # - Rails 3's boot.rb automatically loads .bundle/environment.rb or
180
+ # calls Bundler.setup if that's not available.
181
+ # - Other Rack apps might not have a boot.rb but we still want to setup
182
+ # Bundler.
183
+ #
184
+ # So the strategy is as follows:
185
+
186
+ # If the Bundler lock environment file exists then load that. If it
187
+ # exists then there's a 99.9% chance that loading it is the correct
188
+ # thing to do.
189
+ if File.exist?('.bundle/environment.rb')
190
+ require File.expand_path('.bundle/environment')
191
+
192
+ # If the Bundler environment file doesn't exist then there are two
193
+ # possibilities:
194
+ # 1. Bundler is not used, in which case we don't have to do anything.
195
+ # 2. Bundler *is* used, but the gems are not locked and we're supposed
196
+ # to call Bundler.setup.
197
+ #
198
+ # The existence of Gemfile indicates whether (2) is true:
199
+ elsif File.exist?('Gemfile')
200
+ # In case of Rails 3, config/boot.rb already calls Bundler.setup.
201
+ # However older versions of Rails don't so loading boot.rb might
202
+ # not be the correct thing to do. To be on the safe side we
203
+ # call Bundler.setup ourselves; if this isn't the correct thing
204
+ # to do after all then there's always the load_path_setup_file
205
+ # option.
206
+ require 'rubygems'
207
+ require 'bundler'
208
+ Bundler.setup
209
+ end
210
+
211
+ # Bundler might remove Phusion Passenger from the load path in its zealous
212
+ # attempt to un-require RubyGems, so here we put Phusion Passenger back
213
+ # into the load path.
214
+ if $LOAD_PATH.first != LIBDIR
215
+ $LOAD_PATH.unshift(LIBDIR)
216
+ $LOAD_PATH.uniq!
217
+ end
218
+ end
219
+
166
220
  # Fork a new process and run the given block inside the child process, just like
167
221
  # fork(). Unlike fork(), this method is safe, i.e. there's no way for the child
168
222
  # process to escape the block. Any uncaught exceptions in the child process will
@@ -371,15 +425,7 @@ protected
371
425
  if uid == 0
372
426
  return false
373
427
  else
374
- # Some systems are broken. initgroups can fail because of
375
- # all kinds of stupid reasons. So we ignore any errors
376
- # raised by initgroups.
377
- begin
378
- Process.groups = Process.initgroups(username, gid)
379
- rescue
380
- end
381
- Process::Sys.setgid(gid)
382
- Process::Sys.setuid(uid)
428
+ NativeSupport.switch_user(username, uid, gid)
383
429
  ENV['HOME'] = pw.dir
384
430
  return true
385
431
  end
@@ -538,8 +584,8 @@ class IO
538
584
  # This only works if this IO channel is a Unix socket.
539
585
  #
540
586
  # Raises SystemCallError if something went wrong.
541
- def recv_io
542
- return IO.new(PhusionPassenger::NativeSupport.recv_fd(self.fileno))
587
+ def recv_io(klass = IO)
588
+ return klass.for_fd(PhusionPassenger::NativeSupport.recv_fd(self.fileno))
543
589
  end
544
590
  end
545
591
 
@@ -559,7 +605,6 @@ module Signal
559
605
  result = Signal.list
560
606
  result.delete("ALRM")
561
607
  result.delete("VTALRM")
562
- return result
563
608
  when "jruby"
564
609
  result = Signal.list
565
610
  result.delete("QUIT")
@@ -567,12 +612,21 @@ module Signal
567
612
  result.delete("FPE")
568
613
  result.delete("KILL")
569
614
  result.delete("SEGV")
570
- result.delete("STOP")
571
615
  result.delete("USR1")
572
- return result
573
616
  else
574
- return Signal.list
617
+ result = Signal.list
575
618
  end
619
+
620
+ # Don't touch SIGCHLD no matter what! On OS X waitpid() will
621
+ # malfunction if SIGCHLD doesn't have a correct handler.
622
+ result.delete("CLD")
623
+ result.delete("CHLD")
624
+
625
+ # Other stuff that we don't want to trap no matter which
626
+ # Ruby engine.
627
+ result.delete("STOP")
628
+
629
+ return result
576
630
  end
577
631
  end
578
632
 
@@ -582,7 +636,7 @@ end
582
636
  if RUBY_PLATFORM =~ /freebsd/ || RUBY_PLATFORM =~ /openbsd/ || (RUBY_PLATFORM =~ /darwin/ && RUBY_PLATFORM !~ /universal/)
583
637
  require 'socket'
584
638
  UNIXSocket.class_eval do
585
- def recv_io
639
+ def recv_io(klass = IO)
586
640
  super
587
641
  end
588
642