passenger 3.0.9 → 3.0.10

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 (67) hide show
  1. data/NEWS +32 -0
  2. data/Rakefile +1 -1
  3. data/build/common_library.rb +6 -1
  4. data/build/config.rb +3 -1
  5. data/doc/Users guide Apache.html +120 -39
  6. data/doc/Users guide Apache.txt +64 -0
  7. data/doc/Users guide Nginx.html +50 -2
  8. data/doc/Users guide Nginx.txt +29 -0
  9. data/ext/apache2/Bucket.cpp +7 -5
  10. data/ext/apache2/Bucket.h +2 -1
  11. data/ext/apache2/Configuration.cpp +8 -0
  12. data/ext/apache2/Configuration.hpp +9 -5
  13. data/ext/apache2/HelperAgent.cpp +4 -5
  14. data/ext/apache2/Hooks.cpp +1 -6
  15. data/ext/boost/thread/exceptions.hpp +7 -1
  16. data/ext/boost/thread/locks.hpp +11 -11
  17. data/ext/common/AgentBase.cpp +21 -1
  18. data/ext/common/AgentsStarter.hpp +22 -21
  19. data/ext/common/ApplicationPool/Client.h +0 -8
  20. data/ext/common/ApplicationPool/Server.h +22 -21
  21. data/ext/common/Constants.h +1 -1
  22. data/ext/common/EventedMessageServer.h +6 -2
  23. data/ext/common/IniFile.h +4 -4
  24. data/ext/common/Logging.h +1 -1
  25. data/ext/common/LoggingAgent/LoggingServer.h +2 -2
  26. data/ext/common/LoggingAgent/Main.cpp +2 -2
  27. data/ext/common/MessageChannel.h +20 -62
  28. data/ext/common/MessageReadersWriters.h +4 -4
  29. data/ext/common/MessageServer.h +18 -18
  30. data/ext/common/Process.h +4 -5
  31. data/ext/common/Session.h +6 -40
  32. data/ext/common/SpawnManager.h +20 -25
  33. data/ext/common/Utils.cpp +1 -1
  34. data/ext/common/Utils/Dechunker.h +1 -1
  35. data/ext/common/Utils/MessageIO.h +109 -14
  36. data/ext/common/Utils/StreamBoyerMooreHorspool.h +20 -14
  37. data/ext/common/Utils/VariantMap.h +9 -27
  38. data/ext/common/Watchdog.cpp +53 -42
  39. data/ext/libev/config.h +122 -0
  40. data/ext/nginx/Configuration.c +62 -0
  41. data/ext/nginx/Configuration.h +5 -0
  42. data/ext/nginx/ContentHandler.c +46 -19
  43. data/ext/nginx/HelperAgent.cpp +6 -5
  44. data/ext/nginx/config +12 -12
  45. data/ext/oxt/system_calls.cpp +10 -1
  46. data/ext/ruby/extconf.rb +0 -1
  47. data/ext/ruby/passenger_native_support.c +2 -2
  48. data/helper-scripts/prespawn +1 -1
  49. data/lib/phusion_passenger.rb +4 -4
  50. data/lib/phusion_passenger/classic_rails/application_spawner.rb +2 -2
  51. data/lib/phusion_passenger/dependencies.rb +6 -1
  52. data/lib/phusion_passenger/platform_info.rb +9 -0
  53. data/lib/phusion_passenger/platform_info/compiler.rb +5 -0
  54. data/lib/phusion_passenger/platform_info/operating_system.rb +1 -1
  55. data/lib/phusion_passenger/platform_info/ruby.rb +5 -5
  56. data/lib/phusion_passenger/rack/application_spawner.rb +6 -3
  57. data/lib/phusion_passenger/utils.rb +2 -2
  58. data/lib/phusion_passenger/wsgi/application_spawner.rb +1 -1
  59. data/resources/mime.types +2 -0
  60. data/test/cxx/LoggingTest.cpp +10 -12
  61. data/test/cxx/MessageIOTest.cpp +53 -3
  62. data/test/cxx/MessageReadersWritersTest.cpp +5 -2
  63. data/test/cxx/MessageServerTest.cpp +3 -1
  64. data/test/integration_tests/nginx_tests.rb +14 -1
  65. data/test/stub/rack/config.ru +2 -0
  66. data/test/tut/tut.h +9 -3
  67. metadata +5 -4
@@ -2310,7 +2310,55 @@ applications, each which must be available at all times.</p></div>
2310
2310
  The default value is <em>300</em>.</p></div>
