passenger 1.0.1 → 1.0.2

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 (123) hide show
  1. data/LICENSE +3 -1
  2. data/Rakefile +17 -12
  3. data/bin/passenger-config +22 -0
  4. data/bin/passenger-install-apache2-module +2 -31
  5. data/bin/passenger-make-enterprisey +66 -0
  6. data/bin/passenger-memory-stats +192 -0
  7. data/doc/Users guide.html +150 -66
  8. data/doc/Users guide.txt +141 -51
  9. data/doc/cxxapi/ApplicationPoolClientServer_8h-source.html +1 -1
  10. data/doc/cxxapi/ApplicationPoolServer_8h-source.html +545 -0
  11. data/doc/cxxapi/ApplicationPool_8h-source.html +1 -1
  12. data/doc/cxxapi/Application_8h-source.html +1 -1
  13. data/doc/cxxapi/Configuration_8h-source.html +2 -2
  14. data/doc/cxxapi/DummySpawnManager_8h-source.html +1 -1
  15. data/doc/cxxapi/Exceptions_8h-source.html +1 -1
  16. data/doc/cxxapi/Hooks_8h-source.html +1 -1
  17. data/doc/cxxapi/Logging_8h-source.html +1 -1
  18. data/doc/cxxapi/MessageChannel_8h-source.html +210 -205
  19. data/doc/cxxapi/SpawnManager_8h-source.html +1 -1
  20. data/doc/cxxapi/StandardApplicationPool_8h-source.html +1 -1
  21. data/doc/cxxapi/Utils_8h-source.html +1 -1
  22. data/doc/cxxapi/annotated.html +1 -1
  23. data/doc/cxxapi/classClient-members.html +30 -0
  24. data/doc/cxxapi/classClient.html +112 -0
  25. data/doc/cxxapi/classPassenger_1_1Application-members.html +1 -1
  26. data/doc/cxxapi/classPassenger_1_1Application.html +1 -1
  27. data/doc/cxxapi/classPassenger_1_1ApplicationPool-members.html +1 -1
  28. data/doc/cxxapi/classPassenger_1_1ApplicationPool.html +1 -1
  29. data/doc/cxxapi/classPassenger_1_1ApplicationPoolServer-members.html +1 -1
  30. data/doc/cxxapi/classPassenger_1_1ApplicationPoolServer.html +1 -1
  31. data/doc/cxxapi/classPassenger_1_1Application_1_1Session-members.html +1 -1
  32. data/doc/cxxapi/classPassenger_1_1Application_1_1Session.html +1 -1
  33. data/doc/cxxapi/classPassenger_1_1ConfigurationException-members.html +28 -0
  34. data/doc/cxxapi/classPassenger_1_1ConfigurationException.html +41 -0
  35. data/doc/cxxapi/classPassenger_1_1DummySpawnManager-members.html +1 -1
  36. data/doc/cxxapi/classPassenger_1_1DummySpawnManager.html +1 -1
  37. data/doc/cxxapi/classPassenger_1_1FileNotFoundException-members.html +1 -1
  38. data/doc/cxxapi/classPassenger_1_1FileNotFoundException.html +1 -1
  39. data/doc/cxxapi/classPassenger_1_1IOException-members.html +1 -1
  40. data/doc/cxxapi/classPassenger_1_1IOException.html +1 -1
  41. data/doc/cxxapi/classPassenger_1_1MessageChannel-members.html +1 -1
  42. data/doc/cxxapi/classPassenger_1_1MessageChannel.html +1 -1
  43. data/doc/cxxapi/classPassenger_1_1SpawnException-members.html +1 -1
  44. data/doc/cxxapi/classPassenger_1_1SpawnException.html +1 -1
  45. data/doc/cxxapi/classPassenger_1_1SpawnManager-members.html +1 -1
  46. data/doc/cxxapi/classPassenger_1_1SpawnManager.html +1 -1
  47. data/doc/cxxapi/classPassenger_1_1StandardApplicationPool-members.html +1 -1
  48. data/doc/cxxapi/classPassenger_1_1StandardApplicationPool.html +1 -1
  49. data/doc/cxxapi/classPassenger_1_1SystemException-members.html +1 -1
  50. data/doc/cxxapi/classPassenger_1_1SystemException.html +1 -1
  51. data/doc/cxxapi/definitions_8h-source.html +1 -1
  52. data/doc/cxxapi/files.html +1 -1
  53. data/doc/cxxapi/functions.html +1 -1
  54. data/doc/cxxapi/functions_func.html +1 -1
  55. data/doc/cxxapi/functions_type.html +1 -1
  56. data/doc/cxxapi/graph_legend.html +1 -1
  57. data/doc/cxxapi/graph_legend.png +0 -0
  58. data/doc/cxxapi/group__Configuration.html +3 -3
  59. data/doc/cxxapi/group__Configuration.png +0 -0
  60. data/doc/cxxapi/group__Core.html +1 -1
  61. data/doc/cxxapi/group__Core.png +0 -0
  62. data/doc/cxxapi/group__Exceptions.html +1 -1
  63. data/doc/cxxapi/group__Hooks.html +1 -1
  64. data/doc/cxxapi/group__Hooks.png +0 -0
  65. data/doc/cxxapi/group__Support.html +1 -1
  66. data/doc/cxxapi/hierarchy.html +1 -1
  67. data/doc/cxxapi/inherit__graph__0.png +0 -0
  68. data/doc/cxxapi/inherit__graph__1.png +0 -0
  69. data/doc/cxxapi/inherit__graph__10.map +1 -0
  70. data/doc/cxxapi/inherit__graph__10.md5 +1 -0
  71. data/doc/cxxapi/inherit__graph__10.png +0 -0
  72. data/doc/cxxapi/inherit__graph__2.png +0 -0
  73. data/doc/cxxapi/inherit__graph__3.png +0 -0
  74. data/doc/cxxapi/inherit__graph__4.png +0 -0
  75. data/doc/cxxapi/inherit__graph__5.png +0 -0
  76. data/doc/cxxapi/inherit__graph__6.png +0 -0
  77. data/doc/cxxapi/inherit__graph__7.png +0 -0
  78. data/doc/cxxapi/inherit__graph__8.png +0 -0
  79. data/doc/cxxapi/inherit__graph__9.png +0 -0
  80. data/doc/cxxapi/inherits.html +1 -1
  81. data/doc/cxxapi/main.html +1 -1
  82. data/doc/cxxapi/modules.html +1 -1
  83. data/doc/cxxapi/structPassenger_1_1AnythingToString-members.html +1 -1
  84. data/doc/cxxapi/structPassenger_1_1AnythingToString.html +1 -1
  85. data/doc/cxxapi/structPassenger_1_1AnythingToString_3_01vector_3_01string_01_4_01_4-members.html +1 -1
  86. data/doc/cxxapi/structPassenger_1_1AnythingToString_3_01vector_3_01string_01_4_01_4.html +1 -1
  87. data/doc/rdoc/classes/Passenger/RequestHandler.html +84 -74
  88. data/doc/rdoc/classes/Passenger/SpawnManager.html +54 -49
  89. data/doc/rdoc/classes/PlatformInfo.html +25 -12
  90. data/doc/rdoc/created.rid +1 -1
  91. data/doc/rdoc/files/DEVELOPERS_TXT.html +1 -1
  92. data/doc/rdoc/files/ext/passenger/native_support_c.html +1 -1
  93. data/doc/rdoc/files/lib/passenger/abstract_server_rb.html +1 -1
  94. data/doc/rdoc/files/lib/passenger/application_spawner_rb.html +1 -1
  95. data/doc/rdoc/files/lib/passenger/dependencies_rb.html +1 -1
  96. data/doc/rdoc/files/lib/passenger/framework_spawner_rb.html +1 -1
  97. data/doc/rdoc/files/lib/passenger/platform_info_rb.html +1 -1
  98. data/doc/rdoc/files/lib/passenger/request_handler_rb.html +1 -1
  99. data/doc/rdoc/files/lib/passenger/spawn_manager_rb.html +1 -1
  100. data/ext/apache2/Configuration.h +1 -1
  101. data/ext/apache2/Hooks.cpp +68 -16
  102. data/ext/apache2/Logging.cpp +1 -1
  103. data/ext/apache2/MessageChannel.h +48 -43
  104. data/ext/passenger/native_support.c +46 -43
  105. data/lib/passenger/application_spawner.rb +37 -4
  106. data/lib/passenger/dependencies.rb +5 -1
  107. data/lib/passenger/framework_spawner.rb +2 -0
  108. data/lib/passenger/platform_info.rb +32 -17
  109. data/lib/passenger/request_handler.rb +10 -1
  110. data/lib/passenger/spawn_manager.rb +14 -8
  111. data/lib/passenger/templates/error_layout.html.erb +2 -2
  112. data/test/CxxTestMain.cpp +1 -0
  113. data/test/MessageChannelTest.cpp +3 -1
  114. data/test/application_spawner_spec.rb +2 -0
  115. data/test/framework_spawner_spec.rb +2 -0
  116. data/test/integration_tests.rb +1 -0
  117. data/test/spawn_manager_spec.rb +2 -0
  118. data/test/spawner_privilege_lowering_spec.rb +1 -0
  119. data/test/stub/minimal-railsapp/vendor/rails/actionpack/lib/action_controller.rb +4 -0
  120. data/test/stub/minimal-railsapp/vendor/rails/activerecord/lib/active_record.rb +7 -0
  121. data/test/stub/rails_apps/foobar/config/environments/test.rb +22 -0
  122. metadata +28 -22
  123. data/lib/passenger/templates/osx_broken_apache_warning.txt.erb +0 -23
