passenger 4.0.19 → 4.0.20

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 (65) hide show
  1. checksums.yaml +15 -0
  2. checksums.yaml.gz.asc +12 -0
  3. data.tar.gz.asc +7 -7
  4. data/NEWS +22 -0
  5. data/bin/passenger-install-apache2-module +2 -2
  6. data/bin/passenger-install-nginx-module +2 -2
  7. data/build/agents.rb +6 -0
  8. data/build/apache2.rb +1 -0
  9. data/build/basics.rb +2 -2
  10. data/build/cplusplus_support.rb +6 -1
  11. data/build/cxx_tests.rb +1 -0
  12. data/build/nginx.rb +1 -0
  13. data/build/packaging.rb +1 -1
  14. data/dev/copy_boost_headers.rb +1 -0
  15. data/doc/Users guide Apache.idmap.txt +56 -54
  16. data/doc/Users guide Apache.txt +22 -3
  17. data/doc/Users guide Nginx.idmap.txt +52 -50
  18. data/doc/Users guide Nginx.txt +22 -3
  19. data/ext/apache2/Configuration.hpp +4 -0
  20. data/ext/apache2/ConfigurationCommands.cpp +6 -0
  21. data/ext/apache2/ConfigurationFields.hpp +6 -4
  22. data/ext/apache2/ConfigurationSetters.cpp +11 -0
  23. data/ext/apache2/CreateDirConfig.cpp +1 -0
  24. data/ext/apache2/Hooks.cpp +2 -0
  25. data/ext/apache2/MergeDirConfig.cpp +7 -0
  26. data/ext/boost/type_traits/detail/common_type_imp.hpp +333 -0
  27. data/ext/boost/type_traits/detail/has_binary_operator.hpp +229 -0
  28. data/ext/boost/type_traits/detail/has_postfix_operator.hpp +202 -0
  29. data/ext/boost/type_traits/detail/has_prefix_operator.hpp +210 -0
  30. data/ext/boost/type_traits/detail/is_function_ptr_tester.hpp +654 -0
  31. data/ext/boost/type_traits/detail/is_mem_fun_pointer_tester.hpp +2759 -0
  32. data/ext/boost/type_traits/detail/wrap.hpp +18 -0
  33. data/ext/common/Constants.h +1 -1
  34. data/ext/common/Utils/StrIntUtils.cpp +1 -1
  35. data/ext/common/agents/HelperAgent/Main.cpp +18 -1
  36. data/ext/common/agents/HelperAgent/RequestHandler.h +3 -0
  37. data/ext/common/agents/SpawnPreparer.cpp +25 -0
  38. data/ext/common/agents/TempDirToucher.c +357 -0
  39. data/ext/common/agents/Watchdog/Main.cpp +38 -0
  40. data/ext/nginx/CacheLocationConfig.c +21 -1
  41. data/ext/nginx/CacheLocationConfig.c.erb +1 -1
  42. data/ext/nginx/ConfigurationCommands.c +10 -0
  43. data/ext/nginx/ConfigurationFields.h +18 -16
  44. data/ext/nginx/ConfigurationFields.h.erb +11 -6
  45. data/ext/nginx/CreateLocationConfig.c +4 -0
  46. data/ext/nginx/MergeLocationConfig.c +6 -0
  47. data/helper-scripts/node-loader.js +6 -2
  48. data/lib/phusion_passenger.rb +1 -1
  49. data/lib/phusion_passenger/{rails3_extensions → active_support3_extensions}/init.rb +10 -8
  50. data/lib/phusion_passenger/apache2/config_options.rb +5 -0
  51. data/lib/phusion_passenger/loader_shared_helpers.rb +61 -7
  52. data/lib/phusion_passenger/nginx/config_options.rb +4 -0
  53. data/lib/phusion_passenger/platform_info/apache.rb +6 -1
  54. data/lib/phusion_passenger/platform_info/compiler.rb +29 -2
  55. data/lib/phusion_passenger/platform_info/depcheck_specs/compiler_toolchain.rb +4 -4
  56. data/lib/phusion_passenger/platform_info/ruby.rb +7 -3
  57. data/lib/phusion_passenger/public_api.rb +4 -4
  58. data/lib/phusion_passenger/standalone/command.rb +10 -0
  59. data/lib/phusion_passenger/standalone/runtime_installer.rb +2 -2
  60. data/lib/phusion_passenger/standalone/start_command.rb +14 -8
  61. data/lib/phusion_passenger/utils/unseekable_socket.rb +52 -0
  62. data/resources/templates/standalone/config.erb +11 -0
  63. metadata +14 -15
  64. metadata.gz.asc +7 -7
  65. data/helper-scripts/touch-dir.sh +0 -48