2311
2311
  </div>
2312
2312
  <div class="sect3">
2313
- <h4 id="PassengerPreStart">5.7.5. passenger_pre_start &lt;url&gt;</h4>
2313
+ <h4 id="PassengerMaxRequests">5.7.5. passenger_max_requests &lt;integer&gt;</h4>
2314
+ <div class="paragraph"><p>The maximum number of requests an application instance will process. After
2315
+ serving that many requests, the application instance will be shut down and
2316
+ Phusion Passenger will restart it. A value of 0 means that there is no maximum:
2317
+ an application instance will thus be shut down when its idle timeout has been
2318
+ reached.</p></div>
2319
+ <div class="paragraph"><p>This option is useful if your application is leaking memory. By shutting
2320
+ it down after a certain number of requests, all of its memory is guaranteed
2321
+ to be freed by the operating system.</p></div>
2322
+ <div class="paragraph"><p>This option may occur in the following places:</p></div>
2323
+ <div class="ulist"><ul>
2324
+ <li>
2325
+ <p>
2326
+ In the <em>http</em> configuration block.
2327
+ </p>
2328
+ </li>
2329
+ <li>
2330
+ <p>
2331
+ In a <em>server</em> configuration block.
2332
+ </p>
2333
+ </li>
2334
+ <li>
2335
+ <p>
2336
+ In a <em>location</em> configuration block.
2337
+ </p>
2338
+ </li>
2339
+ <li>
2340
+ <p>
2341
+ In an <em>if</em> configuration scope.
2342
+ </p>
2343
+ </li>
2344
+ </ul></div>
2345
+ <div class="paragraph"><p>In each place, it may be specified at most once. The default value is <em>0</em>.</p></div>
2346
+ <div class="admonitionblock">
2347
+ <table><tr>
2348
+ <td class="icon">
2349
+ <img src="./images/icons/caution.png" alt="Caution">
2350
+ </td>
2351
+ <td class="content">
2352
+ <div class="paragraph"><p>The <a href="#PassengerMaxRequests">passenger_max_requests</a> directive should be considered
2353
+ as a workaround for misbehaving applications. It is advised that you fix the
2354
+ problem in your application rather than relying on these directives as a
2355
+ measure to avoid memory leaks.</p></div>
2356
+ </td>
2357
+ </tr></table>
2358
+ </div>
2359
+ </div>
2360
+ <div class="sect3">
2361
+ <h4 id="PassengerPreStart">5.7.6. passenger_pre_start &lt;url&gt;</h4>
2314
2362
  <div class="paragraph"><p>By default, Phusion Passenger does not start any application instances until said
2315
2363
  web application is first accessed. The result is that the first visitor of said
2316
2364
  web application might experience a small delay as Phusion Passenger is starting
@@ -3704,7 +3752,7 @@ has no effect.</p></div>
3704
3752
  <div id="footnotes"><hr></div>
3705
3753
  <div id="footer">
3706
3754
  <div id="footer-text">
3707
- Last updated 2011-08-11 22:39:09 CEST
3755
+ Last updated 2011-09-15 09:09:01 CEST
3708
3756
  </div>
3709
3757
  </div>
3710
3758
  </body>
@@ -1032,6 +1032,35 @@ applications, each which must be available at all times.
1032
1032
  This option may only occur once, in the 'http' configuration block.
1033
1033
  The default value is '300'.
1034
1034
 
1035
+ [[PassengerMaxRequests]]
1036
+ ==== passenger_max_requests <integer> ====
1037
+ The maximum number of requests an application instance will process. After
1038
+ serving that many requests, the application instance will be shut down and
1039
+ Phusion Passenger will restart it. A value of 0 means that there is no maximum:
1040
+ an application instance will thus be shut down when its idle timeout has been
1041
+ reached.
1042
+
1043
+ This option is useful if your application is leaking memory. By shutting
1044
+ it down after a certain number of requests, all of its memory is guaranteed
1045
+ to be freed by the operating system.
1046
+
1047
+ This option may occur in the following places:
1048
+
1049
+ * In the 'http' configuration block.
1050
+ * In a 'server' configuration block.
1051
+ * In a 'location' configuration block.
1052
+ * In an 'if' configuration scope.
1053
+
1054
+ In each place, it may be specified at most once. The default value is '0'.
1055
+
1056
+ [CAUTION]
1057
+ =====================================================
1058
+ The <<PassengerMaxRequests,passenger_max_requests>> directive should be considered
1059
+ as a workaround for misbehaving applications. It is advised that you fix the
1060
+ problem in your application rather than relying on these directives as a
1061
+ measure to avoid memory leaks.
1062
+ =====================================================
1063
+
1035
1064
  [[PassengerPreStart]]
