passenger 4.0.48 → 4.0.49

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 (218) hide show
  1. checksums.yaml +8 -8
  2. checksums.yaml.gz.asc +7 -7
  3. data.tar.gz.asc +7 -7
  4. data/.editorconfig +36 -2
  5. data/.travis.yml +1 -1
  6. data/CHANGELOG +16 -0
  7. data/Rakefile +0 -1
  8. data/build/apache2.rb +4 -4
  9. data/build/common_library.rb +18 -18
  10. data/build/cplusplus_support.rb +2 -2
  11. data/build/documentation.rb +1 -1
  12. data/build/integration_tests.rb +12 -4
  13. data/build/misc.rb +12 -7
  14. data/build/packaging.rb +14 -14
  15. data/build/preprocessor.rb +10 -10
  16. data/build/rake_extensions.rb +11 -11
  17. data/build/ruby_extension.rb +2 -2
  18. data/dev/ci/inituidgid +24 -0
  19. data/dev/ci/run_jenkins.sh +57 -0
  20. data/dev/ci/run_rpm_tests.sh +77 -0
  21. data/dev/{run_travis.sh → ci/run_travis.sh} +60 -4
  22. data/doc/Users guide Nginx.txt +2 -2
  23. data/doc/users_guide_snippets/environment_variables.txt +0 -2
  24. data/doc/users_guide_snippets/tips.txt +20 -1
  25. data/ext/apache2/Bucket.cpp +18 -18
  26. data/ext/apache2/Bucket.h +4 -4
  27. data/ext/apache2/Configuration.cpp +7 -7
  28. data/ext/apache2/Configuration.hpp +43 -43
  29. data/ext/apache2/DirectoryMapper.h +5 -5
  30. data/ext/apache2/Hooks.cpp +142 -142
  31. data/ext/apache2/MergeDirConfig.cpp +40 -40
  32. data/ext/common/Account.h +17 -17
  33. data/ext/common/AccountsDatabase.h +9 -9
  34. data/ext/common/AgentsStarter.cpp +2 -2
  35. data/ext/common/AgentsStarter.h +40 -40
  36. data/ext/common/ApplicationPool2/Common.h +10 -6
  37. data/ext/common/ApplicationPool2/ComponentInfo.h +2 -2
  38. data/ext/common/ApplicationPool2/DirectSpawner.h +17 -17
  39. data/ext/common/ApplicationPool2/DummySpawner.h +5 -5
  40. data/ext/common/ApplicationPool2/Group.h +54 -38
  41. data/ext/common/ApplicationPool2/Implementation.cpp +76 -49
  42. data/ext/common/ApplicationPool2/Options.h +98 -91
  43. data/ext/common/ApplicationPool2/Pool.h +70 -69
  44. data/ext/common/ApplicationPool2/Process.h +21 -21
  45. data/ext/common/ApplicationPool2/Session.h +11 -11
  46. data/ext/common/ApplicationPool2/SmartSpawner.h +60 -60
  47. data/ext/common/ApplicationPool2/Socket.h +19 -19
  48. data/ext/common/ApplicationPool2/Spawner.h +64 -72
  49. data/ext/common/ApplicationPool2/SpawnerFactory.h +4 -4
  50. data/ext/common/ApplicationPool2/SuperGroup.h +41 -41
  51. data/ext/common/BackgroundEventLoop.cpp +1 -1
  52. data/ext/common/BackgroundEventLoop.h +2 -2
  53. data/ext/common/Constants.h +1 -1
  54. data/ext/common/EventedBufferedInput.h +5 -5
  55. data/ext/common/EventedClient.h +51 -51
  56. data/ext/common/EventedMessageServer.h +39 -39
  57. data/ext/common/EventedServer.h +32 -32
  58. data/ext/common/Exceptions.h +23 -23
  59. data/ext/common/FileDescriptor.h +18 -18
  60. data/ext/common/Logging.cpp +1 -1
  61. data/ext/common/MessageClient.h +27 -27
  62. data/ext/common/MessageReadersWriters.h +79 -79
  63. data/ext/common/MessageServer.h +59 -59
  64. data/ext/common/RandomGenerator.h +12 -12
  65. data/ext/common/ResourceLocator.h +8 -8
  66. data/ext/common/SafeLibev.h +54 -25
  67. data/ext/common/ServerInstanceDir.h +31 -31
  68. data/ext/common/StaticString.h +50 -48
  69. data/ext/common/Utils.cpp +73 -78
  70. data/ext/common/Utils.h +6 -6
  71. data/ext/common/Utils/Base64.cpp +3 -3
  72. data/ext/common/Utils/Base64.h +7 -7
  73. data/ext/common/Utils/BlockingQueue.h +9 -9
  74. data/ext/common/Utils/BufferedIO.h +17 -17
  75. data/ext/common/Utils/CachedFileStat.hpp +16 -16
  76. data/ext/common/Utils/Dechunker.h +25 -25
  77. data/ext/common/Utils/FileChangeChecker.h +10 -10
  78. data/ext/common/Utils/MemZeroGuard.h +5 -5
  79. data/ext/common/Utils/MemoryBarrier.h +1 -1
  80. data/ext/common/Utils/MessageIO.h +61 -61
  81. data/ext/common/Utils/ProcessMetricsCollector.h +40 -40
  82. data/ext/common/Utils/ScopeGuard.h +7 -7
  83. data/ext/common/Utils/SpeedMeter.h +1 -1
  84. data/ext/common/Utils/StrIntUtils.cpp +13 -13
  85. data/ext/common/Utils/StrIntUtils.h +3 -3
  86. data/ext/common/Utils/StringScanning.h +5 -5
  87. data/ext/common/Utils/SystemMetricsCollector.h +2 -2
  88. data/ext/common/Utils/SystemTime.h +10 -10
  89. data/ext/common/Utils/Template.h +2 -2
  90. data/ext/common/Utils/Timer.h +6 -6
  91. data/ext/common/Utils/VariantMap.h +29 -29
  92. data/ext/common/agents/Base.cpp +19 -19
  93. data/ext/common/agents/HelperAgent/AgentOptions.h +1 -1
  94. data/ext/common/agents/HelperAgent/FileBackedPipe.h +6 -6
  95. data/ext/common/agents/HelperAgent/Main.cpp +44 -43
  96. data/ext/common/agents/HelperAgent/RequestHandler.cpp +4 -4
  97. data/ext/common/agents/HelperAgent/RequestHandler.h +29 -28
  98. data/ext/common/agents/HelperAgent/ScgiRequestParser.h +56 -50
  99. data/ext/common/agents/LoggingAgent/AdminController.h +8 -8
  100. data/ext/common/agents/LoggingAgent/DataStoreId.h +17 -17
  101. data/ext/common/agents/LoggingAgent/FilterSupport.h +167 -167
  102. data/ext/common/agents/LoggingAgent/LoggingServer.h +122 -122
  103. data/ext/common/agents/LoggingAgent/Main.cpp +7 -7
  104. data/ext/common/agents/LoggingAgent/RemoteSender.h +54 -54
  105. data/ext/common/agents/SpawnPreparer.cpp +4 -4
  106. data/ext/common/agents/TempDirToucher.c +2 -2
  107. data/ext/common/agents/Watchdog/AgentWatcher.cpp +47 -47
  108. data/ext/common/agents/Watchdog/HelperAgentWatcher.cpp +7 -7
  109. data/ext/common/agents/Watchdog/LoggingAgentWatcher.cpp +7 -7
  110. data/ext/common/agents/Watchdog/Main.cpp +22 -22
  111. data/ext/common/agents/Watchdog/ServerInstanceDirToucher.cpp +9 -9
  112. data/ext/libeio/eio.c +1 -1
  113. data/ext/nginx/Configuration.c +30 -30
  114. data/ext/nginx/Configuration.h +1 -1
  115. data/ext/nginx/ContentHandler.c +54 -54
  116. data/ext/nginx/ContentHandler.h +3 -3
  117. data/ext/nginx/StaticContentHandler.c +2 -2
  118. data/ext/nginx/ngx_http_passenger_module.c +21 -21
  119. data/ext/oxt/detail/backtrace_enabled.hpp +1 -1
  120. data/ext/oxt/detail/context.hpp +1 -1
  121. data/ext/oxt/detail/spin_lock_darwin.hpp +4 -4
  122. data/ext/oxt/detail/spin_lock_gcc_x86.hpp +3 -3
  123. data/ext/oxt/detail/spin_lock_pthreads.hpp +4 -4
  124. data/ext/oxt/detail/tracable_exception_disabled.hpp +1 -1
  125. data/ext/oxt/dynamic_thread_group.hpp +18 -18
  126. data/ext/oxt/implementation.cpp +9 -8
  127. data/ext/oxt/macros.hpp +2 -2
  128. data/ext/oxt/system_calls.cpp +11 -11
  129. data/ext/oxt/system_calls.hpp +13 -13
  130. data/ext/oxt/thread.hpp +22 -14
  131. data/ext/ruby/passenger_native_support.c +55 -55
  132. data/lib/phusion_passenger.rb +24 -24
  133. data/lib/phusion_passenger/common_library.rb +2 -0
  134. data/lib/phusion_passenger/loader_shared_helpers.rb +18 -18
  135. data/lib/phusion_passenger/packaging.rb +9 -4
  136. data/lib/phusion_passenger/platform_info/apache.rb +45 -31
  137. data/lib/phusion_passenger/platform_info/compiler.rb +11 -11
  138. data/lib/phusion_passenger/rack/thread_handler_extension.rb +1 -1
  139. data/lib/phusion_passenger/request_handler/thread_handler.rb +8 -8
  140. data/lib/phusion_passenger/standalone/app_finder.rb +16 -16
  141. data/lib/phusion_passenger/standalone/command.rb +22 -22
  142. data/packaging/rpm/LICENSE.txt +19 -0
  143. data/packaging/rpm/Makefile +13 -0
  144. data/packaging/rpm/README.md +41 -0
  145. data/packaging/rpm/Vagrantfile +38 -0
  146. data/{rpm/Vagrantfile → packaging/rpm/Vagrantfile.centos} +0 -0
  147. data/packaging/rpm/build +170 -0
  148. data/packaging/rpm/create_project +41 -0
  149. data/packaging/rpm/git_update +88 -0
  150. data/packaging/rpm/image/Dockerfile +37 -0
  151. data/packaging/rpm/image/Gemfile +3 -0
  152. data/packaging/rpm/image/Gemfile.lock +12 -0
  153. data/packaging/rpm/image/RPM-GPG-KEY-amazon-ga +19 -0
  154. data/packaging/rpm/image/amazon2014-i386.cfg +96 -0
  155. data/packaging/rpm/image/amazon2014-x86_64.cfg +96 -0
  156. data/packaging/rpm/image/site-defaults.cfg +168 -0
  157. data/packaging/rpm/internal/build_tasks.rb +238 -0
  158. data/packaging/rpm/internal/dummygpg +11 -0
  159. data/packaging/rpm/internal/exec_build +42 -0
  160. data/packaging/rpm/internal/get_distro_arch +14 -0
  161. data/packaging/rpm/internal/get_distro_id +10 -0
  162. data/packaging/rpm/internal/git_update +27 -0
  163. data/packaging/rpm/internal/inituidgid +17 -0
  164. data/packaging/rpm/internal/my_init +344 -0
  165. data/packaging/rpm/internal/python27 +3 -0
  166. data/packaging/rpm/internal/repo_update +46 -0
  167. data/packaging/rpm/internal/setuser +26 -0
  168. data/packaging/rpm/internal/tracking_helper +40 -0
  169. data/packaging/rpm/jenkins_release +99 -0
  170. data/packaging/rpm/lib/build_tasks_support.rb +402 -0
  171. data/packaging/rpm/lib/preprocessor.rb +341 -0
  172. data/packaging/rpm/nginx_spec/404.html +119 -0
  173. data/packaging/rpm/nginx_spec/50x.html +119 -0
  174. data/packaging/rpm/nginx_spec/index.html +116 -0
  175. data/packaging/rpm/nginx_spec/nginx-auto-cc-gcc.patch +13 -0
  176. data/packaging/rpm/nginx_spec/nginx-logo.png +0 -0
  177. data/packaging/rpm/nginx_spec/nginx-upgrade +13 -0
  178. data/packaging/rpm/nginx_spec/nginx-upgrade.8 +151 -0
  179. data/packaging/rpm/nginx_spec/nginx.conf +131 -0
  180. data/packaging/rpm/nginx_spec/nginx.init +144 -0
  181. data/packaging/rpm/nginx_spec/nginx.logrotate +13 -0
  182. data/packaging/rpm/nginx_spec/nginx.service +15 -0
  183. data/packaging/rpm/nginx_spec/nginx.spec.template +559 -0
  184. data/packaging/rpm/nginx_spec/nginx.sysconfig +4 -0
  185. data/packaging/rpm/nginx_spec/passenger.conf +9 -0
  186. data/packaging/rpm/nginx_spec/poweredby.png +0 -0
  187. data/{rpm → packaging/rpm/passenger_spec}/apache-passenger.conf.in +0 -0
  188. data/{rpm → packaging/rpm/passenger_spec}/config.json +0 -0
  189. data/{rpm → packaging/rpm/passenger_spec}/passenger.logrotate +0 -0
  190. data/{rpm → packaging/rpm/passenger_spec}/passenger.spec.template +58 -31
  191. data/{rpm → packaging/rpm/passenger_spec}/passenger_dynamic_thread_group.patch +0 -0
  192. data/{rpm → packaging/rpm/passenger_spec}/passenger_tests_default_config_example.patch +0 -0
  193. data/{rpm → packaging/rpm/passenger_spec}/rubygem-passenger-4.0.18-GLIBC_HAVE_LONG_LONG.patch +0 -0
  194. data/{rpm → packaging/rpm/passenger_spec}/rubygem-passenger-4.0.18-gcc47-include-sys_types.patch +0 -0
  195. data/packaging/rpm/repo_update +114 -0
  196. data/packaging/rpm/setup-system +60 -0
  197. data/packaging/rpm/shell +10 -0
  198. data/resources/templates/standalone/config.erb +3 -1
  199. data/test/config.json.rpm-automation +1 -1
  200. data/test/cxx/ApplicationPool2/DirectSpawnerTest.cpp +11 -11
  201. data/test/cxx/ApplicationPool2/OptionsTest.cpp +5 -5
  202. data/test/cxx/ApplicationPool2/PoolTest.cpp +129 -89
  203. data/test/cxx/ApplicationPool2/ProcessTest.cpp +15 -15
  204. data/test/cxx/ApplicationPool2/SmartSpawnerTest.cpp +22 -22
  205. data/test/cxx/ApplicationPool2/SpawnerTestCases.cpp +11 -11
  206. data/test/cxx/ScgiRequestParserTest.cpp +75 -61
  207. data/test/cxx/UtilsTest.cpp +86 -85
  208. data/test/gdbinit.example +3 -0
  209. data/test/integration_tests/nginx_tests.rb +3 -3
  210. data/test/integration_tests/source_packaging_test.rb +3 -1
  211. data/test/stub/nginx/nginx.conf.erb +8 -1
  212. data/test/support/nginx_controller.rb +7 -7
  213. metadata +62 -17
  214. metadata.gz.asc +7 -7
  215. data/build/rpm.rb +0 -128
  216. data/dev/rpmtool +0 -21
  217. data/dev/test_rpm_packaging.sh +0 -28
  218. data/rpm/get_distro_id.py +0 -4
