colouringcode-passenger 0.1 → 0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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