passenger 5.3.4 → 6.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +69 -0
- data/CONTRIBUTORS +1 -0
- data/README.md +2 -1
- data/Rakefile +0 -5
- data/build/agent.rb +6 -3
- data/build/cxx_tests.rb +28 -19
- data/build/integration_tests.rb +6 -2
- data/build/misc.rb +2 -1
- data/build/packaging.rb +2 -0
- data/build/support/cplusplus.rb +2 -2
- data/build/support/cxx_dependency_map.rb +2651 -2189
- data/dev/colorize-logs +272 -0
- data/dev/show-latest-crashlog-dir +27 -0
- data/resources/templates/standalone/http.erb +2 -0
- data/resources/templates/standalone/server.erb +1 -0
- data/src/agent/AgentMain.cpp +4 -0
- data/src/agent/Core/AdminPanelConnector.h +6 -6
- data/src/agent/Core/ApiServer.h +4 -4
- data/src/agent/Core/ApplicationPool/BasicProcessInfo.h +2 -2
- data/src/agent/Core/ApplicationPool/Context.h +5 -1
- data/src/agent/Core/ApplicationPool/Group/InternalUtils.cpp +2 -2
- data/src/agent/Core/ApplicationPool/Group/LifetimeAndBasics.cpp +5 -0
- data/src/agent/Core/ApplicationPool/Group/Miscellaneous.cpp +2 -1
- data/src/agent/Core/ApplicationPool/Group/OutOfBandWork.cpp +3 -3
- data/src/agent/Core/ApplicationPool/Group/ProcessListManagement.cpp +1 -1
- data/src/agent/Core/ApplicationPool/Group/StateInspection.cpp +13 -20
- data/src/agent/Core/ApplicationPool/Group.h +4 -2
- data/src/agent/Core/ApplicationPool/Implementation.cpp +5 -5
- data/src/agent/Core/ApplicationPool/Options.h +42 -38
- data/src/agent/Core/ApplicationPool/Pool/GroupUtils.cpp +2 -1
- data/src/agent/Core/ApplicationPool/Pool.h +4 -4
- data/src/agent/Core/ApplicationPool/Process.h +13 -15
- data/src/agent/Core/ApplicationPool/Socket.h +5 -5
- data/src/agent/Core/ApplicationPool/TestSession.h +3 -3
- data/src/agent/Core/Config.h +50 -10
- data/src/agent/Core/ConfigChange.cpp +13 -1
- data/src/agent/Core/Controller/Config.h +41 -17
- data/src/agent/Core/Controller/ForwardResponse.cpp +4 -0
- data/src/agent/Core/Controller/InitRequest.cpp +14 -8
- data/src/agent/Core/Controller/InitializationAndShutdown.cpp +5 -0
- data/src/agent/Core/Controller/SendRequest.cpp +9 -9
- data/src/agent/Core/Controller/TurboCaching.h +2 -2
- data/src/agent/Core/Controller.h +7 -5
- data/src/agent/Core/CoreMain.cpp +204 -60
- data/src/agent/Core/OptionParser.h +20 -3
- data/src/agent/Core/ResponseCache.h +3 -3
- data/src/agent/Core/SecurityUpdateChecker.h +4 -2
- data/src/agent/Core/SpawningKit/Config/AutoGeneratedCode.h +1 -1
- data/src/agent/Core/SpawningKit/Config.h +3 -2
- data/src/agent/Core/SpawningKit/Context.h +8 -2
- data/src/agent/Core/SpawningKit/DirectSpawner.h +4 -4
- data/src/agent/Core/SpawningKit/DummySpawner.h +3 -3
- data/src/agent/Core/SpawningKit/ErrorRenderer.h +1 -1
- data/src/agent/Core/SpawningKit/Exceptions.h +21 -14
- data/src/agent/Core/SpawningKit/Factory.h +1 -1
- data/src/agent/Core/SpawningKit/Handshake/BackgroundIOCapturer.h +1 -1
- data/src/agent/Core/SpawningKit/Handshake/Perform.h +14 -2
- data/src/agent/Core/SpawningKit/Handshake/Prepare.h +3 -3
- data/src/agent/Core/SpawningKit/Handshake/WorkDir.h +1 -1
- data/src/agent/Core/SpawningKit/Journey.h +4 -5
- data/src/agent/Core/SpawningKit/PipeWatcher.h +1 -1
- data/src/agent/Core/SpawningKit/README.md +34 -17
- data/src/agent/Core/SpawningKit/Result/AutoGeneratedCode.h +1 -1
- data/src/agent/Core/SpawningKit/Result.h +20 -8
- data/src/agent/Core/SpawningKit/SmartSpawner.h +7 -7
- data/src/agent/Core/SpawningKit/Spawner.h +25 -8
- data/src/agent/Core/SpawningKit/UserSwitchingRules.h +17 -7
- data/src/agent/Core/TelemetryCollector.h +681 -0
- data/src/agent/ExecHelper/ExecHelperMain.cpp +1 -1
- data/src/agent/FileReadHelper/FileReadHelperMain.cpp +198 -0
- data/src/agent/README.md +1 -1
- data/src/agent/Shared/ApiAccountUtils.h +1 -1
- data/src/agent/Shared/ApiServerUtils.h +3 -3
- data/src/agent/Shared/ApplicationPoolApiKey.h +2 -2
- data/src/agent/Shared/Fundamentals/AbortHandler.cpp +324 -98
- data/src/agent/Shared/Fundamentals/AbortHandler.h +31 -4
- data/src/agent/Shared/Fundamentals/Initialization.cpp +4 -5
- data/src/agent/Shared/Fundamentals/Initialization.h +9 -1
- data/src/agent/SpawnEnvSetupper/SpawnEnvSetupperMain.cpp +1 -1
- data/src/agent/SystemMetrics/SystemMetricsMain.cpp +4 -3
- data/src/agent/TempDirToucher/TempDirToucherMain.cpp +3 -3
- data/src/agent/Watchdog/ApiServer.h +3 -3
- data/src/agent/Watchdog/Config.h +24 -5
- data/src/agent/Watchdog/CoreWatcher.cpp +2 -2
- data/src/agent/Watchdog/WatchdogMain.cpp +97 -28
- data/src/apache2_module/Config.cpp +14 -14
- data/src/apache2_module/Config.h +8 -16
- data/src/apache2_module/ConfigGeneral/AutoGeneratedDefinitions.cpp +510 -481
- data/src/apache2_module/ConfigGeneral/AutoGeneratedDefinitions.cpp.cxxcodebuilder +39 -17
- data/src/apache2_module/ConfigGeneral/AutoGeneratedManifestDefaultsInitialization.cpp +5 -0
- data/src/apache2_module/ConfigGeneral/AutoGeneratedSetterFuncs.cpp +69 -1
- data/src/apache2_module/ConfigGeneral/AutoGeneratedSetterFuncs.cpp.cxxcodebuilder +31 -1
- data/src/apache2_module/ConfigGeneral/Common.h +45 -0
- data/src/apache2_module/DirConfig/AutoGeneratedCreateFunction.cpp +17 -1
- data/src/apache2_module/DirConfig/AutoGeneratedCreateFunction.cpp.cxxcodebuilder +16 -1
- data/src/apache2_module/DirConfig/AutoGeneratedHeaderSerialization.cpp +19 -5
- data/src/apache2_module/DirConfig/AutoGeneratedHeaderSerialization.cpp.cxxcodebuilder +26 -9
- data/src/apache2_module/DirConfig/AutoGeneratedManifestGeneration.cpp +19 -1
- data/src/apache2_module/DirConfig/AutoGeneratedManifestGeneration.cpp.cxxcodebuilder +10 -1
- data/src/apache2_module/DirConfig/AutoGeneratedMergeFunction.cpp +14 -1
- data/src/apache2_module/DirConfig/AutoGeneratedMergeFunction.cpp.cxxcodebuilder +11 -1
- data/src/apache2_module/DirConfig/AutoGeneratedStruct.h +36 -1
- data/src/apache2_module/DirConfig/AutoGeneratedStruct.h.cxxcodebuilder +34 -1
- data/src/apache2_module/DirectoryMapper.h +36 -37
- data/src/apache2_module/Hooks.cpp +27 -8
- data/src/apache2_module/ServerConfig/AutoGeneratedManifestGeneration.cpp +20 -0
- data/src/apache2_module/ServerConfig/AutoGeneratedStruct.h +48 -1
- data/src/apache2_module/ServerConfig/AutoGeneratedStruct.h.cxxcodebuilder +36 -1
- data/src/cxx_supportlib/{Utils → Algorithms}/Hasher.cpp +2 -2
- data/src/cxx_supportlib/{Utils → Algorithms}/Hasher.h +4 -4
- data/src/cxx_supportlib/AppLocalConfigFileUtils.h +148 -0
- data/src/cxx_supportlib/AppTypeDetector/CBindings.cpp +147 -0
- data/src/cxx_supportlib/AppTypeDetector/CBindings.h +75 -0
- data/src/cxx_supportlib/{AppTypes.h → AppTypeDetector/Detector.h} +92 -131
- data/src/cxx_supportlib/ConfigKit/README.md +90 -2
- data/src/cxx_supportlib/ConfigKit/Schema.h +60 -15
- data/src/cxx_supportlib/ConfigKit/Store.h +129 -5
- data/src/cxx_supportlib/Constants.h +1 -1
- data/src/cxx_supportlib/{Utils → DataStructures}/HashMap.h +4 -4
- data/src/cxx_supportlib/DataStructures/HashedStaticString.h +5 -5
- data/src/cxx_supportlib/DataStructures/LString.h +3 -3
- data/src/cxx_supportlib/{Utils → DataStructures}/StringMap.h +36 -36
- data/src/cxx_supportlib/FileTools/FileManip.cpp +1 -1
- data/src/cxx_supportlib/FileTools/PathManip.cpp +2 -2
- data/src/cxx_supportlib/FileTools/PathSecurityCheck.cpp +1 -1
- data/src/cxx_supportlib/Hooks.h +2 -2
- data/src/cxx_supportlib/{Utils → IOTools}/BufferedIO.h +5 -5
- data/src/cxx_supportlib/{Utils → IOTools}/IOUtils.cpp +4 -3
- data/src/cxx_supportlib/{Utils → IOTools}/IOUtils.h +3 -3
- data/src/cxx_supportlib/{Utils → IOTools}/MessageIO.h +7 -7
- data/src/cxx_supportlib/{MessageReadersWriters.h → IOTools/MessageSerialization.h} +5 -5
- data/src/cxx_supportlib/InstanceDirectory.h +4 -4
- data/src/cxx_supportlib/Integrations/LibevJsonUtils.h +3 -3
- data/src/cxx_supportlib/{Utils → JsonTools}/JsonUtils.h +5 -5
- data/src/cxx_supportlib/LoggingKit/Context.h +2 -2
- data/src/cxx_supportlib/LoggingKit/Implementation.cpp +3 -3
- data/src/cxx_supportlib/MemoryKit/mbuf.cpp +2 -2
- data/src/cxx_supportlib/ProcessManagement/Ruby.cpp +3 -3
- data/src/cxx_supportlib/ProcessManagement/Ruby.h +7 -2
- data/src/cxx_supportlib/ProcessManagement/Spawn.cpp +19 -12
- data/src/cxx_supportlib/ProcessManagement/Spawn.h +21 -2
- data/src/cxx_supportlib/ProcessManagement/Utils.h +10 -0
- data/src/cxx_supportlib/RandomGenerator.h +2 -2
- data/src/cxx_supportlib/ResourceLocator.h +1 -1
- data/src/cxx_supportlib/{Crypto.cpp → SecurityKit/Crypto.cpp} +4 -4
- data/src/cxx_supportlib/{Crypto.h → SecurityKit/Crypto.h} +4 -4
- data/src/cxx_supportlib/{Utils → SecurityKit}/MemZeroGuard.h +0 -0
- data/src/cxx_supportlib/ServerKit/AcceptLoadBalancer.h +2 -2
- data/src/cxx_supportlib/ServerKit/Channel.h +1 -1
- data/src/cxx_supportlib/ServerKit/ClientRef.h +17 -7
- data/src/cxx_supportlib/ServerKit/Context.h +2 -2
- data/src/cxx_supportlib/ServerKit/FileBufferedChannel.h +1 -1
- data/src/cxx_supportlib/ServerKit/HttpHeaderParser.h +3 -3
- data/src/cxx_supportlib/ServerKit/HttpHeaderParserState.h +2 -2
- data/src/cxx_supportlib/ServerKit/HttpRequestRef.h +17 -7
- data/src/cxx_supportlib/ServerKit/HttpServer.h +16 -10
- data/src/cxx_supportlib/ServerKit/Server.h +3 -4
- data/src/cxx_supportlib/{Utils → StrIntTools}/DateParsing.h +5 -5
- data/src/cxx_supportlib/{Utils → StrIntTools}/StrIntUtils.cpp +3 -3
- data/src/cxx_supportlib/{Utils → StrIntTools}/StrIntUtils.h +0 -0
- data/src/cxx_supportlib/{Utils → StrIntTools}/StrIntUtilsNoStrictAliasing.cpp +12 -12
- data/src/cxx_supportlib/{Utils → StrIntTools}/StringScanning.h +5 -5
- data/src/cxx_supportlib/{Utils → StrIntTools}/Template.h +30 -5
- data/src/cxx_supportlib/SystemTools/ContainerHelpers.h +88 -0
- data/src/cxx_supportlib/{Utils → SystemTools}/ProcessMetricsCollector.h +15 -12
- data/src/cxx_supportlib/{Utils → SystemTools}/SystemMetricsCollector.h +3 -3
- data/src/cxx_supportlib/{Utils → SystemTools}/SystemTime.cpp +1 -1
- data/src/cxx_supportlib/{Utils → SystemTools}/SystemTime.h +0 -0
- data/src/cxx_supportlib/SystemTools/UserDatabase.h +1 -1
- data/src/cxx_supportlib/Utils/CachedFileStat.hpp +3 -3
- data/src/cxx_supportlib/Utils/Curl.h +2 -2
- data/src/cxx_supportlib/Utils/FileChangeChecker.h +2 -2
- data/src/cxx_supportlib/Utils/MessagePassing.h +1 -1
- data/src/cxx_supportlib/Utils/SpeedMeter.h +2 -2
- data/src/cxx_supportlib/Utils/Timer.h +2 -2
- data/src/cxx_supportlib/Utils/VariantMap.h +3 -3
- data/src/cxx_supportlib/Utils.cpp +2 -2
- data/src/cxx_supportlib/WatchdogLauncher.h +3 -3
- data/src/cxx_supportlib/WebSocketCommandReverseServer.h +1 -1
- data/src/cxx_supportlib/WrapperRegistry/CBindings.cpp +85 -0
- data/src/cxx_supportlib/{Utils/MemoryBarrier.h → WrapperRegistry/CBindings.h} +30 -27
- data/src/cxx_supportlib/WrapperRegistry/Entry.h +112 -0
- data/src/cxx_supportlib/WrapperRegistry/README.md +37 -0
- data/src/cxx_supportlib/WrapperRegistry/Registry.h +309 -0
- data/src/cxx_supportlib/vendor-modified/psg_sysqueue.h +3 -0
- data/src/helper-scripts/download_binaries/extconf.rb +6 -2
- data/src/nginx_module/ConfigGeneral/AutoGeneratedDefinitions.c +32 -0
- data/src/nginx_module/ConfigGeneral/AutoGeneratedManifestDefaultsInitialization.c +12 -0
- data/src/nginx_module/ConfigGeneral/AutoGeneratedSetterFuncs.c +36 -0
- data/src/nginx_module/Configuration.c +23 -3
- data/src/nginx_module/ContentHandler.c +331 -32
- data/src/nginx_module/ContentHandler.h +8 -3
- data/src/nginx_module/LocationConfig/AutoGeneratedCreateFunction.c +10 -0
- data/src/nginx_module/LocationConfig/AutoGeneratedManifestGeneration.c +27 -0
- data/src/nginx_module/LocationConfig/AutoGeneratedMergeFunction.c +3 -0
- data/src/nginx_module/LocationConfig/AutoGeneratedStruct.h +7 -0
- data/src/nginx_module/MainConfig/AutoGeneratedCreateFunction.c +11 -0
- data/src/nginx_module/MainConfig/AutoGeneratedManifestGeneration.c +23 -0
- data/src/nginx_module/MainConfig/AutoGeneratedStruct.h +8 -0
- data/src/nginx_module/config +2 -1
- data/src/nginx_module/ngx_http_passenger_module.c +9 -3
- data/src/nginx_module/ngx_http_passenger_module.h +10 -3
- data/src/ruby_supportlib/phusion_passenger/apache2/config_options.rb +19 -0
- data/src/ruby_supportlib/phusion_passenger/common_library.rb +19 -16
- data/src/ruby_supportlib/phusion_passenger/config/agent_compiler.rb +4 -4
- data/src/ruby_supportlib/phusion_passenger/config/download_agent_command.rb +6 -2
- data/src/ruby_supportlib/phusion_passenger/config/download_nginx_engine_command.rb +6 -2
- data/src/ruby_supportlib/phusion_passenger/config/nginx_engine_compiler.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/message_channel.rb +2 -2
- data/src/ruby_supportlib/phusion_passenger/native_support.rb +7 -3
- data/src/ruby_supportlib/phusion_passenger/nginx/config_options.rb +29 -0
- data/src/ruby_supportlib/phusion_passenger/packaging.rb +20 -19
- data/src/ruby_supportlib/phusion_passenger/platform_info/apache.rb +22 -4
- data/src/ruby_supportlib/phusion_passenger/platform_info/ruby.rb +33 -13
- data/src/ruby_supportlib/phusion_passenger/standalone/app_finder.rb +1 -0
- data/src/ruby_supportlib/phusion_passenger/standalone/config_options_list.rb +22 -2
- data/src/ruby_supportlib/phusion_passenger/standalone/start_command/builtin_engine.rb +4 -1
- data/src/ruby_supportlib/phusion_passenger.rb +7 -5
- data/src/schema_printer/SchemaPrinterMain.cpp +2 -0
- metadata +40 -89
- data/.editorconfig +0 -134
- data/CODE_OF_CONDUCT.md +0 -52
- data/dev/boost-patches/0001-Patch-boost-thread-so-that-oxt-thread-can-use-it.patch +0 -48
- data/dev/boost-patches/0002-Make-boost-thread_interrupted-derive-from-oxt-tracab.patch +0 -33
- data/dev/boost-patches/0003-Disable-a-Clang-pragma-to-prevent-warnings-on-OS-X.patch +0 -25
- data/dev/ci/README.md +0 -134
- data/dev/ci/lib/functions.sh +0 -129
- data/dev/ci/lib/set-container-envvars.sh +0 -53
- data/dev/ci/lib/setup-container.sh +0 -46
- data/dev/ci/run-tests-natively +0 -24
- data/dev/ci/run-tests-with-docker +0 -42
- data/dev/ci/scripts/debug-console-wrapper.sh +0 -29
- data/dev/ci/scripts/docker-entrypoint-stage2.sh +0 -17
- data/dev/ci/scripts/docker-entrypoint.sh +0 -17
- data/dev/ci/scripts/inituidgid +0 -17
- data/dev/ci/scripts/run-tests-natively-stage2.sh +0 -17
- data/dev/ci/scripts/setup-host-natively.sh +0 -11
- data/dev/ci/setup-host +0 -56
- data/dev/ci/tests/apache2/run +0 -6
- data/dev/ci/tests/apache2/setup +0 -4
- data/dev/ci/tests/binaries/Jenkinsfile +0 -105
- data/dev/ci/tests/binaries/build-linux +0 -38
- data/dev/ci/tests/binaries/build-macos +0 -40
- data/dev/ci/tests/binaries/prepare-macos +0 -38
- data/dev/ci/tests/binaries/test-linux +0 -45
- data/dev/ci/tests/binaries/test-macos +0 -38
- data/dev/ci/tests/cxx/run +0 -9
- data/dev/ci/tests/cxx/setup +0 -4
- data/dev/ci/tests/debian/Jenkinsfile +0 -89
- data/dev/ci/tests/debian/run +0 -60
- data/dev/ci/tests/nginx/run +0 -5
- data/dev/ci/tests/nginx/setup +0 -4
- data/dev/ci/tests/nginx-dynamic/run +0 -20
- data/dev/ci/tests/nginx-dynamic/setup +0 -4
- data/dev/ci/tests/nodejs/run +0 -4
- data/dev/ci/tests/nodejs/setup +0 -4
- data/dev/ci/tests/rpm/Jenkinsfile +0 -68
- data/dev/ci/tests/rpm/run +0 -63
- data/dev/ci/tests/ruby/run +0 -4
- data/dev/ci/tests/ruby/setup +0 -4
- data/dev/ci/tests/source-packaging/run +0 -4
- data/dev/ci/tests/source-packaging/setup +0 -4
- data/dev/ci/tests/standalone/run +0 -4
- data/dev/ci/tests/standalone/setup +0 -4
- data/dev/configkit-schemas/index.json +0 -1748
- data/dev/configkit-schemas/update_schema_inline_comments.rb +0 -118
- data/dev/rack.test/config.ru +0 -5
- data/dev/rack.test/public/asset.txt +0 -1
- data/dev/vagrant/apache_default_site.conf +0 -35
- data/dev/vagrant/apache_passenger.conf +0 -5
- data/dev/vagrant/apache_passenger.load +0 -1
- data/dev/vagrant/apache_ports.conf +0 -24
- data/dev/vagrant/apache_rack_test.conf +0 -9
- data/dev/vagrant/bashrc +0 -23
- data/dev/vagrant/nginx.conf +0 -39
- data/dev/vagrant/nginx_rakefile +0 -33
- data/dev/vagrant/nginx_start +0 -32
- data/dev/vagrant/provision.sh +0 -117
- data/dev/vagrant/sudoers.conf +0 -5
- data/resources/templates/error_renderer/.editorconfig +0 -19
- data/src/cxx_supportlib/AppTypes.cpp +0 -109
- data/src/cxx_supportlib/vendor-modified/SmallVector.h +0 -653
@@ -20,6 +20,7 @@ ConfigKit is a configuration management system that lets you define configuratio
|
|
20
20
|
- [Flags](#flags)
|
21
21
|
- [Defining default values](#defining-default-values)
|
22
22
|
- [Defining custom validators](#defining-custom-validators)
|
23
|
+
- [Nested schemas](#nested-schemas)
|
23
24
|
- [Inspecting the schema](#inspecting-the-schema)
|
24
25
|
- [Using the store](#using-the-store)
|
25
26
|
- [Putting data in the store](#putting-data-in-the-store)
|
@@ -171,9 +172,9 @@ The following types are available:
|
|
171
172
|
* `UINT_TYPE` -- an unsigned integer.
|
172
173
|
* `FLOAT_TYPE` -- a floating point number.
|
173
174
|
* `BOOL_TYPE` -- a boolean.
|
174
|
-
* `ARRAY_TYPE` --
|
175
|
+
* `ARRAY_TYPE` -- usually a generic array (which may contain any values). But with a special `add()` invocation this can indicate an array of [nested ConfigKit schemas](#nested-schemas).
|
175
176
|
* `STRING_ARRAY_TYPE` -- an array of strings.
|
176
|
-
* `OBJECT_TYPE` -- a generic JSON object
|
177
|
+
* `OBJECT_TYPE` -- usually a generic JSON object (which may contain any values). But with a special `add()` invocation this can indicate a map of [nested ConfigKit schemas](#nested-schemas).
|
177
178
|
* `ANY_TYPE` -- any JSON value.
|
178
179
|
|
179
180
|
#### Flags
|
@@ -227,6 +228,81 @@ Miscellaneous notes about custom validators:
|
|
227
228
|
- They are always run, even if the normal type validation fails. For example if the caller tries to set the "foo" key to an array value (which is incompatible with the string type), then `myValidator` will still be called.
|
228
229
|
- All registered validators are called. A validator cannot prevent other validators from running.
|
229
230
|
|
231
|
+
### Nested schemas
|
232
|
+
|
233
|
+
> **Warning:** do not confuse nested schemas with **subschemas**. The latter is a mechanism for composing multiple schemas together, not a way to define the type of a field.
|
234
|
+
|
235
|
+
It is possible to define a config field that is an array of objects, or a string map of objects, that should conform to a certain schema. We call such a schema a **nested schema**. For example:
|
236
|
+
|
237
|
+
~~~c++
|
238
|
+
ConfigKit::Schema personSchema;
|
239
|
+
personSchema.add("name", STRING_TYPE, REQUIRED);
|
240
|
+
personSchema.add("age", INT_TYPE, OPTIONAL);
|
241
|
+
personSchema.finalize();
|
242
|
+
|
243
|
+
ConfigKit::Schema mainSchema;
|
244
|
+
mainSchema.add("people", ARRAY_TYPE, personSchema, REQUIRED);
|
245
|
+
mainSchema.add("frobnicate", BOOL_TYPE, OPTIONAL, false);
|
246
|
+
mainSchema.finalize();
|
247
|
+
~~~
|
248
|
+
|
249
|
+
A field with a nested schema is defined by calling `add(<field name>, ARRAY_TYPE or OBJECT_TYPE, <nested schema object>, <flags>)`.
|
250
|
+
|
251
|
+
The above example mainSchema says the following format is valid:
|
252
|
+
|
253
|
+
~~~javascript
|
254
|
+
{
|
255
|
+
"people": [
|
256
|
+
{
|
257
|
+
"name": "John",
|
258
|
+
"age": 12 // optional
|
259
|
+
},
|
260
|
+
{
|
261
|
+
"name": "Jane"
|
262
|
+
},
|
263
|
+
// ...
|
264
|
+
}
|
265
|
+
],
|
266
|
+
"frobinate": boolean-value
|
267
|
+
}
|
268
|
+
~~~
|
269
|
+
|
270
|
+
Nested schema fields simply accept corresponding JSON values, like this:
|
271
|
+
|
272
|
+
~~~c++
|
273
|
+
Json::Value initialValue;
|
274
|
+
initialValue["people"][0]["name"] = "John";
|
275
|
+
initialValue["people"][0]["age"] = 12;
|
276
|
+
initialValue["people"][1]["name"] = "Jane";
|
277
|
+
ConfigKit::Store store(mainSchema, initialValue);
|
278
|
+
~~~
|
279
|
+
|
280
|
+
Note that it is not possible to define a nested schema field with a default value. This is because the default values are taken from the nested schema. For example, take this code which inserts an empty object into the "people" array:
|
281
|
+
|
282
|
+
~~~c++
|
283
|
+
ConfigKit::Schema personSchema;
|
284
|
+
personSchema.add("name", STRING_TYPE, OPTIONAL, "anonymous");
|
285
|
+
personSchema.finalize();
|
286
|
+
|
287
|
+
ConfigKit::Schema mainSchema;
|
288
|
+
mainSchema.add("people", ARRAY_TYPE, personSchema, REQUIRED);
|
289
|
+
mainSchema.finalize();
|
290
|
+
|
291
|
+
Json::Value initialValue;
|
292
|
+
initialValue["people"][0] = Json::objectValue;
|
293
|
+
ConfigKit::Store store(mainSchema, initialValue);
|
294
|
+
~~~
|
295
|
+
|
296
|
+
Because personSchema defines a default value of "anonymous" on its "name" field, the above code would result in the following effective values:
|
297
|
+
|
298
|
+
~~~json
|
299
|
+
{
|
300
|
+
"people": [
|
301
|
+
{ "name": "anonymous" }
|
302
|
+
]
|
303
|
+
}
|
304
|
+
~~~
|
305
|
+
|
230
306
|
### Inspecting the schema
|
231
307
|
|
232
308
|
You can inspect the schema using the `inspect()` method. It returns a Json::Value in the following format:
|
@@ -248,6 +324,17 @@ You can inspect the schema using the `inspect()` method. It returns a Json::Valu
|
|
248
324
|
"password": {
|
249
325
|
"type": "string",
|
250
326
|
"secret": true
|
327
|
+
},
|
328
|
+
"people": {
|
329
|
+
"type": "array",
|
330
|
+
"nested_schema": {
|
331
|
+
"name": {
|
332
|
+
"type": "string"
|
333
|
+
},
|
334
|
+
"age": {
|
335
|
+
"type": "integer"
|
336
|
+
}
|
337
|
+
}
|
251
338
|
}
|
252
339
|
}
|
253
340
|
~~~
|
@@ -258,6 +345,7 @@ Description of the members:
|
|
258
345
|
- `required`: whether this key is required.
|
259
346
|
- `has_default_value`: "static" if a static a default value is defined, "dynamic" if a dynamic default value is defined.
|
260
347
|
- `default_value`: the static default value. This field is absent when there is no default value, or if the default value is dynamic.
|
348
|
+
- `nested_schema`: if this field has a [nested schema](#nested-schemas), then a description of that nested schema is stored here.
|
261
349
|
|
262
350
|
## Using the store
|
263
351
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
-
* Copyright (c) 2017 Phusion Holding B.V.
|
3
|
+
* Copyright (c) 2017-2018 Phusion Holding B.V.
|
4
4
|
*
|
5
5
|
* "Passenger", "Phusion Passenger" and "Union Station" are registered
|
6
6
|
* trademarks of Phusion Holding B.V.
|
@@ -40,7 +40,7 @@
|
|
40
40
|
#include <ConfigKit/DummyTranslator.h>
|
41
41
|
#include <ConfigKit/Utils.h>
|
42
42
|
#include <DataStructures/StringKeyTable.h>
|
43
|
-
#include <
|
43
|
+
#include <StrIntTools/StrIntUtils.h>
|
44
44
|
|
45
45
|
namespace Passenger {
|
46
46
|
namespace ConfigKit {
|
@@ -60,18 +60,22 @@ public:
|
|
60
60
|
Flags flags;
|
61
61
|
ValueGetter defaultValueGetter;
|
62
62
|
ValueFilter inspectFilter;
|
63
|
+
// Can only be non-NULL when type == ARRAY_TYPE or OBJECT_TYPE.
|
64
|
+
const Schema *nestedSchema;
|
63
65
|
|
64
66
|
Entry()
|
65
67
|
: type(UNKNOWN_TYPE),
|
66
|
-
flags(OPTIONAL)
|
68
|
+
flags(OPTIONAL),
|
69
|
+
nestedSchema(NULL)
|
67
70
|
{ }
|
68
71
|
|
69
72
|
Entry(Type _type, Flags _flags, const ValueGetter &_defaultValueGetter,
|
70
|
-
const ValueFilter &_inspectFilter)
|
73
|
+
const ValueFilter &_inspectFilter, const Schema *_nestedSchema = NULL)
|
71
74
|
: type(_type),
|
72
75
|
flags(_flags),
|
73
76
|
defaultValueGetter(_defaultValueGetter),
|
74
|
-
inspectFilter(_inspectFilter)
|
77
|
+
inspectFilter(_inspectFilter),
|
78
|
+
nestedSchema(_nestedSchema)
|
75
79
|
{ }
|
76
80
|
|
77
81
|
bool tryTypecastValue(const Json::Value &val, Json::Value &result) const {
|
@@ -117,25 +121,34 @@ public:
|
|
117
121
|
return false;
|
118
122
|
}
|
119
123
|
case ARRAY_TYPE:
|
120
|
-
|
121
|
-
|
122
|
-
|
124
|
+
case OBJECT_TYPE: {
|
125
|
+
Json::ValueType targetType;
|
126
|
+
if (type == ARRAY_TYPE) {
|
127
|
+
targetType = Json::arrayValue;
|
123
128
|
} else {
|
124
|
-
|
129
|
+
targetType = Json::objectValue;
|
125
130
|
}
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
131
|
+
if (val.isConvertibleTo(targetType)) {
|
132
|
+
if (nestedSchema != NULL) {
|
133
|
+
return tryTypecastArrayOrObjectValueWithNestedSchema(val,
|
134
|
+
result, "user_value");
|
135
|
+
} else {
|
136
|
+
result = val;
|
137
|
+
return true;
|
138
|
+
}
|
130
139
|
} else {
|
131
140
|
return false;
|
132
141
|
}
|
142
|
+
}
|
133
143
|
default:
|
134
144
|
result = val;
|
135
145
|
return true;
|
136
146
|
}
|
137
147
|
}
|
138
148
|
|
149
|
+
bool tryTypecastArrayOrObjectValueWithNestedSchema(const Json::Value &val,
|
150
|
+
Json::Value &result, const char *userOrEffectiveValue) const;
|
151
|
+
|
139
152
|
Json::Value inspect() const {
|
140
153
|
Json::Value result(Json::objectValue);
|
141
154
|
inspect(result);
|
@@ -161,6 +174,9 @@ public:
|
|
161
174
|
doc["default_value"] = Schema::getStaticDefaultValue(*this);
|
162
175
|
}
|
163
176
|
}
|
177
|
+
if (nestedSchema != NULL) {
|
178
|
+
doc["nested_schema"] = nestedSchema->inspect();
|
179
|
+
}
|
164
180
|
}
|
165
181
|
};
|
166
182
|
|
@@ -208,6 +224,11 @@ private:
|
|
208
224
|
|
209
225
|
static Json::Value getStaticDefaultValue(const Schema::Entry &entry);
|
210
226
|
|
227
|
+
static bool validateNestedSchemaArrayValue(const HashedStaticString &key,
|
228
|
+
const Entry &entry, const Json::Value &value, vector<Error> &errors);
|
229
|
+
static bool validateNestedSchemaObjectValue(const HashedStaticString &key,
|
230
|
+
const Entry &entry, const Json::Value &value, vector<Error> &errors);
|
231
|
+
|
211
232
|
public:
|
212
233
|
Schema()
|
213
234
|
: finalized(false)
|
@@ -237,6 +258,20 @@ public:
|
|
237
258
|
}
|
238
259
|
}
|
239
260
|
|
261
|
+
/**
|
262
|
+
* Register a new schema entry whose value corresponds to a nested schema.
|
263
|
+
*/
|
264
|
+
EntryBuilder add(const HashedStaticString &key, Type type,
|
265
|
+
const Schema &nestedSchema, unsigned int flags)
|
266
|
+
{
|
267
|
+
assert(!finalized);
|
268
|
+
assert(nestedSchema.finalized);
|
269
|
+
assert(type == ARRAY_TYPE || type == OBJECT_TYPE);
|
270
|
+
Entry entry(type, (Flags) flags, ValueGetter(), ValueFilter(),
|
271
|
+
&nestedSchema);
|
272
|
+
return EntryBuilder(entries.insert(key, entry)->value);
|
273
|
+
}
|
274
|
+
|
240
275
|
/**
|
241
276
|
* Register a new schema entry with a dynamic default value.
|
242
277
|
*/
|
@@ -407,7 +442,12 @@ public:
|
|
407
442
|
}
|
408
443
|
case ARRAY_TYPE:
|
409
444
|
if (value.isConvertibleTo(Json::arrayValue)) {
|
410
|
-
|
445
|
+
if (entry->nestedSchema == NULL) {
|
446
|
+
return true;
|
447
|
+
} else {
|
448
|
+
return validateNestedSchemaArrayValue(key, *entry,
|
449
|
+
value, errors);
|
450
|
+
}
|
411
451
|
} else {
|
412
452
|
errors.push_back(Error("'{{" + key + "}}' must be an array"));
|
413
453
|
return false;
|
@@ -428,7 +468,12 @@ public:
|
|
428
468
|
}
|
429
469
|
case OBJECT_TYPE:
|
430
470
|
if (value.isObject()) {
|
431
|
-
|
471
|
+
if (entry->nestedSchema == NULL) {
|
472
|
+
return true;
|
473
|
+
} else {
|
474
|
+
return validateNestedSchemaObjectValue(key, *entry,
|
475
|
+
value, errors);
|
476
|
+
}
|
432
477
|
} else {
|
433
478
|
errors.push_back(Error("'{{" + key + "}}' must be a JSON object"));
|
434
479
|
return false;
|
@@ -46,7 +46,7 @@
|
|
46
46
|
#include <LoggingKit/Assert.h>
|
47
47
|
#include <Exceptions.h>
|
48
48
|
#include <DataStructures/StringKeyTable.h>
|
49
|
-
#include <
|
49
|
+
#include <StrIntTools/StrIntUtils.h>
|
50
50
|
|
51
51
|
namespace Passenger {
|
52
52
|
namespace ConfigKit {
|
@@ -94,8 +94,16 @@ private:
|
|
94
94
|
Json::Value getEffectiveValue(const Store &store) const {
|
95
95
|
if (userValue.isNull()) {
|
96
96
|
return getDefaultValue(store);
|
97
|
-
} else {
|
97
|
+
} else if (schemaEntry->nestedSchema == NULL) {
|
98
98
|
return userValue;
|
99
|
+
} else {
|
100
|
+
// The user value may contain nulls that should
|
101
|
+
// be populated with the default value from the
|
102
|
+
// corresponding nested schema.
|
103
|
+
Json::Value result;
|
104
|
+
schemaEntry->tryTypecastArrayOrObjectValueWithNestedSchema(
|
105
|
+
userValue, result, "effective_value");
|
106
|
+
return result;
|
99
107
|
}
|
100
108
|
}
|
101
109
|
};
|
@@ -105,12 +113,20 @@ private:
|
|
105
113
|
bool updatedOnce;
|
106
114
|
|
107
115
|
static Json::Value getEffectiveValue(const Json::Value &userValue,
|
108
|
-
const Json::Value &defaultValue)
|
116
|
+
const Json::Value &defaultValue, const Schema::Entry &schemaEntry)
|
109
117
|
{
|
110
118
|
if (userValue.isNull()) {
|
111
119
|
return defaultValue;
|
112
|
-
} else {
|
120
|
+
} else if (schemaEntry.nestedSchema == NULL) {
|
113
121
|
return userValue;
|
122
|
+
} else {
|
123
|
+
// The user value may contain nulls that should
|
124
|
+
// be populated with the default value from the
|
125
|
+
// corresponding nested schema.
|
126
|
+
Json::Value result;
|
127
|
+
schemaEntry.tryTypecastArrayOrObjectValueWithNestedSchema(
|
128
|
+
userValue, result, "effective_value");
|
129
|
+
return result;
|
114
130
|
}
|
115
131
|
}
|
116
132
|
|
@@ -425,7 +441,8 @@ public:
|
|
425
441
|
const Json::Value &effectiveValue =
|
426
442
|
subdoc["effective_value"] =
|
427
443
|
getEffectiveValue(subdoc["user_value"],
|
428
|
-
subdoc["default_value"]
|
444
|
+
subdoc["default_value"],
|
445
|
+
*entry.schemaEntry);
|
429
446
|
schema->validateValue(it.getKey(), effectiveValue, tmpErrors);
|
430
447
|
|
431
448
|
result[it.getKey()] = subdoc;
|
@@ -585,6 +602,39 @@ public:
|
|
585
602
|
};
|
586
603
|
|
587
604
|
|
605
|
+
inline bool
|
606
|
+
Schema::Entry::tryTypecastArrayOrObjectValueWithNestedSchema(const Json::Value &val,
|
607
|
+
Json::Value &result, const char *userOrEffectiveValue) const
|
608
|
+
{
|
609
|
+
assert(type == ARRAY_TYPE || type == OBJECT_TYPE);
|
610
|
+
assert(nestedSchema != NULL);
|
611
|
+
assert(!val.isNull());
|
612
|
+
assert(val.isConvertibleTo(Json::arrayValue)
|
613
|
+
|| val.isConvertibleTo(Json::objectValue));
|
614
|
+
|
615
|
+
bool ok = true;
|
616
|
+
result = val;
|
617
|
+
|
618
|
+
Json::Value::iterator it, end = result.end();
|
619
|
+
for (it = result.begin(); it != end; it++) {
|
620
|
+
Json::Value &userSubdoc = *it;
|
621
|
+
if (!userSubdoc.isConvertibleTo(Json::objectValue)) {
|
622
|
+
ok = false;
|
623
|
+
continue;
|
624
|
+
}
|
625
|
+
|
626
|
+
vector<Error> errors;
|
627
|
+
Json::Value preview = Store(*nestedSchema).previewUpdate(
|
628
|
+
userSubdoc, errors);
|
629
|
+
Json::Value::const_iterator p_it, p_end = preview.end();
|
630
|
+
for (p_it = preview.begin(); p_it != p_end; p_it++) {
|
631
|
+
const Json::Value &previewSubdoc = *p_it;
|
632
|
+
userSubdoc[p_it.name()] = previewSubdoc[userOrEffectiveValue];
|
633
|
+
}
|
634
|
+
}
|
635
|
+
return ok;
|
636
|
+
}
|
637
|
+
|
588
638
|
inline Json::Value
|
589
639
|
Schema::getValueFromSubSchema(
|
590
640
|
const Store &store,
|
@@ -648,6 +698,80 @@ Schema::getStaticDefaultValue(const Schema::Entry &entry) {
|
|
648
698
|
return Store::maybeFilterSecret(storeEntry, storeEntry.getDefaultValue(Store()));
|
649
699
|
}
|
650
700
|
|
701
|
+
inline bool
|
702
|
+
Schema::validateNestedSchemaArrayValue(const HashedStaticString &key,
|
703
|
+
const Schema::Entry &entry, const Json::Value &value, vector<Error> &errors)
|
704
|
+
{
|
705
|
+
bool warnedAboutNonObjectValue = false;
|
706
|
+
bool result = true;
|
707
|
+
|
708
|
+
Json::Value::const_iterator it, end = value.end();
|
709
|
+
for (it = value.begin(); it != end; it++) {
|
710
|
+
if (!it->isConvertibleTo(Json::objectValue)) {
|
711
|
+
if (!warnedAboutNonObjectValue) {
|
712
|
+
warnedAboutNonObjectValue = true;
|
713
|
+
result = false;
|
714
|
+
errors.push_back(Error(
|
715
|
+
"'{{" + key + "}}' may only contain JSON objects"));
|
716
|
+
}
|
717
|
+
continue;
|
718
|
+
}
|
719
|
+
|
720
|
+
Store store(*entry.nestedSchema);
|
721
|
+
vector<Error> nestedSchemaErrors;
|
722
|
+
if (store.update(*it, nestedSchemaErrors)) {
|
723
|
+
continue;
|
724
|
+
}
|
725
|
+
|
726
|
+
vector<Error>::const_iterator e_it, e_end = nestedSchemaErrors.end();
|
727
|
+
for (e_it = nestedSchemaErrors.begin(); e_it != e_end; e_it++) {
|
728
|
+
errors.push_back(Error("'{{" + key + "}}' element "
|
729
|
+
+ Passenger::toString(it.index() + 1) + " is invalid: "
|
730
|
+
+ e_it->getMessage()));
|
731
|
+
}
|
732
|
+
result = false;
|
733
|
+
}
|
734
|
+
|
735
|
+
return result;
|
736
|
+
}
|
737
|
+
|
738
|
+
inline bool
|
739
|
+
Schema::validateNestedSchemaObjectValue(const HashedStaticString &key,
|
740
|
+
const Schema::Entry &entry, const Json::Value &value, vector<Error> &errors)
|
741
|
+
{
|
742
|
+
bool warnedAboutNonObjectValue = false;
|
743
|
+
bool result = true;
|
744
|
+
|
745
|
+
Json::Value::const_iterator it, end = value.end();
|
746
|
+
for (it = value.begin(); it != end; it++) {
|
747
|
+
if (!it->isConvertibleTo(Json::objectValue)) {
|
748
|
+
if (!warnedAboutNonObjectValue) {
|
749
|
+
warnedAboutNonObjectValue = true;
|
750
|
+
result = false;
|
751
|
+
errors.push_back(Error(
|
752
|
+
"'{{" + key + "}}' may only contain JSON objects"));
|
753
|
+
}
|
754
|
+
continue;
|
755
|
+
}
|
756
|
+
|
757
|
+
Store store(*entry.nestedSchema);
|
758
|
+
vector<Error> nestedSchemaErrors;
|
759
|
+
if (store.update(*it, nestedSchemaErrors)) {
|
760
|
+
continue;
|
761
|
+
}
|
762
|
+
|
763
|
+
vector<Error>::const_iterator e_it, e_end = nestedSchemaErrors.end();
|
764
|
+
for (e_it = nestedSchemaErrors.begin(); e_it != e_end; e_it++) {
|
765
|
+
errors.push_back(Error("'{{" + key + "}}' key '"
|
766
|
+
+ it.name() + "' is invalid: "
|
767
|
+
+ e_it->getMessage()));
|
768
|
+
}
|
769
|
+
result = false;
|
770
|
+
}
|
771
|
+
|
772
|
+
return result;
|
773
|
+
}
|
774
|
+
|
651
775
|
|
652
776
|
} // namespace ConfigKit
|
653
777
|
} // namespace Passenger
|
@@ -81,7 +81,7 @@
|
|
81
81
|
#define PASSENGER_API_VERSION_MAJOR 0
|
82
82
|
#define PASSENGER_API_VERSION_MINOR 3
|
83
83
|
#define PASSENGER_DEFAULT_USER "nobody"
|
84
|
-
#define PASSENGER_VERSION "
|
84
|
+
#define PASSENGER_VERSION "6.0.1"
|
85
85
|
#define POOL_HELPER_THREAD_STACK_SIZE 262144
|
86
86
|
#define PROCESS_SHUTDOWN_TIMEOUT 60
|
87
87
|
#define PROCESS_SHUTDOWN_TIMEOUT_DISPLAY "1 minute"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
-
* Copyright (c) 2010-
|
3
|
+
* Copyright (c) 2010-2018 Phusion Holding B.V.
|
4
4
|
*
|
5
5
|
* "Passenger", "Phusion Passenger" and "Union Station" are registered
|
6
6
|
* trademarks of Phusion Holding B.V.
|
@@ -24,8 +24,8 @@
|
|
24
24
|
* THE SOFTWARE.
|
25
25
|
*/
|
26
26
|
|
27
|
-
#ifndef
|
28
|
-
#define
|
27
|
+
#ifndef _PASSENGER_DATA_STRUCTURES_HASH_MAP_H_
|
28
|
+
#define _PASSENGER_DATA_STRUCTURES_HASH_MAP_H_
|
29
29
|
|
30
30
|
/*
|
31
31
|
* There are too many ways to include hash_map/unordered_map!
|
@@ -57,4 +57,4 @@
|
|
57
57
|
#define HashMap boost::unordered_map
|
58
58
|
#endif
|
59
59
|
|
60
|
-
#endif /*
|
60
|
+
#endif /* _PASSENGER_DATA_STRUCTURES_HASH_MAP_H_ */
|
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
-
* Copyright (c) 2014-
|
3
|
+
* Copyright (c) 2014-2018 Phusion Holding B.V.
|
4
4
|
*
|
5
5
|
* "Passenger", "Phusion Passenger" and "Union Station" are registered
|
6
6
|
* trademarks of Phusion Holding B.V.
|
@@ -23,14 +23,14 @@
|
|
23
23
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
24
24
|
* THE SOFTWARE.
|
25
25
|
*/
|
26
|
-
#ifndef
|
27
|
-
#define
|
26
|
+
#ifndef _PASSENGER_DATA_STRUCTURES_HASHED_STATIC_STRING_H_
|
27
|
+
#define _PASSENGER_DATA_STRUCTURES_HASHED_STATIC_STRING_H_
|
28
28
|
|
29
29
|
#include <boost/cstdint.hpp>
|
30
30
|
#include <oxt/macros.hpp>
|
31
31
|
#include <string>
|
32
32
|
#include <StaticString.h>
|
33
|
-
#include <
|
33
|
+
#include <Algorithms/Hasher.h>
|
34
34
|
|
35
35
|
namespace Passenger {
|
36
36
|
|
@@ -101,4 +101,4 @@ public:
|
|
101
101
|
|
102
102
|
} // namespace Passenger
|
103
103
|
|
104
|
-
#endif /*
|
104
|
+
#endif /* _PASSENGER_DATA_STRUCTURES_HASHED_STATIC_STRING_H_ */
|
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
-
* Copyright (c) 2014-
|
3
|
+
* Copyright (c) 2014-2018 Phusion Holding B.V.
|
4
4
|
*
|
5
5
|
* "Passenger", "Phusion Passenger" and "Union Station" are registered
|
6
6
|
* trademarks of Phusion Holding B.V.
|
@@ -36,8 +36,8 @@
|
|
36
36
|
#include <MemoryKit/palloc.h>
|
37
37
|
#include <MemoryKit/mbuf.h>
|
38
38
|
#include <StaticString.h>
|
39
|
-
#include <
|
40
|
-
#include <
|
39
|
+
#include <StrIntTools/StrIntUtils.h>
|
40
|
+
#include <Algorithms/Hasher.h>
|
41
41
|
|
42
42
|
namespace Passenger {
|
43
43
|
|