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
@@ -28,6 +28,7 @@
28
28
 
29
29
  #include <oxt/macros.hpp>
30
30
  #include <LoggingKit/Forward.h>
31
+ #include <StaticString.h>
31
32
  #include <Utils/FastStringStream.h>
32
33
  #include <DataStructures/HashedStaticString.h>
33
34
 
@@ -198,7 +199,8 @@ namespace LoggingKit {
198
199
  * @param message The message that was received.
199
200
  * @param appLogFile an app specific file to log to.
200
201
  */
201
- void logAppOutput(const HashedStaticString &groupName, pid_t pid, const char *channelName, const char *message, unsigned int size, const StaticString &appLogFile);
202
+ void logAppOutput(const HashedStaticString &groupName, pid_t pid, const StaticString &channelName,
203
+ const char *message, unsigned int size, const StaticString &appLogFile);
202
204
 
203
205
  } // namespace LoggingKit
204
206
  } // namespace Passenger
@@ -115,6 +115,48 @@ escapeForXml(const StaticString &input) {
115
115
  return result;
116
116
  }
117
117
 
118
+ string
119
+ escapeShell(const StaticString &value) {
120
+ if (value.empty()) {
121
+ return "''";
122
+ }
123
+
124
+ const char *pos = value.data();
125
+ const char *end = value.data() + value.size();
126
+ string result;
127
+
128
+ result.reserve(value.size() * 1.5);
129
+
130
+ while (pos < end) {
131
+ char ch = *pos;
132
+ if (ch == '\n') {
133
+ // It is not possible to escape a newline with a backslash.
134
+ // This is because a backslash + newline combination
135
+ // is treated to mean a line continuation
136
+ result.append("'\n'", 3);
137
+ } else {
138
+ bool allowed =
139
+ (ch >= 'A' && ch <= 'Z')
140
+ || (ch >= 'a' && ch <= 'z')
141
+ || (ch >= '0' && ch <= '9')
142
+ || ch == '_'
143
+ || ch == '-'
144
+ || ch == '.'
145
+ || ch == ','
146
+ || ch == ':'
147
+ || ch == '/'
148
+ || ch == '@';
149
+ if (!allowed) {
150
+ result.append(1, '\\');
151
+ }
152
+ result.append(1, ch);
153
+ }
154
+ pos++;
155
+ }
156
+
157
+ return result;
158
+ }
159
+
118
160
  string
