passenger 5.2.3 → 5.3.0

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 (241) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +13 -0
  3. data/CONTRIBUTORS +5 -1
  4. data/build/agent.rb +22 -2
  5. data/build/cxx_tests.rb +41 -5
  6. data/build/misc.rb +4 -1
  7. data/build/support/cxx_dependency_map.rb +1746 -908
  8. data/build/support/vendor/cxx_hinted_parser/CxxHintedParser.sublime-project +8 -0
  9. data/build/support/vendor/cxx_hinted_parser/Gemfile +5 -0
  10. data/build/support/vendor/cxx_hinted_parser/Gemfile.lock +30 -0
  11. data/{src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core → build/support/vendor/cxx_hinted_parser}/LICENSE.md +1 -1
  12. data/build/support/vendor/cxx_hinted_parser/README.md +95 -0
  13. data/build/support/vendor/cxx_hinted_parser/Rakefile +4 -0
  14. data/{src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/lib/union_station_hooks_rails/initialize.rb → build/support/vendor/cxx_hinted_parser/lib/cxx_hinted_parser.rb} +2 -9
  15. data/build/support/vendor/cxx_hinted_parser/lib/cxx_hinted_parser/parser.rb +239 -0
  16. data/dev/ci/README.md +15 -2
  17. data/dev/ci/lib/set-container-envvars.sh +6 -0
  18. data/dev/ci/lib/setup-container.sh +4 -1
  19. data/dev/ci/scripts/debug-console-wrapper.sh +3 -1
  20. data/dev/ci/setup-host +5 -0
  21. data/dev/ci/tests/binaries/Jenkinsfile +105 -0
  22. data/dev/ci/tests/binaries/build-linux +38 -0
  23. data/dev/ci/tests/binaries/build-macos +40 -0
  24. data/dev/ci/tests/binaries/prepare-macos +38 -0
  25. data/dev/ci/tests/binaries/test-linux +45 -0
  26. data/dev/ci/tests/binaries/test-macos +38 -0
  27. data/dev/ci/tests/debian/Jenkinsfile +2 -2
  28. data/dev/ci/tests/rpm/Jenkinsfile +1 -1
  29. data/dev/configkit-schemas/index.json +3 -24
  30. data/dev/vagrant/nginx_rakefile +0 -1
  31. data/package.json +15 -5
  32. data/resources/templates/error_renderer/.editorconfig +19 -0
  33. data/resources/templates/error_renderer/with_details/README.md +9 -0
  34. data/resources/templates/error_renderer/with_details/dist/bundle.js +33 -0
  35. data/resources/templates/error_renderer/with_details/dist/styles.css +17 -0
  36. data/resources/templates/error_renderer/with_details/src/DetailsView.jsx +52 -0
  37. data/resources/templates/error_renderer/with_details/src/GetHelpView.jsx +61 -0
  38. data/resources/templates/error_renderer/with_details/src/JourneyView.css +50 -0
  39. data/resources/templates/error_renderer/with_details/src/JourneyView.jsx +621 -0
  40. data/resources/templates/error_renderer/with_details/src/PageMain.css +114 -0
  41. data/resources/templates/error_renderer/with_details/src/PageMain.jsx +136 -0
  42. data/resources/templates/error_renderer/with_details/src/ProblemDescriptionView.jsx +14 -0
  43. data/resources/templates/error_renderer/with_details/src/ProcessDetailsView.jsx +56 -0
  44. data/resources/templates/error_renderer/with_details/src/SolutionDescriptionView.css +5 -0
  45. data/resources/templates/error_renderer/with_details/src/SolutionDescriptionView.jsx +15 -0
  46. data/resources/templates/error_renderer/with_details/src/SummaryView.jsx +35 -0
  47. data/resources/templates/error_renderer/with_details/src/SystemComponentView.css +34 -0
  48. data/resources/templates/error_renderer/with_details/src/SystemComponentView.jsx +168 -0
  49. data/resources/templates/error_renderer/with_details/src/SystemComponentsView.css +13 -0
  50. data/resources/templates/error_renderer/with_details/src/SystemComponentsView.jsx +116 -0
  51. data/resources/templates/error_renderer/with_details/src/Tab.jsx +12 -0
  52. data/resources/templates/error_renderer/with_details/src/Tabs.jsx +104 -0
  53. data/resources/templates/error_renderer/with_details/src/bootstrap/bootstrap.css +3446 -0
  54. data/resources/templates/error_renderer/with_details/src/bootstrap/bootstrap.js +293 -0
  55. data/resources/templates/error_renderer/with_details/src/bootstrap/config.json +401 -0
  56. data/resources/templates/error_renderer/with_details/src/index.html.template +22 -0
  57. data/resources/templates/error_renderer/with_details/src/index.jsx +23 -0
  58. data/resources/templates/error_renderer/with_details/webpack.config.js +47 -0
  59. data/resources/templates/error_renderer/without_details/dist/bundle.js +1 -0
  60. data/resources/templates/error_renderer/without_details/dist/styles.css +1 -0
  61. data/resources/templates/{undisclosed_error.html.template → error_renderer/without_details/src/index.html.template} +7 -11
  62. data/resources/templates/error_renderer/without_details/src/index.js +1 -0
  63. data/resources/templates/{error_layout.css → error_renderer/without_details/src/main.css} +5 -2
  64. data/resources/templates/error_renderer/without_details/webpack.config.js +42 -0
  65. data/src/agent/AgentMain.cpp +3 -3
  66. data/src/agent/Core/ApplicationPool/BasicProcessInfo.h +13 -0
  67. data/src/agent/Core/ApplicationPool/Common.h +3 -4
  68. data/src/agent/Core/ApplicationPool/Context.h +27 -17
  69. data/src/agent/Core/ApplicationPool/Group.h +3 -1
  70. data/src/agent/Core/ApplicationPool/Group/InitializationAndShutdown.cpp +2 -12
  71. data/src/agent/Core/ApplicationPool/Group/InternalUtils.cpp +55 -10
  72. data/src/agent/Core/ApplicationPool/Group/LifetimeAndBasics.cpp +1 -1
  73. data/src/agent/Core/ApplicationPool/Group/OutOfBandWork.cpp +1 -1
  74. data/src/agent/Core/ApplicationPool/Group/SpawningAndRestarting.cpp +13 -6
  75. data/src/agent/Core/ApplicationPool/Implementation.cpp +16 -100
  76. data/src/agent/Core/ApplicationPool/Options.h +8 -65
  77. data/src/agent/Core/ApplicationPool/Pool.h +4 -21
  78. data/src/agent/Core/ApplicationPool/Pool/AnalyticsCollection.cpp +1 -60
  79. data/src/agent/Core/ApplicationPool/Pool/GeneralUtils.cpp +10 -13
  80. data/src/agent/Core/ApplicationPool/Pool/InitializationAndShutdown.cpp +3 -8
  81. data/src/agent/Core/ApplicationPool/Pool/Miscellaneous.cpp +2 -34
  82. data/src/agent/Core/ApplicationPool/Pool/StateInspection.cpp +1 -1
  83. data/src/agent/Core/ApplicationPool/Process.cpp +17 -12
  84. data/src/agent/Core/ApplicationPool/Process.h +146 -93
  85. data/src/agent/Core/ApplicationPool/Session.h +2 -2
  86. data/src/agent/Core/ApplicationPool/Socket.h +28 -27
  87. data/src/agent/Core/Config.h +1 -3
  88. data/src/agent/Core/ConfigChange.cpp +2 -4
  89. data/src/agent/Core/Controller.h +2 -8
  90. data/src/agent/Core/Controller/BufferBody.cpp +0 -2
  91. data/src/agent/Core/Controller/CheckoutSession.cpp +12 -24
  92. data/src/agent/Core/Controller/Config.h +1 -9
  93. data/src/agent/Core/Controller/ForwardResponse.cpp +0 -34
  94. data/src/agent/Core/Controller/Hooks.cpp +0 -7
  95. data/src/agent/Core/Controller/InitRequest.cpp +0 -43
  96. data/src/agent/Core/Controller/InitializationAndShutdown.cpp +0 -4
  97. data/src/agent/Core/Controller/Request.h +1 -35
  98. data/src/agent/Core/Controller/SendRequest.cpp +0 -32
  99. data/src/agent/Core/CoreMain.cpp +19 -32
  100. data/src/agent/Core/SpawningKit/Config.h +329 -55
  101. data/src/agent/Core/SpawningKit/Config/AutoGeneratedCode.h +369 -0
  102. data/src/agent/Core/SpawningKit/Config/AutoGeneratedCode.h.cxxcodebuilder +307 -0
  103. data/src/agent/Core/SpawningKit/Context.h +211 -0
  104. data/src/agent/Core/SpawningKit/DirectSpawner.h +112 -122
  105. data/src/agent/Core/SpawningKit/DummySpawner.h +59 -20
  106. data/src/agent/Core/SpawningKit/ErrorRenderer.h +117 -0
  107. data/src/agent/Core/SpawningKit/Exceptions.h +1157 -0
  108. data/src/agent/Core/SpawningKit/Factory.h +24 -17
  109. data/src/agent/Core/SpawningKit/{BackgroundIOCapturer.h → Handshake/BackgroundIOCapturer.h} +48 -18
  110. data/src/agent/Core/SpawningKit/Handshake/Perform.h +1650 -0
  111. data/src/agent/Core/SpawningKit/Handshake/Prepare.h +582 -0
  112. data/src/agent/Core/SpawningKit/Handshake/Session.h +91 -0
  113. data/src/agent/Core/SpawningKit/Handshake/WorkDir.h +100 -0
  114. data/src/agent/Core/SpawningKit/Journey.h +561 -0
  115. data/src/agent/Core/SpawningKit/PipeWatcher.h +41 -18
  116. data/src/agent/Core/SpawningKit/README.md +534 -0
  117. data/src/agent/Core/SpawningKit/Result.h +182 -7
  118. data/src/agent/Core/SpawningKit/Result/AutoGeneratedCode.h +69 -0
  119. data/src/agent/Core/SpawningKit/Result/AutoGeneratedCode.h.cxxcodebuilder +110 -0
  120. data/src/agent/Core/SpawningKit/SmartSpawner.h +1027 -562
  121. data/src/agent/Core/SpawningKit/Spawner.h +70 -1134
  122. data/src/agent/Core/SpawningKit/UserSwitchingRules.h +3 -33
  123. data/src/agent/README.md +2 -3
  124. data/src/agent/Shared/ApiServerUtils.h +2 -3
  125. data/src/agent/SpawnEnvSetupper/SpawnEnvSetupperMain.cpp +932 -0
  126. data/src/agent/Watchdog/Config.h +1 -3
  127. data/src/agent/Watchdog/WatchdogMain.cpp +2 -1
  128. data/src/apache2_module/ConfigGeneral/AutoGeneratedDefinitions.cpp +5 -0
  129. data/src/apache2_module/ConfigGeneral/AutoGeneratedManifestDefaultsInitialization.cpp +5 -0
  130. data/src/apache2_module/ConfigGeneral/ManifestGeneration.h +22 -13
  131. data/src/apache2_module/DirConfig/AutoGeneratedCreateFunction.cpp +5 -0
  132. data/src/apache2_module/DirConfig/AutoGeneratedHeaderSerialization.cpp +3 -0
  133. data/src/apache2_module/DirConfig/AutoGeneratedManifestGeneration.cpp +13 -0
  134. data/src/apache2_module/DirConfig/AutoGeneratedMergeFunction.cpp +7 -0
  135. data/src/apache2_module/DirConfig/AutoGeneratedStruct.h +13 -0
  136. data/src/cxx_supportlib/Constants.h +3 -1
  137. data/src/cxx_supportlib/Exceptions.h +0 -121
  138. data/src/cxx_supportlib/LoggingKit/Implementation.cpp +7 -6
  139. data/src/cxx_supportlib/LoggingKit/Logging.h +3 -1
  140. data/src/cxx_supportlib/Utils.cpp +42 -0
  141. data/src/cxx_supportlib/Utils.h +7 -0
  142. data/src/cxx_supportlib/Utils/IOUtils.cpp +58 -0
  143. data/src/cxx_supportlib/Utils/IOUtils.h +13 -0
  144. data/src/cxx_supportlib/Utils/JsonUtils.h +130 -23
  145. data/src/cxx_supportlib/Utils/ScopeGuard.h +9 -4
  146. data/src/cxx_supportlib/Utils/StrIntUtils.cpp +7 -0
  147. data/src/cxx_supportlib/Utils/StrIntUtils.h +1 -0
  148. data/src/cxx_supportlib/Utils/SystemTime.h +1 -1
  149. data/src/cxx_supportlib/Utils/Timer.h +1 -1
  150. data/src/cxx_supportlib/WebSocketCommandReverseServer.h +6 -4
  151. data/src/cxx_supportlib/vendor-copy/adhoc_lve.h +1 -0
  152. data/src/helper-scripts/node-loader.js +54 -59
  153. data/src/helper-scripts/rack-loader.rb +63 -60
  154. data/src/helper-scripts/rack-preloader.rb +125 -72
  155. data/src/helper-scripts/wsgi-loader.py +100 -43
  156. data/src/nginx_module/ConfigGeneral/AutoGeneratedDefinitions.c +120 -112
  157. data/src/nginx_module/ConfigGeneral/AutoGeneratedManifestDefaultsInitialization.c +15 -8
  158. data/src/nginx_module/ConfigGeneral/AutoGeneratedSetterFuncs.c +142 -142
  159. data/src/nginx_module/ConfigGeneral/ManifestGeneration.c +26 -15
  160. data/src/nginx_module/ConfigGeneral/ManifestGeneration.h +3 -0
  161. data/src/nginx_module/LocationConfig/AutoGeneratedCreateFunction.c +76 -70
  162. data/src/nginx_module/LocationConfig/AutoGeneratedHeaderSerialization.c +114 -99
  163. data/src/nginx_module/LocationConfig/AutoGeneratedManifestGeneration.c +170 -156
  164. data/src/nginx_module/LocationConfig/AutoGeneratedMergeFunction.c +38 -35
  165. data/src/nginx_module/LocationConfig/AutoGeneratedStruct.h +5 -1
  166. data/src/ruby_supportlib/phusion_passenger.rb +5 -5
  167. data/src/ruby_supportlib/phusion_passenger/admin_tools/instance.rb +14 -1
  168. data/src/ruby_supportlib/phusion_passenger/apache2/config_options.rb +8 -0
  169. data/src/ruby_supportlib/phusion_passenger/common_library.rb +0 -3
  170. data/src/ruby_supportlib/phusion_passenger/config/nginx_engine_compiler.rb +0 -1
  171. data/src/ruby_supportlib/phusion_passenger/constants.rb +2 -0
  172. data/src/ruby_supportlib/phusion_passenger/loader_shared_helpers.rb +646 -238
  173. data/src/ruby_supportlib/phusion_passenger/nginx/config_options.rb +117 -95
  174. data/src/ruby_supportlib/phusion_passenger/packaging.rb +0 -1
  175. data/src/ruby_supportlib/phusion_passenger/platform_info/depcheck_specs/apache2.rb +5 -1
  176. data/src/ruby_supportlib/phusion_passenger/preloader_shared_helpers.rb +92 -69
  177. data/src/ruby_supportlib/phusion_passenger/public_api.rb +0 -17
  178. data/src/ruby_supportlib/phusion_passenger/rack/thread_handler_extension.rb +0 -3
  179. data/src/ruby_supportlib/phusion_passenger/request_handler.rb +4 -5
  180. data/src/ruby_supportlib/phusion_passenger/request_handler/thread_handler.rb +0 -22
  181. metadata +64 -67
  182. data/resources/templates/error_layout.html.template +0 -86
  183. data/resources/templates/general_error.html.template +0 -1
  184. data/resources/templates/general_error_with_html.html.template +0 -1
  185. data/src/agent/Core/ApplicationPool/ErrorRenderer.h +0 -131
  186. data/src/agent/Core/SpawningKit/Options.h +0 -41
  187. data/src/agent/Core/UnionStation/Connection.h +0 -173
  188. data/src/agent/Core/UnionStation/Context.h +0 -536
  189. data/src/agent/Core/UnionStation/StopwatchLog.h +0 -147
  190. data/src/agent/Core/UnionStation/Transaction.h +0 -249
  191. data/src/agent/SpawnPreparer/SpawnPreparerMain.cpp +0 -208
  192. data/src/cxx_supportlib/UnionStationFilterSupport.cpp +0 -67
  193. data/src/cxx_supportlib/UnionStationFilterSupport.h +0 -1622
  194. data/src/nodejs_supportlib/phusion_passenger/log_express.js +0 -106
  195. data/src/nodejs_supportlib/phusion_passenger/log_mongodb.js +0 -202
  196. data/src/nodejs_supportlib/phusion_passenger/ustreporter.js +0 -227
  197. data/src/nodejs_supportlib/phusion_passenger/ustrouter_connector.js +0 -448
  198. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/CONFIG.md +0 -37
  199. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/Gemfile +0 -17
  200. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/Gemfile.lock +0 -59
  201. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/README-API.md +0 -5
  202. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/README.md +0 -117
  203. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/Rakefile +0 -115
  204. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core.rb +0 -423
  205. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/api.rb +0 -238
  206. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/connection.rb +0 -67
  207. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/context.rb +0 -281
  208. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/lock.rb +0 -62
  209. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/log.rb +0 -66
  210. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/message_channel.rb +0 -157
  211. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/request_reporter.rb +0 -150
  212. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/request_reporter/basics.rb +0 -199
  213. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/request_reporter/controllers.rb +0 -187
  214. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/request_reporter/misc.rb +0 -303
  215. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/request_reporter/view_rendering.rb +0 -91
  216. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/simple_json.rb +0 -396
  217. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/spec_helper.rb +0 -279
  218. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/time_point.rb +0 -39
  219. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/transaction.rb +0 -173
  220. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/utils.rb +0 -177
  221. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/version.rb +0 -32
  222. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/version_data.rb +0 -44
  223. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/ruby_versions.yml.example +0 -16
  224. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/ruby_versions.yml.travis +0 -20
  225. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/ruby_versions.yml.travis-with-sudo +0 -18
  226. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/union_station_hooks_core.gemspec +0 -23
  227. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/Gemfile +0 -14
  228. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/Gemfile.lock +0 -45
  229. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/LICENSE.md +0 -19
  230. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/README.md +0 -104
  231. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/Rakefile +0 -160
  232. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/lib/union_station_hooks_rails.rb +0 -200
  233. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/lib/union_station_hooks_rails/action_controller_extension.rb +0 -45
  234. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/lib/union_station_hooks_rails/action_view_subscriber.rb +0 -55
  235. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/lib/union_station_hooks_rails/active_record_subscriber.rb +0 -41
  236. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/lib/union_station_hooks_rails/active_support_benchmarkable_extension.rb +0 -47
  237. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/lib/union_station_hooks_rails/active_support_cache_subscriber.rb +0 -79
  238. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/lib/union_station_hooks_rails/exception_logger.rb +0 -57
  239. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/lib/union_station_hooks_rails/version.rb +0 -32
  240. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/lib/union_station_hooks_rails/version_data.rb +0 -44
  241. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_rails/union_station_hooks_rails.gemspec +0 -34