@@ -41,32 +41,32 @@ static VALUE mNativeSupport;
41
41
  static VALUE
42
42
  send_fd(VALUE self, VALUE socket_fd, VALUE fd_to_send) {
43
43
  int fd;
44
- struct msghdr msg;
45
- struct iovec vec[1];
46
- char buf[1];
47
-
48
44
  struct {
49
- struct cmsghdr hdr;
45
+ struct cmsghdr header;
50
46
  int fd;
51
- } cmsg;
47
+ } control;
48
+ struct msghdr msg;
49
+ struct iovec vec;
50
+ char dummy[1];
51
+
52
+ control.header.cmsg_len = sizeof(control);
53
+ control.header.cmsg_level = SOL_SOCKET;
54
+ control.header.cmsg_type = SCM_RIGHTS;
55
+ control.fd = NUM2INT(fd_to_send);
52
56
 
53
57
  msg.msg_name = NULL;
54
58
  msg.msg_namelen = 0;
55
-
56
- /* Linux and Solaris doesn't work if msg_iov is NULL. */
57
- buf[0] = '\0';
58
- vec[0].iov_base = buf;
59
- vec[0].iov_len = 1;
60
- msg.msg_iov = vec;
59
+
60
+ /* Linux and Solaris require msg_iov to be non-NULL.. */
61
+ dummy[0] = '\0';
62
+ vec.iov_base = dummy;
63
+ vec.iov_len = sizeof(dummy);
64
+ msg.msg_iov = &vec;
61
65
  msg.msg_iovlen = 1;