@@ -98,6 +98,7 @@ struct WorkingObjects {
98
98
  ServerInstanceDir::GenerationPtr generation;
99
99
  uid_t defaultUid;
100
100
  gid_t defaultGid;
101
+ vector<string> cleanupPidfiles;
101
102
  string loggingAgentAddress;
102
103
  string loggingAgentPassword;
103
104
  string loggingAgentAdminAddress;
@@ -271,13 +272,41 @@ waitForStarterProcessOrWatchers(const WorkingObjectsPtr &wo, vector<AgentWatcher
271
272
  }
272
273
  }
273
274
 
275
+ static vector<pid_t>
276
+ readCleanupPids(const WorkingObjectsPtr &wo) {
277
+ vector<pid_t> result;
278
+
279
+ foreach (string filename, wo->cleanupPidfiles) {
280
+ FILE *f = fopen(filename.c_str(), "r");
281
+ if (f != NULL) {
282
+ char buf[33];
283
+ size_t ret;
284
+
285
+ ret = fread(buf, 1, 32, f);
286
+ if (ret > 0) {
287
+ buf[ret] = '\0';
288
+ result.push_back(atoi(buf));
289
+ } else {
290
+ P_WARN("Cannot read cleanup PID file " << filename);
291
+ }
292
+ } else {
293
+ P_WARN("Cannot open cleanup PID file " << filename);
294
+ }
295
+ }
296
+
297
+ return result;
298
+ }
299
+
274
300
  static void