1036
1065
  ==== passenger_pre_start <url> ====
1037
1066
  By default, Phusion Passenger does not start any application instances until said
@@ -44,6 +44,7 @@ struct BucketData {
44
44
  SessionPtr session;
45
45
  PassengerBucketStatePtr state;
46
46
  int stream;
47
+ bool bufferResponse;
47
48
 
48
49
  ~BucketData() {
49
50
  /* The session here is an ApplicationPoolServer::RemoteSession.
@@ -80,7 +81,7 @@ bucket_read(apr_bucket *bucket, const char **str, apr_size_t *len, apr_read_type
80
81
  *str = NULL;
81
82
  *len = 0;
82
83
 
83
- if (block == APR_NONBLOCK_READ) {
84
+ if (!data->bufferResponse && block == APR_NONBLOCK_READ) {
84
85
  /*
85
86
  * The bucket brigade that Hooks::handleRequest() passes using
86
87
  * ap_pass_brigade() is always passed through ap_content_length_filter,
@@ -130,7 +131,7 @@ bucket_read(apr_bucket *bucket, const char **str, apr_size_t *len, apr_read_type
130
131
  * which can read the next chunk from the stream.
131
132
  */
132
133
  APR_BUCKET_INSERT_AFTER(bucket, passenger_bucket_create(
133
- data->session, data->state, bucket->list));
134
+ data->session, data->state, bucket->list, data->bufferResponse));
134
135
 
135
136
  /* The newly created Passenger Bucket has a reference to the session
136
137
  * object, so we can delete data here.
@@ -163,11 +164,12 @@ bucket_read(apr_bucket *bucket, const char **str, apr_size_t *len, apr_read_type
163
164
  }
164
165
 
165
166
  static apr_bucket *
166
- passenger_bucket_make(apr_bucket *bucket, SessionPtr session, PassengerBucketStatePtr state) {
167
+ passenger_bucket_make(apr_bucket *bucket, SessionPtr session, PassengerBucketStatePtr state, bool bufferResponse) {
167
168
  BucketData *data = new BucketData();
168
169
  data->session = session;
169
170
  data->stream = session->getStream();
170
171
  data->state = state;
172
+ data->bufferResponse = bufferResponse;
171
173
 
172
174
  bucket->type = &apr_bucket_type_passenger_pipe;
173
175
  bucket->length = (apr_size_t)(-1);
@@ -177,14 +179,14 @@ passenger_bucket_make(apr_bucket *bucket, SessionPtr session, PassengerBucketSta
177
179
  }
178
180
 
179
181
  apr_bucket *
180
- passenger_bucket_create(SessionPtr session, PassengerBucketStatePtr state, apr_bucket_alloc_t *list) {
182
+ passenger_bucket_create(SessionPtr session, PassengerBucketStatePtr state, apr_bucket_alloc_t *list, bool bufferResponse) {
181
183
  apr_bucket *bucket;
182
184
 
183
185
  bucket = (apr_bucket *) apr_bucket_alloc(sizeof(*bucket), list);
184
186
  APR_BUCKET_INIT(bucket);
185
187
  bucket->free = apr_bucket_free;
186
188
  bucket->list = list;
187
- return passenger_bucket_make(bucket, session, state);
189
+ return passenger_bucket_make(bucket, session, state, bufferResponse);
188
190
  }
189
191
 
190
192
  } // namespace Passenger
data/ext/apache2/Bucket.h CHANGED
@@ -80,7 +80,8 @@ typedef shared_ptr<PassengerBucketState> PassengerBucketStatePtr;
80
80
  */
81
81
  apr_bucket *passenger_bucket_create(SessionPtr session,
82
82
  PassengerBucketStatePtr state,
83
- apr_bucket_alloc_t *list);
83
+ apr_bucket_alloc_t *list,
84
+ bool bufferResponse);
84
85
 
85
86
  } // namespace Passenger
86
87
 
@@ -209,6 +209,7 @@ passenger_config_create_dir(apr_pool_t *p, char *dirspec) {
209
209
  config->uploadBufferDir = NULL;
210
210
  config->friendlyErrorPages = DirConfig::UNSET;
211
211
  config->unionStationSupport = DirConfig::UNSET;
212
+ config->bufferResponse = DirConfig::UNSET;
212
213
  /*************************************/
213
214
  return config;
214
215
  }