@@ -26,8 +26,14 @@
26
26
  #ifndef _PASSENGER_SPAWNING_KIT_DUMMY_SPAWNER_H_
27
27
  #define _PASSENGER_SPAWNING_KIT_DUMMY_SPAWNER_H_
28
28
 
29
- #include <Core/SpawningKit/Spawner.h>
29
+ #include <boost/shared_ptr.hpp>
30
30
  #include <boost/atomic.hpp>
31
+ #include <vector>
32
+
33
+ #include <StaticString.h>
34
+ #include <Utils/StrIntUtils.h>
35
+ #include <Core/SpawningKit/Spawner.h>
36
+ #include <Core/SpawningKit/Exceptions.h>
31
37
 
32
38
  namespace Passenger {
33
39
  namespace SpawningKit {
@@ -41,38 +47,71 @@ class DummySpawner: public Spawner {
41
47
  private:
42
48
  boost::atomic<unsigned int> count;
43
49
 
50
+ void setConfigFromAppPoolOptions(Config *config, Json::Value &extraArgs,
51
+ const AppPoolOptions &options)
52
+ {
53
+ Spawner::setConfigFromAppPoolOptions(config, extraArgs, options);
54
+ config->spawnMethod = P_STATIC_STRING("dummy");
55
+ }
56
+
44
57
  public:
45
58
  unsigned int cleanCount;
46
59
 
47
- DummySpawner(const ConfigPtr &_config)
48
- : Spawner(_config),
60
+ DummySpawner(Context *context)
61
+ : Spawner(context),
49
62
  count(1),
50
63
  cleanCount(0)
51
64
  { }
52
65
 
53
- virtual Result spawn(const Options &options) {
66
+ virtual Result spawn(const AppPoolOptions &options) {
54
67
  TRACE_POINT();
55
68
  possiblyRaiseInternalError(options);
56
69
 
57
- syscalls::usleep(config->spawnTime);
70
+ if (context->debugSupport != NULL) {
71
+ syscalls::usleep(context->debugSupport->dummySpawnDelay);
72
+ }
73
+
74
+ Config config;
75
+ Json::Value extraArgs;
76
+ setConfigFromAppPoolOptions(&config, extraArgs, options);
58
77
 
59
- SocketPair adminSocket = createUnixSocketPair(__FILE__, __LINE__);
60
78
  unsigned int number = count.fetch_add(1, boost::memory_order_relaxed);
61
79
  Result result;
62
- Json::Value socket;
63
-
64
- socket["name"] = "main";
65
- socket["address"] = "tcp://127.0.0.1:1234";
66
- socket["protocol"] = "session";
67
- socket["concurrency"] = config->concurrency;
68
-
69
- result["type"] = "dummy";
70
- result["pid"] = number;
71
- result["gupid"] = "gupid-" + toString(number);
72
- result["spawner_creation_time"] = (Json::UInt64) SystemTime::getUsec();
73
- result["spawn_start_time"] = (Json::UInt64) SystemTime::getUsec();
74
- result["sockets"].append(socket);
75
- result.adminSocket = adminSocket.second;
80
+ Result::Socket socket;
81
+
82
+ socket.address = "tcp://127.0.0.1:1234";
83
+ socket.protocol = "session";
84
+ socket.concurrency = 1;
85
+ socket.acceptHttpRequests = true;
86
+ if (context->debugSupport != NULL) {
87
+ socket.concurrency = context->debugSupport->dummyConcurrency;
88
+ }
89
+
90
+ result.initialize(*context, &config);
91
+ result.pid = number;
92
+ result.dummy = true;
93
+ result.gupid = "gupid-" + toString(number);
94
+ result.spawnEndTime = result.spawnStartTime;
95
+ result.spawnEndTimeMonotonic = result.spawnStartTimeMonotonic;
96
+ result.sockets.push_back(socket);
97
+
98
+ vector<StaticString> internalFieldErrors;
99
+ vector<StaticString> appSuppliedFieldErrors;
100
+ if (!result.validate(internalFieldErrors, appSuppliedFieldErrors)) {
101
+ Journey journey(SPAWN_DIRECTLY, !config.genericApp && config.startsUsingWrapper);
102
+ journey.setStepErrored(SPAWNING_KIT_HANDSHAKE_PERFORM, true);
103
+ SpawnException e(INTERNAL_ERROR, journey, &config);
104
+ e.setSummary("Error spawning the web application:"
105
+ " a bug in " SHORT_PROGRAM_NAME " caused the"
106
+ " spawn result to be invalid: "
107
+ + toString(internalFieldErrors)
108
+ + ", " + toString(appSuppliedFieldErrors));
109
+ e.setProblemDescriptionHTML(
110
+ "Bug: the spawn result is invalid: "
111
+ + toString(internalFieldErrors)
112
+ + ", " + toString(appSuppliedFieldErrors));
113
+ throw e.finalize();
114
+ }
76
115
 
77
116
  return result;
78
117
  }
@@ -0,0 +1,117 @@
1
+ /*
2
+ * Phusion Passenger - https://www.phusionpassenger.com/
3
+ * Copyright (c) 2014-2017 Phusion Holding B.V.
4
+ *
5
+ * "Passenger", "Phusion Passenger" and "Union Station" are registered
6
+ * trademarks of Phusion Holding B.V.
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the "Software"), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in
16
+ * all copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ * THE SOFTWARE.
25
+ */
26
+ #ifndef _PASSENGER_SPAWNING_KIT_ERROR_RENDERER_H_
27
+ #define _PASSENGER_SPAWNING_KIT_ERROR_RENDERER_H_
28
+
29
+ #include <string>
30
+ #include <map>
31
+ #include <cctype>
32
+
33
+ #include <jsoncpp/json.h>
34
+
35
+ #include <Constants.h>
36
+ #include <StaticString.h>
37
+ #include <Utils/Template.h>
38
+ #include <Utils/IOUtils.h>
39
+ #include <Core/SpawningKit/Context.h>
40
+ #include <Core/SpawningKit/Exceptions.h>
41
+
42
+ namespace Passenger {
43
+ namespace SpawningKit {
44
+
45
+ using namespace std;
46
+ using namespace boost;
47
+ using namespace oxt;
48
+
49
+
50
+ class ErrorRenderer {
51
+ private:
52
+ string templatesDir;
53
+
54
+ public:
55
+ ErrorRenderer(const Context &context) {
56
+ templatesDir = context.resourceLocator->getResourcesDir() + "/templates/error_renderer";
57
+ }
58
+
59
+ string renderWithDetails(const SpawningKit::SpawnException &e) const {
60
+ StringMap<StaticString> params;
61
+ string htmlFile = templatesDir + "/with_details/src/index.html.template";
62
+ string cssFile = templatesDir + "/with_details/dist/styles.css";
63
+ string jsFile = templatesDir + "/with_details/dist/bundle.js";
64
+ string cssContent = readAll(cssFile);
65
+ string jsContent = readAll(jsFile);
66
+
67
+ Json::Value spec;
68
+ spec["program_name"] = PROGRAM_NAME;
69
+ spec["short_program_name"] = SHORT_PROGRAM_NAME;
70
+ spec["config"] = e.getConfig().getNonConfidentialFieldsToPassToApp();
71
+ spec["journey"] = e.getJourney().inspectAsJson();
72
+ spec["error"] = e.inspectBasicInfoAsJson();
73
+ spec["diagnostics"]["system_wide"] = e.inspectSystemWideDetailsAsJson();
74
+ spec["diagnostics"]["core_process"] = e.inspectParentProcessDetailsAsJson();
75
+ if (e.getJourney().getType() == SPAWN_THROUGH_PRELOADER) {
76
+ spec["diagnostics"]["preloader_process"] =
77
+ e.inspectPreloaderProcessDetailsAsJson();
78
+ }
79
+ spec["diagnostics"]["subprocess"] = e.inspectSubprocessDetailsAsJson();
80
+
81
+ string specContent = spec.toStyledString();
82
+
83
+ params.set("CSS", cssContent);
84
+ params.set("JS", jsContent);
85
+ params.set("TITLE", "Web application could not be started");
86
+ params.set("SPEC", specContent);
87
+
88
+ return Template::apply(readAll(htmlFile), params);
89
+ }
90
+
91
+ string renderWithoutDetails(const SpawningKit::SpawnException &e) const {
92
+ StringMap<StaticString> params;
93
+ string htmlFile = templatesDir + "/without_details/src/index.html.template";
94
+ string cssFile = templatesDir + "/without_details/dist/styles.css";
95
+ string jsFile = templatesDir + "/without_details/dist/bundle.js";
96
+ string cssContent = readAll(cssFile);
97
+ string jsContent = readAll(jsFile);
98
+
99
+ params.set("CSS", cssContent);
100
+ params.set("JS", jsContent);
101
+ params.set("TITLE", "Web application could not be started");
102
+ params.set("SUMMARY", e.getSummary());
103
+ params.set("ERROR_ID", e.getId());
104
+ params.set("PROGRAM_NAME", PROGRAM_NAME);
105
+ params.set("SHORT_PROGRAM_NAME", SHORT_PROGRAM_NAME);
106
+ params.set("PROGRAM_WEBSITE", PROGRAM_WEBSITE);
107
+ params.set("PROGRAM_AUTHOR", PROGRAM_AUTHOR);
108
+
109
+ return Template::apply(readAll(htmlFile), params);
110
+ }
111
+ };
112
+
113
+
114
+ } // namespace SpawningKit
115
+ } // namespace Passenger
116
+
117
+ #endif /* _PASSENGER_SPAWNING_KIT_ERROR_RENDERER_H_ */
@@ -0,0 +1,1157 @@
1
+ /*
2
+ * Phusion Passenger - https://www.phusionpassenger.com/
3
+ * Copyright (c) 2011-2017 Phusion Holding B.V.
4
+ *
5
+ * "Passenger", "Phusion Passenger" and "Union Station" are registered
6
+ * trademarks of Phusion Holding B.V.
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the "Software"), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in
16
+ * all copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ * THE SOFTWARE.
25
+ */
26
+ #ifndef _PASSENGER_SPAWNING_KIT_EXCEPTIONS_H_
27
+ #define _PASSENGER_SPAWNING_KIT_EXCEPTIONS_H_
28
+
29
+ #include <oxt/tracable_exception.hpp>
30
+ #include <string>
31
+ #include <stdexcept>
32
+
33
+ #include <Constants.h>
34
+ #include <Exceptions.h>
35
+ #include <LoggingKit/LoggingKit.h>
36
+ #include <DataStructures/StringKeyTable.h>
37
+ #include <ProcessManagement/Spawn.h>
38
+ #include <Utils/StrIntUtils.h>
39
+ #include <Utils/SystemMetricsCollector.h>
40
+ #include <Core/SpawningKit/Config.h>
41
+ #include <Core/SpawningKit/Journey.h>
42
+
43
+ extern "C" {
44
+ extern char **environ;
45
+ }
46
+
47
+ namespace Passenger {
48
+ namespace SpawningKit {
49
+
50
+ using namespace std;
51
+ using namespace oxt;
52
+
53
+
54
+ enum ErrorCategory {
55
+ INTERNAL_ERROR,
56
+ FILE_SYSTEM_ERROR,
57
+ OPERATING_SYSTEM_ERROR,
58
+ IO_ERROR,
59
+ TIMEOUT_ERROR,
60
+
61
+ UNKNOWN_ERROR_CATEGORY
62
+ };
63
+
64
+ inline StaticString errorCategoryToString(ErrorCategory category);
65
+ inline ErrorCategory inferErrorCategoryFromAnotherException(const std::exception &e,
66
+ JourneyStep failedJourneyStep);
67
+
68
+
69
+ /**
70
+ * For an introduction see README.md, section "Error reporting".
71
+ */
72
+ class SpawnException: public oxt::tracable_exception {
73
+ private:
74
+ struct EnvDump {
75
+ pid_t pid;
76
+ string envvars;
77
+ string userInfo;
78
+ string ulimits;
79
+
80
+ EnvDump()
81
+ : pid(-1)
82
+ { }
83
+ };
84
+
85
+ ErrorCategory category;
86
+ Journey journey;
87
+ Config config;
88
+
89
+ string summary;
90
+ string advancedProblemDetails;
91
+ string problemDescription;
92
+ string solutionDescription;
93
+ string stdoutAndErrData;
94
+ string id;
95
+
96
+ EnvDump parentProcessEnvDump;
97
+ EnvDump preloaderEnvDump;
98
+ EnvDump subprocessEnvDump;
99
+ string systemMetrics;
100
+ StringKeyTable<string> annotations;
101
+
102
+ static string createDefaultSummary(ErrorCategory category,
103
+ const Journey &journey, const StaticString &advancedProblemDetails)
104
+ {
105
+ string message;
106
+
107
+ switch (category) {
108
+ case TIMEOUT_ERROR:
109
+ // We only return a single error message instead of a customized
110
+ // one based on the failed step, because the timeout
111
+ // applies to the entire journey, not just to a specific step.
112
+ // A timeout at a specific step could be the result of a previous
113
+ // step taking too much time.
114
+ // The way to debug a timeout error is by looking at the timings
115
+ // of each step.
116
+ switch (journey.getType()) {
117
+ case START_PRELOADER:
118
+ message = "A timeout occurred while starting a preloader process";
119
+ break;
120
+ default:
121
+ message = "A timeout occurred while spawning an application process";
122
+ break;
123
+ }
124
+ default:
125
+ string categoryPhraseWithIndefiniteArticle =
126
+ getErrorCategoryPhraseWithIndefiniteArticle(
127
+ category, true);
128
+ switch (journey.getType()) {
129
+ case START_PRELOADER:
130
+ switch (journey.getFirstFailedStep()) {
131
+ case SPAWNING_KIT_PREPARATION:
132
+ message = categoryPhraseWithIndefiniteArticle
133
+ + " occurred while preparing to start a preloader process";
134
+ break;
135
+ default:
136
+ message = categoryPhraseWithIndefiniteArticle
137
+ + " occurred while starting a preloader process";
138
+ break;
139
+ }
140
+ default:
141
+ switch (journey.getFirstFailedStep()) {
142
+ case SPAWNING_KIT_PREPARATION:
143
+ message = categoryPhraseWithIndefiniteArticle
144
+ + " occurred while preparing to spawn an application process";
145
+ break;
146
+ case SPAWNING_KIT_FORK_SUBPROCESS:
147
+ message = categoryPhraseWithIndefiniteArticle
148
+ + " occurred while creating (forking) subprocess";
149
+ break;
150
+ case SPAWNING_KIT_CONNECT_TO_PRELOADER:
151
+ message = categoryPhraseWithIndefiniteArticle
152
+ + " occurred while connecting to the preloader process";
153
+ break;
154
+ case SPAWNING_KIT_SEND_COMMAND_TO_PRELOADER:
155
+ message = categoryPhraseWithIndefiniteArticle
156
+ + " occurred while sending a command to the preloader process";
157
+ break;
158
+ case SPAWNING_KIT_READ_RESPONSE_FROM_PRELOADER:
159
+ message = categoryPhraseWithIndefiniteArticle
160
+ + " occurred while receiving a response from the preloader process";
161
+ break;
162
+ case SPAWNING_KIT_PARSE_RESPONSE_FROM_PRELOADER:
163
+ message = categoryPhraseWithIndefiniteArticle
164
+ + " occurred while parsing a response from the preloader process";
165
+ break;
166
+ case SPAWNING_KIT_PROCESS_RESPONSE_FROM_PRELOADER:
167
+ message = categoryPhraseWithIndefiniteArticle
168
+ + " occurred while processing a response from the preloader process";
169
+ break;
170
+ default:
171
+ message = categoryPhraseWithIndefiniteArticle
172
+ + " occurred while spawning an application process";
173
+ break;
174
+ }
175
+ }
176
+ }
177
+
178
+ if (advancedProblemDetails.empty()) {
179
+ message.append(".");
180
+ } else {
181
+ message.append(": ");
182
+ message.append(advancedProblemDetails);
183
+ }
184
+ return message;
185
+ }
186
+
187
+ static string createDefaultProblemDescription(ErrorCategory category,
188
+ const Journey &journey, const Config &config,
189
+ const StaticString &advancedProblemDetails,
190
+ const StaticString &stdoutAndErrData)
191
+ {
192
+ StaticString categoryStringWithIndefiniteArticle =
193
+ getErrorCategoryPhraseWithIndefiniteArticle(category,
194
+ false);
195
+
196
+ switch (category) {
197
+ case INTERNAL_ERROR:
198
+ case OPERATING_SYSTEM_ERROR:
199
+ case IO_ERROR:
200
+ switch (journey.getType()) {
201
+ case START_PRELOADER:
202
+ switch (journey.getFirstFailedStep()) {
203
+ case SPAWNING_KIT_PREPARATION:
204
+ return wrapInParaAndMaybeAddErrorMessages(
205
+ "The " PROGRAM_NAME " application server tried to"
206
+ " start the web application. In doing so, "
207
+ SHORT_PROGRAM_NAME " had to first start an internal"
208
+ " helper tool called the \"preloader\". But "
209
+ SHORT_PROGRAM_NAME " encountered "
210
+ + categoryStringWithIndefiniteArticle +
211
+ " while performing this preparation work",
212
+ category, advancedProblemDetails, stdoutAndErrData);
213
+ case SPAWNING_KIT_FORK_SUBPROCESS:
214
+ return wrapInParaAndMaybeAddErrorMessages(
215
+ "The " PROGRAM_NAME " application server tried to"
216
+ " start the web application. But " SHORT_PROGRAM_NAME
217
+ " encountered " + categoryStringWithIndefiniteArticle
218
+ + " while creating a subprocess",
219
+ category, advancedProblemDetails, stdoutAndErrData);
220
+ case SPAWNING_KIT_HANDSHAKE_PERFORM:
221
+ return wrapInParaAndMaybeAddErrorMessages(
222
+ "The " PROGRAM_NAME " application server tried to"
223
+ " start the web application. In doing so, "
224
+ SHORT_PROGRAM_NAME " first started an internal"
225
+ " helper tool called the \"preloader\". But "
226
+ SHORT_PROGRAM_NAME " encountered "
227
+ + categoryStringWithIndefiniteArticle +
228
+ " while communicating with"
229
+ " this tool about its startup",
230
+ category, advancedProblemDetails, stdoutAndErrData);
231
+ case SUBPROCESS_BEFORE_FIRST_EXEC:
232
+ return wrapInParaAndMaybeAddErrorMessages(
233
+ "The " PROGRAM_NAME " application server tried to"
234
+ " start the web application. In doing so, "
235
+ SHORT_PROGRAM_NAME " had to first start an internal"
236
+ " helper tool called the \"preloader\". But"
237
+ " the subprocess which was supposed to execute this"
238
+ " preloader encountered "
239
+ + categoryStringWithIndefiniteArticle,
240
+ category, advancedProblemDetails, stdoutAndErrData);
241
+ case SUBPROCESS_OS_SHELL:
242
+ return wrapInParaAndMaybeAddErrorMessages(
243
+ "The " PROGRAM_NAME " application server tried to"
244
+ " start the web application. In doing so, "
245
+ SHORT_PROGRAM_NAME " had to first start an internal"
246
+ " helper tool called the \"preloader\", which"
247
+ " in turn had to be started through the operating"
248
+ " system (OS) shell. But the OS shell encountered "
249
+ + categoryStringWithIndefiniteArticle,
250
+ category, advancedProblemDetails, stdoutAndErrData);
251
+ case SUBPROCESS_SPAWN_ENV_SETUPPER_BEFORE_SHELL:
252
+ case SUBPROCESS_SPAWN_ENV_SETUPPER_AFTER_SHELL:
253
+ return wrapInParaAndMaybeAddErrorMessages(
254
+ "The " PROGRAM_NAME " application server tried to"
255
+ " start the web application. In doing so, "
256
+ SHORT_PROGRAM_NAME " had to first start an internal"
257
+ " helper tool called the \"preloader\", which"
258
+ " in turn had to be started through another internal"
259
+ " tool called the \"SpawnEnvSetupper\". But the"
260
+ " SpawnEnvSetupper encountered "
261
+ + categoryStringWithIndefiniteArticle,
262
+ category, advancedProblemDetails, stdoutAndErrData);
263
+ case SUBPROCESS_EXEC_WRAPPER:
264
+ if (!config.genericApp && config.startsUsingWrapper && config.wrapperSuppliedByThirdParty) {
265
+ return wrapInParaAndMaybeAddErrorMessages(
266
+ "The " PROGRAM_NAME " application server tried to"
267
+ " start the web application through a "
268
+ SHORT_PROGRAM_NAME " helper tool called"
269
+ " the \"wrapper\". This helper tool is not part of "
270
+ SHORT_PROGRAM_NAME ". But " SHORT_PROGRAM_NAME
271
+ " was unable to execute that helper tool"
272
+ " because it encountered "
273
+ + categoryStringWithIndefiniteArticle,
274
+ category, advancedProblemDetails, stdoutAndErrData);
275
+ } else {
276
+ return wrapInParaAndMaybeAddErrorMessages(
277
+ "The " PROGRAM_NAME " application server tried to"
278
+ " start the web application through a "
279
+ SHORT_PROGRAM_NAME "-internal helper tool called"
280
+ " the \"wrapper\". But " SHORT_PROGRAM_NAME
281
+ " was unable to execute that helper tool"
282
+ " because it encountered "
283
+ + categoryStringWithIndefiniteArticle,
284
+ category, advancedProblemDetails, stdoutAndErrData);
285
+ }
286
+ case SUBPROCESS_WRAPPER_PREPARATION:
287
+ if (!config.genericApp && config.startsUsingWrapper && config.wrapperSuppliedByThirdParty) {
288
+ return wrapInParaAndMaybeAddErrorMessages(
289
+ "The " PROGRAM_NAME " application server tried to"
290
+ " start the web application through a "
291
+ SHORT_PROGRAM_NAME " helper tool called"
292
+ " the \"wrapper\"). This tool is not part of "
293
+ SHORT_PROGRAM_NAME ". But that helper tool encountered "
294
+ + categoryStringWithIndefiniteArticle,
295
+ category, advancedProblemDetails, stdoutAndErrData);
296
+ } else {
297
+ return wrapInParaAndMaybeAddErrorMessages(
298
+ "The " PROGRAM_NAME " application server tried to"
299
+ " start the web application through a "
300
+ SHORT_PROGRAM_NAME "-internal helper tool called"
301
+ " the \"wrapper\"). But that helper tool encountered "
302
+ + categoryStringWithIndefiniteArticle,
303
+ category, advancedProblemDetails, stdoutAndErrData);
304
+ }
305
+ case SUBPROCESS_APP_LOAD_OR_EXEC:
306
+ return wrapInParaAndMaybeAddErrorMessages(
307
+ "The " PROGRAM_NAME " application server tried to"
308
+ " start the web application. But the application"
309
+ " itself (and not " SHORT_PROGRAM_NAME ") encountered "
310
+ + categoryStringWithIndefiniteArticle,
311
+ category, advancedProblemDetails, stdoutAndErrData);
312
+ case SUBPROCESS_LISTEN:
313
+ return wrapInParaAndMaybeAddErrorMessages(
314
+ "The " PROGRAM_NAME " application server tried to"
315
+ " start the web application. The application tried "
316
+ " to setup a socket for accepting connections,"
317
+ " but in doing so it encountered "
318
+ + categoryStringWithIndefiniteArticle,
319
+ category, advancedProblemDetails, stdoutAndErrData);
320
+ case SUBPROCESS_FINISH:
321
+ return wrapInParaAndMaybeAddErrorMessages(
322
+ "The " PROGRAM_NAME " application server tried to"
323
+ " start the web application, but the application"
324
+ " encountered "
325
+ + categoryStringWithIndefiniteArticle
326
+ + " while finalizing its startup procedure",
327
+ category, advancedProblemDetails, stdoutAndErrData);
328
+ default:
329
+ P_BUG("Unsupported preloader journey step "
330
+ << toString((int) journey.getFirstFailedStep()));
331
+ }
332
+ default:
333
+ switch (journey.getFirstFailedStep()) {
334
+ case SPAWNING_KIT_PREPARATION:
335
+ return wrapInParaAndMaybeAddErrorMessages(
336
+ "The " PROGRAM_NAME " application server tried to"
337
+ " start the web application, but " SHORT_PROGRAM_NAME
338
+ " encountered " + categoryStringWithIndefiniteArticle
339
+ + " while performing preparation work",
340
+ category, advancedProblemDetails, stdoutAndErrData);
341
+ case SPAWNING_KIT_FORK_SUBPROCESS:
342
+ return wrapInParaAndMaybeAddErrorMessages(
343
+ "The " PROGRAM_NAME " application server tried to"
344
+ " start the web application. But " SHORT_PROGRAM_NAME
345
+ " encountered " + categoryStringWithIndefiniteArticle
346
+ + " while creating a subprocess",
347
+ category, advancedProblemDetails, stdoutAndErrData);
348
+ case SPAWNING_KIT_CONNECT_TO_PRELOADER:
349
+ return wrapInParaAndMaybeAddErrorMessages(
350
+ "The " PROGRAM_NAME " application server tried to"
351
+ " start the web application by communicating with a"
352
+ " helper process that we call a \"preloader\". However, "
353
+ SHORT_PROGRAM_NAME " encountered "
354
+ + categoryStringWithIndefiniteArticle
355
+ + " while connecting to this helper process",
356
+ category, advancedProblemDetails, stdoutAndErrData);
357
+ case SPAWNING_KIT_SEND_COMMAND_TO_PRELOADER:
358
+ return wrapInParaAndMaybeAddErrorMessages(
359
+ "The " PROGRAM_NAME " application server tried to"
360
+ " start the web application by communicating with a"
361
+ " helper process that we call a \"preloader\". However, "
362
+ SHORT_PROGRAM_NAME " encountered "
363
+ + categoryStringWithIndefiniteArticle
364
+ + " while sending a command to this helper process",
365
+ category, advancedProblemDetails, stdoutAndErrData);
366
+ case SPAWNING_KIT_READ_RESPONSE_FROM_PRELOADER:
367
+ return wrapInParaAndMaybeAddErrorMessages(
368
+ "The " PROGRAM_NAME " application server tried to"
369
+ " start the web application by communicating with a"
370
+ " helper process that we call a \"preloader\". However, "
371
+ SHORT_PROGRAM_NAME " encountered "
372
+ + categoryStringWithIndefiniteArticle
373
+ + " while receiving a response to this helper process",
374
+ category, advancedProblemDetails, stdoutAndErrData);
375
+ case SPAWNING_KIT_PARSE_RESPONSE_FROM_PRELOADER:
376
+ return wrapInParaAndMaybeAddErrorMessages(
377
+ "The " PROGRAM_NAME " application server tried to"
378
+ " start the web application by communicating with a"
379
+ " helper process that we call a \"preloader\". However, "
380
+ SHORT_PROGRAM_NAME " encountered "
381
+ + categoryStringWithIndefiniteArticle
382
+ + " while parsing a response from this helper process",
383
+ category, advancedProblemDetails, stdoutAndErrData);
384
+ case SPAWNING_KIT_PROCESS_RESPONSE_FROM_PRELOADER:
385
+ return wrapInParaAndMaybeAddErrorMessages(
386
+ "The " PROGRAM_NAME " application server tried to"
387
+ " start the web application by communicating with a"
388
+ " helper process that we call a \"preloader\". However, "
389
+ SHORT_PROGRAM_NAME " encountered "
390
+ + categoryStringWithIndefiniteArticle
391
+ + " while processing a response from this helper process",
392
+ category, advancedProblemDetails, stdoutAndErrData);
393
+ case SPAWNING_KIT_HANDSHAKE_PERFORM:
394
+ return wrapInParaAndMaybeAddErrorMessages(
395
+ "The " PROGRAM_NAME " application server tried to"
396
+ " start the web application. Everything was looking OK,"
397
+ " but then suddenly " SHORT_PROGRAM_NAME " encountered "
398
+ + categoryStringWithIndefiniteArticle,
399
+ category, advancedProblemDetails, stdoutAndErrData);
400
+ case SUBPROCESS_BEFORE_FIRST_EXEC:
401
+ return wrapInParaAndMaybeAddErrorMessages(
402
+ "The " PROGRAM_NAME " application server tried to"
403
+ " start the web application. " SHORT_PROGRAM_NAME
404
+ " launched a subprocess which was supposed to"
405
+ " execute the application, but instead that"
406
+ " subprocess encountered "
407
+ + categoryStringWithIndefiniteArticle,
408
+ category, advancedProblemDetails, stdoutAndErrData);
409
+ case SUBPROCESS_OS_SHELL:
410
+ return wrapInParaAndMaybeAddErrorMessages(
411
+ "The " PROGRAM_NAME " application server tried to"
412
+ " start the web application through the operating"
413
+ " system (OS) shell. But the OS shell encountered "
414
+ + categoryStringWithIndefiniteArticle,
415
+ category, advancedProblemDetails, stdoutAndErrData);
416
+ case SUBPROCESS_SPAWN_ENV_SETUPPER_BEFORE_SHELL:
417
+ case SUBPROCESS_SPAWN_ENV_SETUPPER_AFTER_SHELL:
418
+ return wrapInParaAndMaybeAddErrorMessages(
419
+ "The " PROGRAM_NAME " application server tried to"
420
+ " start the web application through a "
421
+ SHORT_PROGRAM_NAME "-internal helper tool called the"
422
+ " SpawnEnvSetupper. But that helper tool encountered "
423
+ + categoryStringWithIndefiniteArticle,
424
+ category, advancedProblemDetails, stdoutAndErrData);
425
+ case SUBPROCESS_EXEC_WRAPPER:
426
+ if (!config.genericApp && config.startsUsingWrapper && config.wrapperSuppliedByThirdParty) {
427
+ return wrapInParaAndMaybeAddErrorMessages(
428
+ "The " PROGRAM_NAME " application server tried to"
429
+ " start the web application through a "
430
+ SHORT_PROGRAM_NAME " helper tool called"
431
+ " the \"wrapper\". This helper tool is not part of "
432
+ SHORT_PROGRAM_NAME ". But " SHORT_PROGRAM_NAME
433
+ " was unable to execute that helper tool because"
434
+ " it encountered "
435
+ + categoryStringWithIndefiniteArticle,
436
+ category, advancedProblemDetails, stdoutAndErrData);
437
+ } else {
438
+ return wrapInParaAndMaybeAddErrorMessages(
439
+ "The " PROGRAM_NAME " application server tried to"
440
+ " start the web application through a "
441
+ SHORT_PROGRAM_NAME "-internal helper tool called"
442
+ " the \"wrapper\". But " SHORT_PROGRAM_NAME
443
+ " was unable to execute that helper tool because"
444
+ " it encountered "
445
+ + categoryStringWithIndefiniteArticle,
446
+ category, advancedProblemDetails, stdoutAndErrData);
447
+ }
448
+ case SUBPROCESS_WRAPPER_PREPARATION:
449
+ if (!config.genericApp && config.startsUsingWrapper && config.wrapperSuppliedByThirdParty) {
450
+ return wrapInParaAndMaybeAddErrorMessages(
451
+ "The " PROGRAM_NAME " application server tried to"
452
+ " start the web application through a "
453
+ SHORT_PROGRAM_NAME " helper tool called"
454
+ " the \"wrapper\". This helper tool is not part of "
455
+ SHORT_PROGRAM_NAME ". But that helper tool encountered "
456
+ + categoryStringWithIndefiniteArticle,
457
+ category, advancedProblemDetails, stdoutAndErrData);
458
+ } else {
459
+ return wrapInParaAndMaybeAddErrorMessages(
460
+ "The " PROGRAM_NAME " application server tried to"
461
+ " start the web application through a "
462
+ SHORT_PROGRAM_NAME "-internal helper tool called"
463
+ " the \"wrapper\". But that helper tool encountered "
464
+ + categoryStringWithIndefiniteArticle,
465
+ category, advancedProblemDetails, stdoutAndErrData);
466
+ }
467
+ case SUBPROCESS_APP_LOAD_OR_EXEC:
468
+ return wrapInParaAndMaybeAddErrorMessages(
469
+ "The " PROGRAM_NAME " application server tried to"
470
+ " start the web application. But the application"
471
+ " itself (and not " SHORT_PROGRAM_NAME ") encountered "
472
+ + categoryStringWithIndefiniteArticle,
473
+ category, advancedProblemDetails, stdoutAndErrData);
474
+ case SUBPROCESS_PREPARE_AFTER_FORKING_FROM_PRELOADER:
475
+ return wrapInParaAndMaybeAddErrorMessages(
476
+ "The " PROGRAM_NAME " application server tried to"
477
+ " start the web application through a "
478
+ SHORT_PROGRAM_NAME "-internal helper tool called"
479
+ " the \"preloader\". But the preloader encountered "
480
+ + categoryStringWithIndefiniteArticle,
481
+ category, advancedProblemDetails, stdoutAndErrData);
482
+ case SUBPROCESS_LISTEN:
483
+ return wrapInParaAndMaybeAddErrorMessages(
484
+ "The " PROGRAM_NAME " application server tried to"
485
+ " start the web application. The application tried "
486
+ " to setup a socket for accepting connections,"
487
+ " but in doing so it encountered "
488
+ + categoryStringWithIndefiniteArticle,
489
+ category, advancedProblemDetails, stdoutAndErrData);
490
+ case SUBPROCESS_FINISH:
491
+ return wrapInParaAndMaybeAddErrorMessages(
492
+ "The " PROGRAM_NAME " application server tried to"
493
+ " start the web application, but the application"
494
+ " encountered "
495
+ + categoryStringWithIndefiniteArticle
496
+ + " while finalizing its startup procedure",
497
+ category, advancedProblemDetails, stdoutAndErrData);
498
+ default:
499
+ P_BUG("Unrecognized journey step " <<
500
+ toString((int) journey.getFirstFailedStep()));
501
+ }
502
+ }
503
+
504
+ case TIMEOUT_ERROR:
505
+ // We only return a single error message instead of a customized
506
+ // one based on the failed step, because the timeout
507
+ // applies to the entire journey, not just to a specific step.
508
+ // A timeout at a specific step could be the result of a previous
509
+ // step taking too much time.
510
+ // The way to debug a timeout error is by looking at the timings
511
+ // of each step.
512
+ return wrapInParaAndMaybeAddErrorMessages(
513
+ "The " PROGRAM_NAME " application server tried"
514
+ " to start the web application, but this took too much time,"
515
+ " so " SHORT_PROGRAM_NAME " put a stop to that",
516
+ TIMEOUT_ERROR, string(), stdoutAndErrData);
517
+
518
+ default:
519
+ P_BUG("Unrecognized error category " + toString((int) category));
520
+ return string(); // Never reached, shut up compiler warning.
521
+ }
522
+ }
523
+
524
+ static string createDefaultSolutionDescription(ErrorCategory category,
525
+ const Journey &journey, const Config &config)
526
+ {
527
+ string message;
528
+
529
+ switch (category) {
530
+ case INTERNAL_ERROR:
531
+ return "<p class=\"sole-solution\">"
532
+ "Unfortunately, " SHORT_PROGRAM_NAME " does not know"
533
+ " how to solve this problem. Please try troubleshooting"
534
+ " the problem by studying the <strong>error message</strong>"
535
+ " and the <strong>diagnostics</strong> reports. You can also"
536
+ " consult <a href=\"" SUPPORT_URL "\">the " SHORT_PROGRAM_NAME
537
+ " support resources</a> for help.</p>";
538
+
539
+ case FILE_SYSTEM_ERROR:
540
+ return "<p class=\"sole-solution\">"
541
+ "Unfortunately, " SHORT_PROGRAM_NAME " does not know how to"
542
+ " solve this problem. But it looks like some kind of filesystem error."
543
+ " This generally means that you need to fix nonexistant"
544
+ " files/directories or fix filesystem permissions. Please"
545
+ " try troubleshooting the problem by studying the"
546
+ " <strong>error message</strong> and the"
547
+ " <strong>diagnostics</strong> reports.</p>";
548
+
549
+ case OPERATING_SYSTEM_ERROR:
550
+ case IO_ERROR:
551
+ return "<div class=\"multiple-solutions\">"
552
+
553
+ "<h3>Check whether the server is low on resources</h3>"
554
+ "<p>Maybe the server is currently low on resources. This would"
555
+ " cause errors to occur. Please study the <em>error"
556
+ " message</em> and the <em>diagnostics reports</em> to"
557
+ " verify whether this is the case. Key things to check for:</p>"
558
+ "<ul>"
559
+ "<li>Excessive CPU usage</li>"
560
+ "<li>Memory and swap</li>"
561
+ "<li>Ulimits</li>"
562
+ "</ul>"
563
+ "<p>If the server is indeed low on resources, find a way to"
564
+ " free up some resources.</p>"
565
+
566
+ "<h3>Check your (filesystem) security settings</h3>"
567
+ "<p>Maybe security settings are preventing " SHORT_PROGRAM_NAME
568
+ " from doing the work it needs to do. Please check whether the"
569
+ " error may be caused by your system's security settings, or"
570
+ " whether it may be caused by wrong permissions on a file or"
571
+ " directory.</p>"
572
+
573
+ "<h3>Still no luck?</h3>"
574
+ "<p>Please try troubleshooting the problem by studying the"
575
+ " <em>diagnostics</em> reports.</p>"
576
+
577
+ "</div>";
578
+
579
+ case TIMEOUT_ERROR:
580
+ message = "<div class=\"multiple-solutions\">"
581
+
582
+ "<h3>Check whether the server is low on resources</h3>"
583
+ "<p>Maybe the server is currently so low on resources that"
584
+ " all the work that needed to be done, could not finish within"
585
+ " the given time limit."
586
+ " Please inspect the server resource utilization statistics"
587
+ " in the <em>diagnostics</em> section to verify"
588
+ " whether server is indeed low on resources.</p>"
589
+ "<p>If so, then either increase the spawn timeout (currently"
590
+ " configured at " + toString(config.startTimeoutMsec / 1000)
591
+ + " sec), or find a way to lower the server's resource"
592
+ " utilization.</p>";
593
+
594
+ switch (journey.getFirstFailedStep()) {
595
+ case SUBPROCESS_OS_SHELL:
596
+ message.append(
597
+ "<h3>Check whether your OS shell's startup scripts can"
598
+ " take a long time or get stuck</h3>"
599
+ "<p>One of your OS shell's startup scripts may do too much work,"
600
+ " or it may have invoked a command that then got stuck."
601
+ " Please investigate and debug your OS shell's startup"
602
+ " scripts.</p>");
603
+ break;
604
+ case SUBPROCESS_APP_LOAD_OR_EXEC:
605
+ if (config.appType == "node") {
606
+ message.append(
607
+ "<h3>Check whether the application calls <code>http.Server.listen()</code></h3>"
608
+ "<p>" SHORT_PROGRAM_NAME " requires that the application calls"
609
+ " <code>listen()</code> on an http.Server object. If"
610
+ " the application never calls this, then "
611
+ SHORT_PROGRAM_NAME " will think the application is"
612
+ " stuck. <a href=\"https://www.phusionpassenger.com/"
613
+ "library/indepth/nodejs/reverse_port_binding.html\">"
614
+ "Learn more about this problem.</a></p>");
615
+ }
616
+ message.append(
617
+ "<h3>Check whether the application is stuck during startup</h3>"
618
+ "<p>The easiest way find out where the application is stuck"
619
+ "is by inserting print statements into the application's code.</p>");
620
+ break;
621
+ default:
622
+ break;
623
+ }
624
+
625
+ message.append("<h3>Still no luck?</h3>"
626
+ "<p>Please try troubleshooting the problem by studying the"
627
+ " <em>diagnostics</em> reports.</p>"
628
+
629
+ "</div>");
630
+ return message;
631
+
632
+ default:
633
+ return "(error generating solution description: unknown error category)";
634
+ }
635
+ }
636
+
637
+ static string createDefaultAdvancedProblemDetails(const std::exception &e) {
638
+ const oxt::tracable_exception *te = dynamic_cast<const oxt::tracable_exception *>(&e);
639
+ if (te != NULL) {
640
+ return string(e.what()) + "\n" + te->backtrace();
641
+ } else {
642
+ return e.what();
643
+ }
644
+ }
645
+
646
+ static StaticString getErrorCategoryPhraseWithIndefiniteArticle(
647
+ ErrorCategory category, bool beginOfSentence)
648
+ {
649
+ switch (category) {
650
+ case INTERNAL_ERROR:
651
+ if (beginOfSentence) {
652
+ return P_STATIC_STRING("An internal error");
653
+ } else {
654
+ return P_STATIC_STRING("an internal error");
655
+ }
656
+ case FILE_SYSTEM_ERROR:
657
+ if (beginOfSentence) {
658
+ return P_STATIC_STRING("A file system error");
659
+ } else {
660
+ return P_STATIC_STRING("a file system error");
661
+ }
662
+ case OPERATING_SYSTEM_ERROR:
663
+ if (beginOfSentence) {
664
+ return P_STATIC_STRING("An operating system error");
665
+ } else {
666
+ return P_STATIC_STRING("an operating system error");
667
+ }
668
+ case IO_ERROR:
669
+ if (beginOfSentence) {
670
+ return P_STATIC_STRING("An I/O error");
671
+ } else {
672
+ return P_STATIC_STRING("an I/O error");
673
+ }
674
+ case TIMEOUT_ERROR:
675
+ if (beginOfSentence) {
676
+ return P_STATIC_STRING("A timeout error");
677
+ } else {
678
+ return P_STATIC_STRING("a timeout error");
679
+ }
680
+ default:
681
+ P_BUG("Unsupported error category " + toString((int) category));
682
+ return StaticString();
683
+ }
684
+ }
685
+
686
+ static StaticString getErrorCategoryPhraseWithIndefiniteArticle(
687
+ const std::exception &e, const Journey &journey,
688
+ bool beginOfSentence)
689
+ {
690
+ ErrorCategory category =
691
+ inferErrorCategoryFromAnotherException(
692
+ e, journey.getFirstFailedStep());
693
+ return getErrorCategoryPhraseWithIndefiniteArticle(category, beginOfSentence);
694
+ }
695
+
696
+ static string wrapInParaAndMaybeAddErrorMessages(const StaticString &message,
697
+ ErrorCategory category, const StaticString &advancedProblemDetails,
698
+ const StaticString &stdoutAndErrData)
699
+ {
700
+ string result = "<p>" + message + ".</p>";
701
+ if (!advancedProblemDetails.empty()) {
702
+ if (category == INTERNAL_ERROR || category == FILE_SYSTEM_ERROR) {
703
+ result.append("<p>Error details:</p>"
704
+ "<pre>" + escapeHTML(advancedProblemDetails) + "</pre>");
705
+ } else if (category == IO_ERROR) {
706
+ result.append("<p>The error reported by the I/O layer is:</p>"
707
+ "<pre>" + escapeHTML(advancedProblemDetails) + "</pre>");
708
+ } else {
709
+ P_ASSERT_EQ(category, OPERATING_SYSTEM_ERROR);
710
+ result.append("<p>The error reported by the operating system is:</p>"
711
+ "<pre>" + escapeHTML(advancedProblemDetails) + "</pre>");
712
+ }
713
+ }
714
+ if (!stdoutAndErrData.empty()) {
715
+ result.append("<p>The stdout/stderr output of the subprocess so far is:</p>"
716
+ "<pre>" + escapeHTML(stdoutAndErrData) + "</pre>");
717
+ }
718
+ return result;
719
+ }
720
+
721
+ static string gatherEnvvars() {
722
+ string result;
723
+
724
+ unsigned int i = 0;
725
+ while (environ[i] != NULL) {
726
+ result.append(environ[i]);
727
+ result.append(1, '\n');
728
+ i++;
729
+ }
730
+
731
+ return result;
732
+ }
733
+
734
+ static string gatherUlimits() {
735
+ // On Linux, ulimit is a shell builtin and not a command.
736
+ const char *command[] = { "/bin/sh", "-c", "ulimit -a", NULL };
737
+ try {
738
+ SubprocessInfo info;
739
+ string result;
740
+ runCommandAndCaptureOutput(command, info, result);
741
+ if (result.empty()) {
742
+ result.assign("Error: command 'ulimit -a' failed");
743
+ }
744
+ return result;
745
+ } catch (const SystemException &e) {
746
+ return P_STATIC_STRING("Error: command 'ulimit -a' failed: ") + e.what();
747
+ }
748
+ }
749
+
750
+ static string gatherUserInfo() {
751
+ const char *command[] = { "id", "-a", NULL };
752
+ try {
753
+ SubprocessInfo info;
754
+ string result;
755
+ runCommandAndCaptureOutput(command, info, result);
756
+ if (result.empty()) {
757
+ result.assign("Error: command 'id -a' failed");
758
+ }
759
+ return result;
760
+ } catch (const SystemException &e) {
761
+ return P_STATIC_STRING("Error: command 'id -a' failed: ") + e.what();
762
+ }
763
+ }
764
+
765
+ static string gatherSystemMetrics() {
766
+ SystemMetrics metrics;
767
+
768
+ try {
769
+ SystemMetricsCollector().collect(metrics);
770
+ } catch (const RuntimeException &e) {
771
+ return "Error: cannot parse system metrics: " + StaticString(e.what());
772
+ }
773
+
774
+ FastStringStream<> stream;
775
+ metrics.toDescription(stream);
776
+ return string(stream.data(), stream.size());
777
+ }
778
+
779
+ public:
780
+ SpawnException(ErrorCategory _category, const Journey &_journey,
781
+ const Config *_config)
782
+ : category(_category),
783
+ journey(_journey),
784
+ config(*_config)
785
+ {
786
+ assert(_journey.getFirstFailedStep() != UNKNOWN_JOURNEY_STEP);
787
+ config.internStrings();
788
+ }
789
+
790
+ SpawnException(const std::exception &originalException,
791
+ const Journey &_journey, const Config *_config)
792
+ : category(inferErrorCategoryFromAnotherException(
793
+ originalException, _journey.getFirstFailedStep())),
794
+ journey(_journey),
795
+ config(*_config),
796
+ summary(createDefaultSummary(
797
+ category, _journey, originalException.what())),
798
+ advancedProblemDetails(createDefaultAdvancedProblemDetails(originalException))
799
+ {
800
+ assert(_journey.getFirstFailedStep() != UNKNOWN_JOURNEY_STEP);
801
+ config.internStrings();
802
+ }
803
+
804
+ virtual ~SpawnException() throw() {}
805
+
806
+
807
+ virtual const char *what() const throw() {
808
+ return summary.c_str();
809
+ }
810
+
811
+ ErrorCategory getErrorCategory() const {
812
+ return category;
813
+ }
814
+
815
+ const Journey &getJourney() const {
816
+ return journey;
817
+ }
818
+
819
+ const Config &getConfig() const {
820
+ return config;
821
+ }
822
+
823
+
824
+ const string &getSummary() const {
825
+ return summary;
826
+ }
827
+
828
+ void setSummary(const string &value) {
829
+ summary = value;
830
+ }
831
+
832
+ const string &getAdvancedProblemDetails() const {
833
+ return advancedProblemDetails;
834
+ }
835
+
836
+ void setAdvancedProblemDetails(const string &value) {
837
+ advancedProblemDetails = value;
838
+ }
839
+
840
+ const string &getProblemDescriptionHTML() const {
841
+ return problemDescription;
842
+ }
843
+
844
+ void setProblemDescriptionHTML(const string &value) {
845
+ problemDescription = value;
846
+ }
847
+
848
+ const string &getSolutionDescriptionHTML() const {
849
+ return solutionDescription;
850
+ }
851
+
852
+ void setSolutionDescriptionHTML(const string &value) {
853
+ solutionDescription = value;
854
+ }
855
+
856
+ const string &getStdoutAndErrData() const {
857
+ return stdoutAndErrData;
858
+ }
859
+
860
+ void setStdoutAndErrData(const string &value) {
861
+ stdoutAndErrData = value;
862
+ }
863
+
864
+ const string &getId() const {
865
+ return id;
866
+ }
867
+
868
+ void setId(const string &value) {
869
+ id = value;
870
+ }
871
+
872
+ SpawnException &finalize() {
873
+ TRACE_POINT();
874
+ if (summary.empty()) {
875
+ summary = createDefaultSummary(category, journey,
876
+ advancedProblemDetails);
877
+ }
878
+ if (problemDescription.empty()) {
879
+ problemDescription = createDefaultProblemDescription(
880
+ category, journey, config, advancedProblemDetails,
881
+ stdoutAndErrData);
882
+ }
883
+ if (solutionDescription.empty()) {
884
+ solutionDescription = createDefaultSolutionDescription(
885
+ category, journey, config);
886
+ }
887
+ parentProcessEnvDump.pid = getpid();
888
+ parentProcessEnvDump.envvars = gatherEnvvars();
889
+ parentProcessEnvDump.userInfo = gatherUserInfo();
890
+ parentProcessEnvDump.ulimits = gatherUlimits();
891
+ systemMetrics = gatherSystemMetrics();
892
+ return *this;
893
+ }
894
+
895
+
896
+ const string &getParentProcessEnvvars() const {
897
+ return parentProcessEnvDump.envvars;
898
+ }
899
+
900
+ const string &getParentProcessUserInfo() const {
901
+ return parentProcessEnvDump.userInfo;
902
+ }
903
+
904
+ const string &getParentProcessUlimits() const {
905
+ return parentProcessEnvDump.ulimits;
906
+ }
907
+
908
+
909
+ pid_t getPreloaderPid() const {
910
+ return preloaderEnvDump.pid;
911
+ }
912
+
913
+ void setPreloaderPid(pid_t pid) {
914
+ preloaderEnvDump.pid = pid;
915
+ }
916
+
917
+ const string &getPreloaderEnvvars() const {
918
+ return preloaderEnvDump.envvars;
919
+ }
920
+
921
+ void setPreloaderEnvvars(const string &value) {
922
+ preloaderEnvDump.envvars = value;
923
+ }
924
+
925
+ const string &getPreloaderUserInfo() const {
926
+ return preloaderEnvDump.userInfo;
927
+ }
928
+
929
+ void setPreloaderUserInfo(const string &value) {
930
+ preloaderEnvDump.userInfo = value;
931
+ }
932
+
933
+ const string &getPreloaderUlimits() const {
934
+ return preloaderEnvDump.ulimits;
935
+ }
936
+
937
+ void setPreloaderUlimits(const string &value) {
938
+ preloaderEnvDump.ulimits = value;
939
+ }
940
+
941
+
942
+ pid_t getSubprocessPid() const {
943
+ return subprocessEnvDump.pid;
944
+ }
945
+
946
+ void setSubprocessPid(pid_t pid) {
947
+ subprocessEnvDump.pid = pid;
948
+ }
949
+
950
+ const string &getSubprocessEnvvars() const {
951
+ return subprocessEnvDump.envvars;
952
+ }
953
+
954
+ void setSubprocessEnvvars(const string &value) {
955
+ subprocessEnvDump.envvars = value;
956
+ }
957
+
958
+ const string &getSubprocessUserInfo() const {
959
+ return subprocessEnvDump.userInfo;
960
+ }
961
+
962
+ void setSubprocessUserInfo(const string &value) {
963
+ subprocessEnvDump.userInfo = value;
964
+ }
965
+
966
+ const string &getSubprocessUlimits() const {
967
+ return subprocessEnvDump.ulimits;
968
+ }
969
+
970
+ void setSubprocessUlimits(const string &value) {
971
+ subprocessEnvDump.ulimits = value;
972
+ }
973
+
974
+
975
+ const string &getSystemMetrics() const {
976
+ return systemMetrics;
977
+ }
978
+
979
+ const StringKeyTable<string> &getAnnotations() const {
980
+ return annotations;
981
+ }
982
+
983
+ void setAnnotation(const HashedStaticString &name, const string &value,
984
+ bool overwrite = true)
985
+ {
986
+ annotations.insert(name, value, overwrite);
987
+ }
988
+
989
+ Json::Value inspectBasicInfoAsJson() const {
990
+ Json::Value doc;
991
+
992
+ doc["category"] = errorCategoryToString(category).toString();
993
+ doc["summary"] = summary;
994
+ doc["problem_description_html"] = problemDescription;
995
+ doc["solution_description_html"] = solutionDescription;
996
+ if (!advancedProblemDetails.empty()) {
997
+ doc["aux_details"] = advancedProblemDetails;
998
+ }
999
+ if (!id.empty()) {
1000
+ doc["id"] = id;
1001
+ }
1002
+
1003
+ return doc;
1004
+ }
1005
+
1006
+ Json::Value inspectSystemWideDetailsAsJson() const {
1007
+ Json::Value doc;
1008
+
1009
+ doc["system_metrics"] = systemMetrics;
1010
+
1011
+ return doc;
1012
+ }
1013
+
1014
+ Json::Value inspectParentProcessDetailsAsJson() const {
1015
+ Json::Value doc;
1016
+
1017
+ doc["backtrace"] = backtrace();
1018
+ doc["pid"] = (Json::Int) parentProcessEnvDump.pid;
1019
+ doc["envvars"] = getParentProcessEnvvars();
1020
+ doc["user_info"] = getParentProcessUserInfo();
1021
+ doc["ulimits"] = getParentProcessUlimits();
1022
+
1023
+ return doc;
1024
+ }
1025
+
1026
+ Json::Value inspectPreloaderProcessDetailsAsJson() const {
1027
+ Json::Value doc, annotations(Json::objectValue);
1028
+
1029
+ if (getPreloaderPid() != (pid_t) -1) {
1030
+ doc["pid"] = getPreloaderPid();
1031
+ }
1032
+ doc["envvars"] = getPreloaderEnvvars();
1033
+ doc["user_info"] = getPreloaderUserInfo();
1034
+ doc["ulimits"] = getPreloaderUlimits();
1035
+
1036
+ StringKeyTable<string>::ConstIterator it(this->annotations);
1037
+ while (*it != NULL) {
1038
+ annotations[it.getKey().toString()] = it.getValue();
1039
+ it.next();
1040
+ }
1041
+ doc["annotations"] = annotations;
1042
+
1043
+ return doc;
1044
+ }
1045
+
1046
+ Json::Value inspectSubprocessDetailsAsJson() const {
1047
+ Json::Value doc, annotations(Json::objectValue);
1048
+
1049
+ if (getSubprocessPid() != (pid_t) -1) {
1050
+ doc["pid"] = getSubprocessPid();
1051
+ }
1052
+ doc["envvars"] = getSubprocessEnvvars();
1053
+ doc["user_info"] = getSubprocessUserInfo();
1054
+ doc["ulimits"] = getSubprocessUlimits();
1055
+ doc["stdout_and_err"] = getStdoutAndErrData();
1056
+
1057
+ StringKeyTable<string>::ConstIterator it(this->annotations);
1058
+ while (*it != NULL) {
1059
+ annotations[it.getKey().toString()] = it.getValue();
1060
+ it.next();
1061
+ }
1062
+ doc["annotations"] = annotations;
1063
+
1064
+ return doc;
1065
+ }
1066
+ };
1067
+
1068
+
1069
+ inline StaticString
1070
+ errorCategoryToString(ErrorCategory category) {
1071
+ switch (category) {
1072
+ case INTERNAL_ERROR:
1073
+ return P_STATIC_STRING("INTERNAL_ERROR");
1074
+ case FILE_SYSTEM_ERROR:
1075
+ return P_STATIC_STRING("FILE_SYSTEM_ERROR");
1076
+ case OPERATING_SYSTEM_ERROR:
1077
+ return P_STATIC_STRING("OPERATING_SYSTEM_ERROR");
1078
+ case IO_ERROR:
1079
+ return P_STATIC_STRING("IO_ERROR");
1080
+ case TIMEOUT_ERROR:
1081
+ return P_STATIC_STRING("TIMEOUT_ERROR");
1082
+
1083
+ case UNKNOWN_ERROR_CATEGORY:
1084
+ return P_STATIC_STRING("UNKNOWN_ERROR_CATEGORY");
1085
+
1086
+ default:
1087
+ return P_STATIC_STRING("(invalid value)");
1088
+ }
1089
+ }
1090
+
1091
+ inline bool
1092
+ _isFileSystemError(const std::exception &e) {
1093
+ if (dynamic_cast<const FileSystemException *>(&e) != NULL) {
1094
+ return true;
1095
+ }
1096
+
1097
+ const SystemException *sysEx = dynamic_cast<const SystemException *>(&e);
1098
+ if (sysEx != NULL) {
1099
+ return sysEx->code() == ENOENT
1100
+ || sysEx->code() == ENAMETOOLONG
1101
+ || sysEx->code() == EEXIST
1102
+ || sysEx->code() == EACCES;
1103
+ }
1104
+
1105
+ return false;
1106
+ }
1107
+
1108
+ inline bool
1109
+ _systemErrorIsActuallyIoError(JourneyStep failedJourneyStep) {
1110
+ return failedJourneyStep == SPAWNING_KIT_CONNECT_TO_PRELOADER
1111
+ || failedJourneyStep == SPAWNING_KIT_SEND_COMMAND_TO_PRELOADER
1112
+ || failedJourneyStep == SPAWNING_KIT_READ_RESPONSE_FROM_PRELOADER;
1113
+ }
1114
+
1115
+ inline ErrorCategory
1116
+ inferErrorCategoryFromAnotherException(const std::exception &e,
1117
+ JourneyStep failedJourneyStep)
1118
+ {
1119
+ if (dynamic_cast<const SystemException *>(&e) != NULL) {
1120
+ if (_systemErrorIsActuallyIoError(failedJourneyStep)) {
1121
+ return IO_ERROR;
1122
+ } else {
1123
+ return OPERATING_SYSTEM_ERROR;
1124
+ }
1125
+ } else if (_isFileSystemError(e)) {
1126
+ return FILE_SYSTEM_ERROR;
1127
+ } else if (dynamic_cast<const IOException *>(&e) != NULL) {
1128
+ return IO_ERROR;
1129
+ } else if (dynamic_cast<const TimeoutException *>(&e) != NULL) {
1130
+ return TIMEOUT_ERROR;
1131
+ } else {
1132
+ return INTERNAL_ERROR;
1133
+ }
1134
+ }
1135
+
1136
+ inline ErrorCategory
1137
+ stringToErrorCategory(const StaticString &value) {
1138
+ if (value == P_STATIC_STRING("INTERNAL_ERROR")) {
1139
+ return INTERNAL_ERROR;
1140
+ } else if (value == P_STATIC_STRING("FILE_SYSTEM_ERROR")) {
1141
+ return FILE_SYSTEM_ERROR;
1142
+ } else if (value == P_STATIC_STRING("OPERATING_SYSTEM_ERROR")) {
1143
+ return OPERATING_SYSTEM_ERROR;
1144
+ } else if (value == P_STATIC_STRING("IO_ERROR")) {
1145
+ return IO_ERROR;
1146
+ } else if (value == P_STATIC_STRING("TIMEOUT_ERROR")) {
1147
+ return TIMEOUT_ERROR;
1148
+ } else {
1149
+ return UNKNOWN_ERROR_CATEGORY;
1150
+ }
1151
+ }
1152
+
1153
+
1154
+ } // namespace SpawningKit
1155
+ } // namespace Passenger
1156
+
1157
+ #endif /* _PASSENGER_SPAWNING_KIT_EXCEPTIONS_H_ */