275
301
  cleanupAgentsInBackground(const WorkingObjectsPtr &wo, vector<AgentWatcherPtr> &watchers, char *argv[]) {
276
302
  this_thread::disable_interruption di;
277
303
  this_thread::disable_syscall_interruption dsi;
304
+ vector<pid_t> cleanupPids;
278
305
  pid_t pid;
279
306
  int e;
280
307
 
308
+ cleanupPids = readCleanupPids(wo);
309
+
281
310
  pid = fork();
282
311
  if (pid == 0) {
283
312
  // Child
@@ -345,6 +374,12 @@ cleanupAgentsInBackground(const WorkingObjectsPtr &wo, vector<AgentWatcherPtr> &
345
374
  // Now clean up the server instance directory.
346
375
  delete wo->generation.get();
347
376
  delete wo->serverInstanceDir.get();
377
+
378
+ // Notify given PIDs about our shutdown.
379
+ foreach (pid_t pid, cleanupPids) {
380
+ P_DEBUG("Sending SIGTERM to cleanup PID " << pid);
381
+ kill(pid, SIGTERM);
382
+ }
348
383
 
349
384
  _exit(0);
350
385
 
@@ -519,6 +554,9 @@ initializeWorkingObjects(WorkingObjectsPtr &wo, ServerInstanceDirToucherPtr &ser
519
554
  UPDATE_TRACE_POINT();
520
555
  lookupDefaultUidGid(wo->defaultUid, wo->defaultGid);
521
556
 
557
+ UPDATE_TRACE_POINT();
558
+ wo->cleanupPidfiles = agentsOptions.getStrSet("cleanup_pidfiles", false);
559
+
522
560
  UPDATE_TRACE_POINT();
523
561
  wo->loggingAgentAddress = "unix:" + wo->generation->getPath() + "/logging";
524
562
  wo->loggingAgentPassword = wo->randomGenerator.generateAsciiString(64);
@@ -26,7 +26,7 @@
26
26
  /*
27
27
  * CacheLocationConfig.c is automatically generated from CacheLocationConfig.c.erb,
28
28
  * using definitions from lib/phusion_passenger/nginx/config_options.rb.
29
- * Edits to MergeLocationConfig.c will be lost.
29
+ * Edits to CacheLocationConfig.c will be lost.
30
30
  *
31
31
  * To update CacheLocationConfig.c:
32
32
  * rake nginx
@@ -179,6 +179,13 @@ u_char int_buf[32], *end, *buf, *pos;
179
179
 
180
180
 
181
181
 
182
+ if (conf->load_shell_envvars != NGX_CONF_UNSET) {
183
+ len += 29;
184
+ len += conf->load_shell_envvars ? sizeof("true") : sizeof("false");
185
+ }
186
+
187
+
188
+
182
189
  if (conf->union_station_key.data != NULL) {
183
190
  len += 18;
184
191
  len += conf->union_station_key.len + 1;
@@ -450,6 +457,19 @@ buf = pos = ngx_pnalloc(cf->pool, len);
450
457
 
451
458
 
452
459
 
460
+ if (conf->load_shell_envvars != NGX_CONF_UNSET) {
461
+ pos = ngx_copy(pos,
462
+ "PASSENGER_LOAD_SHELL_ENVVARS",
463
+ 29);
464
+ if (conf->load_shell_envvars) {
465
+ pos = ngx_copy(pos, "true", sizeof("true"));
466
+ } else {
467
+ pos = ngx_copy(pos, "false", sizeof("false"));
468
+ }
469
+ }
470
+
471
+
472
+
453
473
  if (conf->union_station_key.data != NULL) {
454
474
  pos = ngx_copy(pos,
455
475
  "UNION_STATION_KEY",
@@ -26,7 +26,7 @@
26
26
  /*
27
27
  * CacheLocationConfig.c is automatically generated from CacheLocationConfig.c.erb,
28
28
  * using definitions from lib/phusion_passenger/nginx/config_options.rb.
29
- * Edits to MergeLocationConfig.c will be lost.
29
+ * Edits to CacheLocationConfig.c will be lost.
30
30
  *
31
31
  * To update CacheLocationConfig.c:
32
32
  * rake nginx
@@ -329,6 +329,16 @@
329
329
  NULL
330
330
  },
331
331
 
332
+ {
333
+
334
+ ngx_string("passenger_load_shell_envvars"),
335
+ NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_HTTP_LIF_CONF | NGX_CONF_FLAG,
336
+ ngx_conf_set_flag_slot,
337
+ NGX_HTTP_LOC_CONF_OFFSET,
338
+ offsetof(passenger_loc_conf_t, load_shell_envvars),
339
+ NULL
340
+ },
341
+
332
342
  {
333
343
 
334
344
  ngx_string("union_station_key"),
@@ -39,51 +39,53 @@
39
39
 
40
40
 
41
41
 
42
+ ngx_array_t *base_uris;
43
+
44
+ ngx_int_t debugger;
45
+
42
46
  ngx_int_t enabled;
43
47
 
44
- ngx_int_t max_request_queue_size;
48
+ ngx_int_t friendly_error_pages;
45
49
 
46
- ngx_array_t *vars_source;
50
+ ngx_int_t load_shell_envvars;
47
51
 
48
52
  ngx_int_t max_preloader_idle_time;
49
53
 
50
- ngx_int_t friendly_error_pages;
51
-
52
- ngx_int_t min_instances;
54
+ ngx_int_t max_request_queue_size;
53
55
 
54
56
  ngx_int_t max_requests;
55
57
 
56
- ngx_int_t start_timeout;
58
+ ngx_int_t min_instances;
57
59
 
58
- ngx_array_t *base_uris;
60
+ ngx_int_t request_queue_overflow_status_code;
59
61
 
60
62
  ngx_int_t show_version_in_header;
61
63
 
62
- ngx_int_t debugger;
64
+ ngx_int_t start_timeout;
63
65
 
64
66
  ngx_array_t *union_station_filters;
65
67
 
66
68
  ngx_int_t union_station_support;
67
69
 
68
- ngx_int_t request_queue_overflow_status_code;
69
-
70
- ngx_str_t app_rights;
70
+ ngx_array_t *vars_source;
71
71
 
72
72
  ngx_str_t app_group_name;
73
73
 
74
- ngx_str_t group;
74
+ ngx_str_t app_rights;
75
75
 
76
- ngx_str_t user;
76
+ ngx_str_t app_root;
77
77
 
78
78
  ngx_str_t environment;
79
79
 
80
+ ngx_str_t group;
81
+
80
82
  ngx_str_t python;
81
83
 
84
+ ngx_str_t ruby;
85
+
82
86
  ngx_str_t spawn_method;
83
87
 
84
88
  ngx_str_t union_station_key;
85
89
 
86
- ngx_str_t ruby;
87
-
88
- ngx_str_t app_root;
90
+ ngx_str_t user;
89
91
 
@@ -49,22 +49,22 @@ end
49
49
 
50
50
  def struct_field_for(option)
51
51
  if option.has_key?(:field)
52
- return option[:field]
52
+ return option[:field].to_s
53
53
  else
54
54
  return option[:name].sub(/^passenger_/, '')
55
55
  end
56
56
  end
57
57
 
58
- # Returns [definition_source, estimated_size_on_x86_64]
58
+ # Returns [definition_source, estimated_size_on_x86_64, field_name]
59
59
  def definition_for(option)
60
60
  field = struct_field_for(option)
61
61
  case option[:type]
62
62
  when :string
63
- return ["ngx_str_t #{field}", 8 + 4]
63
+ return ["ngx_str_t #{field}", 8 + 4, field]
64
64
  when :integer, :flag
65
- return ["ngx_int_t #{field}", 8]
65
+ return ["ngx_int_t #{field}", 8, field]
66
66
  when :string_array, :string_keyval
67
- return ["ngx_array_t *#{field}", 8];
67
+ return ["ngx_array_t *#{field}", 8, field];
68
68
  else
69
69
  raise "Unknown option type #{option[:type].inspect} for option #{option[:name]}"
70
70
  end
@@ -76,7 +76,12 @@ definitions = eligible_options.map { |o| definition_for(o) }
76
76
  # It's possible to make it even smaller with a smarter algorithm but for now
77
77
  # I don't bother.
78
78
  definitions.sort! do |d1, d2|
79
- d1[1] <=> d2[1]
79
+ if d1[1] == d2[1]
80
+ # After sorting on size, sort alphabetically.
81
+ d1[2] <=> d2[2]
82
+ else
83
+ d1[1] <=> d2[1]
84
+ end
80
85
  end
81
86
  %>
82
87
 
@@ -133,6 +133,10 @@
133
133
 
134
134
 
135
135
 
136
+ conf->load_shell_envvars = NGX_CONF_UNSET;
137
+
138
+
139
+
136
140
  conf->union_station_key.data = NULL;
137
141
  conf->union_station_key.len = 0;
138
142
 
@@ -148,6 +148,12 @@
148
148
 
149
149
 
150
150
 
151
+ ngx_conf_merge_value(conf->load_shell_envvars,
152
+ prev->load_shell_envvars,
153
+ NGX_CONF_UNSET);
154
+
155
+
156
+
151
157
  ngx_conf_merge_str_value(conf->union_station_key,
152
158
  prev->union_station_key,
153
159
  NULL);
@@ -226,16 +226,20 @@ function RequestHandler(readyCallback, clientCallback) {
226
226
 
227
227
  function handleData(data) {
228
228
  if (state == 'PARSING_HEADER') {
229
- parser.feed(data);
229
+ var consumed = parser.feed(data);
230
230
  if (parser.state == SPP_DONE) {
231
231
  state = 'HEADER_SEEN';
232
+ socket.removeListener('data', handleData);
232
233
  PhusionPassenger.emit('request', parser, socket);
234
+ if (consumed != data.length) {
235
+ socket.emit('data', data.slice(consumed));
236
+ }
233
237
  } else if (parser.state == SPP_ERROR) {
234
238
  console.error('Header parse error');
235
239
  socket.destroySoon();
236
240
  }
237
241
  } else {
238
- // Do nothing yet.
242
+ // Do nothing.
239
243
  }
240
244
  }
241
245
 
@@ -30,7 +30,7 @@ module PhusionPassenger
30
30
 
31
31
  PACKAGE_NAME = 'passenger'
32
32
  # Run 'rake ext/common/Constants.h' after changing this number.
33
- VERSION_STRING = '4.0.19'
33
+ VERSION_STRING = '4.0.20'
34
34
 
35
35
  PREFERRED_NGINX_VERSION = '1.4.2'
36
36
  NGINX_SHA256_CHECKSUM = '5361ffb7b0ebf8b1a04369bc3d1295eaed091680c1c58115f88d56c8e51f3611'
@@ -26,17 +26,17 @@ require 'digest/md5'
26
26
 
27
27
  module PhusionPassenger
28
28
 
29
- module Rails3Extensions
29
+ module ActiveSupport3Extensions
30
30
  def self.init!(options, user_options = {})
31
31
  if !AnalyticsLogging.install!(options, user_options)
32
32
  # Remove code to save memory.
33
- PhusionPassenger::Rails3Extensions.send(:remove_const, :AnalyticsLogging)
34
- PhusionPassenger.send(:remove_const, :Rails3Extensions)
33
+ PhusionPassenger::ActiveSupport3Extensions.send(:remove_const, :AnalyticsLogging)
34
+ PhusionPassenger.send(:remove_const, :ActiveSupport3Extensions)
35
35
  end
36
36
  end
37
37
  end
38
38
 
39
- module Rails3Extensions
39
+ module ActiveSupport3Extensions
40
40
  class AnalyticsLogging < ActiveSupport::LogSubscriber
41
41
  def self.install!(options, user_options)
42
42
  analytics_logger = options["analytics_logger"]
@@ -67,9 +67,11 @@ class AnalyticsLogging < ActiveSupport::LogSubscriber
67
67
  exceptions_middleware = ActionDispatch::ShowExceptions
68
68
  end
69
69
  if exceptions_middleware
70
- Rails.application.middleware.insert_after(
71
- exceptions_middleware,
72
- ExceptionLogger, analytics_logger, app_group_name)
70
+ if defined?(Rails)
71
+ Rails.application.middleware.insert_after(
72
+ exceptions_middleware,
73
+ ExceptionLogger, analytics_logger, app_group_name)
74
+ end
73
75
  end
74
76
 
75
77
  if defined?(ActionController::Base)
@@ -231,6 +233,6 @@ class AnalyticsLogging < ActiveSupport::LogSubscriber
231
233
  end
232
234
  end
233
235
  end # class AnalyticsLogging
234
- end # module Rails3Extensions
236
+ end # module ActiveSupport3Extensions
235
237
 
236
238
  end # module PhusionPassenger
@@ -100,5 +100,10 @@ APACHE2_DIRECTORY_CONFIGURATION_OPTIONS = [
100
100
  :min_value => 0,
101
101
  :context => ["OR_ALL"],
102
102
  :desc => "The maximum number of queued requests."
103
+ },
104
+ {
105
+ :name => "PassengerLoadShellEnvvars",
106
+ :type => :flag,
107
+ :desc => "Whether to load environment variables from the shell before running the application."
103
108
  }
104
109
  ]
@@ -187,17 +187,23 @@ module LoaderSharedHelpers
187
187
  elsif File.exist?('config/setup_load_paths.rb')
188
188
  require File.expand_path('config/setup_load_paths')
189
189
 
190
- # If the Bundler lock environment file exists then load that. If it
190
+ # Older versions of Bundler use .bundle/environment.rb as the Bundler
191
+ # environment lock file. This has been replaced by Gemfile.lock in later
192
+ # versions, but we still support the older mechanism.
193
+ # If the Bundler environment lock file exists then load that. If it
191
194
  # exists then there's a 99.9% chance that loading it is the correct
192
195
  # thing to do.
193
196
  elsif File.exist?('.bundle/environment.rb')
194
- require File.expand_path('.bundle/environment')
197
+ running_bundler do
198
+ require File.expand_path('.bundle/environment')
199
+ end
195
200
 
196
- # If the Bundler environment file doesn't exist then there are two
201
+ # If the legacy Bundler environment file doesn't exist then there are two
197
202
  # possibilities:
198
203
  # 1. Bundler is not used, in which case we don't have to do anything.
199
- # 2. Bundler *is* used, but the gems are not locked and we're supposed
200
- # to call Bundler.setup.
204
+ # 2. Bundler *is* used, but either the user is using a newer Bundler versions,
205
+ # or the gems are not locked. In either case, we're supposed to call
206
+ # Bundler.setup.
201
207
  #
202
208
  # The existence of Gemfile indicates whether (2) is true:
203
209
  elsif File.exist?('Gemfile')
@@ -208,8 +214,10 @@ module LoaderSharedHelpers
208
214
  # harmless. If this isn't the correct thing to do after all then
209
215
  # there's always the load_path_setup_file option and
210
216
  # setup_load_paths.rb.
211
- require 'rubygems'
212
- require 'bundler/setup'
217
+ running_bundler do
218
+ require 'rubygems'
219
+ require 'bundler/setup'
220
+ end
213
221
  end
214
222
 
215
223
  # Bundler might remove Phusion Passenger from the load path in its zealous
@@ -319,6 +327,52 @@ module LoaderSharedHelpers
319
327
  def after_handling_requests
320
328
  PhusionPassenger.call_event(:stopping_worker_process)
321
329
  end
330
+
331
+ private
332
+ def running_bundler
333
+ yield
334
+ rescue Exception => e
335
+ if defined?(Bundler::GemNotFound) && e.is_a?(Bundler::GemNotFound)
336
+ prepend_exception_comment(e, "It looks like Bundler could not find a gem. This " +
337
+ "is probably because your\n" +
338
+ "application is being run under a different environment than it's supposed to.\n" +
339
+ "Please check the following:\n\n" +
340
+ " * Is this app supposed to be run as the `#{whoami}` user?\n" +
341
+ " * Is this app being run on the correct Ruby interpreter? Below you will\n" +
342
+ " see which Ruby interpreter Phusion Passenger attempted to use. If you \n" +
343
+ " are using RVM, please also check whether the correct gemset is being used.\n")
344
+ end
345
+ raise e
346
+ end
347
+
348
+ def prepend_exception_comment(e, comment)
349
+ # Since Exception doesn't allow changing the message, we monkeypatch
350
+ # the #message and #to_s methods.
351
+ separator = "\n-------- The exception is as follows: -------\n"
352
+ new_message = comment + separator + e.message
353
+ new_s = comment + separator + e.to_s
354
+ metaclass = class << e; self; end
355
+ metaclass.send(:define_method, :message) do
356
+ new_message
357
+ end
358
+ metaclass.send(:define_method, :to_s) do
359
+ new_s
360
+ end
361
+ end
362
+
363
+ def whoami
364
+ require 'etc'
365
+ begin
366
+ user = Etc.getpwuid(Process.uid)
367
+ rescue ArgumentError
368
+ user = nil
369
+ end
370
+ if user
371
+ return user.name
372
+ else
373
+ return "##{Process.uid}"
374
+ end
375
+ end
322
376
  end
323
377
 
324
378
  end # module PhusionPassenger