119
161
  getProcessUsername(bool fallback) {
120
162
  struct passwd pwd, *result;
@@ -85,6 +85,13 @@ ptr(T *pointer) {
85
85
  */
86
86
  string escapeForXml(const StaticString &input);
87
87
 
88
+ /**
89
+ * Escape the given string into a single value for use in a shell (like Bash).
90
+ *
91
+ * @throws std::bad_alloc Something went wrong.
92
+ */
93
+ string escapeShell(const StaticString &input);
94
+
88
95
  /**
89
96
  * Returns the username of the user that the current process is running as.
90
97
  * If the user has no associated username, then the behavior depends on the
@@ -733,6 +733,64 @@ connectToServer(NConnect_State &state) {
733
733
  }
734
734
  }
735
735
 
736
+ bool
737
+ pingTcpServer(const StaticString &host, unsigned int port, unsigned long long *timeout) {
738
+ TRACE_POINT();
739
+ NTCP_State state;
740
+
741
+ setupNonBlockingTcpSocket(state, host, port, __FILE__, __LINE__);
742
+
743
+ try {
744
+ if (connectToTcpServer(state)) {
745
+ return true;
746
+ }
747
+ } catch (const SystemException &e) {
748
+ if (e.code() == ECONNREFUSED) {
749
+ return false;
750
+ } else {
751
+ throw e;
752
+ }
753
+ }
754
+
755
+ // Cannot connect to the port yet, but that may not mean the
756
+ // port is unavailable. So poll the socket.
757
+
758
+ bool connectable;
759
+ try {
760
+ connectable = waitUntilWritable(state.fd, timeout);
761
+ } catch (const SystemException &e) {
762
+ throw SystemException("Error polling TCP socket "
763
+ + host + ":" + toString(port), e.code());
764
+ }
765
+ if (!connectable) {
766
+ // Timed out. Assume port is not available.
767
+ return false;
768
+ }
769
+
770
+ // Try to connect the socket one last time.
771
+
772
+ try {
773
+ return connectToTcpServer(state);
774
+ } catch (const SystemException &e) {
775
+ if (e.code() == ECONNREFUSED) {
776
+ return false;
777
+ } else if (e.code() == EISCONN || e.code() == EINVAL) {
778
+ #ifdef __FreeBSD__
779
+ // Work around bug in FreeBSD (discovered on
780
+ // January 20 2013 in daemon_controller)
781
+ return false;
782
+ #else
783
+ throw e;
784
+ #endif
785
+
786
+ // Never reached, shut up compiler warning.
787
+ return false;
788
+ } else {
789
+ throw e;
790
+ }
791
+ }
792
+ }
793
+
736
794
  SocketPair
737
795
  createUnixSocketPair(const char *file, unsigned int line) {
738
796
  int fds[2];
@@ -384,6 +384,19 @@ void setupNonBlockingSocket(NConnect_State & restrict_ref state,
384
384
  */
385
385
  bool connectToServer(NConnect_State &state);
386
386
 
387
+ /**
388
+ * Checks whether the given TCP server is connectable. Because this check
389
+ * can take (in theory) an arbitrary amount of time, you must also supply
390
+ * a timeout. When the operation is done, the amount of time taken will be
391
+ * deducted from the `*timeout` value. A timeout of 100000 microseconds is
392
+ * recommended for most use cases.
393
+ *
394
+ * @throws IOException Something went wrong.
395
+ * @throws SystemException Something went wrong.
396
+ * @throws boost::thread_interrupted A system call has been interrupted.
397
+ */
398
+ bool pingTcpServer(const StaticString &host, unsigned int port, unsigned long long *timeout);
399
+
387
400
  /**
388
401
  * Creates a Unix domain socket pair.
389
402
  *
@@ -70,46 +70,82 @@ getJsonField(Json::Value &json, const char *key) {
70
70
  }
71
71
  }
72
72
 
73
+
73
74
  inline int
74
75
  getJsonIntField(const Json::Value &json, const char *key) {
75
- Json::StaticString theKey(key);
76
- if (json.isMember(theKey)) {
77
- return json[theKey].asInt();
76
+ if (json.isMember(key)) {
77
+ return json[key].asInt();
78
78
  } else {
79
79
  throw VariantMap::MissingKeyException(key);
80
80
  }
81
81
  }
82
82
 
83
83
  inline int
84
- getJsonIntField(const Json::Value &json, const char *key, int defaultValue) {
85
- Json::StaticString theKey(key);
86
- if (json.isMember(theKey)) {
87
- return json[theKey].asInt();
84
+ getJsonIntField(const Json::Value &json, const Json::StaticString &key) {
85
+ if (json.isMember(key)) {
86
+ return json[key].asInt();
87
+ } else {
88
+ throw VariantMap::MissingKeyException(key.c_str());
89
+ }
90
+ }
91
+
92
+ inline int
93
+ getJsonIntField(const Json::Value &json, const Json::StaticString &key, int defaultValue) {
94
+ if (json.isMember(key)) {
95
+ return json[key].asInt();
88
96
  } else {
89
97
  return defaultValue;
90
98
  }
91
99
  }
92
100
 
101
+ inline void
102
+ getJsonIntField(const Json::Value &json, const Json::StaticString &key, int *result) {
103
+ if (json.isMember(key)) {
104
+ *result = json[key].asInt();
105
+ }
106
+ }
107
+
108
+ inline void
109
+ getJsonIntField(const Json::Value &json, const string &key, int *result) {
110
+ if (json.isMember(key)) {
111
+ *result = json[key].asInt();
112
+ }
113
+ }
114
+
115
+
93
116
  inline unsigned int
94
- getJsonUintField(const Json::Value &json, const char *key) {
95
- Json::StaticString theKey(key);
96
- if (json.isMember(theKey)) {
97
- return json[theKey].asUInt();
117
+ getJsonUintField(const Json::Value &json, const Json::StaticString &key) {
118
+ if (json.isMember(key)) {
119
+ return json[key].asUInt();
98
120
  } else {
99
- throw VariantMap::MissingKeyException(key);
121
+ throw VariantMap::MissingKeyException(key.c_str());
100
122
  }
101
123
  }
102
124
 
103
125
  inline unsigned int
104
- getJsonUintField(const Json::Value &json, const char *key, unsigned int defaultValue) {
105
- Json::StaticString theKey(key);
106
- if (json.isMember(theKey)) {
107
- return json[theKey].asUInt();
126
+ getJsonUintField(const Json::Value &json, const Json::StaticString &key, unsigned int defaultValue) {
127
+ if (json.isMember(key)) {
128
+ return json[key].asUInt();
108
129
  } else {
109
130
  return defaultValue;
110
131
  }
111
132
  }
112
133
 
134
+ inline void
135
+ getJsonUintField(const Json::Value &json, const Json::StaticString &key, unsigned int *result) {
136
+ if (json.isMember(key)) {
137
+ *result = json[key].asUInt();
138
+ }
139
+ }
140
+
141
+ inline void
142
+ getJsonUintField(const Json::Value &json, const string &key, unsigned int *result) {
143
+ if (json.isMember(key)) {
144
+ *result = json[key].asUInt();
145
+ }
146
+ }
147
+
148
+
113
149
  inline boost::uint64_t
114
150
  getJsonUint64Field(const Json::Value &json, const char *key) {
115
151
  Json::StaticString theKey(key);
@@ -130,23 +166,41 @@ getJsonUint64Field(const Json::Value &json, const char *key, unsigned int defaul
130
166
  }
131
167
  }
132
168
 
169
+
170
+ inline bool
171
+ getJsonBoolField(const Json::Value &json, const char *key) {
172
+ if (json.isMember(key)) {
173
+ return json[key].asBool();
174
+ } else {
175
+ throw VariantMap::MissingKeyException(key);
176
+ }
177
+ }
178
+
179
+
133
180
  inline StaticString
134
181
  getJsonStaticStringField(const Json::Value &json, const char *key) {
135
- Json::StaticString theKey(key);
136
- if (json.isMember(theKey)) {
137
- return json[theKey].asCString();
182
+ if (json.isMember(key)) {
183
+ return json[key].asCString();
138
184
  } else {
139
185
  throw VariantMap::MissingKeyException(key);
140
186
  }
141
187
  }
142
188
 
143
189
  inline StaticString
144
- getJsonStaticStringField(const Json::Value &json, const char *key,
190
+ getJsonStaticStringField(const Json::Value &json, const Json::StaticString &key) {
191
+ if (json.isMember(key)) {
192
+ return json[key].asCString();
193
+ } else {
194
+ throw VariantMap::MissingKeyException(key.c_str());
195
+ }
196
+ }
197
+
198
+ inline StaticString
199
+ getJsonStaticStringField(const Json::Value &json, const Json::StaticString &key,
145
200
  const StaticString &defaultValue)
146
201
  {
147
- Json::StaticString theKey(key);
148
- if (json.isMember(theKey)) {
149
- return json[theKey].asCString();
202
+ if (json.isMember(key)) {
203
+ return json[key].asCString();
150
204
  } else {
151
205
  return defaultValue;
152
206
  }
@@ -236,6 +290,59 @@ timeToJson(unsigned long long timestamp, unsigned long long now = 0) {
236
290
  return doc;
237
291
  }
238
292
 
293
+ /**
294
+ * Encodes the given monotonic timestamp into a JSON object that
295
+ * describes it.
296
+ *
297
+ * MonotonicTimeUsec t = SystemTime::getMonotonicUsec();
298
+ * monoTimeToJson(t - 10000000, t);
299
+ * // {
300
+ * // "timestamp": 1424887842,
301
+ * // "local": "Wed Feb 25 19:10:34 CET 2015",
302
+ * // "relative_timestamp": -10,
303
+ * // "relative": "10s ago"
304
+ * // }
305
+ */
306
+ inline Json::Value
307
+ monoTimeToJson(MonotonicTimeUsec t, MonotonicTimeUsec monoNow, unsigned long long now = 0) {
308
+ if (t == 0) {
309
+ return Json::Value(Json::nullValue);
310
+ }
311
+
312
+ if (now == 0) {
313
+ now = SystemTime::getUsec();
314
+ }
315
+
316
+ unsigned long long wallClockTimeUsec;
317
+ if (monoNow > t) {
318
+ wallClockTimeUsec = now - (monoNow - t);
319
+ } else {
320
+ wallClockTimeUsec = now + (monoNow - t);
321
+ }
322
+
323
+ time_t wallClockTime = (time_t) (wallClockTimeUsec / 1000000ull);
324
+ char timeStr[32];
325
+ size_t len;
326
+ ctime_r(&wallClockTime, timeStr);
327
+ len = strlen(timeStr);
328
+ if (len > 0) {
329
+ // Get rid of trailing newline
330
+ timeStr[len - 1] = '\0';
331
+ }
332
+
333
+ Json::Value doc;
334
+ doc["timestamp"] = wallClockTimeUsec / 1000000.0;
335
+ doc["local"] = timeStr;
336
+ if (t > monoNow) {
337
+ doc["relative_timestamp"] = (t - monoNow) / 1000000.0;
338
+ doc["relative"] = distanceOfTimeInWords(t / 1000000ull, monoNow / 1000000ull) + " from now";
339
+ } else {
340
+ doc["relative_timestamp"] = (monoNow - t) / -1000000.0;
341
+ doc["relative"] = distanceOfTimeInWords(t / 1000000ull, monoNow / 1000000ull) + " ago";
342
+ }
343
+ return doc;
344
+ }
345
+
239
346
  inline Json::Value
240
347
  durationToJson(unsigned long long duration) {
241
348
  Json::Value doc;
@@ -133,15 +133,20 @@ public:
133
133
  }
134
134
 
135
135
  ~FdGuard() {
136
- if (fd != -1) {
137
- safelyClose(fd, ignoreErrors);
138
- P_LOG_FILE_DESCRIPTOR_CLOSE(fd);
139
- }
136
+ runNow();
140
137
  }
141
138
 
142
139
  void clear() {
143
140
  fd = -1;
144
141
  }
142
+
143
+ void runNow() {
144
+ if (fd != -1) {
145
+ safelyClose(fd, ignoreErrors);
146
+ P_LOG_FILE_DESCRIPTOR_CLOSE(fd);
147
+ fd = -1;
148
+ }
149
+ }
145
150
  };
146
151
 
147
152
 
@@ -206,6 +206,13 @@ toString(const vector<StaticString> &vec) {
206
206
  return result;
207
207
  }
208
208
 
209
+ string
210
+ doubleToString(double value) {
211
+ char buf[64];
212
+ int ret = snprintf(buf, sizeof(buf), "%f", value);
213
+ return string(buf, std::min<size_t>(ret, sizeof(buf) - 1));
214
+ }
215
+
209
216
  string
210
217
  pointerToIntString(void *pointer) {
211
218
  return toString((boost::uintptr_t) pointer);
@@ -231,6 +231,7 @@ toString(T something) {
231
231
  string toString(const vector<string> &vec);
232
232
  string toString(const vector<StaticString> &vec);
233
233
 
234
+ string doubleToString(double value);
234
235
  string pointerToIntString(void *pointer);
235
236
 
236
237
  /**
@@ -100,7 +100,7 @@ typedef unsigned long long MonotonicTimeUsec;
100
100
  class SystemTime {
101
101
  public:
102
102
  enum Granularity {
103
- GRAN_1SEC = 1000000000, // 1 millisecond granularity
103
+ GRAN_1SEC = 1000000000, // 1 second granularity
104
104
  GRAN_10MSEC = 10000000, // 10 milliseconds granularity
105
105
  GRAN_1MSEC = 1000000, // 1 millisecond granularity
106
106
  GRAN_1USEC = 1000 // 1 microsecond granularty
@@ -37,7 +37,7 @@ using namespace oxt;
37
37
 
38
38
  /**
39
39
  * A Timer which one can use to check how much time has elapsed since the
40
- * timer started. This timer support miliseconds-resolution, but the exact
40
+ * timer started. This timer supports miliseconds-resolution, but the exact
41
41
  * resolution depends on the OS and the hardware.
42
42
  *
43
43
  * This class is thread-safe.
@@ -582,10 +582,12 @@ private:
582
582
  P_NOTICE(getLogPrefix() << "Closing connection: " << reason);
583
583
  reconnectAfterReply = false;
584
584
  timer->cancel();
585
- conn->close(code, reason, ec);
586
- conn.reset();
587
- if (ec) {
588
- P_WARN(getLogPrefix() << "Error closing connection: " << ec.message());
585
+ if (conn != NULL) {
586
+ conn->close(code, reason, ec);
587
+ conn.reset();
588
+ if (ec) {
589
+ P_WARN(getLogPrefix() << "Error closing connection: " << ec.message());
590
+ }
589
591
  }
590
592
 
591
593
  {