62
-
63
- msg.msg_control = (caddr_t)&cmsg;
64
- msg.msg_controllen = CMSG_SPACE(sizeof(int));
65
- msg.msg_flags = 0;
66
- cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(int));
67
- cmsg.hdr.cmsg_level = SOL_SOCKET;
68
- cmsg.hdr.cmsg_type = SCM_RIGHTS;
69
- cmsg.fd = NUM2INT(fd_to_send);
66
+
67
+ msg.msg_control = (caddr_t) &control;
68
+ msg.msg_controllen = sizeof(control);
69
+ msg.msg_flags = 0;
70
70
 
71
71
  if (sendmsg(NUM2INT(socket_fd), &msg, 0) == -1) {
72
72
  rb_sys_fail("sendmsg(2)");
@@ -88,43 +88,46 @@ send_fd(VALUE self, VALUE socket_fd, VALUE fd_to_send) {
88
88
  */
89
89
  static VALUE
90
90
  recv_fd(VALUE self, VALUE socket_fd) {
91
- struct msghdr msg;
92
- struct iovec vec[2];
93
- char buf[1];
94
91
  struct {
95
- struct cmsghdr hdr;
92
+ struct cmsghdr header;
96
93
  int fd;
97
- } cmsg;
94
+ } control;
98
95
 
99
- msg.msg_name = NULL;
100
- msg.msg_namelen = 0;
96
+ control.header.cmsg_len = sizeof(control);
97
+ control.header.cmsg_level = SOL_SOCKET;
98
+ control.header.cmsg_type = SCM_RIGHTS;
99
+ control.fd = -1;
100
+
101
+ struct msghdr msg;
102
+ struct iovec vec;
103
+ char dummy[1];
101
104
 
102
- vec[0].iov_base = buf;
103
- vec[0].iov_len = sizeof(buf);
104
- msg.msg_iov = vec;
105
+ msg.msg_name = NULL;
106
+ msg.msg_namelen = 0;
107
+
108
+ dummy[0] = '\0';
109
+ vec.iov_base = dummy;
110
+ vec.iov_len = sizeof(dummy);
111
+ msg.msg_iov = &vec;
105
112
  msg.msg_iovlen = 1;
106
113
 
107
- msg.msg_control = (caddr_t)&cmsg;
108
- msg.msg_controllen = CMSG_SPACE(sizeof(int));
109
- msg.msg_flags = 0;
110
- cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(int));
111
- cmsg.hdr.cmsg_level = SOL_SOCKET;
112
- cmsg.hdr.cmsg_type = SCM_RIGHTS;
113
- cmsg.fd = -1;
114
+ msg.msg_control = (caddr_t) &control;
115
+ msg.msg_controllen = sizeof(control);
116
+ msg.msg_flags = 0;
114
117
 
115
118
  if (recvmsg(NUM2INT(socket_fd), &msg, 0) == -1) {
116
119
  rb_sys_fail("Cannot read file descriptor with recvmsg()");
117
120
  return Qnil;
118
121
  }
119
-
120
- if (msg.msg_controllen != CMSG_SPACE(sizeof(int))
121
- || cmsg.hdr.cmsg_len != CMSG_SPACE(0) + sizeof(int)
122
- || cmsg.hdr.cmsg_level != SOL_SOCKET
123
- || cmsg.hdr.cmsg_type != SCM_RIGHTS) {
122
+
123
+ if (msg.msg_controllen != sizeof(control)
124
+ || control.header.cmsg_len != sizeof(control)
125
+ || control.header.cmsg_level != SOL_SOCKET
126
+ || control.header.cmsg_type != SCM_RIGHTS) {
124
127
  rb_sys_fail("No valid file descriptor received.");
125
128
  return Qnil;
126
129
  }
127
- return INT2NUM(cmsg.fd);
130
+ return INT2NUM(control.fd);
128
131
  }
129
132
 
130
133
  /*
@@ -182,6 +182,9 @@ protected
182
182
  lower_privilege! if @lower_privilege
183
183
  preload_application
184
184
  rescue StandardError, ScriptError, NoMemoryError => e
185
+ if ENV['TESTING_PASSENGER'] == '1'
186
+ print_exception(self.class.to_s, e)
187
+ end
185
188
  client.write('exception')
186
189
  client.write_scalar(marshal_exception(e))
187
190
  return
@@ -208,11 +211,14 @@ private
208
211
  begin
209
212
  if user.is_a?(String)
210
213
  pw = Etc.getpwnam(user)
214
+ username = user
211
215
  uid = pw.uid
212
216
  gid = pw.gid
213
217
  else
218
+ pw = Etc.getpwuid(user)
219
+ username = pw.name
214
220
  uid = user
215
- gid = Etc.getpwuid(uid).gid
221
+ gid = pw.gid
216
222
  end
217
223
  rescue
218
224
  return false
@@ -220,6 +226,7 @@ private
220
226
  if uid == ROOT_UID
221
227
  return false
222
228
  else
229
+ Process.groups = Process.initgroups(username, gid)
223
230
  Process::Sys.setgid(gid)
224
231
  Process::Sys.setuid(uid)
225
232
  return true
@@ -230,9 +237,26 @@ private
230
237
  Object.const_set(:RAILS_ROOT, @app_root)
231
238
  if defined?(Rails::Initializer)
232
239
  Rails::Initializer.run(:set_load_path)
240
+
241
+ # The Rails framework is loaded at the moment.
242
+ # environment.rb may set ENV['RAILS_ENV']. So we re-initialize
243
+ # RAILS_ENV in Rails::Initializer.load_environment.
244
+ Rails::Initializer.class_eval do
245
+ def load_environment_with_passenger
246
+ if defined?(::RAILS_ENV)
247
+ Object.send(:remove_const, :RAILS_ENV)
248
+ end
249
+ Object.const_set(:RAILS_ENV, (ENV['RAILS_ENV'] || 'development').dup)
250
+ load_environment_without_passenger
251
+ end
252
+
253
+ alias_method_chain :load_environment, :passenger
254
+ end
233
255
  end
234
256
  require 'config/environment'
235
- ActionController::Base.page_cache_directory = "#{RAILS_ROOT}/public"
257
+ if ActionController::Base.page_cache_directory.blank?
258
+ ActionController::Base.page_cache_directory = "#{RAILS_ROOT}/public"
259
+ end
236
260
  if defined?(ActionController::Dispatcher) \
237
261
  && ActionController::Dispatcher.respond_to?(:error_file_path)
238
262
  ActionController::Dispatcher.error_file_path = "#{RAILS_ROOT}/public"
@@ -241,8 +265,10 @@ private
241
265
  require 'dispatcher'
242
266
  end
243
267
  require_dependency 'application'
244
- Dir.glob('app/{models,controllers,helpers}/*.rb').each do |file|
245
- require_dependency normalize_path(file)
268
+ if GC.copy_on_write_friendly?
269
+ Dir.glob('app/{models,controllers,helpers}/*.rb').each do |file|
270
+ require_dependency normalize_path(file)
271
+ end
246
272
  end
247
273
  end
248
274
 
@@ -277,6 +303,13 @@ private
277
303
  $0 = "Rails: #{@app_root}"
278
304
  reader, writer = IO.pipe
279
305
  begin
306
+ # Re-establish connection if a connection was established
307
+ # in environment.rb. This prevents us from concurrently
308
+ # accessing the same MySQL connection handle.
309
+ if defined?(::ActiveRecord::Base) && ::ActiveRecord::Base.connected?
310
+ ::ActiveRecord::Base.establish_connection
311
+ end
312
+
280
313
  handler = RequestHandler.new(reader)
281
314
  client.write(Process.pid, handler.socket_name,
282
315
  handler.using_abstract_namespace?)
@@ -248,7 +248,7 @@ module Dependencies # :nodoc: all
248
248
  APR_DevHeaders = Dependency.new do |dep|
249
249
  dep.name = "Apache Portable Runtime (APR) development headers"
250
250
  dep.define_checker do |result|
251
- result.found(!APR1_FLAGS.nil?)
251
+ result.found(APR_CONFIG)
252
252
  end
253
253
  if RUBY_PLATFORM =~ /linux/
254
254
  case LINUX_DISTRO
@@ -259,6 +259,10 @@ module Dependencies # :nodoc: all
259
259
  when :gentoo
260
260
  dep.install_command = "emerge -av apr"
261
261
  end
262
+ elsif RUBY_PLATFORM =~ /darwin/
263
+ dep.install_instructions = "Please install Apache from MacPorts, which will " <<
264
+ "provide APR automatically. <b>Or</b>, if you're installing against MacOS X's " <<
265
+ "default provided Apache, then please install the OS X Developer SDK."
262
266
  end
263
267
  dep.website = "http://httpd.apache.org/"
264
268
  dep.website_comments = "APR is an integrated part of Apache."
@@ -294,6 +294,8 @@ private
294
294
  begin
295
295
  app = spawner.spawn_application
296
296
  rescue ApplicationSpawner::Error => e
297
+ spawner.stop
298
+ @spawners.delete(app_root)
297
299
  client.write('exception')
298
300
  client.write_scalar(marshal_exception(e))
299
301
  return
@@ -120,27 +120,40 @@ private
120
120
  end
121
121
  end
122
122
 
123
- def self.determine_apr1_info
124
- flags = nil
125
- libs = nil
126
- if find_command('pkg-config')
127
- flags = `pkg-config --cflags apr-1 apr-util-1 2>/dev/null`.strip
128
- libs = `pkg-config --libs apr-1 apr-util-1 2>/dev/null`.strip
129
- end
130
- if (flags.nil? || flags.empty?) && (libs.nil? || libs.empty?)
123
+ def self.find_apr_config
124
+ if env_defined?('APR_CONFIG')
125
+ apr_config = ENV['APR_CONFIG']
126
+ elsif RUBY_PLATFORM =~ /darwin/ && HTTPD == "/usr/sbin/httpd"
127
+ # If we're on MacOS X, and we're compiling against the
128
+ # default provided Apache, then we'll want to query the
129
+ # correct 'apr-1-config' command. However, that command
130
+ # is not in $PATH by default. Instead, it lives in
131
+ # /Developer/SDKs/MacOSX*sdk/usr/bin.
132
+ sdk_dir = Dir["/Developer/SDKs/MacOSX*sdk"].sort.last
133
+ if sdk_dir
134
+ apr_config = "#{sdk_dir}/usr/bin/apr-1-config"
135
+ if !File.executable?(apr_config)
136
+ apr_config = nil
137
+ end
138
+ end
139
+ else
131
140
  apr_config = find_command('apr-1-config')
132
141
  if apr_config.nil?
133
142
  apr_config = find_command('apr-config')
134
143
  end
135
- if apr_config.nil?
136
- return nil
137
- else
138
- flags = `#{apr_config} --cppflags --includes`.strip
139
- libs = `#{apr_config} --link-ld`.strip
140
- end
141
144
  end
142
- flags.gsub!(/-O\d? /, '')
143
- return [flags, libs]
145
+ return apr_config
146
+ end
147
+
148
+ def self.determine_apr_info
149
+ if APR_CONFIG.nil?
150
+ return nil
151
+ else
152
+ flags = `#{APR_CONFIG} --cppflags --includes`.strip
153
+ libs = `#{APR_CONFIG} --link-ld`.strip
154
+ flags.gsub!(/-O\d? /, '')
155
+ return [flags, libs]
156
+ end
144
157
  end
145
158
 
146
159
  def self.determine_multi_arch_flags
@@ -231,11 +244,13 @@ public
231
244
  APACHE2CTL = find_apache2ctl
232
245
  # The absolute path to the Apache binary (that is, 'httpd', 'httpd2', 'apache' or 'apache2').
233
246
  HTTPD = find_httpd
247
+ # The absolute path to the 'apr-config' or 'apr-1-config' executable.
248
+ APR_CONFIG = find_apr_config
234
249
 
235
250
  # The C compiler flags that are necessary to compile an Apache module.
236
251
  APXS2_FLAGS = determine_apxs2_flags
237
252
  # The C compiler flags that are necessary for programs that use APR.
238
- APR1_FLAGS, APR1_LIBS = determine_apr1_info
253
+ APR_FLAGS, APR_LIBS = determine_apr_info
239
254
 
240
255
  # The C compiler flags that are necessary for building binaries in the same architecture(s) as Apache.
241
256
  MULTI_ARCH_FLAGS = determine_multi_arch_flags
@@ -97,12 +97,17 @@ class RequestHandler
97
97
  DEFAULT = 'DEFAULT' # :nodoc:
98
98
  CONTENT_LENGTH = 'CONTENT_LENGTH' # :nodoc:
99
99
  HTTP_CONTENT_LENGTH = 'HTTP_CONTENT_LENGTH' # :nodoc:
100
+ X_POWERED_BY = 'X-Powered-By'
100
101
 
101
102
  NINJA_PATCHING_LOCK = Mutex.new
102
103
  @@ninja_patched_action_controller = false
103
104
 
104
105
  File.read("#{File.dirname(__FILE__)}/../../Rakefile") =~ /^PACKAGE_VERSION = "(.*)"$/
105
106
  PASSENGER_VERSION = $1
107
+ PASSENGER_HEADER = "Phusion Passenger (mod_rails) #{PASSENGER_VERSION}"
108
+ if File.exist?("#{File.dirname(__FILE__)}/../../enterprisey.txt")
109
+ PASSENGER_HEADER << ", Enterprise Edition"
110
+ end
106
111
 
107
112
  # The name of the socket on which the request handler accepts
108
113
  # new connections. This is either a Unix socket filename, or
@@ -136,7 +141,7 @@ class RequestHandler
136
141
  alias passenger_orig_perform_action perform_action
137
142
 
138
143
  def perform_action(*whatever)
139
- headers["X-Powered-By"] = "Phusion Passenger (mod_rails) #{PASSENGER_VERSION}"
144
+ headers[X_POWERED_BY] = PASSENGER_HEADER
140
145
  passenger_orig_perform_action(*whatever)
141
146
  end
142
147
  end
@@ -273,6 +278,10 @@ private
273
278
  def write(block)
274
279
  @io.write(block)
275
280
  end
281
+
282
+ def <<(block)
283
+ @io.write(block)
284
+ end
276
285
  end
277
286
 
278
287
  def process_request(socket)
@@ -106,14 +106,19 @@ class SpawnManager < AbstractServer
106
106
  spawner.start
107
107
  @spawners[key] = spawner
108
108
  end
109
- end
110
-
111
- spawner.time = Time.now
112
- if spawner.is_a?(FrameworkSpawner)
113
- return spawner.spawn_application(app_root, lower_privilege,
114
- lowest_user)
115
- else
116
- return spawner.spawn_application
109
+ spawner.time = Time.now
110
+ begin
111
+ if spawner.is_a?(FrameworkSpawner)
112
+ return spawner.spawn_application(app_root, lower_privilege,
113
+ lowest_user)
114
+ else
115
+ return spawner.spawn_application
116
+ end
117
+ rescue AbstractServer::ServerError
118
+ spawner.stop
119
+ @spawners.delete(key)
120
+ raise
121
+ end
117
122
  end
118
123
  end
119
124
 
@@ -242,6 +247,7 @@ private
242
247
  end
243
248
 
244
249
  def send_error_page(channel, template_name, options = {})
250
+ options["enterprisey"] = File.exist?("#{File.dirname(__FILE__)}/../../enterprisey.txt")
245
251
  data = HTMLTemplate.new(template_name, options).result
246
252
  channel.write('error_page')
247
253
  channel.write_scalar(data)
@@ -14,7 +14,7 @@
14
14
 
15
15
  <div id="site_container">
16
16
  <div id="site_header">
17
- <ul class="corporate_identity">
17
+ <ul class="corporate_identity <% if @enterprisey %>enterprise_edition<% end %>">
18
18
  <li class="logo"><a href="http://www.modrails.com"><span>Phusion Passenger</span></a></li>
19
19
  </ul>
20
20
  </div>
@@ -28,7 +28,7 @@
28
28
  text. Thank you.
29
29
  -->
30
30
  <div class="container">
31
- Powered by <a href="http://www.modrails.com/">Phusion Passenger</a>,
31
+ Powered by <a href="http://www.modrails.com/">Phusion Passenger</a><% if @enterprisey %> (Enterprise Edition)<% end %>,
32
32
  <tt>mod_rails</tt> for Apache.
33
33
  </div>
34
34
  </div>
@@ -14,6 +14,7 @@ int main() {
14
14
  tut::runner.get().set_callback(&reporter);
15
15
  signal(SIGPIPE, SIG_IGN);
16
16
  setenv("RAILS_ENV", "production", 1);
17
+ setenv("TESTING_PASSENGER", "1", 1);
17
18
  try {
18
19
  tut::runner.get().run_tests();
19
20
  } catch (const std::exception &ex) {
@@ -17,7 +17,9 @@ namespace tut {
17
17
  int p[2];
18
18
 
19
19
  MessageChannelTest() {
20
- pipe(p);
20
+ if (pipe(p) != 0) {
21
+ throw SystemException("Cannot create a pipe", errno);
22
+ }
21
23
  reader = MessageChannel(p[0]);
22
24
  writer = MessageChannel(p[1]);
23
25
  }
@@ -6,6 +6,8 @@ require 'spawner_privilege_lowering_spec'
6
6
  require 'spawner_error_handling_spec'
7
7
  include Passenger
8
8
 
9
+ # TODO: write unit test which checks whether setting ENV['RAILS_ENV'] in environment.rb is respected (issue #6)
10
+
9
11
  describe ApplicationSpawner do
10
12
  before :all do
11
13
  ENV['RAILS_ENV'] = 'production'
@@ -6,6 +6,8 @@ require 'spawner_privilege_lowering_spec'
6
6
  require 'spawner_error_handling_spec'
7
7
  include Passenger
8
8
 
9
+ # TODO: test whether FrameworkSpawner restarts ApplicationSpawner if it crashed
10
+
9
11
  describe FrameworkSpawner do
10
12
  before :all do
11
13
  ENV['RAILS_ENV'] = 'production'
@@ -11,6 +11,7 @@ require 'passenger/platform_info'
11
11
  include PlatformInfo
12
12
 
13
13
  # TODO: test the 'RailsUserSwitching' and 'RailsDefaultUser' option.
14
+ # TODO: test custom page caching directory
14
15
 
15
16
  shared_examples_for "MyCook(tm) beta" do
16
17
  it "should be possible to fetch static assets" do