@@ -30,6 +30,8 @@
30
30
  #include <limits.h>
31
31
  #include <unistd.h>
32
32
  #include <boost/make_shared.hpp>
33
+ #include <boost/ref.hpp>
34
+ #include <boost/cstdint.hpp>
33
35
  #include <boost/date_time/posix_time/posix_time_types.hpp>
34
36
  #include <oxt/backtrace.hpp>
35
37
  #include <ApplicationPool2/Pool.h>
@@ -38,6 +40,7 @@
38
40
  #include <ApplicationPool2/PipeWatcher.h>
39
41
  #include <ApplicationPool2/ErrorRenderer.h>
40
42
  #include <Exceptions.h>
43
+ #include <Hooks.h>
41
44
  #include <MessageReadersWriters.h>
42
45
  #include <Utils.h>
43
46
  #include <Utils/IOUtils.h>
@@ -65,28 +68,28 @@ copyException(const tracable_exception &e) {
65
68
  TRY_COPY_EXCEPTION(FileSystemException);
66
69
  TRY_COPY_EXCEPTION(TimeRetrievalException);
67
70
  TRY_COPY_EXCEPTION(SystemException);
68
-
71
+
69
72
  TRY_COPY_EXCEPTION(FileNotFoundException);
70
73
  TRY_COPY_EXCEPTION(EOFException);
71
74
  TRY_COPY_EXCEPTION(IOException);
72
-
75
+
73
76
  TRY_COPY_EXCEPTION(ConfigurationException);
74
-
77
+
75
78
  TRY_COPY_EXCEPTION(RequestQueueFullException);
76
79
  TRY_COPY_EXCEPTION(GetAbortedException);
77
80
  TRY_COPY_EXCEPTION(SpawnException);
78
-
81
+
79
82
  TRY_COPY_EXCEPTION(InvalidModeStringException);
80
83
  TRY_COPY_EXCEPTION(ArgumentException);
81
-
84
+
82
85
  TRY_COPY_EXCEPTION(RuntimeException);
83
-
86
+
84
87
  TRY_COPY_EXCEPTION(TimeoutException);
85
-
88
+
86
89
  TRY_COPY_EXCEPTION(NonExistentUserException);
87
90
  TRY_COPY_EXCEPTION(NonExistentGroupException);
88
91
  TRY_COPY_EXCEPTION(SecurityException);
89
-
92
+
90
93
  TRY_COPY_EXCEPTION(SyntaxError);
91
94
 
92
95
  TRY_COPY_EXCEPTION(boost::thread_interrupted);
@@ -107,28 +110,28 @@ rethrowException(const ExceptionPtr &e) {
107
110
  TRY_RETHROW_EXCEPTION(FileSystemException);
108
111
  TRY_RETHROW_EXCEPTION(TimeRetrievalException);
109
112
  TRY_RETHROW_EXCEPTION(SystemException);
110
-
113
+
111
114
  TRY_RETHROW_EXCEPTION(FileNotFoundException);
112
115
  TRY_RETHROW_EXCEPTION(EOFException);
113
116
  TRY_RETHROW_EXCEPTION(IOException);
114
-
117
+
115
118
  TRY_RETHROW_EXCEPTION(ConfigurationException);
116
-
119
+
117
120
  TRY_RETHROW_EXCEPTION(SpawnException);
118
121
  TRY_RETHROW_EXCEPTION(RequestQueueFullException);
119
122
  TRY_RETHROW_EXCEPTION(GetAbortedException);
120
-
123
+
121
124
  TRY_RETHROW_EXCEPTION(InvalidModeStringException);
122
125
  TRY_RETHROW_EXCEPTION(ArgumentException);
123
-
126
+
124
127
  TRY_RETHROW_EXCEPTION(RuntimeException);
125
-
128
+
126
129
  TRY_RETHROW_EXCEPTION(TimeoutException);
127
-
130
+
128
131
  TRY_RETHROW_EXCEPTION(NonExistentUserException);
129
132
  TRY_RETHROW_EXCEPTION(NonExistentGroupException);
130
133
  TRY_RETHROW_EXCEPTION(SecurityException);
131
-
134
+
132
135
  TRY_RETHROW_EXCEPTION(SyntaxError);
133
136
 
134
137
  TRY_RETHROW_EXCEPTION(boost::lock_error);
@@ -140,7 +143,7 @@ rethrowException(const ExceptionPtr &e) {
140
143
  TRY_RETHROW_EXCEPTION(boost::thread_interrupted);
141
144
  TRY_RETHROW_EXCEPTION(boost::thread_exception);
142
145
  TRY_RETHROW_EXCEPTION(boost::condition_error);
143
-
146
+
144
147
  throw tracable_exception(*e);
145
148
  }
146
149
 
@@ -282,6 +285,20 @@ void processAndLogNewSpawnException(SpawnException &e, const Options &options,
282
285
  }
283
286
  stream << " Message from application: " << appMessage << "\n";
284
287
  P_ERROR(stream.str());
288
+
289
+ if (config->agentsOptions != NULL) {
290
+ HookScriptOptions hOptions;
291
+ hOptions.name = "spawn_failed";
292
+ hOptions.spec = config->agentsOptions->get("hook_spawn_failed", false);
293
+ hOptions.agentsOptions = config->agentsOptions;
294
+ hOptions.environment.push_back(make_pair("PASSENGER_APP_ROOT", options.appRoot));
295
+ hOptions.environment.push_back(make_pair("PASSENGER_APP_GROUP_NAME", options.getAppGroupName()));
296
+ hOptions.environment.push_back(make_pair("PASSENGER_ERROR_MESSAGE", e.what()));
297
+ hOptions.environment.push_back(make_pair("PASSENGER_ERROR_ID", errorId));
298
+ hOptions.environment.push_back(make_pair("PASSENGER_APP_ERROR_MESSAGE", appMessage));
299
+ oxt::thread(boost::bind(runHookScripts, hOptions),
300
+ "Hook: spawn_failed", 256 * 1024);
301
+ }
285
302
  }
286
303
 
287
304
 
@@ -337,7 +354,7 @@ SuperGroup::realDoInitialize(const Options &options, unsigned int generation) {
337
354
  ExceptionPtr exception;
338
355
 
339
356
  PoolPtr pool = getPool();
340
-
357
+
341
358
  P_TRACE(2, "Initializing SuperGroup " << inspect() << " in the background...");
342
359
  try {
343
360
  componentInfos = loadComponentInfos(options);
@@ -355,7 +372,7 @@ SuperGroup::realDoInitialize(const Options &options, unsigned int generation) {
355
372
  processAndLogNewSpawnException(*spawnException, options,
356
373
  pool->getSpawnerConfig());
357
374
  }
358
-
375
+
359
376
  Pool::DebugSupportPtr debug = pool->debugSupport;
360
377
  vector<Callback> actions;
361
378
  {
@@ -374,14 +391,14 @@ SuperGroup::realDoInitialize(const Options &options, unsigned int generation) {
374
391
  P_TRACE(2, "Initialization of SuperGroup " << inspect() << " almost done; grabbed lock");
375
392
  assert(state == INITIALIZING);
376
393
  verifyInvariants();
377
-
394
+
378
395
  if (componentInfos.empty()) {
379
396
  /* Somehow initialization failed. Maybe something has deleted
380
397
  * the supergroup files while we're working.
381
398
  */
382
399
  assert(exception != NULL);
383
400
  setState(DESTROYED);
384
-
401
+
385
402
  actions.reserve(getWaitlist.size());
386
403
  while (!getWaitlist.empty()) {
387
404
  const GetWaiter &waiter = getWaitlist.front();
@@ -403,7 +420,7 @@ SuperGroup::realDoInitialize(const Options &options, unsigned int generation) {
403
420
  setState(READY);
404
421
  assignGetWaitlistToGroups(actions);
405
422
  }
406
-
423
+
407
424
  verifyInvariants();
408
425
  P_TRACE(2, "Done initializing SuperGroup " << inspect());
409
426
  }
@@ -419,14 +436,14 @@ SuperGroup::realDoRestart(const Options &options, unsigned int generation) {
419
436
  TRACE_POINT();
420
437
  vector<ComponentInfo> componentInfos = loadComponentInfos(options);
421
438
  vector<ComponentInfo>::const_iterator it;
422
-
439
+
423
440
  PoolPtr pool = getPool();
424
441
  Pool::DebugSupportPtr debug = pool->debugSupport;
425
442
  if (debug != NULL && debug->superGroup) {
426
443
  debug->debugger->send("About to finish SuperGroup restart");
427
444
  debug->messages->recv("Proceed with restarting SuperGroup");
428
445
  }
429
-
446
+
430
447
  boost::unique_lock<boost::mutex> lock(getPoolSyncher(pool));
431
448
  if (OXT_UNLIKELY(this->generation != generation)) {
432
449
  return;
@@ -434,14 +451,14 @@ SuperGroup::realDoRestart(const Options &options, unsigned int generation) {
434
451
 
435
452
  assert(state == RESTARTING);
436
453
  verifyInvariants();
437
-
454
+
438
455
  vector<GroupPtr> allGroups;
439
456
  vector<GroupPtr> updatedGroups;
440
457
  vector<GroupPtr> newGroups;
441
458
  vector<GroupPtr>::const_iterator g_it;
442
459
  vector<Callback> actions;
443
460
  this->options = options;
444
-
461
+
445
462
  // Update the component information for existing groups.
446
463
  UPDATE_TRACE_POINT();
447
464
  for (it = componentInfos.begin(); it != componentInfos.end(); it++) {
@@ -464,22 +481,22 @@ SuperGroup::realDoRestart(const Options &options, unsigned int generation) {
464
481
  // allGroups must be in the same order as componentInfos.
465
482
  allGroups.push_back(group);
466
483
  }
467
-
484
+
468
485
  // Some components might have been deleted, so delete the
469
486
  // corresponding groups.
470
487
  detachAllGroups(groups, actions);
471
-
488
+
472
489
  // Tell all previous existing groups to restart.
473
490
  for (g_it = updatedGroups.begin(); g_it != updatedGroups.end(); g_it++) {
474
491
  GroupPtr group = *g_it;
475
492
  group->restart(options);
476
493
  }
477
-
494
+
478
495
  groups = allGroups;
479
496
  defaultGroup = findDefaultGroup(allGroups);
480
497
  setState(READY);
481
498
  assignGetWaitlistToGroups(actions);
482
-
499
+
483
500
  UPDATE_TRACE_POINT();
484
501
  verifyInvariants();
485
502
  lock.unlock();
@@ -491,6 +508,7 @@ Group::Group(const SuperGroupPtr &_superGroup, const Options &options, const Com
491
508
  : superGroup(_superGroup),
492
509
  name(_superGroup->name + "#" + info.name),
493
510
  secret(generateSecret(_superGroup)),
511
+ uuid(generateUuid(_superGroup)),
494
512
  componentInfo(info)
495
513
  {
496
514
  enabledCount = 0;
@@ -565,7 +583,7 @@ Group::onSessionClose(const ProcessPtr &process, Session *session) {
565
583
  P_TRACE(2, "Session closed for process " << process->inspect());
566
584
  verifyInvariants();
567
585
  UPDATE_TRACE_POINT();
568
-
586
+
569
587
  /* Update statistics. */
570
588
  process->sessionClosed(session);
571
589
  assert(process->getLifeStatus() == Process::ALIVE);
@@ -603,6 +621,7 @@ Group::onSessionClose(const ProcessPtr &process, Session *session) {
603
621
  && enabledCount > 0;
604
622
 
605
623
  if (shouldDetach || shouldDisable) {
624
+ UPDATE_TRACE_POINT();
606
625
  vector<Callback> actions;
607
626
 
608
627
  if (shouldDetach) {
@@ -630,12 +649,14 @@ Group::onSessionClose(const ProcessPtr &process, Session *session) {
630
649
  removeFromDisableWaitlist(process, DR_SUCCESS, actions);
631
650
  maybeInitiateOobw(process);
632
651
  }
633
-
652
+
634
653
  pool->fullVerifyInvariants();
635
654
  lock.unlock();
636
655
  runAllActions(actions);
637
656
 
638
657
  } else {
658
+ UPDATE_TRACE_POINT();
659
+
639
660
  // This could change process->enabled.
640
661
  maybeInitiateOobw(process);
641
662
 
@@ -695,7 +716,7 @@ Group::maybeInitiateOobw(const ProcessPtr &process) {
695
716
  void
696
717
  Group::lockAndMaybeInitiateOobw(const ProcessPtr &process, DisableResult result, GroupPtr self) {
697
718
  TRACE_POINT();
698
-
719
+
699
720
  // Standard resource management boilerplate stuff...
700
721
  PoolPtr pool = getPool();
701
722
  boost::unique_lock<boost::mutex> lock(pool->syncher);
@@ -766,10 +787,10 @@ Group::initiateOobw(const ProcessPtr &process) {
766
787
  P_BUG("Unexpected disable() result " << result);
767
788
  }
768
789
  }
769
-
790
+
770
791
  assert(process->enabled == Process::DISABLED);
771
792
  assert(process->sessions == 0);
772
-
793
+
773
794
  P_DEBUG("Initiating OOBW request for process " << process->inspect());
774
795
  interruptableThreads.create_thread(
775
796
  boost::bind(&Group::spawnThreadOOBWRequest, this, shared_from_this(), process),
@@ -795,7 +816,7 @@ Group::spawnThreadOOBWRequest(GroupPtr self, ProcessPtr process) {
795
816
  debug->debugger->send("OOBW request about to start");
796
817
  debug->messages->recv("Proceed with OOBW request");
797
818
  }
798
-
819
+
799
820
  UPDATE_TRACE_POINT();
800
821
  {
801
822
  // Standard resource management boilerplate stuff...
@@ -816,13 +837,13 @@ Group::spawnThreadOOBWRequest(GroupPtr self, ProcessPtr process) {
816
837
  }
817
838
  return;
818
839
  }
819
-
840
+
820
841
  assert(process->oobwStatus == Process::OOBW_IN_PROGRESS);
821
842
  assert(process->sessions == 0);
822
843
  socket = process->sessionSockets.top();
823
844
  assert(socket != NULL);
824
845
  }
825
-
846
+
826
847
  UPDATE_TRACE_POINT();
827
848
  unsigned long long timeout = 1000 * 1000 * 60; // 1 min
828
849
  try {
@@ -835,22 +856,22 @@ Group::spawnThreadOOBWRequest(GroupPtr self, ProcessPtr process) {
835
856
  connection = socket->checkoutConnection();
836
857
  connection.fail = true;
837
858
  ScopeGuard guard(boost::bind(&Socket::checkinConnection, socket, connection));
838
-
859
+
839
860
  // This is copied from RequestHandler when it is sending data using the
840
861
  // "session" protocol.
841
- char sizeField[sizeof(uint32_t)];
862
+ char sizeField[sizeof(boost::uint32_t)];
842
863
  SmallVector<StaticString, 10> data;
843
864
 
844
- data.push_back(StaticString(sizeField, sizeof(uint32_t)));
865
+ data.push_back(StaticString(sizeField, sizeof(boost::uint32_t)));
845
866
  data.push_back(makeStaticStringWithNull("REQUEST_METHOD"));
846
867
  data.push_back(makeStaticStringWithNull("OOBW"));
847
868
 
848
869
  data.push_back(makeStaticStringWithNull("PASSENGER_CONNECT_PASSWORD"));
849
870
  data.push_back(makeStaticStringWithNull(process->connectPassword));
850
871
 
851
- uint32_t dataSize = 0;
872
+ boost::uint32_t dataSize = 0;
852
873
  for (unsigned int i = 1; i < data.size(); i++) {
853
- dataSize += (uint32_t) data[i].size();
874
+ dataSize += (boost::uint32_t) data[i].size();
854
875
  }
855
876
  Uint32Message::generate(sizeField, dataSize);
856
877
 
@@ -864,7 +885,7 @@ Group::spawnThreadOOBWRequest(GroupPtr self, ProcessPtr process) {
864
885
  } catch (const TimeoutException &e) {
865
886
  P_ERROR("*** ERROR: " << e.what() << "\n" << e.backtrace());
866
887
  }
867
-
888
+
868
889
  UPDATE_TRACE_POINT();
869
890
  vector<Callback> actions;
870
891
  {
@@ -874,7 +895,7 @@ Group::spawnThreadOOBWRequest(GroupPtr self, ProcessPtr process) {
874
895
  if (OXT_UNLIKELY(!process->isAlive() || !isAlive())) {
875
896
  return;
876
897
  }
877
-
898
+
878
899
  process->oobwStatus = Process::OOBW_NOT_ACTIVE;
879
900
  if (process->enabled == Process::DISABLED) {
880
901
  enable(process, actions);
@@ -924,7 +945,7 @@ Group::spawnThreadRealMain(const SpawnerPtr &spawner, const Options &options, un
924
945
 
925
946
  PoolPtr pool = getPool();
926
947
  Pool::DebugSupportPtr debug = pool->debugSupport;
927
-
948
+
928
949
  bool done = false;
929
950
  while (!done) {
930
951
  bool shouldFail = false;
@@ -942,7 +963,7 @@ Group::spawnThreadRealMain(const SpawnerPtr &spawner, const Options &options, un
942
963
  P_DEBUG("Begin spawn loop iteration " << iteration);
943
964
  debug->debugger->send("Begin spawn loop iteration " +
944
965
  iteration);
945
-
966
+
946
967
  vector<string> cases;
947
968
  cases.push_back("Proceed with spawn loop iteration " + iteration);
948
969
  cases.push_back("Fail spawn loop iteration " + iteration);
@@ -1094,6 +1115,7 @@ Group::restart(const Options &options, RestartMethod method) {
1094
1115
  processesBeingSpawned = 0;
1095
1116
  m_spawning = false;
1096
1117
  m_restarting = true;
1118
+ uuid = generateUuid(getSuperGroup());
1097
1119
  detachAll(actions);
1098
1120
  getPool()->interruptableThreads.create_thread(
1099
1121
  boost::bind(&Group::finalizeRestart, this, shared_from_this(),
@@ -1153,7 +1175,7 @@ Group::finalizeRestart(GroupPtr self, Options options, RestartMethod method,
1153
1175
  pool->fullVerifyInvariants();
1154
1176
  assert(m_restarting);
1155
1177
  UPDATE_TRACE_POINT();
1156
-
1178
+
1157
1179
  // Atomically swap the new spawner with the old one.
1158
1180
  resetOptions(options);
1159
1181
  oldSpawner = spawner;
@@ -1376,6 +1398,11 @@ Group::generateSecret(const SuperGroupPtr &superGroup) {
1376
1398
  return superGroup->getPool()->getRandomGenerator()->generateAsciiString(43);
1377
1399
  }
1378
1400
 
1401
+ string
1402
+ Group::generateUuid(const SuperGroupPtr &superGroup) {
1403
+ return superGroup->getPool()->getRandomGenerator()->generateAsciiString(20);
1404
+ }
1405
+
1379
1406
 
1380
1407
  PoolPtr
1381
1408
  Process::getPool() const {
@@ -1508,7 +1535,7 @@ PipeWatcher::threadMain() {
1508
1535
  while (!this_thread::interruption_requested()) {
1509
1536
  char buf[1024 * 8];
1510
1537
  ssize_t ret;
1511
-
1538
+
1512
1539
  UPDATE_TRACE_POINT();
1513
1540
  ret = syscalls::read(fd, buf, sizeof(buf));
1514
1541
  if (ret == 0) {
@@ -59,47 +59,47 @@ using namespace boost;
59
59
  * "!STARTUP_FILE!", then the startup file's group will be used. Otherwise,
60
60
  * the primary group of the user that the application process will run as,
61
61
  * will be used as group.
62
- *
62
+ *
63
63
  * If the user or group that the application process attempts to switch to
64
64
  * doesn't exist, then <em>defaultUser</em> and <em>defaultGroup</em>, respectively,
65
65
  * will be used.
66
- *
66
+ *
67
67
  * Phusion Passenger will attempt to avoid running the application process as
68
68
  * root: if <em>user</em> or <em>group</em> is set to the root user or the root group,
69
69
  * or if the startup file is owned by root, then <em>defaultUser</em> and
70
70
  * <em>defaultGroup</em> will be used instead.
71
- *
71
+ *
72
72
  * All this only happen if Phusion Passenger has root privileges. If not, then
73
73
  * these options have no effect.
74
74
  */
75
75
  class Options {
76
76
  private:
77
77
  shared_array<char> storage;
78
-
78
+
79
79
  vector<const StaticString *> getStringFields() const {
80
80
  vector<const StaticString *> result;
81
81
  result.reserve(20);
82
-
82
+
83
83
  result.push_back(&appRoot);
84
84
  result.push_back(&appGroupName);
85
85
  result.push_back(&appType);
86
86
  result.push_back(&startCommand);
87
87
  result.push_back(&startupFile);
88
88
  result.push_back(&processTitle);
89
-
89
+
90
90
  result.push_back(&environment);
91
91
  result.push_back(&baseURI);
92
92
  result.push_back(&spawnMethod);
93
-
93
+
94
94
  result.push_back(&user);
95
95
  result.push_back(&group);
96
96
  result.push_back(&defaultUser);
97
97
  result.push_back(&defaultGroup);
98
98
  result.push_back(&restartDir);
99
-
99
+
100
100
  result.push_back(&preexecChroot);
101
101
  result.push_back(&postexecChroot);
102
-
102
+
103
103
  result.push_back(&ruby);
104
104
  result.push_back(&python);
105
105
  result.push_back(&nodejs);
@@ -110,10 +110,10 @@ private:
110
110
  result.push_back(&hostName);
111
111
  result.push_back(&uri);
112
112
  result.push_back(&unionStationKey);
113
-
113
+
114
114
  return result;
115
115
  }
116
-
116
+
117
117
  static inline void
118
118
  appendKeyValue(vector<string> &vec, const char *key, const StaticString &value) {
119
119
  if (!value.empty()) {
@@ -121,44 +121,44 @@ private:
121
121
  vec.push_back(value.toString());
122
122
  }
123
123
  }
124
-
124
+
125
125
  static inline void
126
126
  appendKeyValue(vector<string> &vec, const char *key, const char *value) {
127
127
  vec.push_back(key);
128
128
  vec.push_back(value);
129
129
  }
130
-
130
+
131
131
  static inline void
132
132
  appendKeyValue2(vector<string> &vec, const char *key, long value) {
133
133
  vec.push_back(key);
134
134
  vec.push_back(toString(value));
135
135
  }
136
-
136
+
137
137
  static inline void
138
138
  appendKeyValue3(vector<string> &vec, const char *key, unsigned long value) {
139
139
  vec.push_back(key);
140
140
  vec.push_back(toString(value));
141
141
  }
142
-
142
+
143
143
  static inline void
144
144
  appendKeyValue4(vector<string> &vec, const char *key, bool value) {
145
145
  vec.push_back(key);
146
146
  vec.push_back(value ? "true" : "false");
147
147
  }
148
-
148
+
149
149
  public:
150
150
  /*********** Spawn options that should be set by the caller ***********
151
151
  * These are the options that are relevant while spawning an application
152
152
  * process. These options are only used during spawning.
153
153
  */
154
-
154
+
155
155
  /**
156
156
  * The root directory of the application to spawn. In case of a Ruby on Rails
157
157
  * application, this is the folder that contains 'app/', 'public/', 'config/',
158
158
  * etc. This must be a valid directory, but the path does not have to be absolute.
159
159
  */
160
160
  StaticString appRoot;
161
-
161
+
162
162
  /**
163
163
  * A name used by ApplicationPool to uniquely identify an application.
164
164
  * If one tries to get() from the application pool with name "A", then get()
@@ -168,7 +168,7 @@ public:
168
168
  * If left empty, then the app root is used as the app group name.
169
169
  */
170
170
  StaticString appGroupName;
171
-
171
+
172
172
  /** The application's type, used for determining the command to invoke to
173
173
  * spawn an application process as well as determining the startup file's
174
174
  * filename. It can be one of the app type names in AppType.cpp, or the
@@ -176,17 +176,17 @@ public:
176
176
  * 'startupFile' (which MUST be set) will dictate the startup command
177
177
  * and the startup file's filename. */
178
178
  StaticString appType;
179
-
179
+
180
180
  /** The command for spawning the application process. This is a list of
181
181
  * arguments, separated by '\t', e.g. "ruby\tfoo.rb". Only used
182
182
  * during spawning and only if appType.empty(). */
183
183
  StaticString startCommand;
184
-
184
+
185
185
  /** Filename of the application's startup file. Only actually used for
186
186
  * determining user switching info. Only used during spawning and only
187
187
  * if appType.empty(). */
188
188
  StaticString startupFile;
189
-
189
+
190
190
  /** The process title to assign to the application process. Only used
191
191
  * during spawning. May be empty in which case no particular process
192
192
  * title is assigned. Only used during spawning and only if
@@ -197,17 +197,17 @@ public:
197
197
  * Defaults to DEFAULT_LOG_LEVEL.
198
198
  */
199
199
  int logLevel;
200
-
200
+
201
201
  /** The maximum amount of time, in milliseconds, that may be spent
202
202
  * on spawning the process or the preloader. */
203
203
  unsigned int startTimeout;
204
-
204
+
205
205
  /**
206
206
  * The RAILS_ENV/RACK_ENV environment that should be used. May not be an
207
207
  * empty string.
208
208
  */
209
209
  StaticString environment;
210
-
210
+
211
211
  /**
212
212
  * The base URI on which the application runs. If the application is
213
213
  * running on the root URI, then this value must be "/".
@@ -215,12 +215,12 @@ public:
215
215
  * @invariant baseURI != ""
216
216
  */
217
217
  StaticString baseURI;
218
-
218
+
219
219
  /**
220
220
  * Spawning method, either "smart" or "direct".
221
221
  */
222
222
  StaticString spawnMethod;
223
-
223
+
224
224
  /** See overview. */
225
225
  StaticString user;
226
226
  /** See class overview. */
@@ -229,16 +229,16 @@ public:
229
229
  StaticString defaultUser;
230
230
  /** See class overview. Defaults to the defaultUser's primary group. */
231
231
  StaticString defaultGroup;
232
-
232
+
233
233
  /**
234
234
  * The directory which contains restart.txt and always_restart.txt.
235
235
  * An empty string means that the default directory should be used.
236
236
  */
237
237
  StaticString restartDir;
238
-
238
+
239
239
  StaticString preexecChroot;
240
240
  StaticString postexecChroot;
241
-
241
+
242
242
  /**
243
243
  * Path to the Ruby interpreter to use, in case the application to spawn
244
244
  * is a Ruby app.
@@ -256,31 +256,31 @@ public:
256
256
  * is a Node.js app.
257
257
  */
258
258
  StaticString nodejs;
259
-
259
+
260
260
  /**
261
261
  * Any rights that the spawned application process may have. The SpawnManager
262
262
  * will create a new account for each spawned app, and that account will be
263
263
  * assigned these rights.
264
264
  */
265
265
  Account::Rights rights;
266
-
266
+
267
267
  /**
268
268
  * Environment variables which should be passed to the spawned application
269
269
  * process.
270
270
  */
271
271
  vector< pair<StaticString, StaticString> > environmentVariables;
272
-
272
+
273
273
  /** Whether debugger support should be enabled. */
274
274
  bool debugger;
275
-
275
+
276
276
  /** Whether to load environment variables set in shell startup
277
277
  * files (e.g. ~/.bashrc) during spawning.
278
278
  */
279
279
  bool loadShellEnvvars;
280
-
280
+
281
281
  /** Whether Union Station logging should be enabled. Enabling this option will
282
282
  * result in:
283
- *
283
+ *
284
284
  * - The application enabling its Union Station support.
285
285
  * - Periodic tasks such as `collectAnalytics()` to log things to Union Station.
286
286
  *
@@ -300,13 +300,13 @@ public:
300
300
  * during unit tests.
301
301
  */
302
302
  bool raiseInternalError;
303
-
304
-
303
+
304
+
305
305
  /*********** Per-group pool options that should be set by the caller ***********
306
306
  * These options dictate how Pool will manage processes, routing, etc. within
307
307
  * a single Group. These options are not process-specific, only group-specific.
308
308
  */
309
-
309
+
310
310
  /**
311
311
  * The minimum number of processes for the current group that the application
312
312
  * pool's cleaner thread should keep around.
@@ -321,7 +321,7 @@ public:
321
321
  * A value of 0 means unspecified, and has no effect.
322
322
  */
323
323
  unsigned int maxProcesses;
324
-
324
+
325
325
  /** The number of seconds that preloader processes may stay alive idling. */
326
326
  long maxPreloaderIdleTime;
327
327
 
@@ -351,20 +351,20 @@ public:
351
351
  StaticString unionStationKey;
352
352
 
353
353
  /*-----------------*/
354
-
355
-
354
+
355
+
356
356
  /*********** Per-request pool options that should be set by the caller ***********
357
357
  * These options also dictate how Pool will manage processes, etc. Unlike the
358
358
  * per-group options, these options are customizable on a per-request basis.
359
359
  * Their effects also don't persist longer than a single request.
360
360
  */
361
-
361
+
362
362
  /** Current request host name. */
363
363
  StaticString hostName;
364
-
364
+
365
365
  /** Current request URI. */
366
366
  StaticString uri;
367
-
367
+
368
368
  /**
369
369
  * The Union Station log transaction that this request belongs to.
370
370
  * May be the null pointer, in which case Union Station logging is
@@ -381,7 +381,7 @@ public:
381
381
  * A sticky session ID for routing to a specific process.
382
382
  */
383
383
  unsigned int stickySessionId;
384
-
384
+
385
385
  /**
386
386
  * A throttling rate for file stats. When set to a non-zero value N,
387
387
  * restart.txt and other files which are usually stat()ted on every
@@ -408,19 +408,26 @@ public:
408
408
 
409
409
  /*-----------------*/
410
410
  /*-----------------*/
411
-
412
-
411
+
412
+
413
413
  /*********** Spawn options automatically set by Pool ***********
414
414
  * These options are passed to the Spawner. The Pool::get() caller may not
415
415
  * see these values.
416
416
  */
417
-
417
+
418
418
  /** The secret key of the pool group that the spawned process is to belong to. */
419
419
  StaticString groupSecret;
420
-
421
-
420
+
421
+ /**
422
+ * A UUID that's generated on Group initialization, and changes every time
423
+ * the Group receives a restart command. Allows Union Station to track app
424
+ * restarts.
425
+ */
426
+ StaticString groupUuid;
427
+
428
+
422
429
  /*********************************/
423
-
430
+
424
431
  /**
425
432
  * Creates a new Options object with the default values filled in.
426
433
  * One must still set appRoot manually, after having used this constructor.
@@ -428,25 +435,25 @@ public:
428
435
  Options() {
429
436
  logLevel = DEFAULT_LOG_LEVEL;
430
437
  startTimeout = 90 * 1000;
431
- environment = "production";
432
- baseURI = "/";
433
- spawnMethod = "smart";
434
- defaultUser = "nobody";
435
- ruby = DEFAULT_RUBY;
436
- python = DEFAULT_PYTHON;
437
- nodejs = DEFAULT_NODEJS;
438
+ environment = P_STATIC_STRING("production");
439
+ baseURI = P_STATIC_STRING("/");
440
+ spawnMethod = P_STATIC_STRING("smart");
441
+ defaultUser = P_STATIC_STRING("nobody");
442
+ ruby = P_STATIC_STRING(DEFAULT_RUBY);
443
+ python = P_STATIC_STRING(DEFAULT_PYTHON);
444
+ nodejs = P_STATIC_STRING(DEFAULT_NODEJS);
438
445
  rights = DEFAULT_BACKEND_ACCOUNT_RIGHTS;
439
446
  debugger = false;
440
447
  loadShellEnvvars = true;
441
448
  analytics = false;
442
449
  raiseInternalError = false;
443
-
450
+
444
451
  minProcesses = 1;
445
452
  maxProcesses = 0;
446
453
  maxPreloaderIdleTime = -1;
447
454
  maxOutOfBandWorkInstances = 1;
448
455
  maxRequestQueueSize = 100;
449
-
456
+
450
457
  stickySessionId = 0;
451
458
  statThrottleRate = 0;
452
459
  maxRequests = 0;
@@ -454,17 +461,17 @@ public:
454
461
 
455
462
  /*********************************/
456
463
  }
457
-
464
+
458
465
  Options copy() const {
459
466
  return *this;
460
467
  }
461
-
468
+
462
469
  Options copyAndPersist() const {
463
470
  Options cpy(*this);
464
471
  cpy.persist(*this);
465
472
  return cpy;
466
473
  }
467
-
474
+
468
475
  /**
469
476
  * Assign <em>other</em>'s string fields' values into this Option
470
477
  * object, and store the data in this Option object's internal storage
@@ -476,9 +483,9 @@ public:
476
483
  unsigned int i;
477
484
  size_t otherLen = 0;
478
485
  char *end;
479
-
486
+
480
487
  assert(strings.size() == otherStrings.size());
481
-
488
+
482
489
  // Calculate the desired length of the internal storage area.
483
490
  // All strings are NULL-terminated.
484
491
  for (i = 0; i < otherStrings.size(); i++) {
@@ -488,53 +495,53 @@ public:
488
495
  otherLen += environmentVariables[i].first.size() + 1;
489
496
  otherLen += environmentVariables[i].second.size() + 1;
490
497
  }
491
-
498
+
492
499
  shared_array<char> data(new char[otherLen]);
493
500
  end = data.get();
494
-
501
+
495
502
  // Copy string fields into the internal storage area.
496
503
  for (i = 0; i < otherStrings.size(); i++) {
497
504
  const StaticString *str = strings[i];
498
505
  const StaticString *otherStr = otherStrings[i];
499
-
506
+
500
507
  // Point current object's field to the data in the
501
508
  // internal storage area.
502
509
  *const_cast<StaticString *>(str) = StaticString(end, otherStr->size());
503
-
510
+
504
511
  // Copy over the string data.
505
512
  memcpy(end, otherStr->c_str(), otherStr->size());
506
513
  end += otherStr->size();
507
514
  *end = '\0';
508
515
  end++;
509
516
  }
510
-
517
+
511
518
  // Copy environmentVariables names and values into the internal storage area.
512
519
  for (i = 0; i < other.environmentVariables.size(); i++) {
513
520
  const pair<StaticString, StaticString> &p = other.environmentVariables[i];
514
-
521
+
515
522
  environmentVariables[i] = make_pair(
516
523
  StaticString(end, p.first.size()),
517
524
  StaticString(end + p.first.size() + 1, p.second.size())
518
525
  );
519
-
526
+
520
527
  // Copy over string data.
521
528
  memcpy(end, p.first.data(), p.first.size());
522
529
  end += p.first.size();
523
530
  *end = '\0';
524
531
  end++;
525
-
532
+
526
533
  // Copy over value data.
527
534
  memcpy(end, p.second.data(), p.second.size());
528
535
  end += p.second.size();
529
536
  *end = '\0';
530
537
  end++;
531
538
  }
532
-
539
+
533
540
  storage = data;
534
-
541
+
535
542
  return *this;
536
543
  }
537
-
544
+
538
545
  Options &clearPerRequestFields() {
539
546
  hostName = StaticString();
540
547
  uri = StaticString();
@@ -553,7 +560,7 @@ public:
553
560
  PER_GROUP_POOL_OPTIONS = 1 << 1,
554
561
  ALL_OPTIONS = ~0
555
562
  };
556
-
563
+
557
564
  /**
558
565
  * Append information in this Options object to the given string vector, except
559
566
  * for environmentVariables. You can customize what information you want through
@@ -601,7 +608,7 @@ public:
601
608
  appendKeyValue3(vec, "max_out_of_band_work_instances", maxOutOfBandWorkInstances);
602
609
  appendKeyValue (vec, "union_station_key", unionStationKey);
603
610
  }
604
-
611
+
605
612
  /*********************************/
606
613
  }
607
614
 
@@ -611,7 +618,7 @@ public:
611
618
  {
612
619
  vector<string> args;
613
620
  unsigned int i;
614
-
621
+
615
622
  toVector(args, resourceLocator, fields);
616
623
  for (i = 0; i < args.size(); i += 2) {
617
624
  stream << "<" << args[i] << ">";
@@ -619,7 +626,7 @@ public:
619
626
  stream << "</" << args[i] << ">";
620
627
  }
621
628
  }
622
-
629
+
623
630
  /**
624
631
  * Returns the app group name. If there is no explicitly set app group name
625
632
  * then the app root is considered to be the app group name.
@@ -631,28 +638,28 @@ public:
631
638
  return appGroupName;
632
639
  }
633
640
  }
634
-
641
+
635
642
  string getStartCommand(const ResourceLocator &resourceLocator) const {
636
- if (appType == "classic-rails") {
643
+ if (appType == P_STATIC_STRING("classic-rails")) {
637
644
  return ruby + "\t" + resourceLocator.getHelperScriptsDir() + "/classic-rails-loader.rb";
638
- } else if (appType == "rack") {
645
+ } else if (appType == P_STATIC_STRING("rack")) {
639
646
  return ruby + "\t" + resourceLocator.getHelperScriptsDir() + "/rack-loader.rb";
640
- } else if (appType == "wsgi") {
647
+ } else if (appType == P_STATIC_STRING("wsgi")) {
641
648
  return python + "\t" + resourceLocator.getHelperScriptsDir() + "/wsgi-loader.py";
642
- } else if (appType == "node") {
649
+ } else if (appType == P_STATIC_STRING("node")) {
643
650
  return nodejs + "\t" + resourceLocator.getHelperScriptsDir() + "/node-loader.js";
644
- } else if (appType == "meteor") {
651
+ } else if (appType == P_STATIC_STRING("meteor")) {
645
652
  return ruby + "\t" + resourceLocator.getHelperScriptsDir() + "/meteor-loader.rb";
646
653
  } else {
647
654
  return startCommand;
648
655
  }
649
656
  }
650
-
657
+
651
658
  StaticString getStartupFile() const {
652
659
  if (startupFile.empty()) {
653
660
  const char *result = getAppTypeStartupFile(getAppType(appType));
654
661
  if (result == NULL) {
655
- return "";
662
+ return P_STATIC_STRING("");
656
663
  } else {
657
664
  return result;
658
665
  }
@@ -660,7 +667,7 @@ public:
660
667
  return startupFile;
661
668
  }
662
669
  }
663
-
670
+
664
671
  StaticString getProcessTitle() const {
665
672
  const char *result = getAppTypeProcessTitle(getAppType(appType));
666
673
  if (result == NULL) {
@@ -669,7 +676,7 @@ public:
669
676
  return result;
670
677
  }
671
678
  }
672
-
679
+
673
680
  unsigned long getMaxPreloaderIdleTime() const {
674
681
  if (maxPreloaderIdleTime == -1) {
675
682
  return 5 * 60;