@@ -259,6 +260,7 @@ passenger_config_merge_dir(apr_pool_t *p, void *basev, void *addv) {
259
260
  MERGE_THREEWAY_CONFIG(allowEncodedSlashes);
260
261
  MERGE_THREEWAY_CONFIG(friendlyErrorPages);
261
262
  MERGE_THREEWAY_CONFIG(unionStationSupport);
263
+ MERGE_THREEWAY_CONFIG(bufferResponse);
262
264
  /*************************************/
263
265
  return config;
264
266
  }
@@ -313,6 +315,7 @@ DEFINE_DIR_THREEWAY_CONFIG_SETTER(cmd_passenger_resolve_symlinks_in_document_roo
313
315
  DEFINE_DIR_THREEWAY_CONFIG_SETTER(cmd_passenger_allow_encoded_slashes, allowEncodedSlashes)
314
316
  DEFINE_DIR_THREEWAY_CONFIG_SETTER(cmd_passenger_friendly_error_pages, friendlyErrorPages)
315
317
  DEFINE_DIR_THREEWAY_CONFIG_SETTER(cmd_union_station_support, unionStationSupport)
318
+ DEFINE_DIR_THREEWAY_CONFIG_SETTER(cmd_passenger_buffer_response, bufferResponse)
316
319
 
317
320
  static const char *
318
321
  cmd_passenger_spawn_method(cmd_parms *cmd, void *pcfg, const char *arg) {
@@ -586,6 +589,11 @@ const command_rec passenger_commands[] = {
586
589
  NULL,
587
590
  OR_ALL,
588
591
  "A filter for Union Station data."),
592
+ AP_INIT_FLAG("PassengerBufferResponse",
593
+ (FlagFunc) cmd_passenger_buffer_response,
594
+ NULL,
595
+ OR_ALL,
596
+ "Whether to enable buffering response."),
589
597
  AP_INIT_FLAG("PassengerResolveSymlinksInDocumentRoot",
590
598
  (FlagFunc) cmd_passenger_resolve_symlinks_in_document_root,
591
599
  NULL,
@@ -26,17 +26,12 @@
26
26
  #define _PASSENGER_CONFIGURATION_HPP_
27
27
 
28
28
  #include "Utils.h"
29
- #include "MessageChannel.h"
30
29
  #include "Logging.h"
31
30
  #include "ServerInstanceDir.h"
32
31
  #include "Constants.h"
33
32
 
34
33
  /* The APR headers must come after the Passenger headers. See Hooks.cpp
35
34
  * to learn why.
36
- *
37
- * MessageChannel.h must be included -- even though we don't actually use
38
- * MessageChannel.h in here, it's necessary to make sure that apr_want.h
39
- * doesn't b0rk on 'struct iovec'.
40
35
  */
41
36
  #include "Configuration.h"
42
37
 
@@ -197,6 +192,11 @@ struct DirConfig {
197
192
  */
198
193
  Threeway unionStationSupport;
199
194
 
195
+ /**
196
+ * Whether response buffering support is enabled.
197
+ */
198
+ Threeway bufferResponse;
199
+
200
200
  /*************************************/
201
201
  /*************************************/
202
202
 
@@ -332,6 +332,10 @@ struct DirConfig {
332
332
  bool useUnionStation() const {
333
333
  return unionStationSupport == ENABLED;
334
334
  }
335
+
336
+ bool getBufferResponse() const {
337
+ return bufferResponse != DISABLED;
338
+ }
335
339
 
336
340
  string getUnionStationFilterString() const {
337
341
  if (unionStationFilters.empty()) {
@@ -49,12 +49,12 @@
49
49
  #include "MessageServer.h"
50
50
  #include "ServerInstanceDir.h"
51
51
  #include "ResourceLocator.h"
52
- #include "MessageChannel.h"
53
52
  #include "FileDescriptor.h"
54
53
  #include "Logging.h"
55
54
  #include "Exceptions.h"
56
55
  #include "Utils.h"
57
56
  #include "Utils/Timer.h"
57
+ #include "Utils/MessageIO.h"
58
58
 
59
59
  using namespace std;
60
60
  using namespace boost;
@@ -137,7 +137,6 @@ private:
137
137
  ServerInstanceDir serverInstanceDir;
138
138
  ServerInstanceDir::GenerationPtr generation;
139
139
  FileDescriptor feedbackFd;
140
- MessageChannel feedbackChannel;
141
140
  AnalyticsLoggerPtr analyticsLogger;
142
141
  AccountsDatabasePtr accountsDatabase;
143
142
  MessageServerPtr messageServer;
@@ -152,7 +151,7 @@ private:
152
151
  TRACE_POINT();
153
152
  vector<string> args;
154
153
 
155
- if (!feedbackChannel.read(args)) {
154
+ if (!readArrayMessage(feedbackFd, args)) {
156
155
  throw IOException("The watchdog unexpectedly closed the connection.");
157
156
  }
158
157
  if (args[0] != "request socket password" && args[0] != "message socket password") {
@@ -218,7 +217,6 @@ public:
218
217
  string loggingAgentPassword;
219
218
 
220
219
  this->feedbackFd = feedbackFd;
221
- feedbackChannel = MessageChannel(feedbackFd);
222
220
 
223
221
  UPDATE_TRACE_POINT();
224
222
  messageSocketPassword = Base64::decode(options.get("message_socket_password"));
@@ -259,7 +257,8 @@ public:
259
257
  messageServer->addHandler(ptr(new ExitHandler(exitEvent)));
260
258
 
261
259
  UPDATE_TRACE_POINT();
262
- feedbackChannel.write("initialized",
260
+ writeArrayMessage(feedbackFd,
261
+ "initialized",
263
262
  "", // Request socket filename; not available in the Apache helper server.
264
263
  messageServer->getSocketFilename().c_str(),
265
264
  NULL);
@@ -54,16 +54,11 @@
54
54
  #include "Logging.h"
55
55
  #include "AgentsStarter.hpp"
56
56
  #include "ApplicationPool/Client.h"
57
- #include "MessageChannel.h"
58
57
  #include "DirectoryMapper.h"
59
58
  #include "Constants.h"
60
59
 
61
60
  /* The Apache/APR headers *must* come after the Boost headers, otherwise
62
61
  * compilation will fail on OpenBSD.
63
- *
64
- * apr_want.h *must* come after MessageChannel.h, otherwise compilation will
65
- * fail on platforms on which apr_want.h tries to redefine 'struct iovec'.
66
- * http://groups.google.com/group/phusion-passenger/browse_thread/thread/7e162f60df212e9c
67
62
  */
68
63
  #include <ap_config.h>
69
64
  #include <ap_release.h>
@@ -726,7 +721,7 @@ private:
726
721
  /* Setup the bucket brigade. */
727
722
  bucketState = ptr(new PassengerBucketState());
728
723
  bb = apr_brigade_create(r->connection->pool, r->connection->bucket_alloc);
729
- b = passenger_bucket_create(session, bucketState, r->connection->bucket_alloc);
724
+ b = passenger_bucket_create(session, bucketState, r->connection->bucket_alloc, config->getBufferResponse());
730
725
 
731
726
  /* The bucket (b) still has a reference to the session, so the reset()
732
727
  * call here is guaranteed not to throw any exceptions.
@@ -38,7 +38,7 @@ namespace boost
38
38
  std::string message;
39
39
 
40
40
  thread_exception():
41
- m_sys_err(0)
41
+ m_sys_err(-1)
42
42
  {}
43
43
 
44
44
  thread_exception(const std::string &description, int sys_err_code):
@@ -107,6 +107,12 @@ namespace boost
107
107
  thread_exception(sys_err_code)
108
108
  {}
109
109
 
110
+ lock_error(const std::string &message)
111
+ {
112
+ this->message = "boost::lock_error: ";
113
+ this->message.append(message);
114
+ }
115
+
110
116
  ~lock_error() throw()
111
117
  {}
112
118
 
@@ -407,7 +407,7 @@ namespace boost
407
407
  {
408
408
  if(owns_lock())
409
409
  {
410
- boost::throw_exception(boost::lock_error());
410
+ boost::throw_exception(boost::lock_error("lock already owned"));
411
411
  }
412
412
  m->lock();
413
413
  is_locked=true;
@@ -416,7 +416,7 @@ namespace boost
416
416
  {
417
417
  if(owns_lock())
418
418
  {
419
- boost::throw_exception(boost::lock_error());
419
+ boost::throw_exception(boost::lock_error("lock already owned"));
420
420
  }
421
421
  is_locked=m->try_lock();
422
422
  return is_locked;
@@ -442,7 +442,7 @@ namespace boost
442
442
  {
443
443
  if(!owns_lock())
444
444
  {
445
- boost::throw_exception(boost::lock_error());
445
+ boost::throw_exception(boost::lock_error("lock not owned"));
446
446
  }
447
447
  m->unlock();
448
448
  is_locked=false;
@@ -650,7 +650,7 @@ namespace boost
650
650
  {
651
651
  if(owns_lock())
652
652
  {
653
- boost::throw_exception(boost::lock_error());
653
+ boost::throw_exception(boost::lock_error("lock already owned"));
654
654
  }
655
655
  m->lock_shared();
656
656
  is_locked=true;
@@ -659,7 +659,7 @@ namespace boost
659
659
  {
660
660
  if(owns_lock())
661
661
  {
662
- boost::throw_exception(boost::lock_error());
662
+ boost::throw_exception(boost::lock_error("lock already owned"));
663
663
  }
664
664
  is_locked=m->try_lock_shared();
665
665
  return is_locked;
@@ -668,7 +668,7 @@ namespace boost
668
668
  {
669
669
  if(owns_lock())
670
670
  {
671
- boost::throw_exception(boost::lock_error());
671
+ boost::throw_exception(boost::lock_error("lock already owned"));
672
672
  }
673
673
  is_locked=m->timed_lock_shared(target_time);
674
674
  return is_locked;
@@ -678,7 +678,7 @@ namespace boost
678
678
  {
679
679
  if(owns_lock())
680
680
  {
681
- boost::throw_exception(boost::lock_error());
681
+ boost::throw_exception(boost::lock_error("lock already owned"));
682
682
  }
683
683
  is_locked=m->timed_lock_shared(target_time);
684
684
  return is_locked;
@@ -687,7 +687,7 @@ namespace boost
687
687
  {
688
688
  if(!owns_lock())
689
689
  {
690
- boost::throw_exception(boost::lock_error());
690
+ boost::throw_exception(boost::lock_error("lock not owned"));
691
691
  }
692
692
  m->unlock_shared();
693
693
  is_locked=false;
@@ -847,7 +847,7 @@ namespace boost
847
847
  {
848
848
  if(owns_lock())
849
849
  {
850
- boost::throw_exception(boost::lock_error());
850
+ boost::throw_exception(boost::lock_error("lock already owned"));
851
851
  }
852
852
  m->lock_upgrade();
853
853
  is_locked=true;
@@ -856,7 +856,7 @@ namespace boost
856
856
  {
857
857
  if(owns_lock())
858
858
  {
859
- boost::throw_exception(boost::lock_error());
859
+ boost::throw_exception(boost::lock_error("lock already owned"));
860
860
  }
861
861
  is_locked=m->try_lock_upgrade();
862
862
  return is_locked;
@@ -865,7 +865,7 @@ namespace boost
865
865
  {
866
866
  if(!owns_lock())
867
867
  {
868
- boost::throw_exception(boost::lock_error());
868
+ boost::throw_exception(boost::lock_error("lock not owned"));
869
869
  }
870
870
  m->unlock_upgrade();
871
871
  is_locked=false;
@@ -66,6 +66,24 @@ ignoreSigpipe() {
66
66
  sigaction(SIGPIPE, &action, NULL);
67
67
  }
68
68
 
69
+ static bool
70
+ hasEnvOption(const char *name, bool defaultValue = false) {
71
+ const char *value = getenv(name);
72
+ if (value != NULL) {
73
+ if (*value != '\0') {
74
+ return strcmp(value, "yes") == 0
75
+ || strcmp(value, "y") == 0
76
+ || strcmp(value, "1") == 0
77
+ || strcmp(value, "on") == 0
78
+ || strcmp(value, "true") == 0;
79
+ } else {
80
+ return defaultValue;
81
+ }
82
+ } else {
83
+ return defaultValue;
84
+ }
85
+ }
86
+
69
87
  // No idea whether strlen() is async signal safe, but let's not risk it
70
88
  // and write our own version instead that's guaranteed to be safe.
71
89
  static size_t
@@ -328,7 +346,9 @@ initializeAgent(int argc, char *argv[], const char *processName) {
328
346
  VariantMap options;
329
347
 
330
348
  ignoreSigpipe();
331
- installAbortHandler();
349
+ if (hasEnvOption("PASSENGER_ABORT_HANDLER", true)) {
350
+ installAbortHandler();
351
+ }
332
352
  setup_syscall_interruption_support();
333
353
  setvbuf(stdout, NULL, _IONBF, 0);
334
354
  setvbuf(stderr, NULL, _IONBF, 0);